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; 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.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.AugmentationsImpl; import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl; 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.XMLBufferListener;
import com.sun.xml.internal.stream.XMLEntityStorage; import com.sun.xml.internal.stream.XMLEntityStorage;
import com.sun.xml.internal.stream.dtd.DTDGrammarUtil; import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
import java.io.CharConversionException;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import javax.xml.XMLConstants; import javax.xml.XMLConstants;
@ -3075,6 +3077,20 @@ public class XMLDocumentFragmentScannerImpl
}//switch }//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 // premature end of file
catch (EOFException e) { catch (EOFException e) {
endOfFileHook(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; 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.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.impl.validation.ValidationManager;
import com.sun.org.apache.xerces.internal.util.NamespaceSupport; import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
import com.sun.org.apache.xerces.internal.util.XMLChar; 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.Entity;
import com.sun.xml.internal.stream.StaxXMLInputSource; import com.sun.xml.internal.stream.StaxXMLInputSource;
import com.sun.xml.internal.stream.dtd.DTDGrammarUtil; import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
import java.io.CharConversionException;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
@ -758,7 +761,19 @@ public class XMLDocumentScannerImpl
return XMLEvent.START_DOCUMENT; 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 // premature end of file
catch (EOFException e) { catch (EOFException e) {
reportFatalError("PrematureEOF", null); 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 // premature end of file
catch (EOFException e) { catch (EOFException e) {
reportFatalError("PrematureEOF", null); reportFatalError("PrematureEOF", null);
@ -1152,7 +1180,19 @@ public class XMLDocumentScannerImpl
} }
} while (complete || again); } 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 // premature end of file
catch (EOFException e) { catch (EOFException e) {
e.printStackTrace(); e.printStackTrace();
@ -1416,7 +1456,18 @@ public class XMLDocumentScannerImpl
} }
default: throw new XNIException("Scanner State " + fScannerState + " not Recognized "); default: throw new XNIException("Scanner State " + fScannerState + " not Recognized ");
}//switch }//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) { } catch (EOFException e) {
// NOTE: This is the only place we're allowed to reach // NOTE: This is the only place we're allowed to reach
// the real end of the document stream. Unless the // 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 * Licensed to the Apache Software Foundation (ASF) under one or more
@ -20,9 +20,11 @@
package com.sun.org.apache.xerces.internal.impl; package com.sun.org.apache.xerces.internal.impl;
import java.io.CharConversionException;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; 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.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.SymbolTable; import com.sun.org.apache.xerces.internal.util.SymbolTable;
import com.sun.org.apache.xerces.internal.xni.XMLString; import com.sun.org.apache.xerces.internal.xni.XMLString;
@ -196,7 +198,21 @@ public class XMLVersionDetector {
return Constants.XML_VERSION_1_0; return Constants.XML_VERSION_1_0;
// premature end of file // 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( fErrorReporter.reportError(
XMLMessageFormatter.XML_DOMAIN, XMLMessageFormatter.XML_DOMAIN,
"PrematureEOF", "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 * 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.AttributePSVI;
import com.sun.org.apache.xerces.internal.xs.ElementPSVI; import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
import com.sun.org.apache.xerces.internal.xs.PSVIProvider; import com.sun.org.apache.xerces.internal.xs.PSVIProvider;
import java.io.CharConversionException;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
import javax.xml.XMLConstants; import javax.xml.XMLConstants;
@ -1143,7 +1144,7 @@ public abstract class AbstractSAXParser
// wrap XNI exceptions as SAX exceptions // wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) { catch (XMLParseException e) {
Exception ex = e.getException(); 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 // must be a parser exception; mine it for locator info and throw
// a SAXParseException // a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl(){ LocatorImpl locatorImpl = new LocatorImpl(){
@ -1163,7 +1164,9 @@ public abstract class AbstractSAXParser
locatorImpl.setSystemId(e.getExpandedSystemId()); locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber()); locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber()); 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) { if (ex instanceof SAXException) {
// why did we create an XMLParseException? // why did we create an XMLParseException?
@ -1216,7 +1219,7 @@ public abstract class AbstractSAXParser
// wrap XNI exceptions as SAX exceptions // wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) { catch (XMLParseException e) {
Exception ex = e.getException(); 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 // must be a parser exception; mine it for locator info and throw
// a SAXParseException // a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl() { LocatorImpl locatorImpl = new LocatorImpl() {
@ -1236,7 +1239,9 @@ public abstract class AbstractSAXParser
locatorImpl.setSystemId(e.getExpandedSystemId()); locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber()); locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber()); 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) { if (ex instanceof SAXException) {
// why did we create an XMLParseException? // 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.XMLInputSource;
import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException; import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
import java.io.CharConversionException;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.xml.sax.EntityResolver; import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler; import org.xml.sax.ErrorHandler;
@ -184,7 +185,7 @@ public class DOMParser
// wrap XNI exceptions as SAX exceptions // wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) { catch (XMLParseException e) {
Exception ex = e.getException(); 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 // must be a parser exception; mine it for locator info and throw
// a SAXParseException // a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl(); LocatorImpl locatorImpl = new LocatorImpl();
@ -192,7 +193,9 @@ public class DOMParser
locatorImpl.setSystemId(e.getExpandedSystemId()); locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber()); locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber()); 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) { if (ex instanceof SAXException) {
// why did we create an XMLParseException? // why did we create an XMLParseException?
@ -246,7 +249,7 @@ public class DOMParser
// wrap XNI exceptions as SAX exceptions // wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) { catch (XMLParseException e) {
Exception ex = e.getException(); 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 // must be a parser exception; mine it for locator info and throw
// a SAXParseException // a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl(); LocatorImpl locatorImpl = new LocatorImpl();
@ -254,7 +257,9 @@ public class DOMParser
locatorImpl.setSystemId(e.getExpandedSystemId()); locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber()); locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber()); 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) { if (ex instanceof SAXException) {
// why did we create an XMLParseException? // 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 * 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.URI;
import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; 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.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.XMLResourceIdentifierImpl;
import com.sun.org.apache.xerces.internal.util.XMLSymbols; 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.XMLSecurityManager;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
import com.sun.org.apache.xerces.internal.xni.Augmentations; import com.sun.org.apache.xerces.internal.xni.Augmentations;
@ -157,8 +157,8 @@ public class XIncludeHandler
public final static String CURRENT_BASE_URI = "currentBaseURI"; public final static String CURRENT_BASE_URI = "currentBaseURI";
// used for adding [base URI] attributes // used for adding [base URI] attributes
public final static String XINCLUDE_BASE = "base".intern(); private final static String XINCLUDE_BASE = "base".intern();
public final static QName XML_BASE_QNAME = private final static QName XML_BASE_QNAME =
new QName( new QName(
XMLSymbols.PREFIX_XML, XMLSymbols.PREFIX_XML,
XINCLUDE_BASE, XINCLUDE_BASE,
@ -166,15 +166,15 @@ public class XIncludeHandler
NamespaceContext.XML_URI); NamespaceContext.XML_URI);
// used for adding [language] attributes // used for adding [language] attributes
public final static String XINCLUDE_LANG = "lang".intern(); private final static String XINCLUDE_LANG = "lang".intern();
public final static QName XML_LANG_QNAME = private final static QName XML_LANG_QNAME =
new QName( new QName(
XMLSymbols.PREFIX_XML, XMLSymbols.PREFIX_XML,
XINCLUDE_LANG, XINCLUDE_LANG,
(XMLSymbols.PREFIX_XML + ":" + XINCLUDE_LANG).intern(), (XMLSymbols.PREFIX_XML + ":" + XINCLUDE_LANG).intern(),
NamespaceContext.XML_URI); NamespaceContext.XML_URI);
public final static QName NEW_NS_ATTR_QNAME = private final static QName NEW_NS_ATTR_QNAME =
new QName( new QName(
XMLSymbols.PREFIX_XMLNS, XMLSymbols.PREFIX_XMLNS,
"", "",
@ -217,6 +217,10 @@ public class XIncludeHandler
protected static final String XINCLUDE_FIXUP_LANGUAGE = protected static final String XINCLUDE_FIXUP_LANGUAGE =
Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE; 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. */ /** Property identifier: symbol table. */
protected static final String SYMBOL_TABLE = protected static final String SYMBOL_TABLE =
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
@ -234,7 +238,7 @@ public class XIncludeHandler
Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
/** property identifier: buffer size. */ /** property identifier: buffer size. */
public static final String BUFFER_SIZE = protected static final String BUFFER_SIZE =
Constants.XERCES_PROPERTY_PREFIX + Constants.BUFFER_SIZE_PROPERTY; Constants.XERCES_PROPERTY_PREFIX + Constants.BUFFER_SIZE_PROPERTY;
protected static final String PARSER_SETTINGS = protected static final String PARSER_SETTINGS =
@ -292,6 +296,7 @@ public class XIncludeHandler
protected XPointerProcessor fXPtrProcessor = null; protected XPointerProcessor fXPtrProcessor = null;
protected XMLLocator fDocLocation; protected XMLLocator fDocLocation;
protected XMLLocatorWrapper fXIncludeLocator = new XMLLocatorWrapper();
protected XIncludeMessageFormatter fXIncludeMessageFormatter = new XIncludeMessageFormatter(); protected XIncludeMessageFormatter fXIncludeMessageFormatter = new XIncludeMessageFormatter();
protected XIncludeNamespaceSupport fNamespaceContext; protected XIncludeNamespaceSupport fNamespaceContext;
protected SymbolTable fSymbolTable; protected SymbolTable fSymbolTable;
@ -305,17 +310,19 @@ public class XIncludeHandler
protected XIncludeTextReader fXInclude11TextReader; protected XIncludeTextReader fXInclude11TextReader;
// these are needed for XML Base processing // these are needed for XML Base processing
protected XMLResourceIdentifier fCurrentBaseURI; protected final XMLResourceIdentifier fCurrentBaseURI;
protected IntStack fBaseURIScope; protected final IntStack fBaseURIScope;
protected Stack<String> fBaseURI; protected final Stack<String> fBaseURI;
protected Stack<String> fLiteralSystemID; protected final Stack<String> fLiteralSystemID;
protected Stack<String> fExpandedSystemID; protected final Stack<String> fExpandedSystemID;
// these are needed for Language Fixup // these are needed for Language Fixup
protected IntStack fLanguageScope; protected final IntStack fLanguageScope;
protected Stack<String> fLanguageStack; protected final Stack<String> fLanguageStack;
protected String fCurrentLanguage; protected String fCurrentLanguage;
protected String fHrefFromParent;
// used for passing features on to child XIncludeHandler objects // used for passing features on to child XIncludeHandler objects
protected ParserConfigurationSettings fSettings; protected ParserConfigurationSettings fSettings;
@ -361,6 +368,9 @@ public class XIncludeHandler
// track whether a DTD is being parsed // track whether a DTD is being parsed
private boolean fInDTD; 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 // track whether the root element of the result infoset has been processed
private boolean fSeenRootElement; private boolean fSeenRootElement;
@ -593,15 +603,21 @@ public class XIncludeHandler
copyFeatures(componentManager, fSettings); copyFeatures(componentManager, fSettings);
// We don't want a schema validator on the new pipeline, // We don't want a schema validator on the new pipeline,
// so if it was enabled, we set the feature to false. If // so if it was enabled, we set the feature to false.
// 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.
try { try {
if (componentManager.getFeature(SCHEMA_VALIDATION)) { if (componentManager.getFeature(SCHEMA_VALIDATION)) {
fSettings.setFeature(SCHEMA_VALIDATION, false); 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); fSettings.setFeature(DYNAMIC_VALIDATION, true);
} }
} }
@ -776,7 +792,15 @@ public class XIncludeHandler
@Override @Override
public void setDocumentHandler(XMLDocumentHandler handler) { 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 @Override
@ -806,36 +830,39 @@ public class XIncludeHandler
// otherwise, the locator from the root document would always be used // otherwise, the locator from the root document would always be used
fErrorReporter.setDocumentLocator(locator); fErrorReporter.setDocumentLocator(locator);
if (!isRootDocument()
&& fParentXIncludeHandler.searchForRecursiveIncludes(locator)) {
reportFatalError(
"RecursiveInclude",
new Object[] { locator.getExpandedSystemId()});
}
if (!(namespaceContext instanceof XIncludeNamespaceSupport)) { if (!(namespaceContext instanceof XIncludeNamespaceSupport)) {
reportFatalError("IncompatibleNamespaceContext"); reportFatalError("IncompatibleNamespaceContext");
} }
fNamespaceContext = (XIncludeNamespaceSupport)namespaceContext; fNamespaceContext = (XIncludeNamespaceSupport)namespaceContext;
fDocLocation = locator; fDocLocation = locator;
fXIncludeLocator.setLocator(fDocLocation);
// initialize the current base URI // initialize the current base URI
fCurrentBaseURI.setBaseSystemId(locator.getBaseSystemId()); setupCurrentBaseURI(locator);
fCurrentBaseURI.setExpandedSystemId(locator.getExpandedSystemId());
fCurrentBaseURI.setLiteralSystemId(locator.getLiteralSystemId());
saveBaseURI(); saveBaseURI();
if (augs == null) { if (augs == null) {
augs = new AugmentationsImpl(); augs = new AugmentationsImpl();
} }
augs.putItem(CURRENT_BASE_URI, fCurrentBaseURI); 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 // initialize the current language
fCurrentLanguage = XMLSymbols.EMPTY_STRING; fCurrentLanguage = XMLSymbols.EMPTY_STRING;
saveLanguage(fCurrentLanguage); saveLanguage(fCurrentLanguage);
if (isRootDocument() && fDocumentHandler != null) { if (isRootDocument() && fDocumentHandler != null) {
fDocumentHandler.startDocument( fDocumentHandler.startDocument(
locator, fXIncludeLocator,
encoding, encoding,
namespaceContext, namespaceContext,
augs); augs);
@ -1671,7 +1698,7 @@ public class XIncludeHandler
catch (IOException | CatalogException e) { catch (IOException | CatalogException e) {
reportResourceError( reportResourceError(
"XMLResourceError", "XMLResourceError",
new Object[] { href, e.getMessage()}); new Object[] { href, e.getMessage()}, e);
return false; return false;
} }
} }
@ -1750,6 +1777,8 @@ public class XIncludeHandler
// ??? // ???
newHandler.setParent(this); newHandler.setParent(this);
newHandler.setHref(href);
newHandler.setXIncludeLocator(fXIncludeLocator);
newHandler.setDocumentHandler(this.getDocumentHandler()); newHandler.setDocumentHandler(this.getDocumentHandler());
fXPointerChildConfig = fChildConfig; fXPointerChildConfig = fChildConfig;
} else { } else {
@ -1758,7 +1787,8 @@ public class XIncludeHandler
Constants.XERCES_PROPERTY_PREFIX Constants.XERCES_PROPERTY_PREFIX
+ Constants.XINCLUDE_HANDLER_PROPERTY); + Constants.XINCLUDE_HANDLER_PROPERTY);
newHandler.setParent(this); newHandler.setParent(this);
newHandler.setHref(href);
newHandler.setDocumentHandler(this.getDocumentHandler()); newHandler.setDocumentHandler(this.getDocumentHandler());
fXIncludeChildConfig = fChildConfig; fXIncludeChildConfig = fChildConfig;
} }
@ -1766,7 +1796,7 @@ public class XIncludeHandler
// If an xpointer attribute is present // If an xpointer attribute is present
if (xpointer != null ) { if (xpointer != null ) {
fChildConfig = fXPointerChildConfig ; fChildConfig = fXPointerChildConfig;
// Parse the XPointer expression // Parse the XPointer expression
try { try {
@ -1790,10 +1820,12 @@ public class XIncludeHandler
fNeedCopyFeatures = false; fNeedCopyFeatures = false;
try { try {
fHasIncludeReportedContent = false;
fNamespaceContext.pushScope(); fNamespaceContext.pushScope();
fChildConfig.parse(includedSource); 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) { if (fErrorReporter != null) {
fErrorReporter.setDocumentLocator(fDocLocation); fErrorReporter.setDocumentLocator(fDocLocation);
} }
@ -1811,23 +1843,32 @@ public class XIncludeHandler
} }
} }
catch (XNIException e) { 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) { if (fErrorReporter != null) {
fErrorReporter.setDocumentLocator(fDocLocation); fErrorReporter.setDocumentLocator(fDocLocation);
} }
reportFatalError("XMLParseError", new Object[] { href, e.getMessage() }); reportFatalError("XMLParseError", new Object[] { href, e.getMessage() });
} }
catch (IOException e) { 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) { if (fErrorReporter != null) {
fErrorReporter.setDocumentLocator(fDocLocation); fErrorReporter.setDocumentLocator(fDocLocation);
} }
// An IOException indicates that we had trouble reading the file, not // If the start document event has been seen on the child pipeline it
// that it was an invalid XML file. So we send a resource error, not a // means the resource was successfully opened and we started reporting
// fatal error. // 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( reportResourceError(
"XMLResourceError", "XMLResourceError",
new Object[] { href, e.getMessage()}); new Object[] { href, e.getMessage()}, e);
return false; return false;
} }
finally { finally {
@ -1841,6 +1882,8 @@ public class XIncludeHandler
XIncludeTextReader textReader = null; XIncludeTextReader textReader = null;
try { try {
fHasIncludeReportedContent = false;
// Setup the appropriate text reader. // Setup the appropriate text reader.
if (!fIsXML11) { if (!fIsXML11) {
if (fXInclude10TextReader == null) { if (fXInclude10TextReader == null) {
@ -1866,16 +1909,22 @@ public class XIncludeHandler
// encoding errors // encoding errors
catch (MalformedByteSequenceException ex) { catch (MalformedByteSequenceException ex) {
fErrorReporter.reportError(ex.getDomain(), ex.getKey(), fErrorReporter.reportError(ex.getDomain(), ex.getKey(),
ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR); ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, ex);
} }
catch (CharConversionException e) { catch (CharConversionException e) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR); "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
} }
catch (IOException 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( reportResourceError(
"TextResourceError", "TextResourceError",
new Object[] { href, e.getMessage()}); new Object[] { href, e.getMessage()}, e);
return false; return false;
} }
finally { finally {
@ -1886,7 +1935,7 @@ public class XIncludeHandler
catch (IOException e) { catch (IOException e) {
reportResourceError( reportResourceError(
"TextResourceError", "TextResourceError",
new Object[] { href, e.getMessage()}); new Object[] { href, e.getMessage()}, e);
return false; return false;
} }
} }
@ -1977,37 +2026,51 @@ public class XIncludeHandler
return parentLanguage != null && parentLanguage.equalsIgnoreCase(fCurrentLanguage); return parentLanguage != null && parentLanguage.equalsIgnoreCase(fCurrentLanguage);
} }
/** private void setupCurrentBaseURI(XMLLocator locator) {
* Checks if the file indicated by the given XMLLocator has already been included fCurrentBaseURI.setBaseSystemId(locator.getBaseSystemId());
* in the current stack. if (locator.getLiteralSystemId() != null) {
* @param includedSource the source to check for inclusion fCurrentBaseURI.setLiteralSystemId(locator.getLiteralSystemId());
* @return true if the source has already been included }
*/ else {
protected boolean searchForRecursiveIncludes(XMLLocator includedSource) { fCurrentBaseURI.setLiteralSystemId(fHrefFromParent);
String includedSystemId = includedSource.getExpandedSystemId(); }
if (includedSystemId == null) { String expandedSystemId = locator.getExpandedSystemId();
if (expandedSystemId == null) {
// attempt to expand it ourselves
try { try {
includedSystemId = expandedSystemId =
XMLEntityManager.expandSystemId( XMLEntityManager.expandSystemId(
includedSource.getLiteralSystemId(), fCurrentBaseURI.getLiteralSystemId(),
includedSource.getBaseSystemId(), fCurrentBaseURI.getBaseSystemId(),
false); false);
if (expandedSystemId == null) {
expandedSystemId = fCurrentBaseURI.getLiteralSystemId();
}
} }
catch (MalformedURIException e) { catch (MalformedURIException e) {
reportFatalError("ExpandedSystemId"); 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; return true;
} }
else if (fParentXIncludeHandler == null) {
if (fParentXIncludeHandler == null) {
return false; return false;
} }
return fParentXIncludeHandler.searchForRecursiveIncludes( else {
includedSource); 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 * unparsed entities are processed as described in the spec, sections 4.5.1 and 4.5.2
* </ul> * </ul>
* @param attributes * @param attributes
* @return * @return the processed XMLAttributes
*/ */
protected XMLAttributes processAttributes(XMLAttributes attributes) { protected XMLAttributes processAttributes(XMLAttributes attributes) {
if (isTopLevelIncludedItem()) { if (isTopLevelIncludedItem()) {
@ -2198,7 +2261,7 @@ public class XIncludeHandler
return relativeURI; return relativeURI;
} }
else { else {
if (relativeURI.equals("")) { if (relativeURI.length() == 0) {
relativeURI = fCurrentBaseURI.getLiteralSystemId(); relativeURI = fCurrentBaseURI.getLiteralSystemId();
} }
@ -2207,7 +2270,7 @@ public class XIncludeHandler
fParentRelativeURI = fParentRelativeURI =
fParentXIncludeHandler.getRelativeBaseURI(); fParentXIncludeHandler.getRelativeBaseURI();
} }
if (fParentRelativeURI.equals("")) { if (fParentRelativeURI.length() == 0) {
return relativeURI; return relativeURI;
} }
@ -2420,7 +2483,7 @@ public class XIncludeHandler
* as an ancestor of the current item. * as an ancestor of the current item.
* *
* @param depth * @param depth
* @return * @return true if an include was seen at the given depth, false otherwise
*/ */
protected boolean getSawInclude(int depth) { protected boolean getSawInclude(int depth) {
if (depth >= fSawInclude.length) { if (depth >= fSawInclude.length) {
@ -2430,11 +2493,15 @@ public class XIncludeHandler
} }
protected void reportResourceError(String key) { protected void reportResourceError(String key) {
this.reportFatalError(key, null); this.reportResourceError(key, null);
} }
protected void reportResourceError(String key, Object[] args) { 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) { protected void reportFatalError(String key) {
@ -2442,16 +2509,21 @@ public class XIncludeHandler
} }
protected void reportFatalError(String key, Object[] args) { 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) { if (fErrorReporter != null) {
fErrorReporter.reportError( fErrorReporter.reportError(
XIncludeMessageFormatter.XINCLUDE_DOMAIN, XIncludeMessageFormatter.XINCLUDE_DOMAIN,
key, key,
args, args,
severity); severity,
exception);
} }
// we won't worry about when error reporter is null, since there should always be // we won't worry about when error reporter is null, since there should always be
// at least the default error reporter // at least the default error reporter
@ -2465,6 +2537,14 @@ public class XIncludeHandler
fParentXIncludeHandler = parent; 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 // used to know whether to pass declarations to the document handler
protected boolean isRootDocument() { protected boolean isRootDocument() {
return fParentXIncludeHandler == null; return fParentXIncludeHandler == null;
@ -2849,7 +2929,7 @@ public class XIncludeHandler
/** /**
* Saves the given language on the top of the stack. * 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) { protected void saveLanguage(String language) {
fLanguageScope.push(fDepth); fLanguageScope.push(fDepth);
@ -3013,7 +3093,7 @@ public class XIncludeHandler
// the second hex character if a character needs to be escaped // the second hex character if a character needs to be escaped
private static final char gAfterEscaping2[] = new char[128]; private static final char gAfterEscaping2[] = new char[128];
private static final char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7', 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 // initialize the above 3 arrays
static { static {
char[] escChs = {' ', '<', '>', '"', '{', '}', '|', '\\', '^', '`'}; char[] escChs = {' ', '<', '>', '"', '{', '}', '|', '\\', '^', '`'};
@ -3104,7 +3184,7 @@ public class XIncludeHandler
// for each byte // for each byte
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
b = bytes[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) { if (b < 0) {
ch = b + 256; ch = b + 256;
buffer.append('%'); buffer.append('%');
@ -3123,7 +3203,7 @@ public class XIncludeHandler
} }
// If escaping happened, create a new string; // If escaping happened, create a new string;
// otherwise, return the orginal one. // otherwise, return the original one.
if (buffer.length() != len) { if (buffer.length() != len) {
return buffer.toString(); 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 * 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.XMLEntityManager;
import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 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.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.io.UTF8Reader;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.EncodingMap; import com.sun.org.apache.xerces.internal.util.EncodingMap;
@ -67,7 +69,7 @@ import java.util.Map;
public class XIncludeTextReader { public class XIncludeTextReader {
private Reader fReader; private Reader fReader;
private XIncludeHandler fHandler; private final XIncludeHandler fHandler;
private XMLInputSource fSource; private XMLInputSource fSource;
private XMLErrorReporter fErrorReporter; private XMLErrorReporter fErrorReporter;
private XMLString fTempString = new XMLString(); private XMLString fTempString = new XMLString();
@ -149,12 +151,12 @@ public class XIncludeTextReader {
stream = new BufferedInputStream(urlCon.getInputStream()); stream = new BufferedInputStream(urlCon.getInputStream());
// content type will be string like "text/xml; charset=UTF-8" or "text/xml" // 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 // 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; String charset = null;
if (index != -1) { if (index != -1) {
// this should be something like "text/xml" // this should be something like "text/xml"
@ -181,14 +183,16 @@ public class XIncludeTextReader {
} }
} }
else { else {
contentType = rawContentType.trim(); contentType = (rawContentType != null) ? rawContentType.trim() : "";
} }
String detectedEncoding = null; String detectedEncoding = null;
/** The encoding of such a resource is determined by: /** The encoding of such a resource is determined by:
1 external encoding information, if available, otherwise 1 external encoding information, if available, otherwise
-- the most common type of external information is the "charset" parameter of a MIME package -- 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 3 the value of the encoding attribute if one exists, otherwise
4 UTF-8. 4 UTF-8.
**/ **/
@ -225,15 +229,17 @@ public class XIncludeTextReader {
// eat the Byte Order Mark // eat the Byte Order Mark
encoding = consumeBOM(stream, encoding); encoding = consumeBOM(stream, encoding);
// If the document is UTF-8 or US-ASCII use // If the document is UTF-8, UTF-16, US-ASCII or ISO-8859-1 use
// the Xerces readers for these encodings. For // the Xerces readers for these encodings. For US-ASCII and ISO-8859-1
// US-ASCII consult the encoding map since // consult the encoding map since these encodings have many aliases.
// this encoding has many aliases.
if (encoding.equals("UTF-8")) { if (encoding.equals("UTF-8")) {
return new UTF8Reader(stream, return createUTF8Reader(stream);
fTempString.ch.length, }
fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), else if (encoding.equals("UTF-16BE")) {
fErrorReporter.getLocale() ); return createUTF16Reader(stream, true);
}
else if (encoding.equals("UTF-16LE")) {
return createUTF16Reader(stream, false);
} }
// Try to use a Java reader. // Try to use a Java reader.
@ -251,16 +257,45 @@ public class XIncludeTextReader {
new Object[] {encoding} ) ); new Object[] {encoding} ) );
} }
else if (javaEncoding.equals("ASCII")) { else if (javaEncoding.equals("ASCII")) {
return new ASCIIReader(stream, return createASCIIReader(stream);
fTempString.ch.length, }
fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), else if (javaEncoding.equals("ISO8859_1")) {
fErrorReporter.getLocale() ); return createLatin1Reader(stream);
} }
return new InputStreamReader(stream, javaEncoding); 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 * 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 * 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); fReader = getReader(fSource);
fSource = null; fSource = null;
int readSize = fReader.read(fTempString.ch, 0, fTempString.ch.length - 1); int readSize = fReader.read(fTempString.ch, 0, fTempString.ch.length - 1);
fHandler.fHasIncludeReportedContent = true;
while (readSize != -1) { while (readSize != -1) {
for (int i = 0; i < readSize; ++i) { for (int i = 0; i < readSize; ++i) {
char ch = fTempString.ch[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>";
}