feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public interface EncodingAlgorithm {
public Object decodeFromBytes(byte[] b, int start, int length) throws EncodingAlgorithmException;
public Object decodeFromInputStream(InputStream s) throws EncodingAlgorithmException, IOException;
public void encodeToOutputStream(Object data, OutputStream s) throws EncodingAlgorithmException, IOException;
public Object convertFromCharacters(char[] ch, int start, int length) throws EncodingAlgorithmException;
public void convertToCharacters(Object data, StringBuffer s) throws EncodingAlgorithmException;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
public class EncodingAlgorithmException extends FastInfosetException {
public EncodingAlgorithmException(String message) {
super(message);
}
public EncodingAlgorithmException(String message, Exception e) {
super(message, e);
}
public EncodingAlgorithmException(Exception e) {
super(e);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
/**
* The indexes of built-in encoding algorithms.
*
* <p>The indexes of the built-in encoding algorithms are specified
* in ITU-T Rec. X.891 | ISO/IEC 24824-1 (Fast Infoset), clause
* 10. The indexes start from 0 instead of 1 as specified.<p>
*
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmContentHandler
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmAttributes
*/
public final class EncodingAlgorithmIndexes {
public static final int HEXADECIMAL = 0;
public static final int BASE64 = 1;
public static final int SHORT = 2;
public static final int INT = 3;
public static final int LONG = 4;
public static final int BOOLEAN = 5;
public static final int FLOAT = 6;
public static final int DOUBLE = 7;
public static final int UUID = 8;
public static final int CDATA = 9;
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
/**
* An external vocabulary.
* <p>
* An external vocabulary has a URI that refers to a vocabulary.
*
* @author Paul.Sandoz@Sun.Com
*/
public class ExternalVocabulary {
/**
* A URI that refers to the external vocabulary.
*/
public final String URI;
/**
* The vocabulary that is refered to by the URI.
*/
public final Vocabulary vocabulary;
public ExternalVocabulary(String URI, Vocabulary vocabulary) {
if (URI == null || vocabulary == null) {
throw new IllegalArgumentException();
}
this.URI = URI;
this.vocabulary = vocabulary;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
public class FastInfosetException extends Exception {
public FastInfosetException(String message) {
super(message);
}
public FastInfosetException(String message, Exception e) {
super(message, e);
}
public FastInfosetException(Exception e) {
super(e);
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
import java.util.Map;
/**
* A general interface for parsers of fast infoset documents.
*
* <p>
* This interface contains common methods that are not specific to any
* API associated with the parsing of fast infoset documents.
*
* @author Paul.Sandoz@Sun.Com
*/
public interface FastInfosetParser {
/**
* The property name to be used for getting and setting the string
* interning property of a parser.
*
*/
public static final String STRING_INTERNING_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/string-interning";
/**
* The property name to be used for getting and setting the buffer size
* of a parser.
*/
public static final String BUFFER_SIZE_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/buffer-size";
/**
* The property name to be used for getting and setting the
* Map containing encoding algorithms.
*
*/
public static final String REGISTERED_ENCODING_ALGORITHMS_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/registered-encoding-algorithms";
/**
* The property name to be used for getting and setting the
* Map containing external vocabularies.
*
*/
public static final String EXTERNAL_VOCABULARIES_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/external-vocabularies";
/**
* The property name to be used for getting and setting the
* flag, which will indicate whether underlying Parser's
* input stream should be really closed
*/
public static final String FORCE_STREAM_CLOSE_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/force-stream-close";
/**
* Set the string interning property.
*
* <p>If the string interning property is set to true then
* <code>String</code> objects instantiated for [namespace name], [prefix]
* and [local name] infoset properties will be interned using the method
* {@link String#intern()}.
*
* @param stringInterning The string interning property.
*/
public void setStringInterning(boolean stringInterning);
/**
* Return the string interning property.
*
* @return The string interning property.
*/
public boolean getStringInterning();
/**
* Set the buffer size.
*
* <p>The size of the buffer for parsing is set using this
* method. Requests for sizes smaller then the current size will be ignored.
* Otherwise the buffer will be resized when the next parse is performed.<p>
*
* @param bufferSize The requested buffer size.
*/
public void setBufferSize(int bufferSize);
/**
* Get the buffer size.
*
* @return The buffer size.
*/
public int getBufferSize();
/**
* Sets the set of registered encoding algorithms.
*
* @param algorithms The set of registered algorithms.
*/
public void setRegisteredEncodingAlgorithms(Map algorithms);
/**
* Gets the set of registered encoding algorithms.
*
* @return The set of registered algorithms.
*/
public Map getRegisteredEncodingAlgorithms();
/**
* Set the map of referenced external vocabularies.
* <p>
* The map (but not the keys and values) be cloned.
*
* @param referencedVocabualries the map of URI to vocabulary.
*/
public void setExternalVocabularies(Map referencedVocabualries);
/**
* Get the map of referenced external vocabularies.
*
* @return the map of URI to vocabulary.
* @deprecated
* The map returned will not be the same instance and contain
* the same entries as the map set by {@link #setExternalVocabularies}
* method.
*/
public Map getExternalVocabularies();
/**
* Set the parse fragments property.
*
* <p>If the parse fragments property is set to true then
* fragments of an XML infoset may be parsed.
*
* @param parseFragments The parse fragments property.
*/
public void setParseFragments(boolean parseFragments);
/**
* Return the parse fragments property.
*
* @return The parse fragments property.
*/
public boolean getParseFragments();
/**
* Set the force stream close property.
*
* <p>If the force stream property is set to true then
* Parser's underlying InputStream will be closed.
*
* @param needForceStreamClose The force stream close property.
*/
public void setForceStreamClose(boolean needForceStreamClose);
/**
* Return the force stream close property.
*
* @return The force stream close property.
*/
public boolean getForceStreamClose();
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
import java.io.OutputStream;
import org.xml.sax.ContentHandler;
import org.xml.sax.ext.LexicalHandler;
import javax.xml.transform.sax.SAXResult;
import com.sun.xml.internal.fastinfoset.sax.SAXDocumentSerializer;
/**
* A JAXP Result implementation that supports the serialization to fast
* infoset documents for use by applications that expect a Result.
*
* <P>The derivation of FIResult from SAXResult is an implementation
* detail.<P>
*
* <P>This implementation is designed for interoperation with JAXP and is not
* not designed with performance in mind. It is recommended that for performant
* interoperation alternative serializer specific solutions be used.<P>
*
* <P>General applications shall not call the following methods:
* <UL>
* <LI>setHandler</LI>
* <LI>setLexicalHandler</LI>
* <LI>setSystemId</LI>
* </UL>
* </P>
*/
public class FastInfosetResult extends SAXResult {
OutputStream _outputStream;
public FastInfosetResult(OutputStream outputStream) {
_outputStream = outputStream;
}
public ContentHandler getHandler() {
ContentHandler handler = super.getHandler();
if (handler == null) {
handler = new SAXDocumentSerializer();
setHandler(handler);
}
((SAXDocumentSerializer) handler).setOutputStream(_outputStream);
return handler;
}
public LexicalHandler getLexicalHandler() {
return (LexicalHandler) getHandler();
}
public OutputStream getOutputStream() {
return _outputStream;
}
public void setOutputStream(OutputStream outputStream) {
_outputStream = outputStream;
}
}

View File

@@ -0,0 +1,362 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
import java.io.OutputStream;
import java.util.Map;
/**
* A general interface for serializers of fast infoset documents.
*
* <p>
* This interface contains common methods that are not specific to any
* API associated with the serialization of XML Infoset to fast infoset
* documents.
*
* @author Paul.Sandoz@Sun.Com
*/
public interface FastInfosetSerializer {
/**
* The feature to ignore the document type declaration and the
* internal subset.
* <p>
* The default value is false. If true a serializer shall ignore document
* type declaration and the internal subset.
*/
public static final String IGNORE_DTD_FEATURE =
"http://jvnet.org/fastinfoset/serializer/feature/ignore/DTD";
/**
* The feature to ignore comments.
* <p>
* The default value is false. If true a serializer shall ignore comments
* and shall not serialize them.
*/
public static final String IGNORE_COMMENTS_FEATURE =
"http://jvnet.org/fastinfoset/serializer/feature/ignore/comments";
/**
* The feature to ignore processing instructions.
* <p>
* The default value is false. If true a serializer shall ignore processing
* instructions and shall not serialize them.
*/
public static final String IGNORE_PROCESSING_INSTRUCTIONS_FEATURE =
"http://jvnet.org/fastinfoset/serializer/feature/ignore/processingInstructions";
/**
* The feature to ignore text content that consists completely of white
* space characters.
* <p>
* The default value is false. If true a serializer shall ignore text
* content that consists completely of white space characters.
*/
public static final String IGNORE_WHITE_SPACE_TEXT_CONTENT_FEATURE =
"http://jvnet.org/fastinfoset/serializer/feature/ignore/whiteSpaceTextContent";
/**
* The property name to be used for getting and setting the buffer size
* of a parser.
*/
public static final String BUFFER_SIZE_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/buffer-size";
/**
* The property name to be used for getting and setting the
* Map containing encoding algorithms.
*
*/
public static final String REGISTERED_ENCODING_ALGORITHMS_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/registered-encoding-algorithms";
/**
* The property name to be used for getting and setting the
* Map containing external vocabularies.
*
*/
public static final String EXTERNAL_VOCABULARIES_PROPERTY =
"http://jvnet.org/fastinfoset/parser/properties/external-vocabularies";
/**
* The default minimum size of the character content chunks,
* that will be indexed.
*/
public final static int MIN_CHARACTER_CONTENT_CHUNK_SIZE = 0;
/**
* The default maximum size of the character content chunks,
* that will be indexed.
*/
public final static int MAX_CHARACTER_CONTENT_CHUNK_SIZE = 32;
/**
* The default value for limit on the size of indexed Map for attribute values
* Limit is measured in bytes not in number of entries
*/
public static final int CHARACTER_CONTENT_CHUNK_MAP_MEMORY_CONSTRAINT = Integer.MAX_VALUE;
/**
* The default minimum size of the attribute values, that will be indexed.
*/
public final static int MIN_ATTRIBUTE_VALUE_SIZE = 0;
/**
* The default maximum size of the attribute values, that will be indexed.
*/
public final static int MAX_ATTRIBUTE_VALUE_SIZE = 32;
/**
* The default value for limit on the size of indexed Map for attribute values
* Limit is measured in bytes not in number of entries
*/
public static final int ATTRIBUTE_VALUE_MAP_MEMORY_CONSTRAINT = Integer.MAX_VALUE;
/**
* The character encoding scheme string for UTF-8.
*/
public static final String UTF_8 = "UTF-8";
/**
* The character encoding scheme string for UTF-16BE.
*/
public static final String UTF_16BE = "UTF-16BE";
/**
* Set the {@link #IGNORE_DTD_FEATURE}.
* @param ignoreDTD true if the feature shall be ignored.
*/
public void setIgnoreDTD(boolean ignoreDTD);
/**
* Get the {@link #IGNORE_DTD_FEATURE}.
* @return true if the feature is ignored, false otherwise.
*/
public boolean getIgnoreDTD();
/**
* Set the {@link #IGNORE_COMMENTS_FEATURE}.
* @param ignoreComments true if the feature shall be ignored.
*/
public void setIgnoreComments(boolean ignoreComments);
/**
* Get the {@link #IGNORE_COMMENTS_FEATURE}.
* @return true if the feature is ignored, false otherwise.
*/
public boolean getIgnoreComments();
/**
* Set the {@link #IGNORE_PROCESSING_INSTRUCTIONS_FEATURE}.
* @param ignoreProcesingInstructions true if the feature shall be ignored.
*/
public void setIgnoreProcesingInstructions(boolean ignoreProcesingInstructions);
/**
* Get the {@link #IGNORE_PROCESSING_INSTRUCTIONS_FEATURE}.
* @return true if the feature is ignored, false otherwise.
*/
public boolean getIgnoreProcesingInstructions();
/**
* Set the {@link #IGNORE_WHITE_SPACE_TEXT_CONTENT_FEATURE}.
* @param ignoreWhiteSpaceTextContent true if the feature shall be ignored.
*/
public void setIgnoreWhiteSpaceTextContent(boolean ignoreWhiteSpaceTextContent);
/**
* Get the {@link #IGNORE_WHITE_SPACE_TEXT_CONTENT_FEATURE}.
* @return true if the feature is ignored, false otherwise.
*/
public boolean getIgnoreWhiteSpaceTextContent();
/**
* Sets the character encoding scheme.
*
* The character encoding can be either UTF-8 or UTF-16BE for the
* the encoding of chunks of CIIs, the [normalized value]
* property of attribute information items, comment information
* items and processing instruction information items.
*
* @param characterEncodingScheme The set of registered algorithms.
*/
public void setCharacterEncodingScheme(String characterEncodingScheme);
/**
* Gets the character encoding scheme.
*
* @return The character encoding scheme.
*/
public String getCharacterEncodingScheme();
/**
* Sets the set of registered encoding algorithms.
*
* @param algorithms The set of registered algorithms.
*/
public void setRegisteredEncodingAlgorithms(Map algorithms);
/**
* Gets the set of registered encoding algorithms.
*
* @return The set of registered algorithms.
*/
public Map getRegisteredEncodingAlgorithms();
/**
* Gets the minimum size of character content chunks
* that will be indexed.
*
* @return The minimum character content chunk size.
*/
public int getMinCharacterContentChunkSize();
/**
* Sets the minimum size of character content chunks
* that will be indexed.
*
* @param size the minimum character content chunk size.
*/
public void setMinCharacterContentChunkSize(int size);
/**
* Gets the maximum size of character content chunks
* that might be indexed.
*
* @return The maximum character content chunk size.
*/
public int getMaxCharacterContentChunkSize();
/**
* Sets the maximum size of character content chunks
* that might be indexed.
*
* @param size the maximum character content chunk size.
*/
public void setMaxCharacterContentChunkSize(int size);
/**
* Gets the limit on the memory size, allocated for indexed character
* content chunks.
*
* @return the limit on the memory size, allocated for indexed character
* content chunks.
*/
public int getCharacterContentChunkMapMemoryLimit();
/**
* Sets the limit on the memory size, allocated for indexed character
* content chunks.
*
* @param size the limit on the memory size, allocated for indexed character
* content chunks.
*/
public void setCharacterContentChunkMapMemoryLimit(int size);
/**
* Gets the minimum size of attribute values
* that will be indexed.
*
* @return The minimum attribute values size.
*/
public int getMinAttributeValueSize();
/**
* Sets the minimum size of attribute values
* that will be indexed.
*
* @param size the minimum attribute values size.
*/
public void setMinAttributeValueSize(int size);
/**
* Gets the maximum size of attribute values
* that will be indexed.
*
* @return The maximum attribute values size.
*/
public int getMaxAttributeValueSize();
/**
* Sets the maximum size of attribute values
* that will be indexed.
*
* @param size the maximum attribute values size.
*/
public void setMaxAttributeValueSize(int size);
/**
* Gets the limit on the memory size of Map of attribute values
* that will be indexed.
*
* @return The attribute value size limit.
*/
public int getAttributeValueMapMemoryLimit();
/**
* Sets the limit on the memory size of Map of attribute values
* that will be indexed.
*
* @param size The attribute value size limit. Any value less
* that a length of size limit will be indexed.
*/
public void setAttributeValueMapMemoryLimit(int size);
/**
* Set the external vocabulary that shall be used when serializing.
*
* @param v the vocabulary.
*/
public void setExternalVocabulary(ExternalVocabulary v);
/**
* Set the application data to be associated with the serializer vocabulary.
*
* @param data the application data.
*/
public void setVocabularyApplicationData(VocabularyApplicationData data);
/**
* Get the application data associated with the serializer vocabulary.
*
* @return the application data.
*/
public VocabularyApplicationData getVocabularyApplicationData();
/**
* Reset the serializer for reuse serializing another XML infoset.
*/
public void reset();
/**
* Set the OutputStream to serialize the XML infoset to a
* fast infoset document.
*
* @param s the OutputStream where the fast infoset document is written to.
*/
public void setOutputStream(OutputStream s);
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
import java.io.InputStream;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import com.sun.xml.internal.fastinfoset.sax.SAXDocumentParser;
/**
* A JAXP Source implementation that supports the parsing fast
* infoset document for use by applications that expect a Source.
*
* <P>The derivation of FISource from SAXSource is an implementation
* detail.<P>
*
* <P>This implementation is designed for interoperation with JAXP and is not
* not designed with performance in mind. It is recommended that for performant
* interoperation alternative parser specific solutions be used.<P>
*
* <P>Applications shall obey the following restrictions:
* <UL>
* <LI>The setXMLReader and setInputSource shall not be called.</LI>
* <LI>The XMLReader object obtained by the getXMLReader method shall
* be used only for parsing the InputSource object returned by
* the getInputSource method.</LI>
* <LI>The InputSource object obtained by the getInputSource method shall
* be used only for being parsed by the XMLReader object returned by
* the getXMLReader method.</LI>
* </UL>
* </P>
*/
public class FastInfosetSource extends SAXSource {
public FastInfosetSource(InputStream inputStream) {
super(new InputSource(inputStream));
}
public XMLReader getXMLReader() {
XMLReader reader = super.getXMLReader();
if (reader == null) {
reader = new SAXDocumentParser();
setXMLReader(reader);
}
((SAXDocumentParser) reader).setInputStream(getInputStream());
return reader;
}
public InputStream getInputStream() {
return getInputSource().getByteStream();
}
public void setInputStream(InputStream inputStream) {
setInputSource(new InputSource(inputStream));
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
public final class RestrictedAlphabet {
public static final String NUMERIC_CHARACTERS = "0123456789-+.E ";
public static final int NUMERIC_CHARACTERS_INDEX = 0;
public static final String DATE_TIME_CHARACTERS = "0123456789-:TZ ";
public static final int DATE_TIME_CHARACTERS_INDEX = 1;
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* A canonical representation of a vocabulary.
* <p>
* Each vocabulary table is represented as a Set. A vocabulary table entry is
* represented as an item in the Set.
* <p>
* The 1st item contained in a Set is assigned the smallest index value,
* n say (where n >= 0). The 2nd item is assigned an index value of n + 1. The kth
* item is assigned an index value of n + (k - 1).
* <p>
* A Fast Infoset parser/serializer implementation will tranform the canonical
* representation of a Vocabulary instance into a more optimal form suitable
* for the efficient usage according to the API implemented by the parsers and
* serialziers.
*/
public class Vocabulary {
/**
* The restricted alphabet table, containing String objects.
*/
public final Set restrictedAlphabets = new LinkedHashSet();
/**
* The encoding algorithm table, containing String objects.
*/
public final Set encodingAlgorithms = new LinkedHashSet();
/**
* The prefix table, containing String objects.
*/
public final Set prefixes = new LinkedHashSet();
/**
* The namespace name table, containing String objects.
*/
public final Set namespaceNames = new LinkedHashSet();
/**
* The local name table, containing String objects.
*/
public final Set localNames = new LinkedHashSet();
/**
* The "other NCName" table, containing String objects.
*/
public final Set otherNCNames = new LinkedHashSet();
/**
* The "other URI" table, containing String objects.
*/
public final Set otherURIs = new LinkedHashSet();
/**
* The "attribute value" table, containing String objects.
*/
public final Set attributeValues = new LinkedHashSet();
/**
* The "other string" table, containing String objects.
*/
public final Set otherStrings = new LinkedHashSet();
/**
* The "character content chunk" table, containing String objects.
*/
public final Set characterContentChunks = new LinkedHashSet();
/**
* The element table, containing QName objects.
*/
public final Set elements = new LinkedHashSet();
/**
* The attribute table, containing QName objects.
*/
public final Set attributes = new LinkedHashSet();
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset;
/**
* Application data that can be associated with a vocabulary.
* <p>
* The application will implement this inteface and provide
* application specific functionality related to a vocabulary.
*
* @author Paul.Sandoz@Sun.Com
*/
public interface VocabularyApplicationData {
/**
* Clear the vocabulary application data.
* <p>
* This method will be invoked when a parser or serializer clears
* the vocabulary.
*/
public void clear();
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax;
import org.xml.sax.Attributes;
/**
* Interface for a list of XML attributes that may contain encoding algorithm
* data.
* <p>
* Implementations shall ensure that the {@link Attributes#getValue(int)} method
* correctly returns a String object even if the attribute is represented
* as algorithm data.
* <p>
* If an attribute has algorithm data then the {@link #getAlgorithmData} method
* shall return a non <code>null</code> value.
*
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.FastInfosetReader
* @see org.xml.sax.XMLReader
*/
public interface EncodingAlgorithmAttributes extends Attributes {
/**
* Return the URI of the encoding algorithm.
*
* <p>If the algorithm data corresponds to a built-in encoding algorithm
* then the null is returned.</p>
*
* <p>If the algorithm data corresponds to an application-defined encoding
* algorithm then the URI of the algorithm is returned.</p>
*
* <p>If {@link #getAlgorithmData(int)} returns null then the result of
* this method is undefined.<p>
*
* @param index The attribute index (zero-based).
* @return The URI. If the index is out of range then null is returned.
*/
public String getAlgorithmURI(int index);
/**
* Return the index of the encoding algorithm.
*
* <p>If {@link #getAlgorithmData(int)} returns null then the result of
* this method is undefined.<p>
*
* @param index The attribute index (zero-based).
* @return The algorithm index. If index is out of range then -1 is returned.
* @see com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes
*/
public int getAlgorithmIndex(int index);
/**
* Return the data of the encoding algorithm.
*
* <p>If the algorithm data corresponds to a built-in encoding algorithm
* then an Object corresponding to the Java primitive type is returned.</p>
*
* <p>If the algorithm data corresponds to an application-defined encoding
* algorithm then an Object that is an instance of <code>byte[]</code>
* is returned if there is no EncodingAlgorithm registered for the
* application-defined encoding algorithm URI. Otherwise, an Object produced
* from the registeredEncodingAlgorithm is returned.</p>
*
* <p>If there no encoding algorithm data associated an attribute then
* <code>null</code> is returned.<p>
*
* @param index The attribute index (zero-based).
* @return The data. If the index is out of range then null is returned.
*/
public Object getAlgorithmData(int index);
/**
* Return the alphabet associated with the attribute value.
*
* @param index The attribute index (zero-based).
* @return The alphabet.
* If the index is out of range then null is returned.
* If there is is no alphabet then null is returned.
*/
public String getAlpababet(int index);
/**
* Return the whether the attribute value should be indexed or not.
*
* @param index The attribute index (zero-based).
* @return True if attribute value should be indexed, otherwise false.
*/
public boolean getToIndex(int index);
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax;
import org.xml.sax.SAXException;
/**
* SAX2 extention handler to receive notification of encoding algorithm data.
*
* <p>This is an optional extension handler for SAX2. XML readers are not
* required to recognize this handler, and it is not part of core-only
* SAX2 distributions.</p>
*
* <p>This interface may be used with with a Fast Infoset
* SAX parser to receive notification of encoding algorithm data specified
* in ITU-T Rec. X.891 | ISO/IEC 24824-1 (Fast Infoset) clause 10 and for
* application defined encoding algorithms specified as part of the
* initial vocabulary of a fast infoset document.<p>
*
* <p>To set the EncodingAlgorithmContentHandler for an XML reader, use the
* {@link org.xml.sax.XMLReader#setProperty setProperty} method
* with the property name
* <code>URI TO BE DEFINED</code>
* and an object implementing this interface (or null) as the value.
* If the reader does not report primitive data types, it will throw a
* {@link org.xml.sax.SAXNotRecognizedException SAXNotRecognizedException}</p>
*
* <p>To set the EncodingAlgorithmContentHandler for an Fast Infoset reader, use
* {@link com.sun.xml.internal.org.jvnet.fastinfoset.sax.FastInfosetReader#setEncodingAlgorithmContentHandler
* setEncodingAlgorithmContentHandler} method.<p>
*
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.PrimitiveTypeContentHandler
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.FastInfosetReader
* @see org.xml.sax.XMLReader
*/
public interface EncodingAlgorithmContentHandler {
/**
* Receive notification of encoding algorithm data as an array
* of byte.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing encoding algorithm data.<p>
*
* <p>The Parser will call the method of this interface to report each
* encoding algorithm data. Parsers MUST return all contiguous
* characters in a single chunk</p>
*
* <p>Parsers may return all contiguous bytes in a single chunk, or
* they may split it into several chunks providing that the length of
* each chunk is of the required length to successfully apply the
* encoding algorithm to the chunk.</p>
*
* @param URI the URI of the encoding algorithm
* @param algorithm the encoding algorithm index
* @param b the array of byte
* @param start the start position in the array
* @param length the number of byte to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
* @see com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes
*/
public void octets(String URI, int algorithm, byte[] b, int start, int length) throws SAXException;
/**
* Receive notification of encoding algorithm data as an object.
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing encoding algorithm data that is converted from an
* array of byte to an object more suitable for processing.<p>
*
* @param URI the URI of the encoding algorithm
* @param algorithm the encoding algorithm index
* @param o the encoding algorithm object
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
* @see com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes
*/
public void object(String URI, int algorithm, Object o) throws SAXException;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
public interface ExtendedContentHandler extends ContentHandler {
/**
* Receive notification of character data.
*
* @param ch the characters from the XML document
* @param start the start position in the array
* @param length the number of characters to read from the array
* @param index true if the characters are indexed, otherwise false.
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
* @see ContentHandler#characters
*/
public void characters(char[] ch, int start, int length, boolean index) throws SAXException;
}

View File

@@ -0,0 +1,255 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax;
import java.io.IOException;
import java.io.InputStream;
import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetParser;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.DeclHandler;
import org.xml.sax.ext.LexicalHandler;
/**
* Interface for reading an Fast Infoset document using callbacks.
*
* <p>FastInfosetReader is the interface that a Fast Infoset parser's
* SAX2 driver must implement. This interface allows an application to
* to register Fast Infoset specific event handlers for encoding algorithms.</p>
*
* <p>The reception of encoding algorithm events is determined by
* the registration of:
* <ul>
* <li>A {@link PrimitiveTypeContentHandler}, for the recieving of events,
* associated with built-in encoding algorithms, for decoded data that
* can be reported as Java primitive types.</li>
* <li>A {@link EncodingAlgorithmContentHandler}, for the recieving of events,
* associated with built-in and application-defined encoding algorithms, for
* decoded data that can be reported as an array of octets or as a Java
* Object.</li>
* <li>{@link com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm} implementations, for
* the receiving of events, associated with application defined algorithms.
* for decoded data that shall be reported as a Java Object by way of the
* registered EncodingAlgorithmContentHandler.</li>
* </ul>
* </p>
*
* <p>The reporting of element content events for built-in algorithms
* is determimed by the following:
* <ul>
* <li>If a PrimitiveContentHandler is registered then decoded data is reported
* as Java primitive types using the corresponding methods on the PrimitiveContentHandler
* interface.</li>
* <li>If a PrimitiveContentHandler is not registered and a
* EncodingAlgorithmContentHandler is registered then decoded data is reported
* as Java Objects using {@link EncodingAlgorithmContentHandler#object(String, int, Object)}.
* An Object shall correspond to the Java primitive type that
* would otherwise be reported using the PrimitiveContentHandler.</li>
* <li>If neither is registered then then decoded data is reported as characters.</li>
* </ul>
* </p>
*
* <p>The reporting of element content events for application-defined algorithms
* is determimed by the following:
* <ul>
* <li>If an EncodingAlgorithmContentHandler is registered and there is no
* EncodingAlgorithm registered for an application-defined encoding algorithm
* then decoded data for such an algoroithm is reported as an array of octets
* using {@link EncodingAlgorithmContentHandler#octets(String, int, byte[], int, int)};
* otherwise</li>
* <li>If there is an EncodingAlgorithm registered for the application-defined
* encoding algorithm then the decoded data is reported as a Java Object,
* returned by decoding according to the EncodingAlgorithm, using
* {@link EncodingAlgorithmContentHandler#object(String, int, Object)}.</li>
* </ul>
* </p>
*
* <p>The reporting of attribute values for encoding algorithms is achieved using
* {@link EncodingAlgorithmAttributes} that extends {@link org.xml.sax.Attributes}.
* The registered ContentHandler may cast the attr paramter of the
* {@link org.xml.sax.ContentHandler#startElement(String, String, String, org.xml.sax.Attributes)}
* to the EncodingAlgorithmAttributes interface to access to encoding algorithm information.
* </p>
*
* <p>The reporting of attribute values for built-in algorithms
* is determimed by the following:
* <ul>
* <li>If a PrimitiveContentHandler or EncodingAlgorithmContentHandler is
* registered then decoded data is reported as Java Objects corresponding
* to the Java primitive types. The Java Objects may be obtained using
* {@link EncodingAlgorithmAttributes#getAlgorithmData(int)}.
* <li>If neither is registered then then decoded data is reported as characters.</li>
* </ul>
* </p>
*
* <p>The reporting of attribute values for application-defined algorithms
* is determimed by the following:
* <ul>
* <li>If an EncodingAlgorithmContentHandler is registered and there is no
* EncodingAlgorithm registered for an application-defined encoding algorithm
* then decoded data for such an algoroithm is reported as Java Object,
* that is an instance of <code>byte[]</code>,
* using {@link EncodingAlgorithmAttributes#getAlgorithmData(int)};
* otherwise</li>
* <li>If there is an EncodingAlgorithm registered for the application-defined
* encoding algorithm then the decoded data is reported as a Java Object,
* returned by decoding according to the EncodingAlgorithm, using
* {@link EncodingAlgorithmAttributes#getAlgorithmData(int)}.</li>
* </ul>
* </p>
*
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.PrimitiveTypeContentHandler
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmContentHandler
* @see org.xml.sax.XMLReader
* @see org.xml.sax.ContentHandler
*/
public interface FastInfosetReader extends XMLReader, FastInfosetParser {
/**
* The property name to be used for getting and setting the
* EncodingAlgorithmContentHandler.
*
*/
public static final String ENCODING_ALGORITHM_CONTENT_HANDLER_PROPERTY =
"http://jvnet.org/fastinfoset/sax/properties/encoding-algorithm-content-handler";
/**
* The property name to be used for getting and setting the
* PrimtiveTypeContentHandler.
*
*/
public static final String PRIMITIVE_TYPE_CONTENT_HANDLER_PROPERTY =
"http://jvnet.org/fastinfoset/sax/properties/primitive-type-content-handler";
/**
* Parse a fast infoset document from an InputStream.
*
* <p>The application can use this method to instruct the Fast Infoset
* reader to begin parsing a fast infoset document from a byte stream.</p>
*
* <p>Applications may not invoke this method while a parse is in progress
* (they should create a new XMLReader instead for each nested XML document).
* Once a parse is complete, an application may reuse the same
* FastInfosetReader object, possibly with a different byte stream.</p>
*
* <p>During the parse, the FastInfosetReader will provide information about
* the fast infoset document through the registered event handlers.<p>
*
* <p> This method is synchronous: it will not return until parsing has ended.
* If a client application wants to terminate parsing early, it should throw
* an exception.<p>
*
* @param s The byte stream to parse from.
*/
public void parse(InputStream s) throws IOException, FastInfosetException, SAXException;
/**
* Allow an application to register a lexical handler.
*
* <p>Applications may register a new or different handler in the
* middle of a parse, and the SAX parser must begin using the new
* handler immediately.</p>
*
* @param handler The lexical handler.
* @see #getLexicalHandler
*/
public void setLexicalHandler(LexicalHandler handler);
/**
* Return the current lexical handler.
*
* @return The current lexical handler, or null if none
* has been registered.
* @see #setLexicalHandler
*/
public LexicalHandler getLexicalHandler();
/**
* Allow an application to register a DTD declaration handler.
*
* <p>Applications may register a new or different handler in the
* middle of a parse, and the SAX parser must begin using the new
* handler immediately.</p>
*
* @param handler The DTD declaration handler.
* @see #getLexicalHandler
*/
public void setDeclHandler(DeclHandler handler);
/**
* Return the current DTD declaration handler.
*
* @return The current DTD declaration handler, or null if none
* has been registered.
* @see #setLexicalHandler
*/
public DeclHandler getDeclHandler();
/**
* Allow an application to register an encoding algorithm handler.
*
* <p>Applications may register a new or different handler in the
* middle of a parse, and the SAX parser must begin using the new
* handler immediately.</p>
*
* @param handler The encoding algorithm handler.
* @see #getEncodingAlgorithmContentHandler
*/
public void setEncodingAlgorithmContentHandler(EncodingAlgorithmContentHandler handler);
/**
* Return the current encoding algorithm handler.
*
* @return The current encoding algorithm handler, or null if none
* has been registered.
* @see #setEncodingAlgorithmContentHandler
*/
public EncodingAlgorithmContentHandler getEncodingAlgorithmContentHandler();
/**
* Allow an application to register a primitive type handler.
*
* <p>Applications may register a new or different handler in the
* middle of a parse, and the SAX parser must begin using the new
* handler immediately.</p>
*
* @param handler The primitive type handler.
* @see #getPrimitiveTypeContentHandler
*/
public void setPrimitiveTypeContentHandler(PrimitiveTypeContentHandler handler);
/**
* Return the current primitive type handler.
*
* @return The current primitive type handler, or null if none
* has been registered.
* @see #setPrimitiveTypeContentHandler
*/
public PrimitiveTypeContentHandler getPrimitiveTypeContentHandler();
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax;
import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetSerializer;
import org.xml.sax.ContentHandler;
import org.xml.sax.ext.LexicalHandler;
public interface FastInfosetWriter extends ContentHandler, LexicalHandler,
EncodingAlgorithmContentHandler, PrimitiveTypeContentHandler,
RestrictedAlphabetContentHandler, ExtendedContentHandler,
FastInfosetSerializer {
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax;
import org.xml.sax.SAXException;
/**
* SAX2 extention handler to receive notification of character data as
* primtive types.
*
* <p>This is an optional extension handler for SAX2. XML readers are not
* required to recognize this handler, and it is not part of core-only
* SAX2 distributions.</p>
*
* <p>This interface may be used with with a Fast Infoset
* SAX parser to receive notification of data encoded using the
* following built-in encoding algorithms specified in ITU-T Rec. X.891 | ISO/IEC 24824-1
* (Fast Infoset), clause 10: "boolean", "base64", "short", "int", "long",
* "float", "double" and "uuid" encoding algorithms.<p>
*
* <p>To set the PrimitiveTypeContentHandler for an XML reader, use the
* {@link org.xml.sax.XMLReader#setProperty setProperty} method
* with the property name
* <code>URI TO BE DEFINED</code>
* and an object implementing this interface (or null) as the value.
* If the reader does not report primitive data types, it will throw a
* {@link org.xml.sax.SAXNotRecognizedException SAXNotRecognizedException}</p>
*
* <p>To set the PrimitiveTypeContentHandler for an Fast Infoset reader, use
* {@link com.sun.xml.internal.org.jvnet.fastinfoset.sax.FastInfosetReader#setPrimitiveTypeContentHandler
* setPrimitiveTypeContentHandler} method.<p>
* <p>The Parser will call methods of this interface to report each
* chunk of character data that has been converted to an array of primitive
* types, for example an array of integer or an array of float. Parsers may
* return all contiguous primtive types in a single chunk, or they may split
* it into several chunks</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmContentHandler
* @see com.sun.xml.internal.org.jvnet.fastinfoset.sax.FastInfosetReader
* @see org.xml.sax.XMLReader
*/
public interface PrimitiveTypeContentHandler {
/**
* Receive notification of character data as an array of boolean.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "boolean" encoding
* algorithm, see subclause 10.7<p>.
*
* @param b the array of boolean
* @param start the start position in the array
* @param length the number of boolean to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void booleans(boolean [] b, int start, int length) throws SAXException;
/**
* Receive notification of character data as an array of byte.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "base64" encoding
* algorithm, see subclause 10.3, or the "hexadecimal" encoding
* algorithm, see subclause 10.2.
*
* <p>Such a notification may occur for binary data that would
* normally require base 64 encoding and reported as character data
* using the {@link org.xml.sax.ContentHandler#characters characters}
* method <p>.
*
* @param b the array of byte
* @param start the start position in the array
* @param length the number of byte to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void bytes(byte[] b, int start, int length) throws SAXException;
/**
* Receive notification of character data as an array of short.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "short" encoding
* algorithm, see subclause 10.4<p>.
*
* @param s the array of short
* @param start the start position in the array
* @param length the number of short to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void shorts(short[] s, int start, int length) throws SAXException;
/**
* Receive notification of character data as an array of int.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "int" encoding
* algorithm, see subclause 10.5<p>.
*
* @param i the array of int
* @param start the start position in the array
* @param length the number of int to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void ints(int [] i, int start, int length) throws SAXException;
/**
* Receive notification of character data as an array of long.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "long" encoding
* algorithm, see subclause 10.6<p>.
*
* @param l the array of long
* @param start the start position in the array
* @param length the number of long to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void longs(long [] l, int start, int length) throws SAXException;
/**
* Receive notification of character data as an array of float.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "float" encoding
* algorithm, see subclause 10.8<p>.
*
* @param f the array of float
* @param start the start position in the array
* @param length the number of float to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void floats(float [] f, int start, int length) throws SAXException;
/**
* Receive notification of character data as an array of double.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "double" encoding
* algorithm, see subclause 10.9<p>.
*
* @param d the array of double
* @param start the start position in the array
* @param length the number of double to read from the array
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void doubles(double [] d, int start, int length) throws SAXException;
/**
* Receive notification of character data as an two array of UUID.
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Such notifications will occur for a Fast Infoset SAX parser
* when processing data encoded using the "uuid" encoding
* algorithm, see subclause 10.10<p>.
*
* @param msblsb the array of long containing pairs of most signficant
* bits and least significant bits of the UUIDs
* @param start the start position in the array
* @param length the number of long to read from the array. This will
* be twice the number of UUIDs, which are pairs of two long values
* @throws org.xml.sax.SAXException any SAX exception, possibly
* wrapping another exception
*/
public void uuids(long[] msblsb, int start, int length) throws SAXException;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax;
import org.xml.sax.SAXException;
public interface RestrictedAlphabetContentHandler {
public void numericCharacters(char ch[], int start, int length) throws SAXException;
public void dateTimeCharacters(char ch[], int start, int length) throws SAXException;
public void alphabetCharacters(String alphabet, char ch[], int start, int length) throws SAXException;
}

View File

@@ -0,0 +1,604 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax.helpers;
import com.sun.xml.internal.fastinfoset.CommonResourceBundle;
import com.sun.xml.internal.fastinfoset.EncodingConstants;
import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory;
import java.io.IOException;
import java.util.Map;
import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm;
import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException;
import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
import com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmAttributes;
import org.xml.sax.Attributes;
/**
* Default implementation of the {@link EncodingAlgorithmAttributes} interface.
*
* <p>This class provides a default implementation of the SAX2
* {@link EncodingAlgorithmAttributes} interface, with the
* addition of manipulators so that the list can be modified or
* reused.</p>
*
* <p>There are two typical uses of this class:</p>
*
* <ol>
* <li>to take a persistent snapshot of an EncodingAlgorithmAttributes object
* in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
* <li>to construct or modify an EncodingAlgorithmAttributes object in a SAX2
* driver or filter.</li>
* </ol>
*/
public class EncodingAlgorithmAttributesImpl implements EncodingAlgorithmAttributes {
private static final int DEFAULT_CAPACITY = 8;
private static final int URI_OFFSET = 0;
private static final int LOCALNAME_OFFSET = 1;
private static final int QNAME_OFFSET = 2;
private static final int TYPE_OFFSET = 3;
private static final int VALUE_OFFSET = 4;
private static final int ALGORITHMURI_OFFSET = 5;
private static final int SIZE = 6;
private Map _registeredEncodingAlgorithms;
private int _length;
private String[] _data;
private int[] _algorithmIds;
private Object[] _algorithmData;
private String[] _alphabets;
private boolean[] _toIndex;
/**
* Construct a new, empty EncodingAlgorithmAttributesImpl object.
*/
public EncodingAlgorithmAttributesImpl() {
this(null, null);
}
/**
* Copy an existing Attributes object.
*
* <p>This constructor is especially useful inside a
* {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
*
* @param attributes The existing Attributes object.
*/
public EncodingAlgorithmAttributesImpl(Attributes attributes) {
this(null, attributes);
}
/**
* Use registered encoding algorithms and copy an existing Attributes object.
*
* <p>This constructor is especially useful inside a
* {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
*
* @param registeredEncodingAlgorithms
* The registeredEncodingAlgorithms encoding algorithms.
* @param attributes The existing Attributes object.
*/
public EncodingAlgorithmAttributesImpl(Map registeredEncodingAlgorithms,
Attributes attributes) {
_data = new String[DEFAULT_CAPACITY * SIZE];
_algorithmIds = new int[DEFAULT_CAPACITY];
_algorithmData = new Object[DEFAULT_CAPACITY];
_alphabets = new String[DEFAULT_CAPACITY];
_toIndex = new boolean[DEFAULT_CAPACITY];
_registeredEncodingAlgorithms = registeredEncodingAlgorithms;
if (attributes != null) {
if (attributes instanceof EncodingAlgorithmAttributes) {
setAttributes((EncodingAlgorithmAttributes)attributes);
} else {
setAttributes(attributes);
}
}
}
/**
* Clear the attribute list for reuse.
*
*/
public final void clear() {
for (int i = 0; i < _length; i++) {
_data[i * SIZE + VALUE_OFFSET] = null;
_algorithmData[i] = null;
}
_length = 0;
}
/**
* Add an attribute to the end of the list.
*
* <p>For the sake of speed, this method does no checking
* to see if the attribute is already in the list: that is
* the responsibility of the application.</p>
*
* @param URI The Namespace URI, or the empty string if
* none is available or Namespace processing is not
* being performed.
* @param localName The local name, or the empty string if
* Namespace processing is not being performed.
* @param qName The qualified (prefixed) name, or the empty string
* if qualified names are not available.
* @param type The attribute type as a string.
* @param value The attribute value.
*/
public void addAttribute(String URI, String localName, String qName,
String type, String value) {
if (_length >= _algorithmData.length) {
resize();
}
int i = _length * SIZE;
_data[i++] = replaceNull(URI);
_data[i++] = replaceNull(localName);
_data[i++] = replaceNull(qName);
_data[i++] = replaceNull(type);
_data[i++] = replaceNull(value);
_toIndex[_length] = false;
_alphabets[_length] = null;
_length++;
}
/**
* Add an attribute to the end of the list.
*
* <p>For the sake of speed, this method does no checking
* to see if the attribute is already in the list: that is
* the responsibility of the application.</p>
*
* @param URI The Namespace URI, or the empty string if
* none is available or Namespace processing is not
* being performed.
* @param localName The local name, or the empty string if
* Namespace processing is not being performed.
* @param qName The qualified (prefixed) name, or the empty string
* if qualified names are not available.
* @param type The attribute type as a string.
* @param value The attribute value.
* @param index True if attribute should be indexed.
* @param alphabet The alphabet associated with the attribute value,
* may be null if there is no associated alphabet.
*/
public void addAttribute(String URI, String localName, String qName,
String type, String value, boolean index, String alphabet) {
if (_length >= _algorithmData.length) {
resize();
}
int i = _length * SIZE;
_data[i++] = replaceNull(URI);
_data[i++] = replaceNull(localName);
_data[i++] = replaceNull(qName);
_data[i++] = replaceNull(type);
_data[i++] = replaceNull(value);
_toIndex[_length] = index;
_alphabets[_length] = alphabet;
_length++;
}
/**
* Add an attribute with built in algorithm data to the end of the list.
*
* <p>For the sake of speed, this method does no checking
* to see if the attribute is already in the list: that is
* the responsibility of the application.</p>
*
* @param URI The Namespace URI, or the empty string if
* none is available or Namespace processing is not
* being performed.
* @param localName The local name, or the empty string if
* Namespace processing is not being performed.
* @param qName The qualified (prefixed) name, or the empty string
* if qualified names are not available.
* @param builtInAlgorithmID The built in algorithm ID.
* @param algorithmData The built in algorithm data.
*/
public void addAttributeWithBuiltInAlgorithmData(String URI, String localName, String qName,
int builtInAlgorithmID, Object algorithmData) {
if (_length >= _algorithmData.length) {
resize();
}
int i = _length * SIZE;
_data[i++] = replaceNull(URI);
_data[i++] = replaceNull(localName);
_data[i++] = replaceNull(qName);
_data[i++] = "CDATA";
_data[i++] = "";
_data[i++] = null;
_algorithmIds[_length] = builtInAlgorithmID;
_algorithmData[_length] = algorithmData;
_toIndex[_length] = false;
_alphabets[_length] = null;
_length++;
}
/**
* Add an attribute with algorithm data to the end of the list.
*
* <p>For the sake of speed, this method does no checking
* to see if the attribute is already in the list: that is
* the responsibility of the application.</p>
*
* @param URI The Namespace URI, or the empty string if
* none is available or Namespace processing is not
* being performed.
* @param localName The local name, or the empty string if
* Namespace processing is not being performed.
* @param qName The qualified (prefixed) name, or the empty string
* if qualified names are not available.
* @param algorithmURI The algorithm URI, or null if a built in algorithm
* @param algorithmID The algorithm ID.
* @param algorithmData The algorithm data.
*/
public void addAttributeWithAlgorithmData(String URI, String localName, String qName,
String algorithmURI, int algorithmID, Object algorithmData) {
if (_length >= _algorithmData.length) {
resize();
}
int i = _length * SIZE;
_data[i++] = replaceNull(URI);
_data[i++] = replaceNull(localName);
_data[i++] = replaceNull(qName);
_data[i++] = "CDATA";
_data[i++] = "";
_data[i++] = algorithmURI;
_algorithmIds[_length] = algorithmID;
_algorithmData[_length] = algorithmData;
_toIndex[_length] = false;
_alphabets[_length] = null;
_length++;
}
/**
* Replace an attribute value with algorithm data.
*
* <p>For the sake of speed, this method does no checking
* to see if the attribute is already in the list: that is
* the responsibility of the application.</p>
*
* @param index The index of the attribute whose value is to be replaced
* @param algorithmURI The algorithm URI, or null if a built in algorithm
* @param algorithmID The algorithm ID.
* @param algorithmData The algorithm data.
*/
public void replaceWithAttributeAlgorithmData(int index,
String algorithmURI, int algorithmID, Object algorithmData) {
if (index < 0 || index >= _length) return;
int i = index * SIZE;
_data[i + VALUE_OFFSET] = null;
_data[i + ALGORITHMURI_OFFSET] = algorithmURI;
_algorithmIds[index] = algorithmID;
_algorithmData[index] = algorithmData;
_toIndex[index] = false;
_alphabets[index] = null;
}
/**
* Copy an entire Attributes object.
*
* @param atts The attributes to copy.
*/
public void setAttributes(Attributes atts) {
_length = atts.getLength();
if (_length > 0) {
if (_length >= _algorithmData.length) {
resizeNoCopy();
}
int index = 0;
for (int i = 0; i < _length; i++) {
_data[index++] = atts.getURI(i);
_data[index++] = atts.getLocalName(i);
_data[index++] = atts.getQName(i);
_data[index++] = atts.getType(i);
_data[index++] = atts.getValue(i);
index++;
_toIndex[i] = false;
_alphabets[i] = null;
}
}
}
/**
* Copy an entire EncodingAlgorithmAttributes object.
*
* @param atts The attributes to copy.
*/
public void setAttributes(EncodingAlgorithmAttributes atts) {
_length = atts.getLength();
if (_length > 0) {
if (_length >= _algorithmData.length) {
resizeNoCopy();
}
int index = 0;
for (int i = 0; i < _length; i++) {
_data[index++] = atts.getURI(i);
_data[index++] = atts.getLocalName(i);
_data[index++] = atts.getQName(i);
_data[index++] = atts.getType(i);
_data[index++] = atts.getValue(i);
_data[index++] = atts.getAlgorithmURI(i);
_algorithmIds[i] = atts.getAlgorithmIndex(i);
_algorithmData[i] = atts.getAlgorithmData(i);
_toIndex[i] = false;
_alphabets[i] = null;
}
}
}
// org.xml.sax.Attributes
public final int getLength() {
return _length;
}
public final String getLocalName(int index) {
if (index >= 0 && index < _length) {
return _data[index * SIZE + LOCALNAME_OFFSET];
} else {
return null;
}
}
public final String getQName(int index) {
if (index >= 0 && index < _length) {
return _data[index * SIZE + QNAME_OFFSET];
} else {
return null;
}
}
public final String getType(int index) {
if (index >= 0 && index < _length) {
return _data[index * SIZE + TYPE_OFFSET];
} else {
return null;
}
}
public final String getURI(int index) {
if (index >= 0 && index < _length) {
return _data[index * SIZE + URI_OFFSET];
} else {
return null;
}
}
public final String getValue(int index) {
if (index >= 0 && index < _length) {
final String value = _data[index * SIZE + VALUE_OFFSET];
if (value != null) return value;
} else {
return null;
}
if (_algorithmData[index] == null || _registeredEncodingAlgorithms == null) {
return null;
}
try {
return _data[index * SIZE + VALUE_OFFSET] = convertEncodingAlgorithmDataToString(
_algorithmIds[index],
_data[index * SIZE + ALGORITHMURI_OFFSET],
_algorithmData[index]).toString();
} catch (IOException e) {
return null;
} catch (FastInfosetException e) {
return null;
}
}
public final int getIndex(String qName) {
for (int index = 0; index < _length; index++) {
if (qName.equals(_data[index * SIZE + QNAME_OFFSET])) {
return index;
}
}
return -1;
}
public final String getType(String qName) {
int index = getIndex(qName);
if (index >= 0) {
return _data[index * SIZE + TYPE_OFFSET];
} else {
return null;
}
}
public final String getValue(String qName) {
int index = getIndex(qName);
if (index >= 0) {
return getValue(index);
} else {
return null;
}
}
public final int getIndex(String uri, String localName) {
for (int index = 0; index < _length; index++) {
if (localName.equals(_data[index * SIZE + LOCALNAME_OFFSET]) &&
uri.equals(_data[index * SIZE + URI_OFFSET])) {
return index;
}
}
return -1;
}
public final String getType(String uri, String localName) {
int index = getIndex(uri, localName);
if (index >= 0) {
return _data[index * SIZE + TYPE_OFFSET];
} else {
return null;
}
}
public final String getValue(String uri, String localName) {
int index = getIndex(uri, localName);
if (index >= 0) {
return getValue(index);
} else {
return null;
}
}
// EncodingAlgorithmAttributes
public final String getAlgorithmURI(int index) {
if (index >= 0 && index < _length) {
return _data[index * SIZE + ALGORITHMURI_OFFSET];
} else {
return null;
}
}
public final int getAlgorithmIndex(int index) {
if (index >= 0 && index < _length) {
return _algorithmIds[index];
} else {
return -1;
}
}
public final Object getAlgorithmData(int index) {
if (index >= 0 && index < _length) {
return _algorithmData[index];
} else {
return null;
}
}
// ExtendedAttributes
public final String getAlpababet(int index) {
if (index >= 0 && index < _length) {
return _alphabets[index];
} else {
return null;
}
}
public final boolean getToIndex(int index) {
if (index >= 0 && index < _length) {
return _toIndex[index];
} else {
return false;
}
}
// -----
private final String replaceNull(String s) {
return (s != null) ? s : "";
}
private final void resizeNoCopy() {
final int newLength = _length * 3 / 2 + 1;
_data = new String[newLength * SIZE];
_algorithmIds = new int[newLength];
_algorithmData = new Object[newLength];
}
private final void resize() {
final int newLength = _length * 3 / 2 + 1;
String[] data = new String[newLength * SIZE];
int[] algorithmIds = new int[newLength];
Object[] algorithmData = new Object[newLength];
String[] alphabets = new String[newLength];
boolean[] toIndex = new boolean[newLength];
System.arraycopy(_data, 0, data, 0, _length * SIZE);
System.arraycopy(_algorithmIds, 0, algorithmIds, 0, _length);
System.arraycopy(_algorithmData, 0, algorithmData, 0, _length);
System.arraycopy(_alphabets, 0, alphabets, 0, _length);
System.arraycopy(_toIndex, 0, toIndex, 0, _length);
_data = data;
_algorithmIds = algorithmIds;
_algorithmData = algorithmData;
_alphabets = alphabets;
_toIndex = toIndex;
}
private final StringBuffer convertEncodingAlgorithmDataToString(
int identifier, String URI, Object data) throws FastInfosetException, IOException {
EncodingAlgorithm ea = null;
if (identifier < EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
ea = BuiltInEncodingAlgorithmFactory.getAlgorithm(identifier);
} else if (identifier == EncodingAlgorithmIndexes.CDATA) {
throw new EncodingAlgorithmException(
CommonResourceBundle.getInstance().getString("message.CDATAAlgorithmNotSupported"));
} else if (identifier >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
if (URI == null) {
throw new EncodingAlgorithmException(
CommonResourceBundle.getInstance().getString("message.URINotPresent") + identifier);
}
ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
if (ea == null) {
throw new EncodingAlgorithmException(
CommonResourceBundle.getInstance().getString("message.algorithmNotRegistered") + URI);
}
} else {
// Reserved built-in algorithms for future use
// TODO should use sax property to decide if event will be
// reported, allows for support through handler if required.
throw new EncodingAlgorithmException(
CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
}
final StringBuffer sb = new StringBuffer();
ea.convertToCharacters(data, sb);
return sb;
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.sax.helpers;
import com.sun.xml.internal.org.jvnet.fastinfoset.sax.*;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.DefaultHandler;
/**
* Default base class for SAX event handlers of a {@link FastInfosetReader}.
* <p>
* This class is available as a convenience for applications: it provides
* default implementations for all of the callbacks of the following:
* <UL>
* <LI>{@link DefaultHandler}</LI>
* <LI>{@link LexicalHandler}</LI>
* <LI>{@link EncodingAlgorithmContentHandler}</LI>
* <LI>{@link PrimitiveTypeContentHandler}</LI>
* </UL>
* Application writers can extend this class when they need to implement only
* part of an interface; parser writers can instantiate this class to provide
* default handlers when the application has not supplied its own.
*/
public class FastInfosetDefaultHandler extends DefaultHandler implements
LexicalHandler, EncodingAlgorithmContentHandler, PrimitiveTypeContentHandler {
// LexicalHandler
public void comment(char[] ch, int start, int length) throws SAXException {
}
public void startCDATA() throws SAXException {
}
public void endCDATA() throws SAXException {
}
public void startDTD(String name, String publicId, String systemId) throws SAXException {
}
public void endDTD() throws SAXException {
}
public void startEntity(String name) throws SAXException {
}
public void endEntity(String name) throws SAXException {
}
// EncodingAlgorithmContentHandler
public void octets(String URI, int algorithm, byte[] b, int start, int length) throws SAXException {
}
public void object(String URI, int algorithm, Object o) throws SAXException {
}
// PrimitiveTypeContentHandler
public void booleans(boolean[] b, int start, int length) throws SAXException {
}
public void bytes(byte[] b, int start, int length) throws SAXException {
}
public void shorts(short[] s, int start, int length) throws SAXException {
}
public void ints(int[] i, int start, int length) throws SAXException {
}
public void longs(long[] l, int start, int length) throws SAXException {
}
public void floats(float[] f, int start, int length) throws SAXException {
}
public void doubles(double[] d, int start, int length) throws SAXException {
}
public void uuids(long[] msblsb, int start, int length) throws SAXException {
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.stax;
import javax.xml.stream.XMLStreamException;
/**
* Fast Infoset Stream Reader.
* <p>
* This interface provides additional optimized methods to that of
* {@link javax.xml.stream.XMLStreamReader}.
*/
public interface FastInfosetStreamReader {
/**
* Peek at the next event.
*
* @return the event, which will be the same as that returned from
* {@link #next}.
*/
public int peekNext() throws XMLStreamException;
// Faster access methods without checks
public int accessNamespaceCount();
public String accessLocalName();
public String accessNamespaceURI();
public String accessPrefix();
/**
* Returns a cloned char[] representation of the internal char[] buffer.
* So be careful, when using this method due to possible performance and
* memory inefficiency.
*
* @return a cloned char[] representation of the internal char[] buffer.
*/
public char[] accessTextCharacters();
public int accessTextStart();
public int accessTextLength();
}

View File

@@ -0,0 +1,205 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
*/
package com.sun.xml.internal.org.jvnet.fastinfoset.stax;
import java.io.IOException;
import javax.xml.stream.XMLStreamException;
/**
* Low level Fast Infoset stream writer.
* <p>
* This interface provides additional stream-based serialization methods for the
* case where an application is in specific control of the serialization
* process and has the knowledge to call the LowLevel methods in the required
* order.
* <p>
* For example, the application may be able to perform efficient information
* to indexing mapping and to provide certain information in UTF-8 encoded form.
* <p>
* These methods may be used in conjuction with {@link javax.xml.stream.XMLStreamWriter}
* as long as an element fragment written using the efficient streaming methods
* are self-contained and no sub-fragment is written using methods from
* {@link javax.xml.stream.XMLStreamWriter}.
* <p>
* The required call sequence is as follows:
* <pre>
* CALLSEQUENCE := {@link #startDocument startDocument}
* initiateLowLevelWriting ELEMENT
* {@link #endDocument endDocument}
* | initiateLowLevelWriting ELEMENT // for fragment
*
* ELEMENT := writeLowLevelTerminationAndMark
* NAMESPACES?
* ELEMENT_NAME
* ATTRIBUTES?
* writeLowLevelEndStartElement
* CONTENTS
* writeLowLevelEndElement
*
* NAMESPACES := writeLowLevelStartNamespaces
* writeLowLevelNamespace*
* writeLowLevelEndNamespaces
*
* ELEMENT_NAME := writeLowLevelStartElementIndexed
* | writeLowLevelStartNameLiteral
* | writeLowLevelStartElement
*
* ATTRUBUTES := writeLowLevelStartAttributes
* (ATTRIBUTE_NAME writeLowLevelAttributeValue)*
*
* ATTRIBUTE_NAME := writeLowLevelAttributeIndexed
* | writeLowLevelStartNameLiteral
* | writeLowLevelAttribute
*
*
* CONTENTS := (ELEMENT | writeLowLevelText writeLowLevelOctets)*
* </pre>
* <p>
* Some methods defer to the application for the mapping of information
* to indexes.
*/
public interface LowLevelFastInfosetStreamWriter {
/**
* Initiate low level writing of an element fragment.
* <p>
* This method must be invoked before other low level method.
*/
public void initiateLowLevelWriting()
throws XMLStreamException;
/**
* Get the next index to apply to an Element Information Item.
* <p>
* This will increment the next obtained index such that:
* <pre>
* i = w.getNextElementIndex();
* j = w.getNextElementIndex();
* i == j + 1;
* </pre>
* @return the index.
*/
public int getNextElementIndex();
/**
* Get the next index to apply to an Attribute Information Item.
* This will increment the next obtained index such that:
* <pre>
* i = w.getNextAttributeIndex();
* j = w.getNextAttributeIndex();
* i == j + 1;
* </pre>
* @return the index.
*/
public int getNextAttributeIndex();
/**
* Get the current index that was applied to an [local name] of an
* Element or Attribute Information Item.
* </pre>
* @return the index.
*/
public int getLocalNameIndex();
/**
* Get the next index to apply to an [local name] of an Element or Attribute
* Information Item.
* This will increment the next obtained index such that:
* <pre>
* i = w.getNextLocalNameIndex();
* j = w.getNextLocalNameIndex();
* i == j + 1;
* </pre>
* @return the index.
*/
public int getNextLocalNameIndex();
public void writeLowLevelTerminationAndMark()
throws IOException;
public void writeLowLevelStartElementIndexed(int type, int index)
throws IOException;
/**
* Write the start of an element.
*
* @return true if element is indexed, otherwise false.
*/
public boolean writeLowLevelStartElement(int type,
String prefix, String localName, String namespaceURI)
throws IOException;
public void writeLowLevelStartNamespaces()
throws IOException;
public void writeLowLevelNamespace(String prefix, String namespaceName)
throws IOException;
public void writeLowLevelEndNamespaces()
throws IOException;
public void writeLowLevelStartAttributes()
throws IOException;
public void writeLowLevelAttributeIndexed(int index)
throws IOException;
/**
* Write an attribute.
*
* @return true if attribute is indexed, otherwise false.
*/
public boolean writeLowLevelAttribute(
String prefix, String namespaceURI, String localName)
throws IOException;
public void writeLowLevelAttributeValue(String value)
throws IOException;
public void writeLowLevelStartNameLiteral(int type,
String prefix, byte[] utf8LocalName, String namespaceURI)
throws IOException;
public void writeLowLevelStartNameLiteral(int type,
String prefix, int localNameIndex, String namespaceURI)
throws IOException;
public void writeLowLevelEndStartElement()
throws IOException;
public void writeLowLevelEndElement()
throws IOException;
public void writeLowLevelText(char[] text, int length)
throws IOException;
public void writeLowLevelText(String text)
throws IOException;
public void writeLowLevelOctets(byte[] octets, int length)
throws IOException;
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* FROM mail.jar */
package com.sun.xml.internal.org.jvnet.mimepull;
final class ASCIIUtility {
// Private constructor so that this class is not instantiated
private ASCIIUtility() { }
/**
* Convert the bytes within the specified range of the given byte
* array into a signed integer in the given radix . The range extends
* from <code>start</code> till, but not including <code>end</code>. <p>
*
* Based on java.lang.Integer.parseInt()
*/
public static int parseInt(byte[] b, int start, int end, int radix)
throws NumberFormatException {
if (b == null) {
throw new NumberFormatException("null");
}
int result = 0;
boolean negative = false;
int i = start;
int limit;
int multmin;
int digit;
if (end > start) {
if (b[i] == '-') {
negative = true;
limit = Integer.MIN_VALUE;
i++;
} else {
limit = -Integer.MAX_VALUE;
}
multmin = limit / radix;
if (i < end) {
digit = Character.digit((char)b[i++], radix);
if (digit < 0) {
throw new NumberFormatException(
"illegal number: " + toString(b, start, end)
);
} else {
result = -digit;
}
}
while (i < end) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit((char)b[i++], radix);
if (digit < 0) {
throw new NumberFormatException("illegal number");
}
if (result < multmin) {
throw new NumberFormatException("illegal number");
}
result *= radix;
if (result < limit + digit) {
throw new NumberFormatException("illegal number");
}
result -= digit;
}
} else {
throw new NumberFormatException("illegal number");
}
if (negative) {
if (i > start + 1) {
return result;
} else { /* Only got "-" */
throw new NumberFormatException("illegal number");
}
} else {
return -result;
}
}
/**
* Convert the bytes within the specified range of the given byte
* array into a String. The range extends from <code>start</code>
* till, but not including <code>end</code>. <p>
*/
public static String toString(byte[] b, int start, int end) {
int size = end - start;
char[] theChars = new char[size];
for (int i = 0, j = start; i < size; ) {
theChars[i++] = (char)(b[j++]&0xff);
}
return new String(theChars);
}
}

View File

@@ -0,0 +1,485 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* FROM mail.jar */
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.*;
/**
* This class implements a BASE64 Decoder. It is implemented as
* a FilterInputStream, so one can just wrap this class around
* any input stream and read bytes from this filter. The decoding
* is done as the bytes are read out.
*
* @author John Mani
* @author Bill Shannon
*/
final class BASE64DecoderStream extends FilterInputStream {
// buffer of decoded bytes for single byte reads
private byte[] buffer = new byte[3];
private int bufsize = 0; // size of the cache
private int index = 0; // index into the cache
// buffer for almost 8K of typical 76 chars + CRLF lines,
// used by getByte method. this buffer contains encoded bytes.
private byte[] input_buffer = new byte[78*105];
private int input_pos = 0;
private int input_len = 0;;
private boolean ignoreErrors = false;
/**
* Create a BASE64 decoder that decodes the specified input stream.
* The System property <code>mail.mime.base64.ignoreerrors</code>
* controls whether errors in the encoded data cause an exception
* or are ignored. The default is false (errors cause exception).
*
* @param in the input stream
*/
public BASE64DecoderStream(InputStream in) {
super(in);
// default to false
ignoreErrors = PropUtil.getBooleanSystemProperty(
"mail.mime.base64.ignoreerrors", false);
}
/**
* Create a BASE64 decoder that decodes the specified input stream.
*
* @param in the input stream
* @param ignoreErrors ignore errors in encoded data?
*/
public BASE64DecoderStream(InputStream in, boolean ignoreErrors) {
super(in);
this.ignoreErrors = ignoreErrors;
}
/**
* Read the next decoded byte from this input stream. The byte
* is returned as an <code>int</code> in the range <code>0</code>
* to <code>255</code>. If no byte is available because the end of
* the stream has been reached, the value <code>-1</code> is returned.
* This method blocks until input data is available, the end of the
* stream is detected, or an exception is thrown.
*
* @return next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
*/
@Override
public int read() throws IOException {
if (index >= bufsize) {
bufsize = decode(buffer, 0, buffer.length);
if (bufsize <= 0) {
return -1;
}
index = 0; // reset index into buffer
}
return buffer[index++] & 0xff; // Zero off the MSB
}
/**
* Reads up to <code>len</code> decoded bytes of data from this input stream
* into an array of bytes. This method blocks until some input is
* available.
* <p>
*
* @param buf the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
@Override
public int read(byte[] buf, int off, int len) throws IOException {
// empty out single byte read buffer
int off0 = off;
while (index < bufsize && len > 0) {
buf[off++] = buffer[index++];
len--;
}
if (index >= bufsize) {
bufsize = index = 0;
}
int bsize = (len / 3) * 3; // round down to multiple of 3 bytes
if (bsize > 0) {
int size = decode(buf, off, bsize);
off += size;
len -= size;
if (size != bsize) { // hit EOF?
if (off == off0) {
return -1;
} else {
return off - off0;
}
}
}
// finish up with a partial read if necessary
for (; len > 0; len--) {
int c = read();
if (c == -1) {
break;
}
buf[off++] = (byte)c;
}
if (off == off0) {
return -1;
} else {
return off - off0;
}
}
/**
* Skips over and discards n bytes of data from this stream.
*/
@Override
public long skip(long n) throws IOException {
long skipped = 0;
while (n-- > 0 && read() >= 0) {
skipped++;
}
return skipped;
}
/**
* Tests if this input stream supports marks. Currently this class
* does not support marks
*/
@Override
public boolean markSupported() {
return false; // Maybe later ..
}
/**
* Returns the number of bytes that can be read from this input
* stream without blocking. However, this figure is only
* a close approximation in case the original encoded stream
* contains embedded CRLFs; since the CRLFs are discarded, not decoded
*/
@Override
public int available() throws IOException {
// This is only an estimate, since in.available()
// might include CRLFs too ..
return ((in.available() * 3)/4 + (bufsize-index));
}
/**
* This character array provides the character to value map
* based on RFC1521.
*/
private final static char pem_array[] = {
'A','B','C','D','E','F','G','H', // 0
'I','J','K','L','M','N','O','P', // 1
'Q','R','S','T','U','V','W','X', // 2
'Y','Z','a','b','c','d','e','f', // 3
'g','h','i','j','k','l','m','n', // 4
'o','p','q','r','s','t','u','v', // 5
'w','x','y','z','0','1','2','3', // 6
'4','5','6','7','8','9','+','/' // 7
};
private final static byte pem_convert_array[] = new byte[256];
static {
for (int i = 0; i < 255; i++) {
pem_convert_array[i] = -1;
}
for (int i = 0; i < pem_array.length; i++) {
pem_convert_array[pem_array[i]] = (byte)i;
}
}
/**
* The decoder algorithm. Most of the complexity here is dealing
* with error cases. Returns the number of bytes decoded, which
* may be zero. Decoding is done by filling an int with 4 6-bit
* values by shifting them in from the bottom and then extracting
* 3 8-bit bytes from the int by shifting them out from the bottom.
*
* @param outbuf the buffer into which to put the decoded bytes
* @param pos position in the buffer to start filling
* @param len the number of bytes to fill
* @return the number of bytes filled, always a multiple
* of three, and may be zero
* @exception IOException if the data is incorrectly formatted
*/
private int decode(byte[] outbuf, int pos, int len) throws IOException {
int pos0 = pos;
while (len >= 3) {
/*
* We need 4 valid base64 characters before we start decoding.
* We skip anything that's not a valid base64 character (usually
* just CRLF).
*/
int got = 0;
int val = 0;
while (got < 4) {
int i = getByte();
if (i == -1 || i == -2) {
boolean atEOF;
if (i == -1) {
if (got == 0) {
return pos - pos0;
}
if (!ignoreErrors) {
throw new DecodingException(
"BASE64Decoder: Error in encoded stream: " +
"needed 4 valid base64 characters " +
"but only got " + got + " before EOF" +
recentChars());
}
atEOF = true; // don't read any more
} else { // i == -2
// found a padding character, we're at EOF
// XXX - should do something to make EOF "sticky"
if (got < 2 && !ignoreErrors) {
throw new DecodingException(
"BASE64Decoder: Error in encoded stream: " +
"needed at least 2 valid base64 characters," +
" but only got " + got +
" before padding character (=)" +
recentChars());
}
// didn't get any characters before padding character?
if (got == 0) {
return pos - pos0;
}
atEOF = false; // need to keep reading
}
// pad partial result with zeroes
// how many bytes will we produce on output?
// (got always < 4, so size always < 3)
int size = got - 1;
if (size == 0) {
size = 1;
}
// handle the one padding character we've seen
got++;
val <<= 6;
while (got < 4) {
if (!atEOF) {
// consume the rest of the padding characters,
// filling with zeroes
i = getByte();
if (i == -1) {
if (!ignoreErrors) {
throw new DecodingException(
"BASE64Decoder: Error in encoded " +
"stream: hit EOF while looking for " +
"padding characters (=)" +
recentChars());
}
} else if (i != -2) {
if (!ignoreErrors) {
throw new DecodingException(
"BASE64Decoder: Error in encoded " +
"stream: found valid base64 " +
"character after a padding character " +
"(=)" + recentChars());
}
}
}
val <<= 6;
got++;
}
// now pull out however many valid bytes we got
val >>= 8; // always skip first one
if (size == 2) {
outbuf[pos + 1] = (byte)(val & 0xff);
}
val >>= 8;
outbuf[pos] = (byte)(val & 0xff);
// len -= size; // not needed, return below
pos += size;
return pos - pos0;
} else {
// got a valid byte
val <<= 6;
got++;
val |= i;
}
}
// read 4 valid characters, now extract 3 bytes
outbuf[pos + 2] = (byte)(val & 0xff);
val >>= 8;
outbuf[pos + 1] = (byte)(val & 0xff);
val >>= 8;
outbuf[pos] = (byte)(val & 0xff);
len -= 3;
pos += 3;
}
return pos - pos0;
}
/**
* Read the next valid byte from the input stream.
* Buffer lots of data from underlying stream in input_buffer,
* for efficiency.
*
* @return the next byte, -1 on EOF, or -2 if next byte is '='
* (padding at end of encoded data)
*/
private int getByte() throws IOException {
int c;
do {
if (input_pos >= input_len) {
try {
input_len = in.read(input_buffer);
} catch (EOFException ex) {
return -1;
}
if (input_len <= 0) {
return -1;
}
input_pos = 0;
}
// get the next byte in the buffer
c = input_buffer[input_pos++] & 0xff;
// is it a padding byte?
if (c == '=') {
return -2;
}
// no, convert it
c = pem_convert_array[c];
// loop until we get a legitimate byte
} while (c == -1);
return c;
}
/**
* Return the most recent characters, for use in an error message.
*/
private String recentChars() {
// reach into the input buffer and extract up to 10
// recent characters, to help in debugging.
StringBuilder errstr = new StringBuilder();
int nc = input_pos > 10 ? 10 : input_pos;
if (nc > 0) {
errstr.append(", the ").append(nc).append(" most recent characters were: \"");
for (int k = input_pos - nc; k < input_pos; k++) {
char c = (char)(input_buffer[k] & 0xff);
switch (c) {
case '\r': errstr.append("\\r"); break;
case '\n': errstr.append("\\n"); break;
case '\t': errstr.append("\\t"); break;
default:
if (c >= ' ' && c < 0177) {
errstr.append(c);
} else {
errstr.append("\\").append((int)c);
}
}
}
errstr.append("\"");
}
return errstr.toString();
}
/**
* Base64 decode a byte array. No line breaks are allowed.
* This method is suitable for short strings, such as those
* in the IMAP AUTHENTICATE protocol, but not to decode the
* entire content of a MIME part.
*
* NOTE: inbuf may only contain valid base64 characters.
* Whitespace is not ignored.
*/
public static byte[] decode(byte[] inbuf) {
int size = (inbuf.length / 4) * 3;
if (size == 0) {
return inbuf;
}
if (inbuf[inbuf.length - 1] == '=') {
size--;
if (inbuf[inbuf.length - 2] == '=') {
size--;
}
}
byte[] outbuf = new byte[size];
int inpos = 0, outpos = 0;
size = inbuf.length;
while (size > 0) {
int val;
int osize = 3;
val = pem_convert_array[inbuf[inpos++] & 0xff];
val <<= 6;
val |= pem_convert_array[inbuf[inpos++] & 0xff];
val <<= 6;
if (inbuf[inpos] != '=') {
val |= pem_convert_array[inbuf[inpos++] & 0xff];
} else {
osize--;
}
val <<= 6;
if (inbuf[inpos] != '=') {
val |= pem_convert_array[inbuf[inpos++] & 0xff];
} else {
osize--;
}
if (osize > 2) {
outbuf[outpos + 2] = (byte)(val & 0xff);
}
val >>= 8;
if (osize > 1) {
outbuf[outpos + 1] = (byte)(val & 0xff);
}
val >>= 8;
outbuf[outpos] = (byte)(val & 0xff);
outpos += osize;
size -= 4;
}
return outbuf;
}
/*** begin TEST program ***
public static void main(String argv[]) throws Exception {
FileInputStream infile = new FileInputStream(argv[0]);
BASE64DecoderStream decoder = new BASE64DecoderStream(infile);
int c;
while ((c = decoder.read()) != -1)
System.out.print((char)c);
System.out.flush();
}
*** end TEST program ***/
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.nio.ByteBuffer;
/**
* @author Kohsuke Kawaguchi
*/
final class Chunk {
volatile Chunk next;
volatile Data data;
public Chunk(Data data) {
this.data = data;
}
/**
* Creates a new chunk and adds to linked list.
*
* @param dataHead of the linked list
* @param buf MIME part partial data
* @return created chunk
*/
public Chunk createNext(DataHead dataHead, ByteBuffer buf) {
return next = new Chunk(data.createNext(dataHead, buf));
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.InputStream;
import java.io.IOException;
/**
* Constructs a InputStream from a linked list of {@link Chunk}s.
*
* @author Kohsuke Kawaguchi
* @author Jitendra Kotamraju
*/
final class ChunkInputStream extends InputStream {
Chunk current;
int offset;
int len;
final MIMEMessage msg;
final MIMEPart part;
byte[] buf;
public ChunkInputStream(MIMEMessage msg, MIMEPart part, Chunk startPos) {
this.current = startPos;
len = current.data.size();
buf = current.data.read();
this.msg = msg;
this.part = part;
}
@Override
public int read(byte b[], int off, int sz) throws IOException {
if (!fetch()) {
return -1;
}
sz = Math.min(sz, len-offset);
System.arraycopy(buf,offset,b,off,sz);
return sz;
}
public int read() throws IOException {
if (!fetch()) {
return -1;
}
return (buf[offset++] & 0xff);
}
/**
* Gets to the next chunk if we are done with the current one.
* @return
*/
private boolean fetch() {
if (current == null) {
throw new IllegalStateException("Stream already closed");
}
while(offset==len) {
while(!part.parsed && current.next == null) {
msg.makeProgress();
}
current = current.next;
if (current == null) {
return false;
}
this.offset = 0;
this.buf = current.data.read();
this.len = current.data.size();
}
return true;
}
@Override
public void close() throws IOException {
super.close();
current = null;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.util.concurrent.Executor;
public abstract class CleanUpExecutorFactory {
private static final String DEFAULT_PROPERTY_NAME = CleanUpExecutorFactory.class
.getName();
protected CleanUpExecutorFactory() {
}
public static CleanUpExecutorFactory newInstance() {
try {
return (CleanUpExecutorFactory) FactoryFinder.find(DEFAULT_PROPERTY_NAME);
} catch (Exception e) {
return null;
}
}
public abstract Executor getExecutor();
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.nio.ByteBuffer;
/**
* @author Kohsuke Kawaguchi
* @author Jitendra Kotamraju
*/
interface Data {
/**
* size of the chunk given by the parser
*
* @return size of the chunk
*/
int size();
/**
* TODO: should the return type be ByteBuffer ??
* Return part's partial data. The data is read only.
*
* @return a byte array which contains {#size()} bytes. The returned
* array may be larger than {#size()} bytes and contains data
* from offset 0.
*/
byte[] read();
/**
* Write this partial data to a file
*
* @param file to which the data needs to be written
* @return file pointer before the write operation(at which the data is
* written from)
*/
long writeTo(DataFile file);
/**
* Factory method to create a Data. The implementation could
* be file based one or memory based one.
*
* @param dataHead start of the linked list of data objects
* @param buf contains partial content for a part
* @return Data
*/
Data createNext(DataHead dataHead, ByteBuffer buf);
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.*;
/**
* Use {@link RandomAccessFile} for concurrent access of read
* and write partial part's content.
*
* @author Kohsuke Kawaguchi
* @author Jitendra Kotamraju
*/
final class DataFile {
private WeakDataFile weak;
private long writePointer;
DataFile(File file) {
writePointer=0;
weak = new WeakDataFile(this, file);
}
/**
*
*/
void close() {
weak.close();
}
/**
* Read data from the given file pointer position.
*
* @param pointer read position
* @param buf that needs to be filled
* @param offset the start offset of the data.
* @param length of data that needs to be read
*/
synchronized void read(long pointer, byte[] buf, int offset, int length ) {
weak.read(pointer, buf, offset, length);
}
void renameTo(File f) {
weak.renameTo(f);
}
/**
* Write data to the file
*
* @param data that needs to written to a file
* @param offset start offset in the data
* @param length no bytes to write
* @return file pointer before the write operation(or at which the
* data is written)
*/
synchronized long writeTo(byte[] data, int offset, int length) {
long temp = writePointer;
writePointer = weak.writeTo(writePointer, data, offset, length);
return temp;
}
}

View File

@@ -0,0 +1,276 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.*;
import java.nio.ByteBuffer;
/**
* Represents an attachment part in a MIME message. MIME message parsing is done
* lazily using a pull parser, so the part may not have all the data. {@link #read}
* and {@link #readOnce} may trigger the actual parsing the message. In fact,
* parsing of an attachment part may be triggered by calling {@link #read} methods
* on some other attachment parts. All this happens behind the scenes so the
* application developer need not worry about these details.
*
* @author Jitendra Kotamraju
*/
final class DataHead {
/**
* Linked list to keep the part's content
*/
volatile Chunk head, tail;
/**
* If the part is stored in a file, non-null.
*/
DataFile dataFile;
private final MIMEPart part;
boolean readOnce;
volatile long inMemory;
/**
* Used only for debugging. This records where readOnce() is called.
*/
private Throwable consumedAt;
DataHead(MIMEPart part) {
this.part = part;
}
void addBody(ByteBuffer buf) {
synchronized(this) {
inMemory += buf.limit();
}
if (tail != null) {
tail = tail.createNext(this, buf);
} else {
head = tail = new Chunk(new MemoryData(buf, part.msg.config));
}
}
void doneParsing() {
}
void moveTo(File f) {
if (dataFile != null) {
dataFile.renameTo(f);
} else {
try {
OutputStream os = new FileOutputStream(f);
try {
InputStream in = readOnce();
byte[] buf = new byte[8192];
int len;
while((len=in.read(buf)) != -1) {
os.write(buf, 0, len);
}
} finally {
if (os != null) {
os.close();
}
}
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
}
}
void close() {
head = tail = null;
if (dataFile != null) {
dataFile.close();
}
}
/**
* Can get the attachment part's content multiple times. That means
* the full content needs to be there in memory or on the file system.
* Calling this method would trigger parsing for the part's data. So
* do not call this unless it is required(otherwise, just wrap MIMEPart
* into a object that returns InputStream for e.g DataHandler)
*
* @return data for the part's content
*/
public InputStream read() {
if (readOnce) {
throw new IllegalStateException("readOnce() is called before, read() cannot be called later.");
}
// Trigger parsing for the part
while(tail == null) {
if (!part.msg.makeProgress()) {
throw new IllegalStateException("No such MIME Part: "+part);
}
}
if (head == null) {
throw new IllegalStateException("Already read. Probably readOnce() is called before.");
}
return new ReadMultiStream();
}
/**
* Used for an assertion. Returns true when readOnce() is not already called.
* or otherwise throw an exception.
*
* <p>
* Calling this method also marks the stream as 'consumed'
*
* @return true if readOnce() is not called before
*/
@SuppressWarnings("ThrowableInitCause")
private boolean unconsumed() {
if (consumedAt != null) {
AssertionError error = new AssertionError("readOnce() is already called before. See the nested exception from where it's called.");
error.initCause(consumedAt);
throw error;
}
consumedAt = new Exception().fillInStackTrace();
return true;
}
/**
* Can get the attachment part's content only once. The content
* will be lost after the method. Content data is not be stored
* on the file system or is not kept in the memory for the
* following case:
* - Attachement parts contents are accessed sequentially
*
* In general, take advantage of this when the data is used only
* once.
*
* @return data for the part's content
*/
public InputStream readOnce() {
assert unconsumed();
if (readOnce) {
throw new IllegalStateException("readOnce() is called before. It can only be called once.");
}
readOnce = true;
// Trigger parsing for the part
while(tail == null) {
if (!part.msg.makeProgress() && tail == null) {
throw new IllegalStateException("No such Part: "+part);
}
}
InputStream in = new ReadOnceStream();
head = null;
return in;
}
class ReadMultiStream extends InputStream {
Chunk current;
int offset;
int len;
byte[] buf;
boolean closed;
public ReadMultiStream() {
this.current = head;
len = current.data.size();
buf = current.data.read();
}
@Override
public int read(byte b[], int off, int sz) throws IOException {
if (!fetch()) {
return -1;
}
sz = Math.min(sz, len-offset);
System.arraycopy(buf,offset,b,off,sz);
offset += sz;
return sz;
}
@Override
public int read() throws IOException {
if (!fetch()) {
return -1;
}
return (buf[offset++] & 0xff);
}
void adjustInMemoryUsage() {
// Nothing to do in this case.
}
/**
* Gets to the next chunk if we are done with the current one.
* @return true if any data available
* @throws IOException when i/o error
*/
private boolean fetch() throws IOException {
if (closed) {
throw new IOException("Stream already closed");
}
if (current == null) {
return false;
}
while(offset==len) {
while(!part.parsed && current.next == null) {
part.msg.makeProgress();
}
current = current.next;
if (current == null) {
return false;
}
adjustInMemoryUsage();
this.offset = 0;
this.buf = current.data.read();
this.len = current.data.size();
}
return true;
}
@Override
public void close() throws IOException {
super.close();
current = null;
closed = true;
}
}
final class ReadOnceStream extends ReadMultiStream {
@Override
void adjustInMemoryUsage() {
synchronized(DataHead.this) {
inMemory -= current.data.size(); // adjust current memory usage
}
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* FROM mail.jar */
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.IOException;
/**
* A special IOException that indicates a failure to decode data due
* to an error in the formatting of the data. This allows applications
* to distinguish decoding errors from other I/O errors.
*
* @author Bill Shannon
*/
public final class DecodingException extends IOException {
/**
* Constructor
*/
public DecodingException(String s) {
super(s);
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
class FactoryFinder {
private static ClassLoader cl = FactoryFinder.class.getClassLoader();
static Object find(String factoryId) throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
String systemProp = System.getProperty(factoryId);
if (systemProp != null) {
return newInstance(systemProp);
}
String providerName = findJarServiceProviderName(factoryId);
if (providerName != null && providerName.trim().length() > 0) {
return newInstance(providerName);
}
return null;
}
static Object newInstance(String className) throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
Class providerClass = cl.loadClass(className);
Object instance = providerClass.newInstance();
return instance;
}
private static String findJarServiceProviderName(String factoryId) {
String serviceId = "META-INF/services/" + factoryId;
InputStream is;
is = cl.getResourceAsStream(serviceId);
if (is == null) {
return null;
}
String factoryClassName;
BufferedReader rd = null;
try {
try {
rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
} catch (java.io.UnsupportedEncodingException e) {
rd = new BufferedReader(new InputStreamReader(is));
}
try {
factoryClassName = rd.readLine();
} catch (IOException x) {
return null;
}
} finally {
if (rd != null) {
try {
rd.close();
} catch (IOException ex) {
Logger.getLogger(FactoryFinder.class.getName()).log(Level.INFO, null, ex);
}
}
}
return factoryClassName;
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.nio.ByteBuffer;
/**
* Keeps the Part's partial content data in a file.
*
* @author Kohsuke Kawaguchi
* @author Jitendra Kotamraju
*/
final class FileData implements Data {
private final DataFile file;
private final long pointer; // read position
private final int length;
FileData(DataFile file, ByteBuffer buf) {
this(file, file.writeTo(buf.array(), 0, buf.limit()), buf.limit());
}
FileData(DataFile file, long pointer, int length) {
this.file = file;
this.pointer = pointer;
this.length = length;
}
@Override
public byte[] read() {
byte[] buf = new byte[length];
file.read(pointer, buf, 0, length);
return buf;
}
/*
* This shouldn't be called
*/
@Override
public long writeTo(DataFile file) {
throw new IllegalStateException();
}
@Override
public int size() {
return length;
}
/*
* Always create FileData
*/
@Override
public Data createNext(DataHead dataHead, ByteBuffer buf) {
return new FileData(file, buf);
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.util.ArrayList;
import java.util.Collection;
/**
* {@link java.util.ArrayList} with the final keyword.
*
* <p>
* This gives HotSpot a better hint that all methods can be inlined.
*
* @author Kohsuke Kawaguchi
*/
final class FinalArrayList<T> extends ArrayList<T> {
public FinalArrayList(int initialCapacity) {
super(initialCapacity);
}
public FinalArrayList() {
}
public FinalArrayList(Collection<? extends T> ts) {
super(ts);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
/**
* The Header class stores a name/value pair to represent headers.
*
* @author John Mani
*/
public interface Header {
/**
* Returns the name of this header.
*
* @return name of the header
*/
String getName();
/**
* Returns the value of this header.
*
* @return value of the header
*/
String getValue();
}

View File

@@ -0,0 +1,244 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.List;
/**
* InternetHeaders is a utility class that manages RFC822 style
* headers. Given an RFC822 format message stream, it reads lines
* until the blank line that indicates end of header. The input stream
* is positioned at the start of the body. The lines are stored
* within the object and can be extracted as either Strings or
* {@link Header} objects. <p>
* <p/>
* This class is mostly intended for service providers. MimeMessage
* and MimeBody use this class for holding their headers. <p>
* <p/>
* <hr> <strong>A note on RFC822 and MIME headers</strong><p>
* <p/>
* RFC822 and MIME header fields <strong>must</strong> contain only
* US-ASCII characters. If a header contains non US-ASCII characters,
* it must be encoded as per the rules in RFC 2047. The MimeUtility
* class provided in this package can be used to to achieve this.
* Callers of the <code>setHeader</code>, <code>addHeader</code>, and
* <code>addHeaderLine</code> methods are responsible for enforcing
* the MIME requirements for the specified headers. In addition, these
* header fields must be folded (wrapped) before being sent if they
* exceed the line length limitation for the transport (1000 bytes for
* SMTP). Received headers may have been folded. The application is
* responsible for folding and unfolding headers as appropriate. <p>
*
* @author John Mani
* @author Bill Shannon
*/
final class InternetHeaders {
private final FinalArrayList<Hdr> headers = new FinalArrayList<Hdr>();
/**
* Read and parse the given RFC822 message stream till the
* blank line separating the header from the body. Store the
* header lines inside this InternetHeaders object. <p>
* <p/>
* Note that the header lines are added into this InternetHeaders
* object, so any existing headers in this object will not be
* affected.
*
* @param lis RFC822 input stream
*/
InternetHeaders(MIMEParser.LineInputStream lis) {
// Read header lines until a blank line. It is valid
// to have BodyParts with no header lines.
String line;
String prevline = null; // the previous header line, as a string
// a buffer to accumulate the header in, when we know it's needed
StringBuilder lineBuffer = new StringBuilder();
try {
//while ((line = lis.readLine()) != null) {
do {
line = lis.readLine();
if (line != null &&
(line.startsWith(" ") || line.startsWith("\t"))) {
// continuation of header
if (prevline != null) {
lineBuffer.append(prevline);
prevline = null;
}
lineBuffer.append("\r\n");
lineBuffer.append(line);
} else {
// new header
if (prevline != null) {
addHeaderLine(prevline);
} else if (lineBuffer.length() > 0) {
// store previous header first
addHeaderLine(lineBuffer.toString());
lineBuffer.setLength(0);
}
prevline = line;
}
} while (line != null && line.length() > 0);
} catch (IOException ioex) {
throw new MIMEParsingException("Error in input stream", ioex);
}
}
/**
* Return all the values for the specified header. The
* values are String objects. Returns <code>null</code>
* if no headers with the specified name exist.
*
* @param name header name
* @return array of header values, or null if none
*/
List<String> getHeader(String name) {
// XXX - should we just step through in index order?
FinalArrayList<String> v = new FinalArrayList<String>(); // accumulate return values
int len = headers.size();
for( int i=0; i<len; i++ ) {
Hdr h = (Hdr) headers.get(i);
if (name.equalsIgnoreCase(h.name)) {
v.add(h.getValue());
}
}
return (v.size() == 0) ? null : v;
}
/**
* Return all the headers as an Enumeration of
* {@link Header} objects.
*
* @return Header objects
*/
FinalArrayList<? extends Header> getAllHeaders() {
return headers; // conceptually it should be read-only, but for performance reason I'm not wrapping it here
}
/**
* Add an RFC822 header line to the header store.
* If the line starts with a space or tab (a continuation line),
* add it to the last header line in the list. <p>
* <p/>
* Note that RFC822 headers can only contain US-ASCII characters
*
* @param line raw RFC822 header line
*/
void addHeaderLine(String line) {
try {
char c = line.charAt(0);
if (c == ' ' || c == '\t') {
Hdr h = (Hdr) headers.get(headers.size() - 1);
h.line += "\r\n" + line;
} else {
headers.add(new Hdr(line));
}
} catch (StringIndexOutOfBoundsException e) {
// line is empty, ignore it
} catch (NoSuchElementException e) {
// XXX - vector is empty?
}
}
}
/*
* A private utility class to represent an individual header.
*/
class Hdr implements Header {
String name; // the canonicalized (trimmed) name of this header
// XXX - should name be stored in lower case?
String line; // the entire RFC822 header "line"
/*
* Constructor that takes a line and splits out
* the header name.
*/
Hdr(String l) {
int i = l.indexOf(':');
if (i < 0) {
// should never happen
name = l.trim();
} else {
name = l.substring(0, i).trim();
}
line = l;
}
/*
* Constructor that takes a header name and value.
*/
Hdr(String n, String v) {
name = n;
line = n + ": " + v;
}
/*
* Return the "name" part of the header line.
*/
@Override
public String getName() {
return name;
}
/*
* Return the "value" part of the header line.
*/
@Override
public String getValue() {
int i = line.indexOf(':');
if (i < 0) {
return line;
}
int j;
if (name.equalsIgnoreCase("Content-Description")) {
// Content-Description should retain the folded whitespace after header unfolding -
// rf. RFC2822 section 2.2.3, rf. RFC2822 section 3.2.3
for (j = i + 1; j < line.length(); j++) {
char c = line.charAt(j);
if (!(/*c == ' ' ||*/c == '\t' || c == '\r' || c == '\n')) {
break;
}
}
} else {
// skip whitespace after ':'
for (j = i + 1; j < line.length(); j++) {
char c = line.charAt(j);
if (!(c == ' ' || c == '\t' || c == '\r' || c == '\n')) {
break;
}
}
}
return line.substring(j);
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* FROM mail.jar */
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.*;
/**
* This class is to support reading CRLF terminated lines that
* contain only US-ASCII characters from an input stream. Provides
* functionality that is similar to the deprecated
* <code>DataInputStream.readLine()</code>. Expected use is to read
* lines as String objects from a RFC822 stream.
*
* It is implemented as a FilterInputStream, so one can just wrap
* this class around any input stream and read bytes from this filter.
*
* @author John Mani
*/
final class LineInputStream extends FilterInputStream {
private char[] lineBuffer = null; // reusable byte buffer
private static int MAX_INCR = 1024*1024; // 1MB
public LineInputStream(InputStream in) {
super(in);
}
/**
* Read a line containing only ASCII characters from the input
* stream. A line is terminated by a CR or NL or CR-NL sequence.
* A common error is a CR-CR-NL sequence, which will also terminate
* a line.
* The line terminator is not returned as part of the returned
* String. Returns null if no data is available. <p>
*
* This class is similar to the deprecated
* <code>DataInputStream.readLine()</code>
*/
public String readLine() throws IOException {
//InputStream in = this.in;
char[] buf = lineBuffer;
if (buf == null) {
buf = lineBuffer = new char[128];
}
int c1;
int room = buf.length;
int offset = 0;
while ((c1 = in.read()) != -1) {
if (c1 == '\n') {
break;
} else if (c1 == '\r') {
// Got CR, is the next char NL ?
boolean twoCRs = false;
if (in.markSupported()) {
in.mark(2);
}
int c2 = in.read();
if (c2 == '\r') { // discard extraneous CR
twoCRs = true;
c2 = in.read();
}
if (c2 != '\n') {
/*
* If the stream supports it (which we hope will always
* be the case), reset to after the first CR. Otherwise,
* we wrap a PushbackInputStream around the stream so we
* can unread the characters we don't need. The only
* problem with that is that the caller might stop
* reading from this LineInputStream, throw it away,
* and then start reading from the underlying stream.
* If that happens, the pushed back characters will be
* lost forever.
*/
if (in.markSupported()) {
in.reset();
} else {
if (!(in instanceof PushbackInputStream)) {
in /*= this.in*/ = new PushbackInputStream(in, 2);
}
if (c2 != -1) {
((PushbackInputStream)in).unread(c2);
}
if (twoCRs) {
((PushbackInputStream)in).unread('\r');
}
}
}
break; // outa here.
}
// Not CR, NL or CR-NL ...
// .. Insert the byte into our byte buffer
if (--room < 0) { // No room, need to grow.
if (buf.length < MAX_INCR) {
buf = new char[buf.length * 2];
} else {
buf = new char[buf.length + MAX_INCR];
}
room = buf.length - offset - 1;
System.arraycopy(lineBuffer, 0, buf, 0, offset);
lineBuffer = buf;
}
buf[offset++] = (char)c1;
}
if ((c1 == -1) && (offset == 0)) {
return null;
}
return String.copyValueOf(buf, 0, offset);
}
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Configuration for MIME message parsing and storing.
*
* @author Jitendra Kotamraju
*/
public class MIMEConfig {
private static final int DEFAULT_CHUNK_SIZE = 8192;
private static final long DEFAULT_MEMORY_THRESHOLD = 1048576L;
private static final String DEFAULT_FILE_PREFIX = "MIME";
private static final Logger LOGGER = Logger.getLogger(MIMEConfig.class.getName());
// Parses the entire message eagerly
boolean parseEagerly;
// Approximate Chunk size
int chunkSize;
// Maximum in-memory data per attachment
long memoryThreshold;
// temp Dir to store large files
File tempDir;
String prefix;
String suffix;
private MIMEConfig(boolean parseEagerly, int chunkSize,
long inMemoryThreshold, String dir, String prefix, String suffix) {
this.parseEagerly = parseEagerly;
this.chunkSize = chunkSize;
this.memoryThreshold = inMemoryThreshold;
this.prefix = prefix;
this.suffix = suffix;
setDir(dir);
}
public MIMEConfig() {
this(false, DEFAULT_CHUNK_SIZE, DEFAULT_MEMORY_THRESHOLD, null,
DEFAULT_FILE_PREFIX, null);
}
boolean isParseEagerly() {
return parseEagerly;
}
public void setParseEagerly(boolean parseEagerly) {
this.parseEagerly = parseEagerly;
}
int getChunkSize() {
return chunkSize;
}
void setChunkSize(int chunkSize) {
this.chunkSize = chunkSize;
}
long getMemoryThreshold() {
return memoryThreshold;
}
/**
* If the attachment is greater than the threshold, it is
* written to the disk.
*
* @param memoryThreshold no of bytes per attachment
* if -1, then the whole attachment is kept in memory
*/
public void setMemoryThreshold(long memoryThreshold) {
this.memoryThreshold = memoryThreshold;
}
boolean isOnlyMemory() {
return memoryThreshold == -1L;
}
File getTempDir() {
return tempDir;
}
String getTempFilePrefix() {
return prefix;
}
String getTempFileSuffix() {
return suffix;
}
/**
* @param dir
*/
public final void setDir(String dir) {
if (tempDir == null && dir != null && !dir.equals("")) {
tempDir = new File(dir);
}
}
/**
* Validates if it can create temporary files. Otherwise, it stores
* attachment contents in memory.
*/
public void validate() {
if (!isOnlyMemory()) {
try {
File tempFile = (tempDir == null)
? File.createTempFile(prefix, suffix)
: File.createTempFile(prefix, suffix, tempDir);
boolean deleted = tempFile.delete();
if (!deleted) {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "File {0} was not deleted", tempFile.getAbsolutePath());
}
}
} catch(Exception ioe) {
memoryThreshold = -1L; // whole attachment will be in-memory
}
}
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.nio.ByteBuffer;
/**
* @author Jitendra Kotamraju
*/
abstract class MIMEEvent {
enum EVENT_TYPE {START_MESSAGE, START_PART, HEADERS, CONTENT, END_PART, END_MESSAGE}
/**
* Returns a event for parser's current cursor location in the MIME message.
*
* <p>
* {@link EVENT_TYPE#START_MESSAGE} and {@link EVENT_TYPE#START_MESSAGE} events
* are generated only once.
*
* <p>
* {@link EVENT_TYPE#START_PART}, {@link EVENT_TYPE#END_PART}, {@link EVENT_TYPE#HEADERS}
* events are generated only once for each attachment part.
*
* <p>
* {@link EVENT_TYPE#CONTENT} event may be generated more than once for an attachment
* part.
*
* @return event type
*/
abstract EVENT_TYPE getEventType();
static final StartMessage START_MESSAGE = new StartMessage();
static final StartPart START_PART = new StartPart();
static final EndPart END_PART = new EndPart();
static final EndMessage END_MESSAGE = new EndMessage();
static final class StartMessage extends MIMEEvent {
EVENT_TYPE getEventType() {
return EVENT_TYPE.START_MESSAGE;
}
}
static final class StartPart extends MIMEEvent {
EVENT_TYPE getEventType() {
return EVENT_TYPE.START_PART;
}
}
static final class EndPart extends MIMEEvent {
EVENT_TYPE getEventType () {
return EVENT_TYPE.END_PART;
}
}
static final class Headers extends MIMEEvent {
InternetHeaders ih;
Headers(InternetHeaders ih) {
this.ih = ih;
}
EVENT_TYPE getEventType() {
return EVENT_TYPE.HEADERS;
}
InternetHeaders getHeaders() {
return ih;
}
}
static final class Content extends MIMEEvent {
private final ByteBuffer buf;
Content(ByteBuffer buf) {
this.buf = buf;
}
EVENT_TYPE getEventType() {
return EVENT_TYPE.CONTENT;
}
ByteBuffer getData() {
return buf;
}
}
static final class EndMessage extends MIMEEvent {
EVENT_TYPE getEventType() {
return EVENT_TYPE.END_MESSAGE;
}
}
}

View File

@@ -0,0 +1,250 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Represents MIME message. MIME message parsing is done lazily using a
* pull parser.
*
* @author Jitendra Kotamraju
*/
public class MIMEMessage {
private static final Logger LOGGER = Logger.getLogger(MIMEMessage.class.getName());
MIMEConfig config;
private final InputStream in;
private final List<MIMEPart> partsList;
private final Map<String, MIMEPart> partsMap;
private final Iterator<MIMEEvent> it;
private boolean parsed; // true when entire message is parsed
private MIMEPart currentPart;
private int currentIndex;
/**
* @see MIMEMessage(InputStream, String, MIMEConfig)
*/
public MIMEMessage(InputStream in, String boundary) {
this(in, boundary, new MIMEConfig());
}
/**
* Creates a MIME message from the content's stream. The content stream
* is closed when EOF is reached.
*
* @param in MIME message stream
* @param boundary the separator for parts(pass it without --)
* @param config various configuration parameters
*/
public MIMEMessage(InputStream in, String boundary, MIMEConfig config) {
this.in = in;
this.config = config;
MIMEParser parser = new MIMEParser(in, boundary, config);
it = parser.iterator();
partsList = new ArrayList<MIMEPart>();
partsMap = new HashMap<String, MIMEPart>();
if (config.isParseEagerly()) {
parseAll();
}
}
/**
* Gets all the attachments by parsing the entire MIME message. Avoid
* this if possible since it is an expensive operation.
*
* @return list of attachments.
*/
public List<MIMEPart> getAttachments() {
if (!parsed) {
parseAll();
}
return partsList;
}
/**
* Creates nth attachment lazily. It doesn't validate
* if the message has so many attachments. To
* do the validation, the message needs to be parsed.
* The parsing of the message is done lazily and is done
* while reading the bytes of the part.
*
* @param index sequential order of the part. starts with zero.
* @return attachemnt part
*/
public MIMEPart getPart(int index) {
LOGGER.log(Level.FINE, "index={0}", index);
MIMEPart part = (index < partsList.size()) ? partsList.get(index) : null;
if (parsed && part == null) {
throw new MIMEParsingException("There is no "+index+" attachment part ");
}
if (part == null) {
// Parsing will done lazily and will be driven by reading the part
part = new MIMEPart(this);
partsList.add(index, part);
}
LOGGER.log(Level.FINE, "Got attachment at index={0} attachment={1}", new Object[]{index, part});
return part;
}
/**
* Creates a lazy attachment for a given Content-ID. It doesn't validate
* if the message contains an attachment with the given Content-ID. To
* do the validation, the message needs to be parsed. The parsing of the
* message is done lazily and is done while reading the bytes of the part.
*
* @param contentId Content-ID of the part, expects Content-ID without <, >
* @return attachemnt part
*/
public MIMEPart getPart(String contentId) {
LOGGER.log(Level.FINE, "Content-ID={0}", contentId);
MIMEPart part = getDecodedCidPart(contentId);
if (parsed && part == null) {
throw new MIMEParsingException("There is no attachment part with Content-ID = "+contentId);
}
if (part == null) {
// Parsing is done lazily and is driven by reading the part
part = new MIMEPart(this, contentId);
partsMap.put(contentId, part);
}
LOGGER.log(Level.FINE, "Got attachment for Content-ID={0} attachment={1}", new Object[]{contentId, part});
return part;
}
// this is required for Indigo interop, it writes content-id without escaping
private MIMEPart getDecodedCidPart(String cid) {
MIMEPart part = partsMap.get(cid);
if (part == null) {
if (cid.indexOf('%') != -1) {
try {
String tempCid = URLDecoder.decode(cid, "utf-8");
part = partsMap.get(tempCid);
} catch(UnsupportedEncodingException ue) {
// Ignore it
}
}
}
return part;
}
/**
* Parses the whole MIME message eagerly
*/
public final void parseAll() {
while(makeProgress()) {
// Nothing to do
}
}
/**
* Parses the MIME message in a pull fashion.
*
* @return
* false if the parsing is completed.
*/
public synchronized boolean makeProgress() {
if (!it.hasNext()) {
return false;
}
MIMEEvent event = it.next();
switch(event.getEventType()) {
case START_MESSAGE :
LOGGER.log(Level.FINE, "MIMEEvent={0}", MIMEEvent.EVENT_TYPE.START_MESSAGE);
break;
case START_PART :
LOGGER.log(Level.FINE, "MIMEEvent={0}", MIMEEvent.EVENT_TYPE.START_PART);
break;
case HEADERS :
LOGGER.log(Level.FINE, "MIMEEvent={0}", MIMEEvent.EVENT_TYPE.HEADERS);
MIMEEvent.Headers headers = (MIMEEvent.Headers)event;
InternetHeaders ih = headers.getHeaders();
List<String> cids = ih.getHeader("content-id");
String cid = (cids != null) ? cids.get(0) : currentIndex+"";
if (cid.length() > 2 && cid.charAt(0)=='<') {
cid = cid.substring(1,cid.length()-1);
}
MIMEPart listPart = (currentIndex < partsList.size()) ? partsList.get(currentIndex) : null;
MIMEPart mapPart = getDecodedCidPart(cid);
if (listPart == null && mapPart == null) {
currentPart = getPart(cid);
partsList.add(currentIndex, currentPart);
} else if (listPart == null) {
currentPart = mapPart;
partsList.add(currentIndex, mapPart);
} else if (mapPart == null) {
currentPart = listPart;
currentPart.setContentId(cid);
partsMap.put(cid, currentPart);
} else if (listPart != mapPart) {
throw new MIMEParsingException("Created two different attachments using Content-ID and index");
}
currentPart.setHeaders(ih);
break;
case CONTENT :
LOGGER.log(Level.FINER, "MIMEEvent={0}", MIMEEvent.EVENT_TYPE.CONTENT);
MIMEEvent.Content content = (MIMEEvent.Content)event;
ByteBuffer buf = content.getData();
currentPart.addBody(buf);
break;
case END_PART :
LOGGER.log(Level.FINE, "MIMEEvent={0}", MIMEEvent.EVENT_TYPE.END_PART);
currentPart.doneParsing();
++currentIndex;
break;
case END_MESSAGE :
LOGGER.log(Level.FINE, "MIMEEvent={0}", MIMEEvent.EVENT_TYPE.END_MESSAGE);
parsed = true;
try {
in.close();
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
break;
default :
throw new MIMEParsingException("Unknown Parser state = "+event.getEventType());
}
return true;
}
}

View File

@@ -0,0 +1,502 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.InputStream;
import java.io.IOException;
import java.util.*;
import java.util.logging.Logger;
import java.nio.ByteBuffer;
import java.util.logging.Level;
/**
* Pull parser for the MIME messages. Applications can use pull API to continue
* the parsing MIME messages lazily.
*
* <pre>
* for e.g.:
* <p>
*
* MIMEParser parser = ...
* Iterator<MIMEEvent> it = parser.iterator();
* while(it.hasNext()) {
* MIMEEvent event = it.next();
* ...
* }
* </pre>
*
* @author Jitendra Kotamraju
*/
class MIMEParser implements Iterable<MIMEEvent> {
private static final Logger LOGGER = Logger.getLogger(MIMEParser.class.getName());
private static final String HEADER_ENCODING = "ISO8859-1";
// Actually, the grammar doesn't support whitespace characters
// after boundary. But the mail implementation checks for it.
// We will only check for these many whitespace characters after boundary
private static final int NO_LWSP = 1000;
private enum STATE {START_MESSAGE, SKIP_PREAMBLE, START_PART, HEADERS, BODY, END_PART, END_MESSAGE}
private STATE state = STATE.START_MESSAGE;
private final InputStream in;
private final byte[] bndbytes;
private final int bl;
private final MIMEConfig config;
private final int[] bcs = new int[128]; // BnM algo: Bad Character Shift table
private final int[] gss; // BnM algo : Good Suffix Shift table
/**
* Have we parsed the data from our InputStream yet?
*/
private boolean parsed;
/*
* Read and process body partsList until we see the
* terminating boundary line (or EOF).
*/
private boolean done = false;
private boolean eof;
private final int capacity;
private byte[] buf;
private int len;
private boolean bol; // beginning of the line
/*
* Parses the MIME content. At the EOF, it also closes input stream
*/
MIMEParser(InputStream in, String boundary, MIMEConfig config) {
this.in = in;
this.bndbytes = getBytes("--"+boundary);
bl = bndbytes.length;
this.config = config;
gss = new int[bl];
compileBoundaryPattern();
// \r\n + boundary + "--\r\n" + lots of LWSP
capacity = config.chunkSize+2+bl+4+NO_LWSP;
createBuf(capacity);
}
/**
* Returns iterator for the parsing events. Use the iterator to advance
* the parsing.
*
* @return iterator for parsing events
*/
@Override
public Iterator<MIMEEvent> iterator() {
return new MIMEEventIterator();
}
class MIMEEventIterator implements Iterator<MIMEEvent> {
@Override
public boolean hasNext() {
return !parsed;
}
@Override
public MIMEEvent next() {
switch(state) {
case START_MESSAGE :
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "MIMEParser state={0}", STATE.START_MESSAGE);}
state = STATE.SKIP_PREAMBLE;
return MIMEEvent.START_MESSAGE;
case SKIP_PREAMBLE :
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "MIMEParser state={0}", STATE.SKIP_PREAMBLE);}
skipPreamble();
// fall through
case START_PART :
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "MIMEParser state={0}", STATE.START_PART);}
state = STATE.HEADERS;
return MIMEEvent.START_PART;
case HEADERS :
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "MIMEParser state={0}", STATE.HEADERS);}
InternetHeaders ih = readHeaders();
state = STATE.BODY;
bol = true;
return new MIMEEvent.Headers(ih);
case BODY :
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "MIMEParser state={0}", STATE.BODY);}
ByteBuffer buf = readBody();
bol = false;
return new MIMEEvent.Content(buf);
case END_PART :
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "MIMEParser state={0}", STATE.END_PART);}
if (done) {
state = STATE.END_MESSAGE;
} else {
state = STATE.START_PART;
}
return MIMEEvent.END_PART;
case END_MESSAGE :
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "MIMEParser state={0}", STATE.END_MESSAGE);}
parsed = true;
return MIMEEvent.END_MESSAGE;
default :
throw new MIMEParsingException("Unknown Parser state = "+state);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* Collects the headers for the current part by parsing mesage stream.
*
* @return headers for the current part
*/
private InternetHeaders readHeaders() {
if (!eof) {
fillBuf();
}
return new InternetHeaders(new LineInputStream());
}
/**
* Reads and saves the part of the current attachment part's content.
* At the end of this method, buf should have the remaining data
* at index 0.
*
* @return a chunk of the part's content
*
*/
private ByteBuffer readBody() {
if (!eof) {
fillBuf();
}
int start = match(buf, 0, len); // matches boundary
if (start == -1) {
// No boundary is found
assert eof || len >= config.chunkSize;
int chunkSize = eof ? len : config.chunkSize;
if (eof) {
done = true;
throw new MIMEParsingException("Reached EOF, but there is no closing MIME boundary.");
}
return adjustBuf(chunkSize, len-chunkSize);
}
// Found boundary.
// Is it at the start of a line ?
int chunkLen = start;
if (bol && start == 0) {
// nothing to do
} else if (start > 0 && (buf[start-1] == '\n' || buf[start-1] =='\r')) {
--chunkLen;
if (buf[start-1] == '\n' && start >1 && buf[start-2] == '\r') {
--chunkLen;
}
} else {
return adjustBuf(start+1, len-start-1); // boundary is not at beginning of a line
}
if (start+bl+1 < len && buf[start+bl] == '-' && buf[start+bl+1] == '-') {
state = STATE.END_PART;
done = true;
return adjustBuf(chunkLen, 0);
}
// Consider all the whitespace in boundary+whitespace+"\r\n"
int lwsp = 0;
for(int i=start+bl; i < len && (buf[i] == ' ' || buf[i] == '\t'); i++) {
++lwsp;
}
// Check for \n or \r\n in boundary+whitespace+"\n" or boundary+whitespace+"\r\n"
if (start+bl+lwsp < len && buf[start+bl+lwsp] == '\n') {
state = STATE.END_PART;
return adjustBuf(chunkLen, len-start-bl-lwsp-1);
} else if (start+bl+lwsp+1 < len && buf[start+bl+lwsp] == '\r' && buf[start+bl+lwsp+1] == '\n') {
state = STATE.END_PART;
return adjustBuf(chunkLen, len-start-bl-lwsp-2);
} else if (start+bl+lwsp+1 < len) {
return adjustBuf(chunkLen+1, len-chunkLen-1); // boundary string in a part data
} else if (eof) {
done = true;
throw new MIMEParsingException("Reached EOF, but there is no closing MIME boundary.");
}
// Some more data needed to determine if it is indeed a proper boundary
return adjustBuf(chunkLen, len-chunkLen);
}
/**
* Returns a chunk from the original buffer. A new buffer is
* created with the remaining bytes.
*
* @param chunkSize create a chunk with these many bytes
* @param remaining bytes from the end of the buffer that need to be copied to
* the beginning of the new buffer
* @return chunk
*/
private ByteBuffer adjustBuf(int chunkSize, int remaining) {
assert buf != null;
assert chunkSize >= 0;
assert remaining >= 0;
byte[] temp = buf;
// create a new buf and adjust it without this chunk
createBuf(remaining);
System.arraycopy(temp, len-remaining, buf, 0, remaining);
len = remaining;
return ByteBuffer.wrap(temp, 0, chunkSize);
}
private void createBuf(int min) {
buf = new byte[min < capacity ? capacity : min];
}
/**
* Skips the preamble to find the first attachment part
*/
private void skipPreamble() {
while(true) {
if (!eof) {
fillBuf();
}
int start = match(buf, 0, len); // matches boundary
if (start == -1) {
// No boundary is found
if (eof) {
throw new MIMEParsingException("Missing start boundary");
} else {
adjustBuf(len-bl+1, bl-1);
continue;
}
}
if (start > config.chunkSize) {
adjustBuf(start, len-start);
continue;
}
// Consider all the whitespace boundary+whitespace+"\r\n"
int lwsp = 0;
for(int i=start+bl; i < len && (buf[i] == ' ' || buf[i] == '\t'); i++) {
++lwsp;
}
// Check for \n or \r\n
if (start+bl+lwsp < len && (buf[start+bl+lwsp] == '\n' || buf[start+bl+lwsp] == '\r') ) {
if (buf[start+bl+lwsp] == '\n') {
adjustBuf(start+bl+lwsp+1, len-start-bl-lwsp-1);
break;
} else if (start+bl+lwsp+1 < len && buf[start+bl+lwsp+1] == '\n') {
adjustBuf(start+bl+lwsp+2, len-start-bl-lwsp-2);
break;
}
}
adjustBuf(start+1, len-start-1);
}
if (LOGGER.isLoggable(Level.FINE)) {LOGGER.log(Level.FINE, "Skipped the preamble. buffer len={0}", len);}
}
private static byte[] getBytes(String s) {
char [] chars= s.toCharArray();
int size = chars.length;
byte[] bytes = new byte[size];
for (int i = 0; i < size;) {
bytes[i] = (byte) chars[i++];
}
return bytes;
}
/**
* Boyer-Moore search method. Copied from java.util.regex.Pattern.java
*
* Pre calculates arrays needed to generate the bad character
* shift and the good suffix shift. Only the last seven bits
* are used to see if chars match; This keeps the tables small
* and covers the heavily used ASCII range, but occasionally
* results in an aliased match for the bad character shift.
*/
private void compileBoundaryPattern() {
int i, j;
// Precalculate part of the bad character shift
// It is a table for where in the pattern each
// lower 7-bit value occurs
for (i = 0; i < bndbytes.length; i++) {
bcs[bndbytes[i]&0x7F] = i + 1;
}
// Precalculate the good suffix shift
// i is the shift amount being considered
NEXT: for (i = bndbytes.length; i > 0; i--) {
// j is the beginning index of suffix being considered
for (j = bndbytes.length - 1; j >= i; j--) {
// Testing for good suffix
if (bndbytes[j] == bndbytes[j-i]) {
// src[j..len] is a good suffix
gss[j-1] = i;
} else {
// No match. The array has already been
// filled up with correct values before.
continue NEXT;
}
}
// This fills up the remaining of optoSft
// any suffix can not have larger shift amount
// then its sub-suffix. Why???
while (j > 0) {
gss[--j] = i;
}
}
// Set the guard value because of unicode compression
gss[bndbytes.length -1] = 1;
}
/**
* Finds the boundary in the given buffer using Boyer-Moore algo.
* Copied from java.util.regex.Pattern.java
*
* @param mybuf boundary to be searched in this mybuf
* @param off start index in mybuf
* @param len number of bytes in mybuf
*
* @return -1 if there is no match or index where the match starts
*/
private int match(byte[] mybuf, int off, int len) {
int last = len - bndbytes.length;
// Loop over all possible match positions in text
NEXT: while (off <= last) {
// Loop over pattern from right to left
for (int j = bndbytes.length - 1; j >= 0; j--) {
byte ch = mybuf[off+j];
if (ch != bndbytes[j]) {
// Shift search to the right by the maximum of the
// bad character shift and the good suffix shift
off += Math.max(j + 1 - bcs[ch&0x7F], gss[j]);
continue NEXT;
}
}
// Entire pattern matched starting at off
return off;
}
return -1;
}
/**
* Fills the remaining buf to the full capacity
*/
private void fillBuf() {
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "Before fillBuf() buffer len={0}", len);}
assert !eof;
while(len < buf.length) {
int read;
try {
read = in.read(buf, len, buf.length-len);
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
if (read == -1) {
eof = true;
try {
if (LOGGER.isLoggable(Level.FINE)) {LOGGER.fine("Closing the input stream.");}
in.close();
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
break;
} else {
len += read;
}
}
if (LOGGER.isLoggable(Level.FINER)) {LOGGER.log(Level.FINER, "After fillBuf() buffer len={0}", len);}
}
private void doubleBuf() {
byte[] temp = new byte[2*len];
System.arraycopy(buf, 0, temp, 0, len);
buf = temp;
if (!eof) {
fillBuf();
}
}
class LineInputStream {
private int offset;
/*
* Read a line containing only ASCII characters from the input
* stream. A line is terminated by a CR or NL or CR-NL sequence.
* A common error is a CR-CR-NL sequence, which will also terminate
* a line.
* The line terminator is not returned as part of the returned
* String. Returns null if no data is available. <p>
*
* This class is similar to the deprecated
* <code>DataInputStream.readLine()</code>
*/
public String readLine() throws IOException {
int hdrLen = 0;
int lwsp = 0;
while(offset+hdrLen < len) {
if (buf[offset+hdrLen] == '\n') {
lwsp = 1;
break;
}
if (offset+hdrLen+1 == len) {
doubleBuf();
}
if (offset+hdrLen+1 >= len) { // No more data in the stream
assert eof;
return null;
}
if (buf[offset+hdrLen] == '\r' && buf[offset+hdrLen+1] == '\n') {
lwsp = 2;
break;
}
++hdrLen;
}
if (hdrLen == 0) {
adjustBuf(offset+lwsp, len-offset-lwsp);
return null;
}
String hdr = new String(buf, offset, hdrLen, HEADER_ENCODING);
offset += hdrLen+lwsp;
return hdr;
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
/**
* @author Jitendra Kotamraju
*/
/**
* The <code>MIMEParsingException</code> class is the base
* exception class for all MIME message parsing exceptions.
*
*/
public class MIMEParsingException extends java.lang.RuntimeException {
/**
* Constructs a new exception with <code>null</code> as its
* detail message. The cause is not initialized.
*/
public MIMEParsingException() {
super();
}
/**
* Constructs a new exception with the specified detail
* message. The cause is not initialized.
*
* @param message The detail message which is later
* retrieved using the getMessage method
*/
public MIMEParsingException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail
* message and cause.
*
* @param message The detail message which is later retrieved
* using the getMessage method
* @param cause The cause which is saved for the later
* retrieval throw by the getCause method
*/
public MIMEParsingException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new WebServiceException with the specified cause
* and a detail message of <tt>(cause==null ? null :
* cause.toString())</tt> (which typically contains the
* class and detail message of <tt>cause</tt>).
*
* @param cause The cause which is saved for the later
* retrieval throw by the getCause method.
* (A <tt>null</tt> value is permitted, and
* indicates that the cause is nonexistent or
* unknown.)
*/
public MIMEParsingException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,250 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.File;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Represents an attachment part in a MIME message. MIME message parsing is done
* lazily using a pull parser, so the part may not have all the data. {@link #read}
* and {@link #readOnce} may trigger the actual parsing the message. In fact,
* parsing of an attachment part may be triggered by calling {@link #read} methods
* on some other attachment parts. All this happens behind the scenes so the
* application developer need not worry about these details.
*
* @author Jitendra Kotamraju, Martin Grebac
*/
public class MIMEPart {
private static final Logger LOGGER = Logger.getLogger(MIMEPart.class.getName());
private volatile InternetHeaders headers;
private volatile String contentId;
private String contentType;
private String contentTransferEncoding;
volatile boolean parsed; // part is parsed or not
final MIMEMessage msg;
private final DataHead dataHead;
MIMEPart(MIMEMessage msg) {
this.msg = msg;
this.dataHead = new DataHead(this);
}
MIMEPart(MIMEMessage msg, String contentId) {
this(msg);
this.contentId = contentId;
}
/**
* Can get the attachment part's content multiple times. That means
* the full content needs to be there in memory or on the file system.
* Calling this method would trigger parsing for the part's data. So
* do not call this unless it is required(otherwise, just wrap MIMEPart
* into a object that returns InputStream for e.g DataHandler)
*
* @return data for the part's content
*/
public InputStream read() {
InputStream is = null;
try {
is = MimeUtility.decode(dataHead.read(), contentTransferEncoding);
} catch (DecodingException ex) { //ignore
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, null, ex);
}
}
return is;
}
/**
* Cleans up any resources that are held by this part (for e.g. deletes
* the temp file that is used to serve this part's content). After
* calling this, one shouldn't call {@link #read()} or {@link #readOnce()}
*/
public void close() {
dataHead.close();
}
/**
* Can get the attachment part's content only once. The content
* will be lost after the method. Content data is not be stored
* on the file system or is not kept in the memory for the
* following case:
* - Attachement parts contents are accessed sequentially
*
* In general, take advantage of this when the data is used only
* once.
*
* @return data for the part's content
*/
public InputStream readOnce() {
InputStream is = null;
try {
is = MimeUtility.decode(dataHead.readOnce(), contentTransferEncoding);
} catch (DecodingException ex) { //ignore
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, null, ex);
}
}
return is;
}
public void moveTo(File f) {
dataHead.moveTo(f);
}
/**
* Returns Content-ID MIME header for this attachment part
*
* @return Content-ID of the part
*/
public String getContentId() {
if (contentId == null) {
getHeaders();
}
return contentId;
}
/**
* Returns Content-Transfer-Encoding MIME header for this attachment part
*
* @return Content-Transfer-Encoding of the part
*/
public String getContentTransferEncoding() {
if (contentTransferEncoding == null) {
getHeaders();
}
return contentTransferEncoding;
}
/**
* Returns Content-Type MIME header for this attachment part
*
* @return Content-Type of the part
*/
public String getContentType() {
if (contentType == null) {
getHeaders();
}
return contentType;
}
private void getHeaders() {
// Trigger parsing for the part headers
while(headers == null) {
if (!msg.makeProgress()) {
if (headers == null) {
throw new IllegalStateException("Internal Error. Didn't get Headers even after complete parsing.");
}
}
}
}
/**
* Return all the values for the specified header.
* Returns <code>null</code> if no headers with the
* specified name exist.
*
* @param name header name
* @return list of header values, or null if none
*/
public List<String> getHeader(String name) {
getHeaders();
assert headers != null;
return headers.getHeader(name);
}
/**
* Return all the headers
*
* @return list of Header objects
*/
public List<? extends Header> getAllHeaders() {
getHeaders();
assert headers != null;
return headers.getAllHeaders();
}
/**
* Callback to set headers
*
* @param headers MIME headers for the part
*/
void setHeaders(InternetHeaders headers) {
this.headers = headers;
List<String> ct = getHeader("Content-Type");
this.contentType = (ct == null) ? "application/octet-stream" : ct.get(0);
List<String> cte = getHeader("Content-Transfer-Encoding");
this.contentTransferEncoding = (cte == null) ? "binary" : cte.get(0);
}
/**
* Callback to notify that there is a partial content for the part
*
* @param buf content data for the part
*/
void addBody(ByteBuffer buf) {
dataHead.addBody(buf);
}
/**
* Callback to indicate that parsing is done for this part
* (no more update events for this part)
*/
void doneParsing() {
parsed = true;
dataHead.doneParsing();
}
/**
* Callback to set Content-ID for this part
* @param cid Content-ID of the part
*/
void setContentId(String cid) {
this.contentId = cid;
}
/**
* Callback to set Content-Transfer-Encoding for this part
* @param cte Content-Transfer-Encoding of the part
*/
void setContentTransferEncoding(String cte) {
this.contentTransferEncoding = cte;
}
@Override
public String toString() {
return "Part="+contentId+":"+contentTransferEncoding;
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.nio.ByteBuffer;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Keeps the Part's partial content data in memory.
*
* @author Kohsuke Kawaguchi
* @author Jitendra Kotamraju
*/
final class MemoryData implements Data {
private static final Logger LOGGER = Logger.getLogger(MemoryData.class.getName());
private final byte[] data;
private final int len;
private final MIMEConfig config;
MemoryData(ByteBuffer buf, MIMEConfig config) {
data = buf.array();
len = buf.limit();
this.config = config;
}
// size of the chunk given by the parser
@Override
public int size() {
return len;
}
@Override
public byte[] read() {
return data;
}
@Override
public long writeTo(DataFile file) {
return file.writeTo(data, 0, len);
}
/**
*
* @param dataHead
* @param buf
* @return
*/
@Override
public Data createNext(DataHead dataHead, ByteBuffer buf) {
if (!config.isOnlyMemory() && dataHead.inMemory >= config.memoryThreshold) {
try {
String prefix = config.getTempFilePrefix();
String suffix = config.getTempFileSuffix();
File tempFile = TempFiles.createTempFile(prefix, suffix, config.getTempDir());
// delete the temp file when VM exits as a last resort for file clean up
tempFile.deleteOnExit();
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Created temp file = {0}", tempFile);
}
// delete the temp file when VM exits as a last resort for file clean up
tempFile.deleteOnExit();
if (LOGGER.isLoggable(Level.FINE)) {LOGGER.log(Level.FINE, "Created temp file = {0}", tempFile);}
dataHead.dataFile = new DataFile(tempFile);
} catch (IOException ioe) {
throw new MIMEParsingException(ioe);
}
if (dataHead.head != null) {
for (Chunk c = dataHead.head; c != null; c = c.next) {
long pointer = c.data.writeTo(dataHead.dataFile);
c.data = new FileData(dataHead.dataFile, pointer, len);
}
}
return new FileData(dataHead.dataFile, buf);
} else {
return new MemoryData(buf, config);
}
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.*;
/**
* This is a utility class that provides various MIME related
* functionality. <p>
*
* There are a set of methods to encode and decode MIME headers as
* per RFC 2047. Note that, in general, these methods are
* <strong>not</strong> needed when using methods such as
* <code>setSubject</code> and <code>setRecipients</code>; JavaMail
* will automatically encode and decode data when using these "higher
* level" methods. The methods below are only needed when maniuplating
* raw MIME headers using <code>setHeader</code> and <code>getHeader</code>
* methods. A brief description on handling such headers is given below: <p>
*
* RFC 822 mail headers <strong>must</strong> contain only US-ASCII
* characters. Headers that contain non US-ASCII characters must be
* encoded so that they contain only US-ASCII characters. Basically,
* this process involves using either BASE64 or QP to encode certain
* characters. RFC 2047 describes this in detail. <p>
*
* In Java, Strings contain (16 bit) Unicode characters. ASCII is a
* subset of Unicode (and occupies the range 0 - 127). A String
* that contains only ASCII characters is already mail-safe. If the
* String contains non US-ASCII characters, it must be encoded. An
* additional complexity in this step is that since Unicode is not
* yet a widely used charset, one might want to first charset-encode
* the String into another charset and then do the transfer-encoding.
* <p>
* Note that to get the actual bytes of a mail-safe String (say,
* for sending over SMTP), one must do
* <p><blockquote><pre>
*
* byte[] bytes = string.getBytes("iso-8859-1");
*
* </pre></blockquote><p>
*
* The <code>setHeader</code> and <code>addHeader</code> methods
* on MimeMessage and MimeBodyPart assume that the given header values
* are Unicode strings that contain only US-ASCII characters. Hence
* the callers of those methods must insure that the values they pass
* do not contain non US-ASCII characters. The methods in this class
* help do this. <p>
*
* The <code>getHeader</code> family of methods on MimeMessage and
* MimeBodyPart return the raw header value. These might be encoded
* as per RFC 2047, and if so, must be decoded into Unicode Strings.
* The methods in this class help to do this. <p>
*
* Several System properties control strict conformance to the MIME
* spec. Note that these are not session properties but must be set
* globally as System properties. <p>
*
* The <code>mail.mime.decodetext.strict</code> property controls
* decoding of MIME encoded words. The MIME spec requires that encoded
* words start at the beginning of a whitespace separated word. Some
* mailers incorrectly include encoded words in the middle of a word.
* If the <code>mail.mime.decodetext.strict</code> System property is
* set to <code>"false"</code>, an attempt will be made to decode these
* illegal encoded words. The default is true. <p>
*
* The <code>mail.mime.encodeeol.strict</code> property controls the
* choice of Content-Transfer-Encoding for MIME parts that are not of
* type "text". Often such parts will contain textual data for which
* an encoding that allows normal end of line conventions is appropriate.
* In rare cases, such a part will appear to contain entirely textual
* data, but will require an encoding that preserves CR and LF characters
* without change. If the <code>mail.mime.encodeeol.strict</code>
* System property is set to <code>"true"</code>, such an encoding will
* be used when necessary. The default is false. <p>
*
* In addition, the <code>mail.mime.charset</code> System property can
* be used to specify the default MIME charset to use for encoded words
* and text parts that don't otherwise specify a charset. Normally, the
* default MIME charset is derived from the default Java charset, as
* specified in the <code>file.encoding</code> System property. Most
* applications will have no need to explicitly set the default MIME
* charset. In cases where the default MIME charset to be used for
* mail messages is different than the charset used for files stored on
* the system, this property should be set. <p>
*
* The current implementation also supports the following System property.
* <p>
* The <code>mail.mime.ignoreunknownencoding</code> property controls
* whether unknown values in the <code>Content-Transfer-Encoding</code>
* header, as passed to the <code>decode</code> method, cause an exception.
* If set to <code>"true"</code>, unknown values are ignored and 8bit
* encoding is assumed. Otherwise, unknown values cause a MessagingException
* to be thrown.
*
* @author John Mani
* @author Bill Shannon
*/
/* FROM mail.jar */
final class MimeUtility {
// This class cannot be instantiated
private MimeUtility() { }
private static final boolean ignoreUnknownEncoding =
PropUtil.getBooleanSystemProperty(
"mail.mime.ignoreunknownencoding", false);
/**
* Decode the given input stream. The Input stream returned is
* the decoded input stream. All the encodings defined in RFC 2045
* are supported here. They include "base64", "quoted-printable",
* "7bit", "8bit", and "binary". In addition, "uuencode" is also
* supported. <p>
*
* In the current implementation, if the
* <code>mail.mime.ignoreunknownencoding</code> system property is set to
* <code>"true"</code>, unknown encoding values are ignored and the
* original InputStream is returned.
*
* @param is input stream
* @param encoding the encoding of the stream.
* @return decoded input stream.
* @exception MessagingException if the encoding is unknown
*/
public static InputStream decode(InputStream is, String encoding)
throws DecodingException {
if (encoding.equalsIgnoreCase("base64"))
return new BASE64DecoderStream(is);
else if (encoding.equalsIgnoreCase("quoted-printable"))
return new QPDecoderStream(is);
else if (encoding.equalsIgnoreCase("uuencode") ||
encoding.equalsIgnoreCase("x-uuencode") ||
encoding.equalsIgnoreCase("x-uue"))
return new UUDecoderStream(is);
else if (encoding.equalsIgnoreCase("binary") ||
encoding.equalsIgnoreCase("7bit") ||
encoding.equalsIgnoreCase("8bit"))
return is;
else {
if (!ignoreUnknownEncoding) {
throw new DecodingException("Unknown encoding: " + encoding);
}
return is;
}
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* FROM mail.jar */
package com.sun.xml.internal.org.jvnet.mimepull;
import java.util.*;
/**
* Utilities to make it easier to get property values.
* Properties can be strings or type-specific value objects.
*
* @author Bill Shannon
*/
final class PropUtil {
// No one should instantiate this class.
private PropUtil() {
}
/**
* Get a boolean valued System property.
*/
public static boolean getBooleanSystemProperty(String name, boolean def) {
try {
return getBoolean(getProp(System.getProperties(), name), def);
} catch (SecurityException sex) {
// fall through...
}
/*
* If we can't get the entire System Properties object because
* of a SecurityException, just ask for the specific property.
*/
try {
String value = System.getProperty(name);
if (value == null) {
return def;
}
if (def) {
return !value.equalsIgnoreCase("false");
} else {
return value.equalsIgnoreCase("true");
}
} catch (SecurityException sex) {
return def;
}
}
/**
* Get the value of the specified property.
* If the "get" method returns null, use the getProperty method,
* which might cascade to a default Properties object.
*/
private static Object getProp(Properties props, String name) {
Object val = props.get(name);
if (val != null) {
return val;
} else {
return props.getProperty(name);
}
}
/**
* Interpret the value object as a boolean,
* returning def if unable.
*/
private static boolean getBoolean(Object value, boolean def) {
if (value == null) {
return def;
}
if (value instanceof String) {
/*
* If the default is true, only "false" turns it off.
* If the default is false, only "true" turns it on.
*/
if (def) {
return !((String)value).equalsIgnoreCase("false");
} else {
return ((String)value).equalsIgnoreCase("true");
}
}
if (value instanceof Boolean) {
return ((Boolean)value).booleanValue();
}
return def;
}
}

View File

@@ -0,0 +1,207 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* FROM mail.jar */
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.*;
/**
* This class implements a QP Decoder. It is implemented as
* a FilterInputStream, so one can just wrap this class around
* any input stream and read bytes from this filter. The decoding
* is done as the bytes are read out.
*
* @author John Mani
*/
final class QPDecoderStream extends FilterInputStream {
private byte[] ba = new byte[2];
private int spaces = 0;
/**
* Create a Quoted Printable decoder that decodes the specified
* input stream.
* @param in the input stream
*/
public QPDecoderStream(InputStream in) {
super(new PushbackInputStream(in, 2)); // pushback of size=2
}
/**
* Read the next decoded byte from this input stream. The byte
* is returned as an <code>int</code> in the range <code>0</code>
* to <code>255</code>. If no byte is available because the end of
* the stream has been reached, the value <code>-1</code> is returned.
* This method blocks until input data is available, the end of the
* stream is detected, or an exception is thrown.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
*/
@Override
public int read() throws IOException {
if (spaces > 0) {
// We have cached space characters, return one
spaces--;
return ' ';
}
int c = in.read();
if (c == ' ') {
// Got space, keep reading till we get a non-space char
while ((c = in.read()) == ' ') {
spaces++;
}
if (c == '\r' || c == '\n' || c == -1) {
spaces = 0;
} else {
// The non-space char is NOT CR/LF, the spaces are valid.
((PushbackInputStream)in).unread(c);
c = ' ';
}
return c; // return either <SPACE> or <CR/LF>
}
else if (c == '=') {
// QP Encoded atom. Decode the next two bytes
int a = in.read();
if (a == '\n') {
/* Hmm ... not really confirming QP encoding, but lets
* allow this as a LF terminated encoded line .. and
* consider this a soft linebreak and recurse to fetch
* the next char.
*/
return read();
} else if (a == '\r') {
// Expecting LF. This forms a soft linebreak to be ignored.
int b = in.read();
if (b != '\n') {
((PushbackInputStream)in).unread(b);
}
return read();
} else if (a == -1) {
// Not valid QP encoding, but we be nice and tolerant here !
return -1;
} else {
ba[0] = (byte)a;
ba[1] = (byte)in.read();
try {
return ASCIIUtility.parseInt(ba, 0, 2, 16);
} catch (NumberFormatException nex) {
/*
System.err.println(
"Illegal characters in QP encoded stream: " +
ASCIIUtility.toString(ba, 0, 2)
);
*/
((PushbackInputStream)in).unread(ba);
return c;
}
}
}
return c;
}
/**
* Reads up to <code>len</code> decoded bytes of data from this input stream
* into an array of bytes. This method blocks until some input is
* available.
* <p>
*
* @param buf the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
@Override
public int read(byte[] buf, int off, int len) throws IOException {
int i, c;
for (i = 0; i < len; i++) {
if ((c = read()) == -1) {
if (i == 0) {
i = -1; // return -1 , NOT 0.
}
break;
}
buf[off+i] = (byte)c;
}
return i;
}
/**
* Skips over and discards n bytes of data from this stream.
*/
@Override
public long skip(long n) throws IOException {
long skipped = 0;
while (n-- > 0 && read() >= 0) {
skipped++;
}
return skipped;
}
/**
* Tests if this input stream supports marks. Currently this class
* does not support marks
*/
@Override
public boolean markSupported() {
return false;
}
/**
* Returns the number of bytes that can be read from this input
* stream without blocking. The QP algorithm does not permit
* a priori knowledge of the number of bytes after decoding, so
* this method just invokes the <code>available</code> method
* of the original input stream.
*/
@Override
public int available() throws IOException {
// This is bogus ! We don't really know how much
// bytes are available *after* decoding
return in.available();
}
/**** begin TEST program
public static void main(String argv[]) throws Exception {
FileInputStream infile = new FileInputStream(argv[0]);
QPDecoderStream decoder = new QPDecoderStream(infile);
int c;
while ((c = decoder.read()) != -1)
System.out.print((char)c);
System.out.println();
}
*** end TEST program ****/
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Helper utility to support jdk <= jdk1.6. After jdk1.6 EOL reflection can be removed and API can be used directly.
*/
class TempFiles {
private static final Logger LOGGER = Logger.getLogger(TempFiles.class.getName());
private static final Class<?> CLASS_FILES;
private static final Class<?> CLASS_PATH;
private static final Class<?> CLASS_FILE_ATTRIBUTE;
private static final Class<?> CLASS_FILE_ATTRIBUTES;
private static final Method METHOD_FILE_TO_PATH;
private static final Method METHOD_FILES_CREATE_TEMP_FILE;
private static final Method METHOD_FILES_CREATE_TEMP_FILE_WITHPATH;
private static final Method METHOD_PATH_TO_FILE;
private static boolean useJdk6API;
static {
useJdk6API = isJdk6();
CLASS_FILES = safeGetClass("java.nio.file.Files");
CLASS_PATH = safeGetClass("java.nio.file.Path");
CLASS_FILE_ATTRIBUTE = safeGetClass("java.nio.file.attribute.FileAttribute");
CLASS_FILE_ATTRIBUTES = safeGetClass("[Ljava.nio.file.attribute.FileAttribute;");
METHOD_FILE_TO_PATH = safeGetMethod(File.class, "toPath");
METHOD_FILES_CREATE_TEMP_FILE = safeGetMethod(CLASS_FILES, "createTempFile", String.class, String.class, CLASS_FILE_ATTRIBUTES);
METHOD_FILES_CREATE_TEMP_FILE_WITHPATH = safeGetMethod(CLASS_FILES, "createTempFile", CLASS_PATH, String.class, String.class, CLASS_FILE_ATTRIBUTES);
METHOD_PATH_TO_FILE = safeGetMethod(CLASS_PATH, "toFile");
}
private static boolean isJdk6() {
String javaVersion = System.getProperty("java.version");
LOGGER.log(Level.FINEST, "Detected java version = {0}", javaVersion);
return javaVersion.startsWith("1.6.");
}
private static Class<?> safeGetClass(String className) {
// it is jdk 6 or something failed already before
if (useJdk6API) return null;
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
LOGGER.log(Level.SEVERE, "Exception cought", e);
LOGGER.log(Level.WARNING, "Class {0} not found. Temp files will be created using old java.io API.", className);
useJdk6API = true;
return null;
}
}
private static Method safeGetMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
// it is jdk 6 or something failed already before
if (useJdk6API) return null;
try {
return clazz.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
LOGGER.log(Level.SEVERE, "Exception cought", e);
LOGGER.log(Level.WARNING, "Method {0} not found. Temp files will be created using old java.io API.", methodName);
useJdk6API = true;
return null;
}
}
static Object toPath(File f) throws InvocationTargetException, IllegalAccessException {
return METHOD_FILE_TO_PATH.invoke(f);
}
static File toFile(Object path) throws InvocationTargetException, IllegalAccessException {
return (File) METHOD_PATH_TO_FILE.invoke(path);
}
static File createTempFile(String prefix, String suffix, File dir) throws IOException {
if (useJdk6API) {
LOGGER.log(Level.FINEST, "Jdk6 detected, temp file (prefix:{0}, suffix:{1}) being created using old java.io API.", new Object[]{prefix, suffix});
return File.createTempFile(prefix, suffix, dir);
} else {
try {
if (dir != null) {
Object path = toPath(dir);
LOGGER.log(Level.FINEST, "Temp file (path: {0}, prefix:{1}, suffix:{2}) being created using NIO API.", new Object[]{dir.getAbsolutePath(), prefix, suffix});
return toFile(METHOD_FILES_CREATE_TEMP_FILE_WITHPATH.invoke(null, path, prefix, suffix, Array.newInstance(CLASS_FILE_ATTRIBUTE, 0)));
} else {
LOGGER.log(Level.FINEST, "Temp file (prefix:{0}, suffix:{1}) being created using NIO API.", new Object[]{prefix, suffix});
return toFile(METHOD_FILES_CREATE_TEMP_FILE.invoke(null, prefix, suffix, Array.newInstance(CLASS_FILE_ATTRIBUTE, 0)));
}
} catch (IllegalAccessException e) {
LOGGER.log(Level.SEVERE, "Exception caught", e);
LOGGER.log(Level.WARNING, "Error invoking java.nio API, temp file (path: {0}, prefix:{1}, suffix:{2}) being created using old java.io API.",
new Object[]{dir != null ? dir.getAbsolutePath() : null, prefix, suffix});
return File.createTempFile(prefix, suffix, dir);
} catch (InvocationTargetException e) {
LOGGER.log(Level.SEVERE, "Exception caught", e);
LOGGER.log(Level.WARNING, "Error invoking java.nio API, temp file (path: {0}, prefix:{1}, suffix:{2}) being created using old java.io API.",
new Object[]{dir != null ? dir.getAbsolutePath() : null, prefix, suffix});
return File.createTempFile(prefix, suffix, dir);
}
}
}
}

View File

@@ -0,0 +1,357 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* FROM mail.jar */
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.*;
/**
* This class implements a UUDecoder. It is implemented as
* a FilterInputStream, so one can just wrap this class around
* any input stream and read bytes from this filter. The decoding
* is done as the bytes are read out.
*
* @author John Mani
* @author Bill Shannon
*/
final class UUDecoderStream extends FilterInputStream {
private String name;
private int mode;
private byte[] buffer = new byte[45]; // max decoded chars in a line = 45
private int bufsize = 0; // size of the cache
private int index = 0; // index into the cache
private boolean gotPrefix = false;
private boolean gotEnd = false;
private LineInputStream lin;
private boolean ignoreErrors;
private boolean ignoreMissingBeginEnd;
private String readAhead;
/**
* Create a UUdecoder that decodes the specified input stream.
* The System property <code>mail.mime.uudecode.ignoreerrors</code>
* controls whether errors in the encoded data cause an exception
* or are ignored. The default is false (errors cause exception).
* The System property <code>mail.mime.uudecode.ignoremissingbeginend</code>
* controls whether a missing begin or end line cause an exception
* or are ignored. The default is false (errors cause exception).
* @param in the input stream
*/
public UUDecoderStream(InputStream in) {
super(in);
lin = new LineInputStream(in);
// default to false
ignoreErrors = PropUtil.getBooleanSystemProperty(
"mail.mime.uudecode.ignoreerrors", false);
// default to false
ignoreMissingBeginEnd = PropUtil.getBooleanSystemProperty(
"mail.mime.uudecode.ignoremissingbeginend", false);
}
/**
* Create a UUdecoder that decodes the specified input stream.
* @param in the input stream
* @param ignoreErrors ignore errors?
* @param ignoreMissingBeginEnd ignore missing begin or end?
*/
public UUDecoderStream(InputStream in, boolean ignoreErrors,
boolean ignoreMissingBeginEnd) {
super(in);
lin = new LineInputStream(in);
this.ignoreErrors = ignoreErrors;
this.ignoreMissingBeginEnd = ignoreMissingBeginEnd;
}
/**
* Read the next decoded byte from this input stream. The byte
* is returned as an <code>int</code> in the range <code>0</code>
* to <code>255</code>. If no byte is available because the end of
* the stream has been reached, the value <code>-1</code> is returned.
* This method blocks until input data is available, the end of the
* stream is detected, or an exception is thrown.
*
* @return next byte of data, or <code>-1</code> if the end of
* stream is reached.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
*/
@Override
public int read() throws IOException {
if (index >= bufsize) {
readPrefix();
if (!decode()) {
return -1;
}
index = 0; // reset index into buffer
}
return buffer[index++] & 0xff; // return lower byte
}
@Override
public int read(byte[] buf, int off, int len) throws IOException {
int i, c;
for (i = 0; i < len; i++) {
if ((c = read()) == -1) {
if (i == 0) {// At end of stream, so we should
i = -1; // return -1, NOT 0.
}
break;
}
buf[off+i] = (byte)c;
}
return i;
}
@Override
public boolean markSupported() {
return false;
}
@Override
public int available() throws IOException {
// This is only an estimate, since in.available()
// might include CRLFs too ..
return ((in.available() * 3)/4 + (bufsize-index));
}
/**
* Get the "name" field from the prefix. This is meant to
* be the pathname of the decoded file
*
* @return name of decoded file
* @exception IOException if an I/O error occurs.
*/
public String getName() throws IOException {
readPrefix();
return name;
}
/**
* Get the "mode" field from the prefix. This is the permission
* mode of the source file.
*
* @return permission mode of source file
* @exception IOException if an I/O error occurs.
*/
public int getMode() throws IOException {
readPrefix();
return mode;
}
/**
* UUencoded streams start off with the line:
* "begin <mode> <filename>"
* Search for this prefix and gobble it up.
*/
private void readPrefix() throws IOException {
if (gotPrefix) {
return;
}
mode = 0666; // defaults, overridden below
name = "encoder.buf"; // same default used by encoder
String line;
for (;;) {
// read till we get the prefix: "begin MODE FILENAME"
line = lin.readLine(); // NOTE: readLine consumes CRLF pairs too
if (line == null) {
if (!ignoreMissingBeginEnd) {
throw new DecodingException("UUDecoder: Missing begin");
}
// at EOF, fake it
gotPrefix = true;
gotEnd = true;
break;
}
if (line.regionMatches(false, 0, "begin", 0, 5)) {
try {
mode = Integer.parseInt(line.substring(6,9));
} catch (NumberFormatException ex) {
if (!ignoreErrors) {
throw new DecodingException(
"UUDecoder: Error in mode: " + ex.toString());
}
}
if (line.length() > 10) {
name = line.substring(10);
} else {
if (!ignoreErrors) {
throw new DecodingException(
"UUDecoder: Missing name: " + line);
}
}
gotPrefix = true;
break;
} else if (ignoreMissingBeginEnd && line.length() != 0) {
int count = line.charAt(0);
count = (count - ' ') & 0x3f;
int need = ((count * 8)+5)/6;
if (need == 0 || line.length() >= need + 1) {
/*
* Looks like a legitimate encoded line.
* Pretend we saw the "begin" line and
* save this line for later processing in
* decode().
*/
readAhead = line;
gotPrefix = true; // fake it
break;
}
}
}
}
private boolean decode() throws IOException {
if (gotEnd) {
return false;
}
bufsize = 0;
int count = 0;
String line;
for (;;) {
/*
* If we ignored a missing "begin", the first line
* will be saved in readAhead.
*/
if (readAhead != null) {
line = readAhead;
readAhead = null;
} else {
line = lin.readLine();
}
/*
* Improperly encoded data sometimes omits the zero length
* line that starts with a space character, we detect the
* following "end" line here.
*/
if (line == null) {
if (!ignoreMissingBeginEnd) {
throw new DecodingException(
"UUDecoder: Missing end at EOF");
}
gotEnd = true;
return false;
}
if (line.equals("end")) {
gotEnd = true;
return false;
}
if (line.length() == 0) {
continue;
}
count = line.charAt(0);
if (count < ' ') {
if (!ignoreErrors) {
throw new DecodingException(
"UUDecoder: Buffer format error");
}
continue;
}
/*
* The first character in a line is the number of original (not
* the encoded atoms) characters in the line. Note that all the
* code below has to handle the <SPACE> character that indicates
* end of encoded stream.
*/
count = (count - ' ') & 0x3f;
if (count == 0) {
line = lin.readLine();
if (line == null || !line.equals("end")) {
if (!ignoreMissingBeginEnd) {
throw new DecodingException(
"UUDecoder: Missing End after count 0 line");
}
}
gotEnd = true;
return false;
}
int need = ((count * 8)+5)/6;
//System.out.println("count " + count + ", need " + need + ", len " + line.length());
if (line.length() < need + 1) {
if (!ignoreErrors) {
throw new DecodingException(
"UUDecoder: Short buffer error");
}
continue;
}
// got a line we're committed to, break out and decode it
break;
}
int i = 1;
byte a, b;
/*
* A correct uuencoder always encodes 3 characters at a time, even
* if there aren't 3 characters left. But since some people out
* there have broken uuencoders we handle the case where they
* don't include these "unnecessary" characters.
*/
while (bufsize < count) {
// continue decoding until we get 'count' decoded chars
a = (byte)((line.charAt(i++) - ' ') & 0x3f);
b = (byte)((line.charAt(i++) - ' ') & 0x3f);
buffer[bufsize++] = (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3));
if (bufsize < count) {
a = b;
b = (byte)((line.charAt(i++) - ' ') & 0x3f);
buffer[bufsize++] =
(byte)(((a << 4) & 0xf0) | ((b >>> 2) & 0xf));
}
if (bufsize < count) {
a = b;
b = (byte)((line.charAt(i++) - ' ') & 0x3f);
buffer[bufsize++] = (byte)(((a << 6) & 0xc0) | (b & 0x3f));
}
}
return true;
}
/*** begin TEST program *****
public static void main(String argv[]) throws Exception {
FileInputStream infile = new FileInputStream(argv[0]);
UUDecoderStream decoder = new UUDecoderStream(infile);
int c;
try {
while ((c = decoder.read()) != -1)
System.out.write(c);
System.out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
**** end TEST program ****/
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.mimepull;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Removing files based on this
* <a href="http://java.sun.com/developer/technicalArticles/javase/finalization/">article</a>
*
* @author Jitendra Kotamraju
*/
final class WeakDataFile extends WeakReference<DataFile> {
private static final Logger LOGGER = Logger.getLogger(WeakDataFile.class.getName());
//private static final int MAX_ITERATIONS = 2;
private static ReferenceQueue<DataFile> refQueue = new ReferenceQueue<DataFile>();
private static List<WeakDataFile> refList = new ArrayList<WeakDataFile>();
private final File file;
private final RandomAccessFile raf;
private static boolean hasCleanUpExecutor = false;
static {
CleanUpExecutorFactory executorFactory = CleanUpExecutorFactory.newInstance();
if (executorFactory!=null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Initializing clean up executor for MIMEPULL: {0}", executorFactory.getClass().getName());
}
Executor executor = executorFactory.getExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
WeakDataFile weak;
while (true) {
try {
weak = (WeakDataFile) refQueue.remove();
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file);
}
weak.close();
} catch (InterruptedException e) {
}
}
}
});
hasCleanUpExecutor = true;
}
}
WeakDataFile(DataFile df, File file) {
super(df, refQueue);
refList.add(this);
this.file = file;
try {
raf = new RandomAccessFile(file, "rw");
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
if (!hasCleanUpExecutor) {
drainRefQueueBounded();
}
}
synchronized void read(long pointer, byte[] buf, int offset, int length ) {
try {
raf.seek(pointer);
raf.readFully(buf, offset, length);
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
}
synchronized long writeTo(long pointer, byte[] data, int offset, int length) {
try {
raf.seek(pointer);
raf.write(data, offset, length);
return raf.getFilePointer(); // Update pointer for next write
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
}
void close() {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Deleting file = {0}", file.getName());
}
refList.remove(this);
try {
raf.close();
boolean deleted = file.delete();
if (!deleted) {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "File {0} was not deleted", file.getAbsolutePath());
}
}
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
}
void renameTo(File f) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Moving file={0} to={1}", new Object[]{file, f});
}
refList.remove(this);
try {
raf.close();
boolean renamed = file.renameTo(f);
if (!renamed) {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "File {0} was not moved to {1}", new Object[] {file.getAbsolutePath(), f.getAbsolutePath()});
}
}
} catch(IOException ioe) {
throw new MIMEParsingException(ioe);
}
}
static void drainRefQueueBounded() {
WeakDataFile weak;
while (( weak = (WeakDataFile) refQueue.poll()) != null ) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file);
}
weak.close();
}
}
}

View File

@@ -0,0 +1,534 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
// for testing method
//import com.sun.xml.internal.stream.writers.XMLStreamWriterImpl;
//import java.io.FileNotFoundException;
//import java.io.FileWriter;
//import javax.activation.FileDataSource;
/**
* Binary data represented as base64-encoded string
* in XML.
*
* <p>
* Used in conjunction with {@link XMLStreamReaderEx}
* and {@link XMLStreamWriterEx}.
*
* @author Kohsuke Kawaguchi, Martin Grebac
*/
public class Base64Data implements CharSequence, Cloneable {
// either dataHandler or (data,dataLen,mimeType?) must be present
// (note that having both is allowed)
private DataHandler dataHandler;
private byte[] data;
/**
* Length of the valid data in {@link #data}.
*/
private int dataLen;
/**
* True if {@link #data} can be cloned by reference
* if Base64Data instance is cloned.
*/
private boolean dataCloneByRef;
/**
* Optional MIME type of {@link #data}.
*
* Unused when {@link #dataHandler} is set.
* Use {@link DataHandler#getContentType()} in that case.
*/
private String mimeType;
/**
* Default constructor
*/
public Base64Data() {
}
private static final Logger logger = Logger.getLogger(Base64Data.class.getName());
/**
* Clone constructor
* @param that needs to be cloned
*/
public Base64Data(Base64Data that) {
that.get();
if (that.dataCloneByRef) {
this.data = that.data;
} else {
this.data = new byte[that.dataLen];
System.arraycopy(that.data, 0, this.data, 0, that.dataLen);
}
this.dataCloneByRef = true;
this.dataLen = that.dataLen;
this.dataHandler = null;
this.mimeType = that.mimeType;
}
/**
* Fills in the data object by a portion of the byte[].
*
* @param data actual data
* @param len
* data[0] to data[len-1] are treated as the data.
* @param mimeType MIME type
* @param cloneByRef
* true if data[] can be cloned by reference
*/
public void set(byte[] data, int len, String mimeType, boolean cloneByRef) {
this.data = data;
this.dataLen = len;
this.dataCloneByRef = cloneByRef;
this.dataHandler = null;
this.mimeType = mimeType;
}
/**
* Fills in the data object by a portion of the byte[].
*
* @param data actual data bytes
* @param len
* data[0] to data[len-1] are treated as the data.
* @param mimeType MIME type
*/
public void set(byte[] data, int len, String mimeType) {
set(data,len,mimeType,false);
}
/**
* Fills in the data object by the byte[] of the exact length.
*
* @param data
* this buffer may be owned directly by the unmarshaleld JAXB object.
* @param mimeType MIME type
*/
public void set(byte[] data,String mimeType) {
set(data,data.length,mimeType,false);
}
/**
* Fills in the data object by a {@link DataHandler}.
*
* @param data DataHandler for the data
*/
public void set(DataHandler data) {
assert data!=null;
this.dataHandler = data;
this.data = null;
}
/**
* Gets the raw data. If the returned DataHandler is {@link StreamingDataHandler},
* callees may need to downcast to take advantage of its capabilities.
*
* @see StreamingDataHandler
* @return DataHandler for the data
*/
public DataHandler getDataHandler() {
if(dataHandler==null){
dataHandler = new Base64StreamingDataHandler(new Base64DataSource());
} else if (!(dataHandler instanceof StreamingDataHandler)) {
dataHandler = new FilterDataHandler(dataHandler);
}
return dataHandler;
}
private final class Base64DataSource implements DataSource {
public String getContentType() {
return getMimeType();
}
public InputStream getInputStream() {
return new ByteArrayInputStream(data,0,dataLen);
}
public String getName() {
return null;
}
public OutputStream getOutputStream() {
throw new UnsupportedOperationException();
}
}
private final class Base64StreamingDataHandler extends StreamingDataHandler {
Base64StreamingDataHandler(DataSource source) {
super(source);
}
public InputStream readOnce() throws IOException {
return getDataSource().getInputStream();
}
public void moveTo(File dst) throws IOException {
FileOutputStream fout = new FileOutputStream(dst);
try {
fout.write(data, 0, dataLen);
} finally {
fout.close();
}
}
public void close() throws IOException {
// nothing to do
}
}
private static final class FilterDataHandler extends StreamingDataHandler {
FilterDataHandler(DataHandler dh) {
super(dh.getDataSource());
}
public InputStream readOnce() throws IOException {
return getDataSource().getInputStream();
}
public void moveTo(File dst) throws IOException {
byte[] buf = new byte[8192];
InputStream in = null;
OutputStream out = null;
try {
in = getDataSource().getInputStream();
out = new FileOutputStream(dst);
while (true) {
int amountRead = in.read(buf);
if (amountRead == -1) {
break;
}
out.write(buf, 0, amountRead);
}
} finally {
if (in != null) {
try {
in.close();
} catch(IOException ioe) {
// nothing to do
}
}
if (out != null) {
try {
out.close();
} catch(IOException ioe) {
// nothing to do
}
}
}
}
public void close() throws IOException {
// nothing to do
}
}
/**
* Gets the byte[] of the exact length.
*
* @return byte[] for data
*/
public byte[] getExact() {
get();
if(dataLen!=data.length) {
byte[] buf = new byte[dataLen];
System.arraycopy(data,0,buf,0,dataLen);
data = buf;
}
return data;
}
/**
* Gets the data as an {@link InputStream}.
*
* @return data as InputStream
* @throws IOException if i/o error occurs
*/
public InputStream getInputStream() throws IOException {
if(dataHandler!=null) {
return dataHandler.getInputStream();
} else {
return new ByteArrayInputStream(data,0,dataLen);
}
}
/**
* Returns false if this object only has {@link DataHandler} and therefore
* {@link #get()} operation is likely going to be expensive.
*
* @return false if it has only DataHandler
*/
public boolean hasData() {
return data!=null;
}
/**
* Gets the raw data. The size of the byte array maybe larger than the actual length.
*
* @return data as byte[], the array may be larger
*/
public byte[] get() {
if(data==null) {
try {
ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
InputStream is = dataHandler.getDataSource().getInputStream();
baos.readFrom(is);
is.close();
data = baos.getBuffer();
dataLen = baos.size();
dataCloneByRef = true;
} catch (IOException e) {
// TODO: report the error to the unmarshaller
dataLen = 0; // recover by assuming length-0 data
}
}
return data;
}
/**
* Gets the length of the binary data counted in bytes.
*
* Note that if this object encapsulates {@link DataHandler},
* this method would have to read the whole thing into {@code byte[]}
* just to count the length, because {@link DataHandler}
* doesn't easily expose the length.
*
* @return no of bytes
*/
public int getDataLen() {
get();
return dataLen;
}
public String getMimeType() {
if (mimeType==null) {
return "application/octet-stream";
}
return mimeType;
}
/**
* Gets the number of characters needed to represent
* this binary data in the base64 encoding.
*/
public int length() {
// for each 3 bytes you use 4 chars
// if the remainder is 1 or 2 there will be 4 more
get(); // fill in the buffer if necessary
return ((dataLen+2)/3)*4;
}
/**
* Encode this binary data in the base64 encoding
* and returns the character at the specified position.
*/
public char charAt(int index) {
// we assume that the length() method is called before this method
// (otherwise how would the caller know that the index is valid?)
// so we assume that the byte[] is already populated
int offset = index%4;
int base = (index/4)*3;
byte b1,b2;
switch(offset) {
case 0:
return Base64Encoder.encode(data[base]>>2);
case 1:
if (base+1<dataLen) {
b1 = data[base+1];
} else {
b1 = 0;
}
return Base64Encoder.encode(
((data[base]&0x3)<<4) |
((b1>>4)&0xF));
case 2:
if (base+1<dataLen) {
b1 = data[base+1];
if (base+2<dataLen) {
b2 = data[base+2];
} else {
b2 = 0;
}
return Base64Encoder.encode(
((b1&0xF)<<2)|
((b2>>6)&0x3));
} else {
return '=';
}
case 3:
if(base+2<dataLen) {
return Base64Encoder.encode(data[base+2]&0x3F);
} else {
return '=';
}
}
throw new IllegalStateException();
}
/**
* Internally this is only used to split a text to a list,
* which doesn't happen that much for base64.
* So this method should be smaller than faster.
*/
public CharSequence subSequence(int start, int end) {
StringBuilder buf = new StringBuilder();
get(); // fill in the buffer if we haven't done so
for (int i=start; i<end; i++ ) {
buf.append(charAt(i));
}
return buf;
}
/**
* Returns the base64 encoded string of this data.
*/
@Override
public String toString() {
get(); // fill in the buffer
return Base64Encoder.print(data, 0, dataLen);
}
public void writeTo(char[] buf, int start) {
get();
Base64Encoder.print(data, 0, dataLen, buf, start);
}
private static final int CHUNK_SIZE;
static {
int bufSize = 1024;
try {
String bufSizeStr = getProperty("com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize");
if (bufSizeStr != null) {
bufSize = Integer.parseInt(bufSizeStr);
}
} catch (Exception e) {
logger.log(Level.INFO, "Error reading com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize property", e);
}
CHUNK_SIZE = bufSize;
}
public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
if (data==null) {
try {
InputStream is = dataHandler.getDataSource().getInputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // dev-null stream
Base64EncoderStream encWriter = new Base64EncoderStream(output, outStream);
int b;
byte[] buffer = new byte[CHUNK_SIZE];
while ((b = is.read(buffer)) != -1) {
encWriter.write(buffer, 0, b);
}
outStream.close();
encWriter.close();
} catch (IOException e) {
dataLen = 0; // recover by assuming length-0 data
throw e;
}
} else {
// the data is already in memory and not streamed
String s = Base64Encoder.print(data, 0, dataLen);
output.writeCharacters(s);
}
}
@Override
public Base64Data clone() {
try {
Base64Data clone = (Base64Data) super.clone();
clone.get();
if (clone.dataCloneByRef) {
this.data = clone.data;
} else {
this.data = new byte[clone.dataLen];
System.arraycopy(clone.data, 0, this.data, 0, clone.dataLen);
}
this.dataCloneByRef = true;
this.dataLen = clone.dataLen;
this.dataHandler = null;
this.mimeType = clone.mimeType;
return clone;
} catch (CloneNotSupportedException ex) {
Logger.getLogger(Base64Data.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
static String getProperty(final String propName) {
if (System.getSecurityManager() == null) {
return System.getProperty(propName);
} else {
return (String) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public java.lang.Object run() {
return System.getProperty(propName);
}
});
}
}
// public static void main(String[] args) throws FileNotFoundException, IOException, XMLStreamException {
// Base64Data data = new Base64Data();
//
// File f = new File("/Users/snajper/work/builds/weblogic/wls1211_dev.zip");
// FileDataSource fds = new FileDataSource(f);
// DataHandler dh = new DataHandler(fds);
// data.set(dh);
//
// FileWriter fw = new FileWriter(new File("/Users/snajper/Desktop/b.txt"));
// XMLStreamWriterImpl wi = new XMLStreamWriterImpl(fw, null);
//
// data.writeTo(wi);
// wi.flush();fw.flush();
// //System.out.println("SW: " + sw.toString());
//
// }
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
/**
* @author Kohsuke Kawaguchi
*/
class Base64Encoder {
private static final char[] encodeMap = initEncodeMap();
private static char[] initEncodeMap() {
char[] map = new char[64];
int i;
for( i= 0; i<26; i++ ) map[i] = (char)('A'+i);
for( i=26; i<52; i++ ) map[i] = (char)('a'+(i-26));
for( i=52; i<62; i++ ) map[i] = (char)('0'+(i-52));
map[62] = '+';
map[63] = '/';
return map;
}
public static char encode( int i ) {
return encodeMap[i&0x3F];
}
public static byte encodeByte( int i ) {
return (byte)encodeMap[i&0x3F];
}
public static String print(byte[] input, int offset, int len) {
char[] buf = new char[((len+2)/3)*4];
int ptr = print(input,offset,len,buf,0);
assert ptr==buf.length;
return new String(buf);
}
/**
* Encodes a byte array into a char array by doing base64 encoding.
*
* The caller must supply a big enough buffer.
*
* @return
* the value of {@code ptr+((len+2)/3)*4}, which is the new offset
* in the output buffer where the further bytes should be placed.
*/
public static int print(byte[] input, int offset, int len, char[] buf, int ptr) {
for( int i=offset; i<len; i+=3 ) {
switch( len-i ) {
case 1:
buf[ptr++] = encode(input[i]>>2);
buf[ptr++] = encode(((input[i])&0x3)<<4);
buf[ptr++] = '=';
buf[ptr++] = '=';
break;
case 2:
buf[ptr++] = encode(input[i]>>2);
buf[ptr++] = encode(
((input[i]&0x3)<<4) |
((input[i+1]>>4)&0xF));
buf[ptr++] = encode((input[i+1]&0xF)<<2);
buf[ptr++] = '=';
break;
default:
buf[ptr++] = encode(input[i]>>2);
buf[ptr++] = encode(
((input[i]&0x3)<<4) |
((input[i+1]>>4)&0xF));
buf[ptr++] = encode(
((input[i+1]&0xF)<<2)|
((input[i+2]>>6)&0x3));
buf[ptr++] = encode(input[i+2]&0x3F);
break;
}
}
return ptr;
}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
// for testing method
//import com.sun.xml.internal.stream.writers.XMLStreamWriterImpl;
/**
* This class implements a BASE64 Encoder. It is implemented as
* a FilterOutputStream, so one can just wrap this class around
* any output stream and write bytes into this filter. The Encoding
* is done as the bytes are written out.
*
* @author John Mani
* @author Bill Shannon
* @author Martin Grebac
*/
public class Base64EncoderStream extends FilterOutputStream {
private byte[] buffer; // cache of bytes that are yet to be encoded
private int bufsize = 0; // size of the cache
private XMLStreamWriter outWriter;
public Base64EncoderStream(OutputStream out) {
super(out);
buffer = new byte[3];
}
/**
* Create a BASE64 encoder that encodes the specified input stream
*/
public Base64EncoderStream(XMLStreamWriter outWriter, OutputStream out) {
super(out);
buffer = new byte[3];
this.outWriter = outWriter;
}
/**
* Encodes <code>len</code> bytes from the specified
* <code>byte</code> array starting at offset <code>off</code> to
* this output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs.
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
for (int i = 0; i < len; i++)
write(b[off + i]);
}
/**
* Encodes <code>b.length</code> bytes to this output stream.
* @param b the data to be written.
* @exception IOException if an I/O error occurs.
*/
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
/**
* Encodes the specified <code>byte</code> to this output stream.
* @param c the <code>byte</code>.
* @exception IOException if an I/O error occurs.
*/
@Override
public void write(int c) throws IOException {
buffer[bufsize++] = (byte)c;
if (bufsize == 3) { // Encoding unit = 3 bytes
encode();
bufsize = 0;
}
}
/**
* Flushes this output stream and forces any buffered output bytes
* to be encoded out to the stream.
* @exception IOException if an I/O error occurs.
*/
@Override
public void flush() throws IOException {
if (bufsize > 0) { // If there's unencoded characters in the buffer ..
encode(); // .. encode them
bufsize = 0;
}
out.flush();
try {
outWriter.flush();
} catch (XMLStreamException ex) {
Logger.getLogger(Base64EncoderStream.class.getName()).log(Level.SEVERE, null, ex);
throw new IOException(ex);
}
}
/**
* Forces any buffered output bytes to be encoded out to the stream
* and closes this output stream
*/
@Override
public void close() throws IOException {
flush();
out.close();
}
/** This array maps the characters to their 6 bit values */
private final static char pem_array[] = {
'A','B','C','D','E','F','G','H', // 0
'I','J','K','L','M','N','O','P', // 1
'Q','R','S','T','U','V','W','X', // 2
'Y','Z','a','b','c','d','e','f', // 3
'g','h','i','j','k','l','m','n', // 4
'o','p','q','r','s','t','u','v', // 5
'w','x','y','z','0','1','2','3', // 6
'4','5','6','7','8','9','+','/' // 7
};
private void encode() throws IOException {
byte a, b, c;
char[] buf = new char[4];
if (bufsize == 1) {
a = buffer[0];
b = 0;
c = 0;
buf[0] = pem_array[(a >>> 2) & 0x3F];
buf[1] = pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)];
buf[2] = '='; // pad character
buf[3] = '='; // pad character
} else if (bufsize == 2) {
a = buffer[0];
b = buffer[1];
c = 0;
buf[0] = pem_array[(a >>> 2) & 0x3F];
buf[1] = pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)];
buf[2] = pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)];
buf[3] = '='; // pad character
} else {
a = buffer[0];
b = buffer[1];
c = buffer[2];
buf[0] = pem_array[(a >>> 2) & 0x3F];
buf[1] = pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)];
buf[2] = pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)];
buf[3] = pem_array[c & 0x3F];
}
try {
outWriter.writeCharacters(buf, 0, 4);
} catch (XMLStreamException ex) {
Logger.getLogger(Base64EncoderStream.class.getName()).log(Level.SEVERE, null, ex);
throw new IOException(ex);
}
}
// public static void main(String argv[]) throws Exception {
// FileInputStream infile = new FileInputStream(new File(argv[0]));
// StringWriter sw = new StringWriter();
// XMLStreamWriterImpl wi = new XMLStreamWriterImpl(sw, null);
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Base64EncoderStream encoder = new Base64EncoderStream(wi, baos);
// int c;
//
// while ((c = infile.read()) != -1)
// encoder.write(c);
// encoder.close();
//
// System.out.println("SW: " + sw.toString());
// System.out.println("BAOS: " + baos.toString());
//
// }
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
/**
* {@link ByteArrayOutputStream} with access to its raw buffer.
*
* @author Kohsuke Kawaguchi
*/
final class ByteArrayOutputStreamEx extends ByteArrayOutputStream {
public ByteArrayOutputStreamEx() {
}
public ByteArrayOutputStreamEx(int size) {
super(size);
}
public void set(Base64Data dt,String mimeType) {
dt.set(buf,count,mimeType);
}
public byte[] getBuffer() {
return buf;
}
/**
* Reads the given {@link InputStream} completely into the buffer.
*/
public void readFrom(InputStream is) throws IOException {
while(true) {
if(count==buf.length) {
// realllocate
byte[] data = new byte[buf.length*2];
System.arraycopy(buf,0,data,0,buf.length);
buf = data;
}
int sz = is.read(buf,count,buf.length-count);
if(sz<0) return;
count += sz;
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
import javax.xml.namespace.NamespaceContext;
import java.util.Iterator;
/**
* Extended {@link NamespaceContext}.
*
* @author Kohsuke Kawaguchi
* @author Paul Sandoz
*/
public interface NamespaceContextEx extends NamespaceContext, Iterable<NamespaceContextEx.Binding> {
/**
* Iterates all the in-scope namespace bindings.
*
* <p>
* This method enumerates all the active in-scope namespace bindings.
* This does not include implicit bindings, such as
* <tt>"xml"->"http://www.w3.org/XML/1998/namespace"</tt>
* or <tt>""->""</tt> (the implicit default namespace URI.)
*
* <p>
* The returned iterator may not include the same prefix more than once.
* For example, the returned iterator may only contain <tt>f=ns2</tt>
* if the document is as follows and this method is used at the bar element.
*
* <pre><xmp>
* <foo xmlns:f='ns1'>
* <bar xmlns:f='ns2'>
* ...
* </xmp></pre>
*
* <p>
* The iteration may be done in no particular order.
*
* @return
* may return an empty iterator, but never null.
*/
Iterator<Binding> iterator();
/**
* Prefix to namespace URI binding.
*/
interface Binding {
/**
* Gets the prefix.
*
* <p>
* The default namespace URI is represented by using an
* empty string "", not null.
*
* @return
* never null. String like "foo", "ns12", or "".
*/
String getPrefix();
/**
* Gets the namespace URI.
*
* <p>
* The empty namespace URI is represented by using
* an empty string "", not null.
*
* @return
* never null. String like "http://www.w3.org/XML/1998/namespace",
* "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", or "".
*/
String getNamespaceURI();
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* {@link DataHandler} extended to offer better buffer management
* in a streaming environment.
*
* <p>
* {@link DataHandler} is used commonly as a data format across
* multiple systems (such as JAXB/WS.) Unfortunately, {@link DataHandler}
* has the semantics of "read as many times as you want", so this makes
* it difficult for involving parties to handle a BLOB in a streaming fashion.
*
* <p>
* {@link StreamingDataHandler} solves this problem by offering methods
* that enable faster bulk "consume once" read operation.
*
* @author Jitendra Kotamraju
*/
public abstract class StreamingDataHandler extends DataHandler implements Closeable {
public StreamingDataHandler(Object o, String s) {
super(o, s);
}
public StreamingDataHandler(URL url) {
super(url);
}
public StreamingDataHandler(DataSource dataSource) {
super(dataSource);
}
/**
* Works like {@link #getInputStream()} except that this method
* can be invoked only once.
*
* <p>
* This is used as a signal from the caller that there will
* be no further {@link #getInputStream()} invocation nor
* {@link #readOnce()} invocation on this object (which would
* result in {@link IOException}.)
*
* <p>
* When {@link DataHandler} is backed by a streaming BLOB
* (such as an attachment in a web service read from the network),
* this allows the callee to avoid unnecessary buffering.
*
* <p>
* Note that it is legal to call {@link #getInputStream()}
* multiple times and then call {@link #readOnce()} afterward.
* Streams created such a way can be read in any order &mdash;
* there's no requirement that streams created earlier must be read
* first.
*
* @return
* always non-null. Represents the content of this BLOB.
* The returned stream is generally not buffered, so for
* better performance read in a big batch or wrap this into
* {@link BufferedInputStream}.
* @throws IOException
* if any i/o error
*/
public abstract InputStream readOnce() throws IOException;
/**
* Obtains the BLOB into a specified file.
*
* <p>
* Semantically, this method is roughly equivalent to the following
* code, except that the actual implementation is likely to be a lot faster.
*
* <pre>
* InputStream i = getInputStream();
* OutputStream o = new FileOutputStream(dst);
* int ch;
* while((ch=i.read())!=-1) o.write(ch);
* i.close();
* o.close();
* </pre>
*
* <p>
* The main motivation behind this method is that often
* {@link DataHandler} that reads data from a streaming source
* will use a temporary file as a data store to hold data
* (think of commons-fileupload.) In such case this method
* can be as fast as calling {@link File#renameTo(File)}.
*
* <p>
* This method shouldn't be called when there are any
* open streams.
*
* <p>
* After this method is invoked, {@link #readOnce()} and
* {@link #getInputStream()} will simply open the destination
* file you've specified as an argument. So if you further
* move the file or delete this file, those methods will
* behave in undefined fashion. For a simliar reason,
* calling this method multiple times will cause
* undefined behavior.
*/
public abstract void moveTo(File dst) throws IOException;
/**
* Releases any resources associated with this DataHandler.
* (such as an attachment in a web service read from a temp
* file will be deleted.) After calling this method, it is
* illegal to call any other methods.
*/
public abstract void close() throws IOException;
}

View File

@@ -0,0 +1,185 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamException;
/**
* {@link XMLStreamReader} extended for reading binary data.
*
* <p>
* Some producer of infoset (in particular, such as FastInfoset,
* XOP decoder), uses a native format that enables efficient
* treatment of binary data. For ordinary infoset consumer
* (that just uses {@link XMLStreamReader}, those binary data
* will just look like base64-encoded string, but this interface
* allows consumers of such infoset to access this raw binary data.
* Such infoset producer may choose to implement this additoinal
* interface, to expose this functionality.
*
* <p>
* Consumers that are capable of using this interface can query
* {@link XMLStreamReader} if it supports this by simply downcasting
* it to this interface like this:
*
* <pre>
* XMLStreamReader reader = ...;
* if( reader instanceof XMLStreamReaderEx ) {
* // this reader supports binary data exchange
* ...
* } else {
* // noop
* ...
* }
* </pre>
*
* <p>
* Also note that it is also allowed for the infoset producer
* to implement this interface in such a way that {@link #getPCDATA()}
* always delegate to {@link #getText()}, although it's not desirable.
*
* <p>
* This interface is a private contract between such producers
* and consumers to allow them to exchange binary data without
* converting it to base64.
*
* @see XMLStreamWriterEx
* @author Kohsuke Kawaguchi
* @author Paul Sandoz
*/
public interface XMLStreamReaderEx extends XMLStreamReader {
///**
// * Works like {@link XMLStreamReader#getText()}
// * but returns text as {@link DataSource}.
// *
// * <p>
// * This method can be invoked whenever {@link XMLStreamReader#getText()}
// * can be invoked. Invoking this method means the caller is assuming
// * that the text is (conceptually) base64-encoded binary data.
// *
// * <p>
// * This abstraction is necessary to treat XOP as infoset encoding.
// * That is, you can either access the XOP-attached binary through
// * {@link XMLStreamReader#getText()} (in which case you'll see the
// * base64 encoded string), or you can access it as a binary data
// * directly by using this method.
// *
// * <p>
// * Note that even if you are reading from non XOP-aware {@link XMLStreamReader},
// * this method must be still supported; if the reader is pointing
// * to a text, this method is responsible for decoding base64 and
// * producing a {@link DataHandler} with "application/octet-stream"
// * as the content type.
// *
// * @return
// * always non-null valid object.
// * Invocations of this method may return the same object as long
// * as the {@link XMLStreamReader#next()} method is not used,
// * but otherwise {@link DataSource} object returned from this method
// * is considered to be owned by the client, and therefore it shouldn't
// * be reused by the implementation of this method.
// *
// * <p>
// * The returned {@link DataSource} is read-only, and the caller
// * must not invoke {@link DataSource#getOutputStream()}.
// *
// * @throws IllegalStateException
// * if the parser is not pointing at characters infoset item.
// * @throws XMLStreamException
// * if the parser points to text but text is not base64-encoded text,
// * or if some other parsing error occurs (such as if the &lt;xop:Include>
// * points to a non-existing attachment.)
// *
// * <p>
// * It is also OK for this method to return successfully, only to fail
// * during an {@link InputStream} is read from {@link DataSource}.
// */
//DataSource getTextAsDataHandler() throws XMLStreamException;
///**
// * Works like {@link XMLStreamReader#getText()}
// * but returns text as {@link byte[]}.
// *
// * <p>
// * The contract of this method is mostly the same as
// * {@link #getTextAsDataHandler()}, except that this
// * method returns the binary datas as an exact-size byte[].
// *
// * <p>
// * This method is also not capable of reporting the content type
// * of this binary data, even if it is available to the parser.
// *
// * @see #getTextAsDataHandler()
// */
//byte[] getTextAsByteArray() throws XMLStreamException;
/**
* Works like {@link #getText()}
* but hides the actual data representation.
*
* @return
* The {@link CharSequence} that represents the
* character infoset items at the current position.
*
* <p>
* The {@link CharSequence} is normally a {@link String},
* but can be any other {@link CharSequence} implementation.
* For binary data, however, use of {@link Base64Data} is
* recommended (so that the consumer interested in seeing it
* as binary data may take advantage of mor efficient
* data representation.)
*
* <p>
* The object returned from this method belongs to the parser,
* and its content is guaranteed to be the same only until
* the {@link #next()} method is invoked.
*
* @throws IllegalStateException
* if the parser is not pointing at characters infoset item.
*
* TODO:
* fix the dependency to JAXB internal class.
*/
CharSequence getPCDATA() throws XMLStreamException;
/**
* {@inheritDoc}
*/
NamespaceContextEx getNamespaceContext();
/**
* Works like {@link #getElementText()} but trims the leading
* and trailing whitespace.
*
* <p>
* The parser can often do this more efficiently than
* {@code getElementText().trim()}.
*
* @see #getElementText()
*/
String getElementTextTrim() throws XMLStreamException;
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.org.jvnet.staxex;
import javax.activation.DataHandler;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.OutputStream;
/**
* {@link XMLStreamWriter} extended to support XOP.
*
* <p>
* Some infoset serializer (such as XOP encoder, FastInfoset) uses a format
* that can represent binary data more efficiently than base64 encoding.
* Such infoset serializer may choose to implement this interface, to allow
* the caller to pass in binary data more efficiently without first converting
* it to binary data.
*
* <p>
* Callers capable of using this interface can see if the serializer supports
* it by simply downcasting {@link XMLStreamWriter} to {@link XMLStreamWriterEx}.
*
* <h2>TODO</h2>
* <ol>
* <li>
* Add methods to write other primitive types, such as hex and integers
* (and arrays of).
* A textual implementation would write characters in accordance
* to the canonical lexical definitions specified in W3C XML Schema: datatypes.
* A MTOM implementation would write characters except for the case where octets
* that would otherwise be base64 encoded when using the textual implementation.
* A Fast Infoset implementation would encoded binary data the primitive types in
* binary form.
* <li>
* Consider renaming writeBinary to writeBytesAsBase64 to be consistent with
* infoset abstraction.
* <li>
* Add the ability to writeStart and writeEnd on attributes so that the same
* methods for writing primitive types (and characters, which will require new methods)
* can be used for writing attribute values as well as element content.
* </ol>
*
* @see XMLStreamReaderEx
* @author Kohsuke Kawaguchi
* @author Paul Sandoz
*/
public interface XMLStreamWriterEx extends XMLStreamWriter {
/**
* Write the binary data.
*
* <p>
* Conceptually (infoset-wise), this produces the base64-encoded binary data on the
* output. But this allows implementations like FastInfoset or XOP to do the smart
* thing.
*
* <p>
* The use of this method has some restriction to support XOP. Namely, this method
* must be invoked as a sole content of an element.
*
* <p>
* (data,start,len) triplet identifies the binary data to be written.
* After the method invocation, the callee owns the buffer.
*
* @param contentType
* this mandatory parameter identifies the MIME type of the binary data.
* If the MIME type isn't known by the caller, "application/octet-stream" can
* be always used to indicate "I don't know." Never null.
*/
void writeBinary(byte[] data, int start, int len, String contentType) throws XMLStreamException;
/**
* Writes the binary data.
*
* <p>
* This method works like the {@link #writeBinary(byte[], int, int, String)} method,
* except that it takes the binary data in the form of {@link DataHandler}, which
* contains a MIME type ({@link DataHandler#getContentType()} as well as the payload
* {@link DataHandler#getInputStream()}.
*
* @param data
* always non-null. After this method call, the callee owns the data handler.
*/
void writeBinary(DataHandler data) throws XMLStreamException;
/**
* Writes the binary data.
*
* <p>
* This version of the writeBinary method allows the caller to produce
* the binary data by writing it to {@link OutputStream}.
*
* <p>
* It is the caller's responsibility to write and close
* a stream before it invokes any other methods on {@link XMLStreamWriter}.
*
* TODO: experimental. appreciate feedback
* @param contentType
* See the content-type parameter of
* {@link #writeBinary(byte[], int, int, String)}. Must not be null.
*
* @return
* always return a non-null {@link OutputStream}.
*/
OutputStream writeBinary(String contentType) throws XMLStreamException;
/**
* Writes like {@link #writeCharacters(String)} but hides
* actual data format.
*
* @param data
* The {@link CharSequence} that represents the
* character infoset items to be written.
*
* <p>
* The {@link CharSequence} is normally a {@link String},
* but can be any other {@link CharSequence} implementation.
* For binary data, however, use of {@link Base64Data} is
* recommended (so that the consumer interested in seeing it
* as binary data may take advantage of mor efficient
* data representation.)
*
*/
void writePCDATA(CharSequence data) throws XMLStreamException;
/**
* {@inheritDoc}
*/
NamespaceContextEx getNamespaceContext();
}