8038043: Xerces Update: XInclude update

Reviewed-by: joehw
This commit is contained in:
Aleksei Efimov 2018-02-27 12:47:58 +00:00
parent 4932677ba4
commit efeaca8cda
11 changed files with 1236 additions and 113 deletions

View File

@ -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.org.apache.xerces.internal.xni.parser.XMLInputSource;
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 @@ public class XMLDocumentFragmentScannerImpl
}//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);

View File

@ -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.org.apache.xerces.internal.xni.parser.XMLInputSource;
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 @@ public class XMLDocumentScannerImpl
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 @@ public class XMLDocumentScannerImpl
*/
}
}
// 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 @@ public class XMLDocumentScannerImpl
}
} 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 @@ public class XMLDocumentScannerImpl
}
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

View File

@ -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 @@ public class XMLVersionDetector {
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",

View File

@ -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

View File

@ -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

View File

@ -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.xni.parser.XMLParserConfiguration;
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 @@ public abstract class AbstractSAXParser
// 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 @@ public abstract class AbstractSAXParser
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 @@ public abstract class AbstractSAXParser
// 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 @@ public abstract class AbstractSAXParser
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?

View File

@ -40,6 +40,7 @@ import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
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 @@ public class DOMParser
// 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 @@ public class DOMParser
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 @@ public class DOMParser
// 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 @@ public class DOMParser
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?

View File

@ -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;
}
}

View File

@ -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.MalformedURIException;
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 class XIncludeHandler
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 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
// 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 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
@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 @@ public class XIncludeHandler
// 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 @@ public class XIncludeHandler
catch (IOException | CatalogException e) {
reportResourceError(
"XMLResourceError",
new Object[] { href, e.getMessage()});
new Object[] { href, e.getMessage()}, e);
return false;
}
}
@ -1750,6 +1777,8 @@ public class XIncludeHandler
// ???
newHandler.setParent(this);
newHandler.setHref(href);
newHandler.setXIncludeLocator(fXIncludeLocator);
newHandler.setDocumentHandler(this.getDocumentHandler());
fXPointerChildConfig = fChildConfig;
} else {
@ -1758,7 +1787,8 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
// If an xpointer attribute is present
if (xpointer != null ) {
fChildConfig = fXPointerChildConfig ;
fChildConfig = fXPointerChildConfig;
// Parse the XPointer expression
try {
@ -1790,10 +1820,12 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
}
}
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 @@ public class XIncludeHandler
XIncludeTextReader textReader = null;
try {
fHasIncludeReportedContent = false;
// Setup the appropriate text reader.
if (!fIsXML11) {
if (fXInclude10TextReader == null) {
@ -1866,16 +1909,22 @@ public class XIncludeHandler
// 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 @@ public class XIncludeHandler
catch (IOException e) {
reportResourceError(
"TextResourceError",
new Object[] { href, e.getMessage()});
new Object[] { href, e.getMessage()}, e);
return false;
}
}
@ -1977,37 +2026,51 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
* 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 @@ public class XIncludeHandler
return relativeURI;
}
else {
if (relativeURI.equals("")) {
if (relativeURI.length() == 0) {
relativeURI = fCurrentBaseURI.getLiteralSystemId();
}
@ -2207,7 +2270,7 @@ public class XIncludeHandler
fParentRelativeURI =
fParentXIncludeHandler.getRelativeBaseURI();
}
if (fParentRelativeURI.equals("")) {
if (fParentRelativeURI.length() == 0) {
return relativeURI;
}
@ -2420,7 +2483,7 @@ public class XIncludeHandler
* 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 @@ public class XIncludeHandler
}
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 @@ public class XIncludeHandler
}
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 @@ public class XIncludeHandler
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 @@ public class XIncludeHandler
/**
* 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 @@ public class XIncludeHandler
// 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 @@ public class XIncludeHandler
// 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 @@ public class XIncludeHandler
}
// If escaping happened, create a new string;
// otherwise, return the orginal one.
// otherwise, return the original one.
if (buffer.length() != len) {
return buffer.toString();
}

View File

@ -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 @@ package com.sun.org.apache.xerces.internal.xinclude;
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 @@ import java.util.Map;
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 @@ public class XIncludeTextReader {
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 @@ public class XIncludeTextReader {
}
}
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 @@ public class XIncludeTextReader {
// 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 @@ public class XIncludeTextReader {
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 @@ public class XIncludeTextReader {
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];

View File

@ -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>";
}