feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 ***/
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 ****/
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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 ****/
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 —
|
||||
* 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;
|
||||
|
||||
}
|
||||
@@ -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 <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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user