--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java Mon Feb 26 17:18:15 2018 -0800
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java Tue Feb 27 12:47:58 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -21,6 +21,7 @@
package com.sun.org.apache.xerces.internal.impl;
+import com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
@@ -45,6 +46,7 @@
import com.sun.xml.internal.stream.XMLBufferListener;
import com.sun.xml.internal.stream.XMLEntityStorage;
import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
+import java.io.CharConversionException;
import java.io.EOFException;
import java.io.IOException;
import javax.xml.XMLConstants;
@@ -3075,6 +3077,20 @@
}//switch
}
+ // encoding errors
+ catch (MalformedByteSequenceException e) {
+ fErrorReporter.reportError(e.getDomain(), e.getKey(),
+ e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
+ }
+ catch (CharConversionException e) {
+ fErrorReporter.reportError(
+ XMLMessageFormatter.XML_DOMAIN,
+ "CharConversionFailure",
+ null,
+ XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
+ }
// premature end of file
catch (EOFException e) {
endOfFileHook(e);
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java Mon Feb 26 17:18:15 2018 -0800
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java Tue Feb 27 12:47:58 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -22,6 +22,8 @@
package com.sun.org.apache.xerces.internal.impl;
import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDDescription;
+import com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException;
+import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
import com.sun.org.apache.xerces.internal.util.XMLChar;
@@ -38,6 +40,7 @@
import com.sun.xml.internal.stream.Entity;
import com.sun.xml.internal.stream.StaxXMLInputSource;
import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
+import java.io.CharConversionException;
import java.io.EOFException;
import java.io.IOException;
import javax.xml.stream.XMLInputFactory;
@@ -758,7 +761,19 @@
return XMLEvent.START_DOCUMENT;
}
-
+ // encoding errors
+ catch (MalformedByteSequenceException e) {
+ fErrorReporter.reportError(e.getDomain(), e.getKey(),
+ e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
+ } catch (CharConversionException e) {
+ fErrorReporter.reportError(
+ XMLMessageFormatter.XML_DOMAIN,
+ "CharConversionFailure",
+ null,
+ XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
+ }
// premature end of file
catch (EOFException e) {
reportFatalError("PrematureEOF", null);
@@ -980,6 +995,19 @@
*/
}
}
+ // encoding errors
+ catch (MalformedByteSequenceException e) {
+ fErrorReporter.reportError(e.getDomain(), e.getKey(),
+ e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
+ } catch (CharConversionException e) {
+ fErrorReporter.reportError(
+ XMLMessageFormatter.XML_DOMAIN,
+ "CharConversionFailure",
+ null,
+ XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
+ }
// premature end of file
catch (EOFException e) {
reportFatalError("PrematureEOF", null);
@@ -1152,7 +1180,19 @@
}
} while (complete || again);
}
-
+ // encoding errors
+ catch (MalformedByteSequenceException e) {
+ fErrorReporter.reportError(e.getDomain(), e.getKey(),
+ e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return false;
+ } catch (CharConversionException e) {
+ fErrorReporter.reportError(
+ XMLMessageFormatter.XML_DOMAIN,
+ "CharConversionFailure",
+ null,
+ XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return false;
+ }
// premature end of file
catch (EOFException e) {
e.printStackTrace();
@@ -1416,7 +1456,18 @@
}
default: throw new XNIException("Scanner State " + fScannerState + " not Recognized ");
}//switch
-
+ // encoding errors
+ } catch (MalformedByteSequenceException e) {
+ fErrorReporter.reportError(e.getDomain(), e.getKey(),
+ e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
+ } catch (CharConversionException e) {
+ fErrorReporter.reportError(
+ XMLMessageFormatter.XML_DOMAIN,
+ "CharConversionFailure",
+ null,
+ XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ return -1;
} catch (EOFException e) {
// NOTE: This is the only place we're allowed to reach
// the real end of the document stream. Unless the
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLVersionDetector.java Mon Feb 26 17:18:15 2018 -0800
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLVersionDetector.java Tue Feb 27 12:47:58 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -20,9 +20,11 @@
package com.sun.org.apache.xerces.internal.impl;
+import java.io.CharConversionException;
import java.io.EOFException;
import java.io.IOException;
+import com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.SymbolTable;
import com.sun.org.apache.xerces.internal.xni.XMLString;
@@ -196,7 +198,21 @@
return Constants.XML_VERSION_1_0;
// premature end of file
}
- catch (EOFException e) {
+ // encoding errors
+ catch (MalformedByteSequenceException e) {
+ fErrorReporter.reportError(e.getDomain(), e.getKey(),
+ e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ scanner.detectingVersion = false;
+ return Constants.XML_VERSION_1_0;
+ } catch (CharConversionException e) {
+ fErrorReporter.reportError(
+ XMLMessageFormatter.XML_DOMAIN,
+ "CharConversionFailure",
+ null,
+ XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
+ scanner.detectingVersion = false;
+ return Constants.XML_VERSION_1_0;
+ } catch (EOFException e) {
fErrorReporter.reportError(
XMLMessageFormatter.XML_DOMAIN,
"PrematureEOF",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/Latin1Reader.java Tue Feb 27 12:47:58 2018 +0000
@@ -0,0 +1,219 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.org.apache.xerces.internal.impl.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * <p>
+ * Reader for the ISO-8859-1 encoding.</p>
+ *
+ * @xerces.internal
+ *
+ * @author Michael Glavassevich, IBM
+ *
+ * @version $Id: Latin1Reader.java 718095 2008-11-16 20:00:14Z mrglavas $
+ */
+public final class Latin1Reader
+ extends Reader {
+
+ //
+ // Constants
+ //
+ /**
+ * Default byte buffer size (2048).
+ */
+ public static final int DEFAULT_BUFFER_SIZE = 2048;
+
+ //
+ // Data
+ //
+ /**
+ * Input stream.
+ */
+ protected final InputStream fInputStream;
+
+ /**
+ * Byte buffer.
+ */
+ protected final byte[] fBuffer;
+
+ //
+ // Constructors
+ //
+ /**
+ * Constructs an ISO-8859-1 reader from the specified input stream using the
+ * default buffer size.
+ *
+ * @param inputStream The input stream.
+ */
+ public Latin1Reader(InputStream inputStream) {
+ this(inputStream, DEFAULT_BUFFER_SIZE);
+ } // <init>(InputStream)
+
+ /**
+ * Constructs an ISO-8859-1 reader from the specified input stream and
+ * buffer size.
+ *
+ * @param inputStream The input stream.
+ * @param size The initial buffer size.
+ */
+ public Latin1Reader(InputStream inputStream, int size) {
+ this(inputStream, new byte[size]);
+ } // <init>(InputStream, int)
+
+ /**
+ * Constructs an ISO-8859-1 reader from the specified input stream and
+ * buffer.
+ *
+ * @param inputStream The input stream.
+ * @param buffer The byte buffer.
+ */
+ public Latin1Reader(InputStream inputStream, byte[] buffer) {
+ fInputStream = inputStream;
+ fBuffer = buffer;
+ } // <init>(InputStream, byte[])
+
+ //
+ // Reader methods
+ //
+ /**
+ * Read a single character. This method will block until a character is
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * <p>
+ * Subclasses that intend to support efficient single-character input should
+ * override this method.
+ *
+ * @return The character read, as an integer in the range 0 to 255
+ * (<tt>0x00-0xff</tt>), or -1 if the end of the stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ return fInputStream.read();
+ } // read():int
+
+ /**
+ * Read characters into a portion of an array. This method will block until
+ * some input is available, an I/O error occurs, or the end of the stream is
+ * reached.
+ *
+ * @param ch Destination buffer
+ * @param offset Offset at which to start storing characters
+ * @param length Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the stream has
+ * been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char ch[], int offset, int length) throws IOException {
+ if (length > fBuffer.length) {
+ length = fBuffer.length;
+ }
+ int count = fInputStream.read(fBuffer, 0, length);
+ for (int i = 0; i < count; ++i) {
+ ch[offset + i] = (char) (fBuffer[i] & 0xff);
+ }
+ return count;
+ } // read(char[],int,int)
+
+ /**
+ * Skip characters. This method will block until some characters are
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * @param n The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ return fInputStream.skip(n);
+ } // skip(long):long
+
+ /**
+ * Tell whether this stream is ready to be read.
+ *
+ * @return True if the next read() is guaranteed not to block for input,
+ * false otherwise. Note that returning false does not guarantee that the
+ * next read will block.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return false;
+ } // ready()
+
+ /**
+ * Tell whether this stream supports the mark() operation.
+ */
+ public boolean markSupported() {
+ return fInputStream.markSupported();
+ } // markSupported()
+
+ /**
+ * Mark the present position in the stream. Subsequent calls to reset() will
+ * attempt to reposition the stream to this point. Not all character-input
+ * streams support the mark() operation.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be read
+ * while still preserving the mark. After reading this many characters,
+ * attempting to reset the stream may fail.
+ *
+ * @exception IOException If the stream does not support mark(), or if some
+ * other I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ fInputStream.mark(readAheadLimit);
+ } // mark(int)
+
+ /**
+ * Reset the stream. If the stream has been marked, then attempt to
+ * reposition it at the mark. If the stream has not been marked, then
+ * attempt to reset it in some way appropriate to the particular stream, for
+ * example by repositioning it to its starting point. Not all
+ * character-input streams support the reset() operation, and some support
+ * reset() without supporting mark().
+ *
+ * @exception IOException If the stream has not been marked, or if the mark
+ * has been invalidated, or if the stream does not support reset(), or if
+ * some other I/O error occurs
+ */
+ public void reset() throws IOException {
+ fInputStream.reset();
+ } // reset()
+
+ /**
+ * Close the stream. Once a stream has been closed, further read(), ready(),
+ * mark(), or reset() invocations will throw an IOException. Closing a
+ * previously-closed stream, however, has no effect.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void close() throws IOException {
+ fInputStream.close();
+ } // close()
+
+} // class Latin1Reader
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/UTF16Reader.java Tue Feb 27 12:47:58 2018 +0000
@@ -0,0 +1,333 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.org.apache.xerces.internal.impl.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.Locale;
+
+import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
+import com.sun.org.apache.xerces.internal.util.MessageFormatter;
+
+/**
+ * <p>
+ * A UTF-16 reader. Can also be used for UCS-2 (i.e. ISO-10646-UCS-2).</p>
+ *
+ * @xerces.internal
+ *
+ * @author Michael Glavassevich, IBM
+ *
+ * @version $Id: UTF16Reader.java 718095 2008-11-16 20:00:14Z mrglavas $
+ */
+public final class UTF16Reader
+ extends Reader {
+
+ //
+ // Constants
+ //
+ /**
+ * Default byte buffer size (4096).
+ */
+ public static final int DEFAULT_BUFFER_SIZE = 4096;
+
+ //
+ // Data
+ //
+ /**
+ * Input stream.
+ */
+ protected final InputStream fInputStream;
+
+ /**
+ * Byte buffer.
+ */
+ protected final byte[] fBuffer;
+
+ /**
+ * Endianness.
+ */
+ protected final boolean fIsBigEndian;
+
+ // message formatter; used to produce localized exception messages
+ private final MessageFormatter fFormatter;
+
+ // Locale to use for messages
+ private final Locale fLocale;
+
+ //
+ // Constructors
+ //
+ /**
+ * Constructs a UTF-16 reader from the specified input stream using the
+ * default buffer size. Primarily for testing.
+ *
+ * @param inputStream The input stream.
+ * @param isBigEndian The byte order.
+ */
+ public UTF16Reader(InputStream inputStream, boolean isBigEndian) {
+ this(inputStream, DEFAULT_BUFFER_SIZE, isBigEndian,
+ new XMLMessageFormatter(), Locale.getDefault());
+ } // <init>(InputStream, boolean)
+
+ /**
+ * Constructs a UTF-16 reader from the specified input stream using the
+ * default buffer size and the given MessageFormatter.
+ *
+ * @param inputStream The input stream.
+ * @param isBigEndian The byte order.
+ */
+ public UTF16Reader(InputStream inputStream, boolean isBigEndian,
+ MessageFormatter messageFormatter, Locale locale) {
+ this(inputStream, DEFAULT_BUFFER_SIZE, isBigEndian, messageFormatter, locale);
+ } // <init>(InputStream, boolean, MessageFormatter, Locale)
+
+ /**
+ * Constructs a UTF-16 reader from the specified input stream and buffer
+ * size and given MessageFormatter.
+ *
+ * @param inputStream The input stream.
+ * @param size The initial buffer size.
+ * @param isBigEndian The byte order.
+ * @param messageFormatter Given MessageFormatter
+ * @param locale Locale to use for messages
+ */
+ public UTF16Reader(InputStream inputStream, int size, boolean isBigEndian,
+ MessageFormatter messageFormatter, Locale locale) {
+ this(inputStream, new byte[size], isBigEndian, messageFormatter, locale);
+ } // <init>(InputStream, int, boolean, MessageFormatter, Locale)
+
+ /**
+ * Constructs a UTF-16 reader from the specified input stream, buffer and
+ * MessageFormatter.
+ *
+ * @param inputStream The input stream.
+ * @param buffer The byte buffer.
+ * @param isBigEndian The byte order.
+ * @param messageFormatter Given MessageFormatter
+ * @param locale Locale to use for messages
+ */
+ public UTF16Reader(InputStream inputStream, byte[] buffer, boolean isBigEndian,
+ MessageFormatter messageFormatter, Locale locale) {
+ fInputStream = inputStream;
+ fBuffer = buffer;
+ fIsBigEndian = isBigEndian;
+ fFormatter = messageFormatter;
+ fLocale = locale;
+ } // <init>(InputStream, byte[], boolean, MessageFormatter, Locale)
+
+ //
+ // Reader methods
+ //
+ /**
+ * Read a single character. This method will block until a character is
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * <p>
+ * Subclasses that intend to support efficient single-character input should
+ * override this method.
+ *
+ * @return The character read, as an integer in the range 0 to 65535
+ * (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ final int b0 = fInputStream.read();
+ if (b0 == -1) {
+ return -1;
+ }
+ final int b1 = fInputStream.read();
+ if (b1 == -1) {
+ expectedTwoBytes();
+ }
+ // UTF-16BE
+ if (fIsBigEndian) {
+ return (b0 << 8) | b1;
+ }
+ // UTF-16LE
+ return (b1 << 8) | b0;
+ } // read():int
+
+ /**
+ * Read characters into a portion of an array. This method will block until
+ * some input is available, an I/O error occurs, or the end of the stream is
+ * reached.
+ *
+ * @param ch Destination buffer
+ * @param offset Offset at which to start storing characters
+ * @param length Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the stream has
+ * been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char ch[], int offset, int length) throws IOException {
+ int byteLength = length << 1;
+ if (byteLength > fBuffer.length) {
+ byteLength = fBuffer.length;
+ }
+ int byteCount = fInputStream.read(fBuffer, 0, byteLength);
+ if (byteCount == -1) {
+ return -1;
+ }
+ // If an odd number of bytes were read, we still need to read one more.
+ if ((byteCount & 1) != 0) {
+ int b = fInputStream.read();
+ if (b == -1) {
+ expectedTwoBytes();
+ }
+ fBuffer[byteCount++] = (byte) b;
+ }
+ final int charCount = byteCount >> 1;
+ if (fIsBigEndian) {
+ processBE(ch, offset, charCount);
+ } else {
+ processLE(ch, offset, charCount);
+ }
+ return charCount;
+ } // read(char[],int,int)
+
+ /**
+ * Skip characters. This method will block until some characters are
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * @param n The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ long bytesSkipped = fInputStream.skip(n << 1);
+ if ((bytesSkipped & 1) != 0) {
+ int b = fInputStream.read();
+ if (b == -1) {
+ expectedTwoBytes();
+ }
+ ++bytesSkipped;
+ }
+ return bytesSkipped >> 1;
+ } // skip(long):long
+
+ /**
+ * Tell whether this stream is ready to be read.
+ *
+ * @return True if the next read() is guaranteed not to block for input,
+ * false otherwise. Note that returning false does not guarantee that the
+ * next read will block.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return false;
+ } // ready()
+
+ /**
+ * Tell whether this stream supports the mark() operation.
+ */
+ public boolean markSupported() {
+ return false;
+ } // markSupported()
+
+ /**
+ * Mark the present position in the stream. Subsequent calls to reset() will
+ * attempt to reposition the stream to this point. Not all character-input
+ * streams support the mark() operation.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be read
+ * while still preserving the mark. After reading this many characters,
+ * attempting to reset the stream may fail.
+ *
+ * @exception IOException If the stream does not support mark(), or if some
+ * other I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ throw new IOException(fFormatter.formatMessage(fLocale, "OperationNotSupported", new Object[]{"mark()", "UTF-16"}));
+ } // mark(int)
+
+ /**
+ * Reset the stream. If the stream has been marked, then attempt to
+ * reposition it at the mark. If the stream has not been marked, then
+ * attempt to reset it in some way appropriate to the particular stream, for
+ * example by repositioning it to its starting point. Not all
+ * character-input streams support the reset() operation, and some support
+ * reset() without supporting mark().
+ *
+ * @exception IOException If the stream has not been marked, or if the mark
+ * has been invalidated, or if the stream does not support reset(), or if
+ * some other I/O error occurs
+ */
+ public void reset() throws IOException {
+ } // reset()
+
+ /**
+ * Close the stream. Once a stream has been closed, further read(), ready(),
+ * mark(), or reset() invocations will throw an IOException. Closing a
+ * previously-closed stream, however, has no effect.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void close() throws IOException {
+ fInputStream.close();
+ } // close()
+
+ //
+ // Private methods
+ //
+ /**
+ * Decodes UTF-16BE *
+ */
+ private void processBE(final char ch[], int offset, final int count) {
+ int curPos = 0;
+ for (int i = 0; i < count; ++i) {
+ final int b0 = fBuffer[curPos++] & 0xff;
+ final int b1 = fBuffer[curPos++] & 0xff;
+ ch[offset++] = (char) ((b0 << 8) | b1);
+ }
+ } // processBE(char[],int,int)
+
+ /**
+ * Decodes UTF-16LE *
+ */
+ private void processLE(final char ch[], int offset, final int count) {
+ int curPos = 0;
+ for (int i = 0; i < count; ++i) {
+ final int b0 = fBuffer[curPos++] & 0xff;
+ final int b1 = fBuffer[curPos++] & 0xff;
+ ch[offset++] = (char) ((b1 << 8) | b0);
+ }
+ } // processLE(char[],int,int)
+
+ /**
+ * Throws an exception for expected byte.
+ */
+ private void expectedTwoBytes()
+ throws MalformedByteSequenceException {
+ throw new MalformedByteSequenceException(fFormatter,
+ fLocale,
+ XMLMessageFormatter.XML_DOMAIN,
+ "ExpectedByte",
+ new Object[]{"2", "2"});
+ } // expectedTwoBytes()
+
+} // class UTF16Reader
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java Mon Feb 26 17:18:15 2018 -0800
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java Tue Feb 27 12:47:58 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -46,6 +46,7 @@
import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
import com.sun.org.apache.xerces.internal.xs.PSVIProvider;
+import java.io.CharConversionException;
import java.io.IOException;
import java.util.Locale;
import javax.xml.XMLConstants;
@@ -1143,7 +1144,7 @@
// wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) {
Exception ex = e.getException();
- if (ex == null) {
+ if (ex == null || ex instanceof CharConversionException) {
// must be a parser exception; mine it for locator info and throw
// a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl(){
@@ -1163,7 +1164,9 @@
locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber());
- throw new SAXParseException(e.getMessage(), locatorImpl);
+ throw (ex == null) ?
+ new SAXParseException(e.getMessage(), locatorImpl) :
+ new SAXParseException(e.getMessage(), locatorImpl, ex);
}
if (ex instanceof SAXException) {
// why did we create an XMLParseException?
@@ -1216,7 +1219,7 @@
// wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) {
Exception ex = e.getException();
- if (ex == null) {
+ if (ex == null || ex instanceof CharConversionException) {
// must be a parser exception; mine it for locator info and throw
// a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl() {
@@ -1236,7 +1239,9 @@
locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber());
- throw new SAXParseException(e.getMessage(), locatorImpl);
+ throw (ex == null) ?
+ new SAXParseException(e.getMessage(), locatorImpl) :
+ new SAXParseException(e.getMessage(), locatorImpl, ex);
}
if (ex instanceof SAXException) {
// why did we create an XMLParseException?
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/DOMParser.java Mon Feb 26 17:18:15 2018 -0800
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/DOMParser.java Tue Feb 27 12:47:58 2018 +0000
@@ -40,6 +40,7 @@
import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
+import java.io.CharConversionException;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
@@ -184,7 +185,7 @@
// wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) {
Exception ex = e.getException();
- if (ex == null) {
+ if (ex == null || ex instanceof CharConversionException) {
// must be a parser exception; mine it for locator info and throw
// a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl();
@@ -192,7 +193,9 @@
locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber());
- throw new SAXParseException(e.getMessage(), locatorImpl);
+ throw (ex == null) ?
+ new SAXParseException(e.getMessage(), locatorImpl) :
+ new SAXParseException(e.getMessage(), locatorImpl, ex);
}
if (ex instanceof SAXException) {
// why did we create an XMLParseException?
@@ -246,7 +249,7 @@
// wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) {
Exception ex = e.getException();
- if (ex == null) {
+ if (ex == null || ex instanceof CharConversionException) {
// must be a parser exception; mine it for locator info and throw
// a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl();
@@ -254,7 +257,9 @@
locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber());
- throw new SAXParseException(e.getMessage(), locatorImpl);
+ throw (ex == null) ?
+ new SAXParseException(e.getMessage(), locatorImpl) :
+ new SAXParseException(e.getMessage(), locatorImpl, ex);
}
if (ex instanceof SAXException) {
// why did we create an XMLParseException?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/XMLLocatorWrapper.java Tue Feb 27 12:47:58 2018 +0000
@@ -0,0 +1,113 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sun.org.apache.xerces.internal.util;
+
+import com.sun.org.apache.xerces.internal.xni.XMLLocator;
+
+/**
+ * <p>A light wrapper around an <code>XMLLocator</code>.</p>
+ *
+ * @author Michael Glavassevich, IBM
+ *
+ * @version $Id: XMLLocatorWrapper.java 533423 2007-04-28 20:47:15Z mrglavas $
+ */
+public final class XMLLocatorWrapper implements XMLLocator {
+
+ private XMLLocator fLocator = null;
+
+ public XMLLocatorWrapper() {}
+
+ public void setLocator(XMLLocator locator) {
+ fLocator = locator;
+ }
+
+ public XMLLocator getLocator() {
+ return fLocator;
+ }
+
+ /*
+ * XMLLocator methods
+ */
+
+ public String getPublicId() {
+ if (fLocator != null) {
+ return fLocator.getPublicId();
+ }
+ return null;
+ }
+
+ public String getLiteralSystemId() {
+ if (fLocator != null) {
+ return fLocator.getLiteralSystemId();
+ }
+ return null;
+ }
+
+ public String getBaseSystemId() {
+ if (fLocator != null) {
+ return fLocator.getBaseSystemId();
+ }
+ return null;
+ }
+
+ public String getExpandedSystemId() {
+ if (fLocator != null) {
+ return fLocator.getExpandedSystemId();
+ }
+ return null;
+ }
+
+ public int getLineNumber() {
+ if (fLocator != null) {
+ return fLocator.getLineNumber();
+ }
+ return -1;
+ }
+
+ public int getColumnNumber() {
+ if (fLocator != null) {
+ return fLocator.getColumnNumber();
+ }
+ return -1;
+ }
+
+ public int getCharacterOffset() {
+ if (fLocator != null) {
+ return fLocator.getCharacterOffset();
+ }
+ return -1;
+ }
+
+ public String getEncoding() {
+ if (fLocator != null) {
+ return fLocator.getEncoding();
+ }
+ return null;
+ }
+
+ public String getXMLVersion() {
+ if (fLocator != null) {
+ return fLocator.getXMLVersion();
+ }
+ return null;
+ }
+}
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeHandler.java Mon Feb 26 17:18:15 2018 -0800
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeHandler.java Tue Feb 27 12:47:58 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -36,9 +36,9 @@
import com.sun.org.apache.xerces.internal.util.URI;
import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
import com.sun.org.apache.xerces.internal.util.XMLChar;
+import com.sun.org.apache.xerces.internal.util.XMLLocatorWrapper;
import com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl;
import com.sun.org.apache.xerces.internal.util.XMLSymbols;
-import com.sun.org.apache.xerces.internal.utils.ObjectFactory;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
import com.sun.org.apache.xerces.internal.xni.Augmentations;
@@ -157,8 +157,8 @@
public final static String CURRENT_BASE_URI = "currentBaseURI";
// used for adding [base URI] attributes
- public final static String XINCLUDE_BASE = "base".intern();
- public final static QName XML_BASE_QNAME =
+ private final static String XINCLUDE_BASE = "base".intern();
+ private final static QName XML_BASE_QNAME =
new QName(
XMLSymbols.PREFIX_XML,
XINCLUDE_BASE,
@@ -166,15 +166,15 @@
NamespaceContext.XML_URI);
// used for adding [language] attributes
- public final static String XINCLUDE_LANG = "lang".intern();
- public final static QName XML_LANG_QNAME =
+ private final static String XINCLUDE_LANG = "lang".intern();
+ private final static QName XML_LANG_QNAME =
new QName(
XMLSymbols.PREFIX_XML,
XINCLUDE_LANG,
(XMLSymbols.PREFIX_XML + ":" + XINCLUDE_LANG).intern(),
NamespaceContext.XML_URI);
- public final static QName NEW_NS_ATTR_QNAME =
+ private final static QName NEW_NS_ATTR_QNAME =
new QName(
XMLSymbols.PREFIX_XMLNS,
"",
@@ -217,6 +217,10 @@
protected static final String XINCLUDE_FIXUP_LANGUAGE =
Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE;
+ /** Property identifier: JAXP schema language. */
+ protected static final String JAXP_SCHEMA_LANGUAGE =
+ Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE;
+
/** Property identifier: symbol table. */
protected static final String SYMBOL_TABLE =
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
@@ -234,7 +238,7 @@
Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
/** property identifier: buffer size. */
- public static final String BUFFER_SIZE =
+ protected static final String BUFFER_SIZE =
Constants.XERCES_PROPERTY_PREFIX + Constants.BUFFER_SIZE_PROPERTY;
protected static final String PARSER_SETTINGS =
@@ -292,6 +296,7 @@
protected XPointerProcessor fXPtrProcessor = null;
protected XMLLocator fDocLocation;
+ protected XMLLocatorWrapper fXIncludeLocator = new XMLLocatorWrapper();
protected XIncludeMessageFormatter fXIncludeMessageFormatter = new XIncludeMessageFormatter();
protected XIncludeNamespaceSupport fNamespaceContext;
protected SymbolTable fSymbolTable;
@@ -305,17 +310,19 @@
protected XIncludeTextReader fXInclude11TextReader;
// these are needed for XML Base processing
- protected XMLResourceIdentifier fCurrentBaseURI;
- protected IntStack fBaseURIScope;
- protected Stack<String> fBaseURI;
- protected Stack<String> fLiteralSystemID;
- protected Stack<String> fExpandedSystemID;
+ protected final XMLResourceIdentifier fCurrentBaseURI;
+ protected final IntStack fBaseURIScope;
+ protected final Stack<String> fBaseURI;
+ protected final Stack<String> fLiteralSystemID;
+ protected final Stack<String> fExpandedSystemID;
// these are needed for Language Fixup
- protected IntStack fLanguageScope;
- protected Stack<String> fLanguageStack;
+ protected final IntStack fLanguageScope;
+ protected final Stack<String> fLanguageStack;
protected String fCurrentLanguage;
+ protected String fHrefFromParent;
+
// used for passing features on to child XIncludeHandler objects
protected ParserConfigurationSettings fSettings;
@@ -361,6 +368,9 @@
// track whether a DTD is being parsed
private boolean fInDTD;
+ // tracks whether content has been reported on the child pipeline
+ boolean fHasIncludeReportedContent;
+
// track whether the root element of the result infoset has been processed
private boolean fSeenRootElement;
@@ -593,15 +603,21 @@
copyFeatures(componentManager, fSettings);
// We don't want a schema validator on the new pipeline,
- // so if it was enabled, we set the feature to false. If
- // the validation feature was also enabled we turn on
- // dynamic validation, so that DTD validation is performed
- // on the included documents only if they have a DOCTYPE.
- // This is consistent with the behaviour on the main pipeline.
+ // so if it was enabled, we set the feature to false.
try {
if (componentManager.getFeature(SCHEMA_VALIDATION)) {
fSettings.setFeature(SCHEMA_VALIDATION, false);
- if (componentManager.getFeature(VALIDATION)) {
+ // If the value of the JAXP 1.2 schema language property
+ // is http://www.w3.org/2001/XMLSchema we're only validating
+ // against XML schema so we disable validation on the new pipeline.
+ if (Constants.NS_XMLSCHEMA.equals(componentManager.getProperty(JAXP_SCHEMA_LANGUAGE))) {
+ fSettings.setFeature(VALIDATION, false);
+ }
+ // If the validation feature was also enabled we turn on
+ // dynamic validation, so that DTD validation is performed
+ // on the included documents only if they have a DOCTYPE.
+ // This is consistent with the behaviour on the main pipeline.
+ else if (componentManager.getFeature(VALIDATION)) {
fSettings.setFeature(DYNAMIC_VALIDATION, true);
}
}
@@ -776,7 +792,15 @@
@Override
public void setDocumentHandler(XMLDocumentHandler handler) {
- fDocumentHandler = handler;
+ if (fDocumentHandler != handler) {
+ fDocumentHandler = handler;
+ if (fXIncludeChildConfig != null) {
+ fXIncludeChildConfig.setDocumentHandler(handler);
+ }
+ if (fXPointerChildConfig != null) {
+ fXPointerChildConfig.setDocumentHandler(handler);
+ }
+ }
}
@Override
@@ -806,36 +830,39 @@
// otherwise, the locator from the root document would always be used
fErrorReporter.setDocumentLocator(locator);
- if (!isRootDocument()
- && fParentXIncludeHandler.searchForRecursiveIncludes(locator)) {
- reportFatalError(
- "RecursiveInclude",
- new Object[] { locator.getExpandedSystemId()});
- }
-
if (!(namespaceContext instanceof XIncludeNamespaceSupport)) {
reportFatalError("IncompatibleNamespaceContext");
}
fNamespaceContext = (XIncludeNamespaceSupport)namespaceContext;
fDocLocation = locator;
+ fXIncludeLocator.setLocator(fDocLocation);
// initialize the current base URI
- fCurrentBaseURI.setBaseSystemId(locator.getBaseSystemId());
- fCurrentBaseURI.setExpandedSystemId(locator.getExpandedSystemId());
- fCurrentBaseURI.setLiteralSystemId(locator.getLiteralSystemId());
+ setupCurrentBaseURI(locator);
saveBaseURI();
if (augs == null) {
augs = new AugmentationsImpl();
}
augs.putItem(CURRENT_BASE_URI, fCurrentBaseURI);
+ // abort here if we detect a recursive include
+ if (!isRootDocument()) {
+ fParentXIncludeHandler.fHasIncludeReportedContent = true;
+ if (fParentXIncludeHandler.searchForRecursiveIncludes(
+ fCurrentBaseURI.getExpandedSystemId())) {
+ reportFatalError(
+ "RecursiveInclude",
+ new Object[] { fCurrentBaseURI.getExpandedSystemId()});
+ }
+ }
+
// initialize the current language
fCurrentLanguage = XMLSymbols.EMPTY_STRING;
saveLanguage(fCurrentLanguage);
if (isRootDocument() && fDocumentHandler != null) {
fDocumentHandler.startDocument(
- locator,
+ fXIncludeLocator,
encoding,
namespaceContext,
augs);
@@ -1671,7 +1698,7 @@
catch (IOException | CatalogException e) {
reportResourceError(
"XMLResourceError",
- new Object[] { href, e.getMessage()});
+ new Object[] { href, e.getMessage()}, e);
return false;
}
}
@@ -1750,6 +1777,8 @@
// ???
newHandler.setParent(this);
+ newHandler.setHref(href);
+ newHandler.setXIncludeLocator(fXIncludeLocator);
newHandler.setDocumentHandler(this.getDocumentHandler());
fXPointerChildConfig = fChildConfig;
} else {
@@ -1758,7 +1787,8 @@
Constants.XERCES_PROPERTY_PREFIX
+ Constants.XINCLUDE_HANDLER_PROPERTY);
- newHandler.setParent(this);
+ newHandler.setParent(this);
+ newHandler.setHref(href);
newHandler.setDocumentHandler(this.getDocumentHandler());
fXIncludeChildConfig = fChildConfig;
}
@@ -1766,7 +1796,7 @@
// If an xpointer attribute is present
if (xpointer != null ) {
- fChildConfig = fXPointerChildConfig ;
+ fChildConfig = fXPointerChildConfig;
// Parse the XPointer expression
try {
@@ -1790,10 +1820,12 @@
fNeedCopyFeatures = false;
try {
+ fHasIncludeReportedContent = false;
fNamespaceContext.pushScope();
fChildConfig.parse(includedSource);
- // necessary to make sure proper location is reported in errors
+ // necessary to make sure proper location is reported to the application and in errors
+ fXIncludeLocator.setLocator(fDocLocation);
if (fErrorReporter != null) {
fErrorReporter.setDocumentLocator(fDocLocation);
}
@@ -1811,23 +1843,32 @@
}
}
catch (XNIException e) {
- // necessary to make sure proper location is reported in errors
+ // necessary to make sure proper location is reported to the application and in errors
+ fXIncludeLocator.setLocator(fDocLocation);
if (fErrorReporter != null) {
fErrorReporter.setDocumentLocator(fDocLocation);
}
reportFatalError("XMLParseError", new Object[] { href, e.getMessage() });
}
catch (IOException e) {
- // necessary to make sure proper location is reported in errors
+ // necessary to make sure proper location is reported to the application and in errors
+ fXIncludeLocator.setLocator(fDocLocation);
if (fErrorReporter != null) {
fErrorReporter.setDocumentLocator(fDocLocation);
}
- // An IOException indicates that we had trouble reading the file, not
- // that it was an invalid XML file. So we send a resource error, not a
- // fatal error.
+ // If the start document event has been seen on the child pipeline it
+ // means the resource was successfully opened and we started reporting
+ // document events. If an IOException is thrown after the start document
+ // event we had a failure midstream and cannot recover.
+ if (fHasIncludeReportedContent) {
+ throw new XNIException(e);
+ }
+ // In other circumstances an IOException indicates that we had trouble
+ // accessing or opening the file, not that it was an invalid XML file. So we
+ // send a resource error, not a fatal error.
reportResourceError(
"XMLResourceError",
- new Object[] { href, e.getMessage()});
+ new Object[] { href, e.getMessage()}, e);
return false;
}
finally {
@@ -1841,6 +1882,8 @@
XIncludeTextReader textReader = null;
try {
+ fHasIncludeReportedContent = false;
+
// Setup the appropriate text reader.
if (!fIsXML11) {
if (fXInclude10TextReader == null) {
@@ -1866,16 +1909,22 @@
// encoding errors
catch (MalformedByteSequenceException ex) {
fErrorReporter.reportError(ex.getDomain(), ex.getKey(),
- ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR);
+ ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, ex);
}
catch (CharConversionException e) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
- "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR);
+ "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
}
catch (IOException e) {
+ // If a characters event has already been sent down the pipeline it
+ // means the resource was successfully opened and that this IOException
+ // is from a failure midstream from which we cannot recover.
+ if (fHasIncludeReportedContent) {
+ throw new XNIException(e);
+ }
reportResourceError(
"TextResourceError",
- new Object[] { href, e.getMessage()});
+ new Object[] { href, e.getMessage()}, e);
return false;
}
finally {
@@ -1886,7 +1935,7 @@
catch (IOException e) {
reportResourceError(
"TextResourceError",
- new Object[] { href, e.getMessage()});
+ new Object[] { href, e.getMessage()}, e);
return false;
}
}
@@ -1977,37 +2026,51 @@
return parentLanguage != null && parentLanguage.equalsIgnoreCase(fCurrentLanguage);
}
- /**
- * Checks if the file indicated by the given XMLLocator has already been included
- * in the current stack.
- * @param includedSource the source to check for inclusion
- * @return true if the source has already been included
- */
- protected boolean searchForRecursiveIncludes(XMLLocator includedSource) {
- String includedSystemId = includedSource.getExpandedSystemId();
+ private void setupCurrentBaseURI(XMLLocator locator) {
+ fCurrentBaseURI.setBaseSystemId(locator.getBaseSystemId());
+ if (locator.getLiteralSystemId() != null) {
+ fCurrentBaseURI.setLiteralSystemId(locator.getLiteralSystemId());
+ }
+ else {
+ fCurrentBaseURI.setLiteralSystemId(fHrefFromParent);
+ }
- if (includedSystemId == null) {
+ String expandedSystemId = locator.getExpandedSystemId();
+ if (expandedSystemId == null) {
+ // attempt to expand it ourselves
try {
- includedSystemId =
+ expandedSystemId =
XMLEntityManager.expandSystemId(
- includedSource.getLiteralSystemId(),
- includedSource.getBaseSystemId(),
+ fCurrentBaseURI.getLiteralSystemId(),
+ fCurrentBaseURI.getBaseSystemId(),
false);
+ if (expandedSystemId == null) {
+ expandedSystemId = fCurrentBaseURI.getLiteralSystemId();
+ }
}
catch (MalformedURIException e) {
reportFatalError("ExpandedSystemId");
}
}
+ fCurrentBaseURI.setExpandedSystemId(expandedSystemId);
+ }
- if (includedSystemId.equals(fCurrentBaseURI.getExpandedSystemId())) {
+ /**
+ * Checks if the file indicated by the given system id has already been
+ * included in the current stack.
+ * @param includedSysId the system id to check for inclusion
+ * @return true if the source has already been included
+ */
+ protected boolean searchForRecursiveIncludes(String includedSysId) {
+ if (includedSysId.equals(fCurrentBaseURI.getExpandedSystemId())) {
return true;
}
-
- if (fParentXIncludeHandler == null) {
+ else if (fParentXIncludeHandler == null) {
return false;
}
- return fParentXIncludeHandler.searchForRecursiveIncludes(
- includedSource);
+ else {
+ return fParentXIncludeHandler.searchForRecursiveIncludes(includedSysId);
+ }
}
/**
@@ -2045,7 +2108,7 @@
* unparsed entities are processed as described in the spec, sections 4.5.1 and 4.5.2
* </ul>
* @param attributes
- * @return
+ * @return the processed XMLAttributes
*/
protected XMLAttributes processAttributes(XMLAttributes attributes) {
if (isTopLevelIncludedItem()) {
@@ -2198,7 +2261,7 @@
return relativeURI;
}
else {
- if (relativeURI.equals("")) {
+ if (relativeURI.length() == 0) {
relativeURI = fCurrentBaseURI.getLiteralSystemId();
}
@@ -2207,7 +2270,7 @@
fParentRelativeURI =
fParentXIncludeHandler.getRelativeBaseURI();
}
- if (fParentRelativeURI.equals("")) {
+ if (fParentRelativeURI.length() == 0) {
return relativeURI;
}
@@ -2420,7 +2483,7 @@
* as an ancestor of the current item.
*
* @param depth
- * @return
+ * @return true if an include was seen at the given depth, false otherwise
*/
protected boolean getSawInclude(int depth) {
if (depth >= fSawInclude.length) {
@@ -2430,11 +2493,15 @@
}
protected void reportResourceError(String key) {
- this.reportFatalError(key, null);
+ this.reportResourceError(key, null);
}
protected void reportResourceError(String key, Object[] args) {
- this.reportError(key, args, XMLErrorReporter.SEVERITY_WARNING);
+ this.reportResourceError(key, args, null);
+ }
+
+ protected void reportResourceError(String key, Object[] args, Exception exception) {
+ this.reportError(key, args, XMLErrorReporter.SEVERITY_WARNING, exception);
}
protected void reportFatalError(String key) {
@@ -2442,16 +2509,21 @@
}
protected void reportFatalError(String key, Object[] args) {
- this.reportError(key, args, XMLErrorReporter.SEVERITY_FATAL_ERROR);
+ this.reportFatalError(key, args, null);
}
- private void reportError(String key, Object[] args, short severity) {
+ protected void reportFatalError(String key, Object[] args, Exception exception) {
+ this.reportError(key, args, XMLErrorReporter.SEVERITY_FATAL_ERROR, exception);
+ }
+
+ private void reportError(String key, Object[] args, short severity, Exception exception) {
if (fErrorReporter != null) {
fErrorReporter.reportError(
XIncludeMessageFormatter.XINCLUDE_DOMAIN,
key,
args,
- severity);
+ severity,
+ exception);
}
// we won't worry about when error reporter is null, since there should always be
// at least the default error reporter
@@ -2465,6 +2537,14 @@
fParentXIncludeHandler = parent;
}
+ protected void setHref(String href) {
+ fHrefFromParent = href;
+ }
+
+ protected void setXIncludeLocator(XMLLocatorWrapper locator) {
+ fXIncludeLocator = locator;
+ }
+
// used to know whether to pass declarations to the document handler
protected boolean isRootDocument() {
return fParentXIncludeHandler == null;
@@ -2849,7 +2929,7 @@
/**
* Saves the given language on the top of the stack.
*
- * @param lanaguage the language to push onto the stack.
+ * @param language the language to push onto the stack.
*/
protected void saveLanguage(String language) {
fLanguageScope.push(fDepth);
@@ -3013,7 +3093,7 @@
// the second hex character if a character needs to be escaped
private static final char gAfterEscaping2[] = new char[128];
private static final char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
// initialize the above 3 arrays
static {
char[] escChs = {' ', '<', '>', '"', '{', '}', '|', '\\', '^', '`'};
@@ -3104,7 +3184,7 @@
// for each byte
for (i = 0; i < len; i++) {
b = bytes[i];
- // for non-ascii character: make it positive, then escape
+ // for non-ASCII character: make it positive, then escape
if (b < 0) {
ch = b + 256;
buffer.append('%');
@@ -3123,7 +3203,7 @@
}
// If escaping happened, create a new string;
- // otherwise, return the orginal one.
+ // otherwise, return the original one.
if (buffer.length() != len) {
return buffer.toString();
}
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeTextReader.java Mon Feb 26 17:18:15 2018 -0800
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeTextReader.java Tue Feb 27 12:47:58 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,6 +23,8 @@
import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
import com.sun.org.apache.xerces.internal.impl.io.ASCIIReader;
+import com.sun.org.apache.xerces.internal.impl.io.Latin1Reader;
+import com.sun.org.apache.xerces.internal.impl.io.UTF16Reader;
import com.sun.org.apache.xerces.internal.impl.io.UTF8Reader;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.EncodingMap;
@@ -67,7 +69,7 @@
public class XIncludeTextReader {
private Reader fReader;
- private XIncludeHandler fHandler;
+ private final XIncludeHandler fHandler;
private XMLInputSource fSource;
private XMLErrorReporter fErrorReporter;
private XMLString fTempString = new XMLString();
@@ -149,12 +151,12 @@
stream = new BufferedInputStream(urlCon.getInputStream());
// content type will be string like "text/xml; charset=UTF-8" or "text/xml"
- String rawContentType = urlCon.getContentType();
+ final String rawContentType = urlCon.getContentType();
// text/xml and application/xml offer only one optional parameter
- int index = (rawContentType != null) ? rawContentType.indexOf(';') : -1;
+ final int index = (rawContentType != null) ? rawContentType.indexOf(';') : -1;
- String contentType = null;
+ final String contentType;
String charset = null;
if (index != -1) {
// this should be something like "text/xml"
@@ -181,14 +183,16 @@
}
}
else {
- contentType = rawContentType.trim();
+ contentType = (rawContentType != null) ? rawContentType.trim() : "";
}
String detectedEncoding = null;
/** The encoding of such a resource is determined by:
1 external encoding information, if available, otherwise
-- the most common type of external information is the "charset" parameter of a MIME package
- 2 if the media type of the resource is text/xml, application/xml, or matches the conventions text/*+xml or application/*+xml as described in XML Media Types [IETF RFC 3023], the encoding is recognized as specified in XML 1.0, otherwise
+ 2 if the media type of the resource is text/xml, application/xml, or matches the conventions
+ text/*+xml or application/*+xml as described in XML Media Types [IETF RFC 3023], the encoding
+ is recognized as specified in XML 1.0, otherwise
3 the value of the encoding attribute if one exists, otherwise
4 UTF-8.
**/
@@ -225,15 +229,17 @@
// eat the Byte Order Mark
encoding = consumeBOM(stream, encoding);
- // If the document is UTF-8 or US-ASCII use
- // the Xerces readers for these encodings. For
- // US-ASCII consult the encoding map since
- // this encoding has many aliases.
+ // If the document is UTF-8, UTF-16, US-ASCII or ISO-8859-1 use
+ // the Xerces readers for these encodings. For US-ASCII and ISO-8859-1
+ // consult the encoding map since these encodings have many aliases.
if (encoding.equals("UTF-8")) {
- return new UTF8Reader(stream,
- fTempString.ch.length,
- fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN),
- fErrorReporter.getLocale() );
+ return createUTF8Reader(stream);
+ }
+ else if (encoding.equals("UTF-16BE")) {
+ return createUTF16Reader(stream, true);
+ }
+ else if (encoding.equals("UTF-16LE")) {
+ return createUTF16Reader(stream, false);
}
// Try to use a Java reader.
@@ -251,16 +257,45 @@
new Object[] {encoding} ) );
}
else if (javaEncoding.equals("ASCII")) {
- return new ASCIIReader(stream,
- fTempString.ch.length,
- fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN),
- fErrorReporter.getLocale() );
+ return createASCIIReader(stream);
}
-
+ else if (javaEncoding.equals("ISO8859_1")) {
+ return createLatin1Reader(stream);
+ }
return new InputStreamReader(stream, javaEncoding);
}
}
+ /** Create a new UTF-8 reader from the InputStream. **/
+ private Reader createUTF8Reader(InputStream stream) {
+ return new UTF8Reader(stream,
+ fTempString.ch.length,
+ fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN),
+ fErrorReporter.getLocale());
+ }
+
+ /** Create a new UTF-16 reader from the InputStream. **/
+ private Reader createUTF16Reader(InputStream stream, boolean isBigEndian) {
+ return new UTF16Reader(stream,
+ (fTempString.ch.length << 1),
+ isBigEndian,
+ fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN),
+ fErrorReporter.getLocale());
+ }
+
+ /** Create a new ASCII reader from the InputStream. **/
+ private Reader createASCIIReader(InputStream stream) {
+ return new ASCIIReader(stream,
+ fTempString.ch.length,
+ fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN),
+ fErrorReporter.getLocale());
+ }
+
+ /** Create a new ISO-8859-1 reader from the InputStream. **/
+ private Reader createLatin1Reader(InputStream stream) {
+ return new Latin1Reader(stream, fTempString.ch.length);
+ }
+
/**
* XMLEntityManager cares about endian-ness, since it creates its own optimized
* readers. Since we're just using generic Java readers for now, we're not caring
@@ -416,6 +451,7 @@
fReader = getReader(fSource);
fSource = null;
int readSize = fReader.read(fTempString.ch, 0, fTempString.ch.length - 1);
+ fHandler.fHasIncludeReportedContent = true;
while (readSize != -1) {
for (int i = 0; i < readSize; ++i) {
char ch = fTempString.ch[i];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/EncodingErrorsReportingTest.java Tue Feb 27 12:47:58 2018 +0000
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 8038043
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @run testng/othervm common.EncodingErrorsReportingTest
+ * @run testng/othervm -DrunSecMngr=true common.EncodingErrorsReportingTest
+ * @summary Verifies that parsers reports location of wrong UTF-8 symbols in
+ * XML files parsed and included via xi:include element
+ */
+package common;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.function.Function;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+@Listeners({jaxp.library.BasePolicy.class})
+public class EncodingErrorsReportingTest implements EntityResolver {
+
+ /*
+ * Test reporting of wrong UTF8 byte sequence location by SAX and DOM parsers
+ */
+ @Test(dataProvider = "invalidUTF8BytesInXml")
+ public void testMalformedByteException(Function<byte[], Exception> parseF,
+ byte[] xmlData, int expLine, int expColumn) {
+ // Check if data was generated without errors
+ Assert.assertNotNull(xmlData, "Error in xml test data generation");
+
+ // Execute supplier to get parse exception
+ Exception caughtEx = parseF.apply(xmlData);
+
+ // Check if exception was thrown
+ Assert.assertNotNull(caughtEx, "No caught exception");
+ boolean isSPE = caughtEx instanceof SAXParseException;
+ Assert.assertTrue(isSPE, "Caught exception is not SAXParseException");
+ SAXParseException spe = (SAXParseException) caughtEx;
+
+ // Check if cause is properly set
+ Throwable cause = spe.getCause();
+ Assert.assertNotNull(cause, "Cause is null");
+ Assert.assertEquals("com.sun.org.apache.xerces.internal" +
+ ".impl.io.MalformedByteSequenceException",
+ cause.getClass().getName(),
+ "Cause is not MalformedByteSequenceException");
+
+ // Check error locator parameters
+ int column_number = spe.getColumnNumber();
+ int line_number = spe.getLineNumber();
+ Assert.assertEquals(line_number, expLine, "Wrong line number reported");
+ Assert.assertEquals(column_number, expColumn, "Wrong column number reported");
+ }
+
+ // Provider with supplier functions that process XML content with different parsers
+ @DataProvider(name = "invalidUTF8BytesInXml")
+ public Object[][] parsersResultsSupplier() {
+ return new Object[][]{
+ // Tests for invalid UTF-8 byte in xml element
+ {(Function<byte[], Exception>) this::parseWithSAX,
+ invalidByteInXmlElement(), 3, 15},
+ {(Function<byte[], Exception>) this::parseWithDOM,
+ invalidByteInXmlElement(), 3, 15},
+ // Tests for invalid UTF-8 byte in xml attribute
+ {(Function<byte[], Exception>) this::parseWithSAX,
+ invalidByteInXmlAttribute(), 4, 21},
+ {(Function<byte[], Exception>) this::parseWithDOM,
+ invalidByteInXmlAttribute(), 4, 21},
+ // Tests for invalid UTF-8 byte in xml version string
+ {(Function<byte[], Exception>) this::parseWithSAX,
+ invalidByteInXmlVersionDecl(), 1, 16},
+ {(Function<byte[], Exception>) this::parseWithDOM,
+ invalidByteInXmlVersionDecl(), 1, 16},
+ // Tests for invalid byte in XML file included
+ // into parsed XML file with xi:include element
+ {(Function<byte[], Exception>) this::parseSaxAndXinclude,
+ XINCLUDE_TEST_XML.getBytes(), 5, 53},
+ {(Function<byte[], Exception>) this::parseDomAndXinclude,
+ XINCLUDE_TEST_XML.getBytes(), 5, 53},
+ };
+ }
+
+ // Parse constructed XML with SAXParser and save the observed exception
+ private Exception parseWithSAX(byte[] data) {
+ Exception caughtEx = null;
+ try {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ InputStream inputStream = new ByteArrayInputStream(data);
+ saxParser.parse(inputStream, new DefaultHandler());
+ } catch (Exception e) {
+ caughtEx = e;
+ }
+ return caughtEx;
+ }
+
+ // Parse constructed XML with DOMParser and save the observed exception
+ private Exception parseWithDOM(byte[] data) {
+ Exception caughtEx = null;
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ InputStream inputStream = new ByteArrayInputStream(data);
+ db.parse(inputStream);
+ } catch (Exception e) {
+ caughtEx = e;
+ }
+ return caughtEx;
+ }
+
+ // Parse XML content that includes faulty XML content with xi:include element.
+ // XML data is parsed by SAX parser
+ private Exception parseSaxAndXinclude(byte[] data) {
+ Exception caughtEx = null;
+ try {
+ // Create SAX parser factory and make it xi:include aware
+ SAXParserFactory spf = SAXParserFactory.newDefaultInstance();
+ spf.setNamespaceAware(true);
+ spf.setXIncludeAware(true);
+ // Set this test class as entity resolver
+ XMLReader reader = spf.newSAXParser().getXMLReader();
+ reader.setEntityResolver(this);
+ // Parse XML
+ InputStream inputStream = new ByteArrayInputStream(data);
+ reader.parse(new InputSource(inputStream));
+ } catch (Exception e) {
+ caughtEx = e;
+ }
+ return caughtEx;
+ }
+
+ // Parse XML content that includes faulty XML content with xi:include element.
+ // XML data is parsed by DOM parser
+ private Exception parseDomAndXinclude(byte[] data) {
+ Exception caughtEx = null;
+ try {
+ // Create DOM builder factory and make it xi:include aware
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ dbf.setXIncludeAware(true);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ // Set this test class as entity resolver
+ db.setEntityResolver(this);
+ InputStream inputStream = new ByteArrayInputStream(data);
+ // Parse XML
+ db.parse(inputStream);
+ } catch (Exception e) {
+ caughtEx = e;
+ }
+ return caughtEx;
+ }
+
+ // EntityResolver method to intercept load of test XML file content and
+ // redirect it to ByteArrayInputStream
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException {
+ if (systemId != null && systemId.endsWith(XINCLUDE_TEST_FN)) {
+ return new InputSource(
+ new ByteArrayInputStream(
+ generateXmlBytes("Wrong byte is ", "here", 0xFE)
+ )
+ );
+ }
+ return null;
+ }
+
+ // Construct XML content with invalid byte in xml element
+ private static byte[] invalidByteInXmlElement() {
+ final String prefix = "<?xml version=\"1.0\"?>\n<test>\n<bad-encoding>";
+ final String postfix = "</bad-encoding></test>";
+ return generateXmlBytes(prefix, postfix, 0xFA);
+ }
+
+ // Construct XML content with invalid byte in xml version declaration
+ private static byte[] invalidByteInXmlVersionDecl() {
+ final String prefix = "<?xml version=\"";
+ final String postfix = "1.0\"?><test><bad-encoding></bad-encoding></test>";
+ return generateXmlBytes(prefix, postfix, 0xFB);
+ }
+
+ // Construct XML content with invalid byte in xml attribute
+ private static byte[] invalidByteInXmlAttribute() {
+ final String prefix = "<?xml version=\"1.0\"?>\n<test>\n\n<bad-att attribute=\"";
+ final String postfix = "\"></bad-att></test>";
+ return generateXmlBytes(prefix, postfix, 0xFC);
+ }
+
+ // Test helper function to generate XML text with invalid UTF-8 byte inside
+ private static byte[] generateXmlBytes(String prefix, String postfix, int b) {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(prefix.getBytes());
+ baos.write(b);
+ baos.write(postfix.getBytes());
+ return baos.toByteArray();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ // XML file name to be included with xi:include directive
+ private final static String XINCLUDE_TEST_FN = "xincludeTestFile.xml";
+
+ // xi:include test XML file that includes xml content with invalid byte
+ private final static String XINCLUDE_TEST_XML =
+ "<?xml version=\"1.0\"?>\n" +
+ "<!DOCTYPE testXInclude [\n" +
+ "<!ENTITY xincludeTestFile \""+XINCLUDE_TEST_FN+"\">]>\n" +
+ "<testXInclude xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n" +
+ "<xi:include href=\"&xincludeTestFile;\" parse=\"text\"/>\n" +
+ "</testXInclude>";
+}