From: <bo...@us...> - 2007-03-28 16:19:24
|
Revision: 161 http://xmlunit.svn.sourceforge.net/xmlunit/?rev=161&view=rev Author: bodewig Date: 2007-03-28 09:19:23 -0700 (Wed, 28 Mar 2007) Log Message: ----------- I know this fails for some documents with DOCTYPEs, commit it now anyway: refactor Validator support for InputStreams Modified Paths: -------------- trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeReader.java trunk/xmlunit/src/java/org/custommonkey/xmlunit/Validator.java Added Paths: ----------- trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeConstants.java trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeInputStream.java trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeSupport.java trunk/xmlunit/tests/java/org/custommonkey/xmlunit/test_DoctypeInputStream.java Added: trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeConstants.java =================================================================== --- trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeConstants.java (rev 0) +++ trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeConstants.java 2007-03-28 16:19:23 UTC (rev 161) @@ -0,0 +1,45 @@ +/* +****************************************************************** +Copyright (c) 2001, Jeff Martin, Tim Bacon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the xmlunit.sourceforge.net nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +****************************************************************** +*/ + +package org.custommonkey.xmlunit; + +interface DoctypeConstants { + String DOCTYPE_OPEN_DECL = "<!"; + int DECL_LENGTH = DOCTYPE_OPEN_DECL.length(); + String DOCTYPE_CLOSE_DECL = ">"; + String DOCTYPE = "DOCTYPE "; + String SYSTEM = " SYSTEM \""; +} \ No newline at end of file Property changes on: trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeConstants.java ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Added: trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeInputStream.java =================================================================== --- trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeInputStream.java (rev 0) +++ trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeInputStream.java 2007-03-28 16:19:23 UTC (rev 161) @@ -0,0 +1,216 @@ +/* +****************************************************************** +Copyright (c) 2001, Jeff Martin, Tim Bacon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the xmlunit.sourceforge.net nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +****************************************************************** +*/ + +package org.custommonkey.xmlunit; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * Adapts the marked-up content in a source InputStream to specify that it + * conforms to a different DTD. + * Combines InputStream semantics with the ability to specify a target doctype + * for a byte stream containing XML markup. + * Used by Validator class to wrap an InputStrea, when performing validation of a + * document against a DTD. + * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a> + */ +public class DoctypeInputStream extends InputStream { + private final InputStream wrappedStream; + + private static final byte[] DOCTYPE_BYTES = { + 'D', 'O', 'C', 'T', 'Y', 'P', 'E', ' ' + }; + + private byte[] readAheadBeforeDeclBuffer = null; + private int readAheadBeforeDeclOffset = 0; + private byte[] readAheadAfterDeclBuffer = null; + private int readAheadAfterDeclOffset = 0; + + private final DoctypeSupport docType; + private boolean writeDecl = false; + + + /** + * Create an InputStream whose XML content is provided by the + * originalSource with the exception of the DOCTYPE which is + * provided by the doctypeName and systemID. + * @param originalSource + * @param doctypeName + * @param systemID + */ + public DoctypeInputStream(InputStream originalSource, String doctypeName, + String systemID) { + wrappedStream = originalSource instanceof BufferedInputStream + ? originalSource : new BufferedInputStream(originalSource); + docType = new DoctypeSupport(doctypeName, systemID); + } + + /** + * Read DOCTYPE-replaced content from the wrapped Reader + */ + public int read() throws IOException { + int nextByte = -1; + + if (writeDecl) { + // currently writing our own DOCTYPE declaration + nextByte = docType.read(); + if (nextByte == -1) { + writeDecl = false; + } else { + return nextByte; + } + } + + if (readAheadBeforeDeclBuffer != null) { + // in part of original document before our DOCTYPE - this + // has already been read + nextByte = readAheadBeforeDeclBuffer[readAheadBeforeDeclOffset++]; + if (readAheadBeforeDeclOffset >= readAheadBeforeDeclBuffer.length) { + readAheadBeforeDeclBuffer = null; + writeDecl = true; + } + } else if (!docType.hasBeenRead()) { + // DOCTYPE not written, yet, need to see where it should go + + // read ahead until we find a good place to insert the doctype, + // store bytes in readAheadBuffers + ByteArrayOutputStream beforeDecl = new ByteArrayOutputStream(); + ByteArrayOutputStream afterDecl = new ByteArrayOutputStream(); + int current; + boolean ready = false; + while (!ready && (current = wrappedStream.read()) != -1) { + byte c = (byte) current; + if (c >= 0 && Character.isWhitespace((char) c)) { + beforeDecl.write(c); + } else if (c == '<') { + // could be XML declaration, comment, PI, DOCTYPE + // or the first element + byte[] elementOrDeclOr = readUntilCloseCharacterIsReached(); + if (elementOrDeclOr.length > 0) { + if (elementOrDeclOr[0] == '?') { + // XML declaration or PI + beforeDecl.write('<'); + beforeDecl.write(elementOrDeclOr, 0, + elementOrDeclOr.length); + } else if (elementOrDeclOr[0] != '!') { + // first element + afterDecl.write('<'); + afterDecl.write(elementOrDeclOr, 0, + elementOrDeclOr.length); + ready = true; + } else { + // comment or doctype + if (indexOfDoctype(elementOrDeclOr) == -1) { + afterDecl.write('<'); + afterDecl.write(elementOrDeclOr, 0, + elementOrDeclOr.length); + } // else swallow old declaration + ready = true; + } + } + + } else { + afterDecl.write(c); + ready = true; + } + } + readAheadBeforeDeclBuffer = beforeDecl.size() > 0 + ? beforeDecl.toByteArray() : null; + readAheadAfterDeclBuffer = afterDecl.size() > 0 + ? afterDecl.toByteArray() : null; + writeDecl = (readAheadBeforeDeclBuffer == null); + return read(); + } else if (readAheadAfterDeclBuffer != null) { + // in part of original document read ahead after our DOCTYPE + nextByte = readAheadAfterDeclBuffer[readAheadAfterDeclOffset++]; + if (readAheadAfterDeclOffset >= readAheadAfterDeclBuffer.length) { + readAheadAfterDeclBuffer = null; + } + } else { + nextByte = wrappedStream.read(); + } + return nextByte; + } + + private byte[] readUntilCloseCharacterIsReached() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int byteRead = -1; + int openCount = 1; + while (openCount > 0 && (byteRead = wrappedStream.read()) != -1) { + byte c = (byte) byteRead; + baos.write(c); + if (c == '<') { + openCount++; + } + if (c == '>') { + openCount--; + } + } + return baos.toByteArray(); + } + + public void close() throws IOException { + wrappedStream.close(); + } + + /** + * Could be faster when searching from the other end, but should do. + */ + private static int indexOfDoctype(byte[] b) { + int index = -1; + for (int i = 0; i < b.length - DOCTYPE_BYTES.length + 1; i++) { + if (b[i] == DOCTYPE_BYTES[0]) { + boolean found = false; + int j = 1; + for (; !found && j < DOCTYPE_BYTES.length; j++) { + if (b[i + j] != DOCTYPE_BYTES[j]) { + found = true; + } + } + if (found) { + index = i; + break; + } else { + i += j - 1; + } + } + } + return index; + } +} \ No newline at end of file Property changes on: trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeInputStream.java ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Modified: trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeReader.java =================================================================== --- trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeReader.java 2007-03-28 04:10:28 UTC (rev 160) +++ trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeReader.java 2007-03-28 16:19:23 UTC (rev 161) @@ -38,10 +38,7 @@ import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; -import java.io.StringReader; /** * Adapts the marked-up content in a source Reader to specify that it @@ -52,19 +49,19 @@ * document against a DTD. * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a> */ -public class DoctypeReader extends Reader { - private static final String DOCTYPE_OPEN_DECL = "<!"; - private static final int DECL_LENGTH = DOCTYPE_OPEN_DECL.length(); - private static final String DOCTYPE_CLOSE_DECL = ">"; - private static final String DOCTYPE = "DOCTYPE "; - private static final String SYSTEM = " SYSTEM \""; - private final Reader originalSource; +public class DoctypeReader extends Reader implements DoctypeConstants { + + private final Reader originalReader; private final StringBuffer sourceBuffer = new StringBuffer(1024); - private final String doctypeName; - private final String systemId; - private Reader replacementReader; + private char[] readAheadBeforeDeclBuffer = null; + private int readAheadBeforeDeclOffset = 0; + private char[] readAheadAfterDeclBuffer = null; + private int readAheadAfterDeclOffset = 0; + private final DoctypeSupport docType; + private boolean writeDecl = false; + /** * Create a Reader whose XML content is provided by the originalSource with * the exception of the DOCTYPE which is provided by the doctypeName @@ -75,44 +72,20 @@ */ public DoctypeReader(Reader originalSource, String doctypeName, String systemID) { - this.originalSource = originalSource; - this.doctypeName = doctypeName; - this.systemId = systemID; + originalReader = originalSource instanceof BufferedReader + ? originalSource : new BufferedReader(originalSource); + docType = new DoctypeSupport(doctypeName, systemID); } /** - * Create a Reader whose XML content is provided by the originalSource with - * the exception of the DOCTYPE which is provided by the doctypeName - * and systemID. - * @param originalSource - * @param doctypeName - * @param systemID - */ - public DoctypeReader(InputStream originalSource, String encoding, - String doctypeName, String systemID) - throws IOException { - this(encoding != null - ? new InputStreamReader(originalSource, encoding) - : xmlStreamToReader(originalSource), - doctypeName, systemID); - } - - // XXX - we are cheating here, we should read into the source - // stream to see whether the XML decl (if any) specifies the - // encoding and then return an InputStreamReader using the proper - // encoding - private static Reader xmlStreamToReader(InputStream originalSource) - throws IOException { - return new InputStreamReader(originalSource); - } - - /** * @return the content of the original source, without amendments or * substitutions. Safe to call multiple times. * @throws IOException if thrown while reading from the original source + * @deprecated this method is only here for BWC, it is no longer + * used by this class */ protected String getContent() throws IOException { - return getContent(originalSource).toString(); + return obsoleteGetContent(originalReader).toString(); } /** @@ -120,7 +93,8 @@ * @return the contents of the originalSource within a StringBuffer * @throws IOException if thrown while reading from the original source */ - private StringBuffer getContent(Reader originalSource) throws IOException { + private StringBuffer obsoleteGetContent(Reader originalSource) + throws IOException { if (sourceBuffer.length() == 0) { BufferedReader bufferedReader; if (originalSource instanceof BufferedReader) { @@ -152,7 +126,7 @@ * @param withinContent * @return */ - private int findStartDoctype(StringBuffer withinContent) { + private int obsoleteFindStartDoctype(StringBuffer withinContent) { int startAt = -1; char curChar; boolean canInsert = true; @@ -183,6 +157,8 @@ * @param doctypeName * @param systemId * @return the content, after DOCTYPE amendment / addition + * @deprecated this method is only here for BWC, it is no longer + * used by this class */ public String replaceDoctype(StringBuffer withinContent, String doctypeName, String systemId) { @@ -190,7 +166,7 @@ int startDoctype = content.indexOf(DOCTYPE); boolean noCurrentDoctype = false; if (startDoctype == -1) { - startDoctype = findStartDoctype(withinContent); + startDoctype = obsoleteFindStartDoctype(withinContent); noCurrentDoctype = true; } @@ -227,18 +203,6 @@ } /** - * Wrap the DOCTYPE-replaced content in a StringReader - * @return a StringReader from which the DOCTYPE-replaced content can be read - * @throws IOException - */ - private Reader getReplacementReader() throws IOException { - StringBuffer originalContent = getContent(originalSource); - String replacedContent = replaceDoctype(originalContent, - doctypeName, systemId); - return new StringReader(replacedContent); - } - - /** * Read DOCTYPE-replaced content from the wrapped Reader * @param cbuf * @param off @@ -248,17 +212,115 @@ * @throws IOException */ public int read(char cbuf[], int off, int len) throws IOException { - if (replacementReader == null) { - replacementReader = getReplacementReader(); + int startPos = off; + int currentlyRead; + while (off - startPos < len && (currentlyRead = read()) != -1) { + cbuf[off++] = (char) currentlyRead; } - return replacementReader.read(cbuf, off, len); + return off == startPos && len != 0 ? -1 : off - startPos; } /** - * Close the wrapped Reader - * @throws IOException + * Read DOCTYPE-replaced content from the wrapped Reader */ + public int read() throws IOException { + int nextChar = -1; + + if (writeDecl) { + // currently writing our own DOCTYPE declaration + nextChar = docType.read(); + if (nextChar == -1) { + writeDecl = false; + } else { + return nextChar; + } + } + + if (readAheadBeforeDeclBuffer != null) { + // in part of original document before our DOCTYPE - this + // has already been read + nextChar = readAheadBeforeDeclBuffer[readAheadBeforeDeclOffset++]; + if (readAheadBeforeDeclOffset >= readAheadBeforeDeclBuffer.length) { + readAheadBeforeDeclBuffer = null; + writeDecl = true; + } + } else if (!docType.hasBeenRead()) { + // DOCTYPE not written, yet, need to see where it should go + + // read ahead until we find a good place to insert the doctype, + // store characters in readAheadBuffers + StringBuffer beforeDecl = new StringBuffer(); + StringBuffer afterDecl = new StringBuffer(); + int current; + boolean ready = false; + while (!ready && (current = originalReader.read()) != -1) { + char c = (char) current; + if (Character.isWhitespace(c)) { + beforeDecl.append(c); + } else if (c == '<') { + // could be XML declaration, comment, PI, DOCTYPE + // or the first element + String elementOrDeclOr = readUntilCloseCharacterIsReached(); + if (elementOrDeclOr.length() > 0) { + if (elementOrDeclOr.charAt(0) == '?') { + // XML declaration or PI + beforeDecl.append('<').append(elementOrDeclOr); + } else if (elementOrDeclOr.charAt(0) != '!') { + // first element + afterDecl.append('<').append(elementOrDeclOr); + ready = true; + } else { + // comment or doctype + if (elementOrDeclOr.indexOf(DOCTYPE) == -1) { + afterDecl.append('<').append(elementOrDeclOr); + } // else swallow old declaration + ready = true; + } + } + + } else { + afterDecl.append(c); + ready = true; + } + } + readAheadBeforeDeclBuffer = beforeDecl.length() > 0 + ? beforeDecl.toString().toCharArray() + : null; + readAheadAfterDeclBuffer = afterDecl.length() > 0 + ? afterDecl.toString().toCharArray() + : null; + writeDecl = (readAheadBeforeDeclBuffer == null); + return read(); + } else if (readAheadAfterDeclBuffer != null) { + // in part of original document read ahead after our DOCTYPE + nextChar = readAheadAfterDeclBuffer[readAheadAfterDeclOffset++]; + if (readAheadAfterDeclOffset >= readAheadAfterDeclBuffer.length) { + readAheadAfterDeclBuffer = null; + } + } else { + nextChar = originalReader.read(); + } + return nextChar; + } + + private String readUntilCloseCharacterIsReached() throws IOException { + StringBuffer sb = new StringBuffer(); + int characterRead = -1; + int openCount = 1; + while (openCount > 0 && (characterRead = originalReader.read()) != -1) { + char c = (char) characterRead; + sb.append(c); + if (c == '<') { + openCount++; + } + if (c == '>') { + openCount--; + } + } + return sb.toString(); + } + public void close() throws IOException { - replacementReader.close(); + originalReader.close(); } } Added: trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeSupport.java =================================================================== --- trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeSupport.java (rev 0) +++ trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeSupport.java 2007-03-28 16:19:23 UTC (rev 161) @@ -0,0 +1,74 @@ +/* +****************************************************************** +Copyright (c) 2001, Jeff Martin, Tim Bacon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the xmlunit.sourceforge.net nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +****************************************************************** +*/ + +package org.custommonkey.xmlunit; + +/** + * Contains some common code for DoctypeReader and DoctypeInputStream. + * + * <p>When used with DoctypeInputStream it assumes that the whole + * DOCTYPE declaration consists of US-ASCII characters.</p> + */ +final class DoctypeSupport implements DoctypeConstants { + + private final String decl; + private int offset = 0; + + /** + * Encapsulates a DOCTYPE declaration for the given name and system id. + */ + DoctypeSupport(String name, String systemId) { + StringBuffer sb = new StringBuffer(DOCTYPE_OPEN_DECL); + sb.append(DOCTYPE).append(name).append(SYSTEM) + .append(systemId).append("\"").append(DOCTYPE_CLOSE_DECL); + decl = sb.toString(); + } + + /** + * Whether anybody has started to read the declaration. + */ + boolean hasBeenRead() { + return offset != 0; + } + + /** + * Reads the next character from the declaration. + * @return -1 if the end of the declaration has been reached. + */ + int read() { + return offset >= decl.length() ? -1 : decl.charAt(offset++); + } +} \ No newline at end of file Property changes on: trunk/xmlunit/src/java/org/custommonkey/xmlunit/DoctypeSupport.java ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Modified: trunk/xmlunit/src/java/org/custommonkey/xmlunit/Validator.java =================================================================== --- trunk/xmlunit/src/java/org/custommonkey/xmlunit/Validator.java 2007-03-28 04:10:28 UTC (rev 160) +++ trunk/xmlunit/src/java/org/custommonkey/xmlunit/Validator.java 2007-03-28 16:19:23 UTC (rev 161) @@ -251,14 +251,15 @@ */ public Validator(InputSource sourceForValidation, String systemID, String doctype) - throws SAXException, IOException, ConfigurationException { + throws SAXException, ConfigurationException { this(sourceForValidation.getCharacterStream() != null - ? new DoctypeReader(sourceForValidation.getCharacterStream(), - doctype, systemID) - : new DoctypeReader(sourceForValidation.getByteStream(), - sourceForValidation.getEncoding(), - doctype, systemID), - systemID); + ? new InputSource(new DoctypeReader(sourceForValidation + .getCharacterStream(), + doctype, systemID)) + : new InputSource(new DoctypeInputStream(sourceForValidation + .getByteStream(), + doctype, systemID)), + systemID, true); } /** @@ -380,8 +381,8 @@ isValid = Boolean.TRUE; } else if (usingDoctypeReader) { try { - messages.append("\nContent was: ").append(((DoctypeReader) - validationInputSource.getCharacterStream()).getContent()); + messages.append("\nContent was: ") + .append(readFully(validationInputSource)); } catch (IOException e) { // silent but deadly? } @@ -490,4 +491,31 @@ parser.setProperty(JAXPConstants.Properties.SCHEMA_SOURCE, schemaSource); } + + private static String readFully(InputSource s) throws IOException { + return s.getCharacterStream() != null + ? readFully(s.getCharacterStream()) : readFully(s.getByteStream()); + } + + private static String readFully(Reader r) throws IOException { + StringBuffer sb = new StringBuffer(); + char[] buffer = new char[4096]; + int charsRead = -1; + while ((charsRead = r.read(buffer)) > -1) { + sb.append(buffer, 0, charsRead); + } + return sb.toString(); + } + + private static String readFully(java.io.InputStream is) throws IOException { + java.io.ByteArrayOutputStream baos = + new java.io.ByteArrayOutputStream(); + byte[] buffer = new byte[8192]; + int bytesRead = -1; + while ((bytesRead = is.read(buffer)) > -1) { + baos.write(buffer, 0, bytesRead); + } + return new String(baos.toByteArray()); + } + } Added: trunk/xmlunit/tests/java/org/custommonkey/xmlunit/test_DoctypeInputStream.java =================================================================== --- trunk/xmlunit/tests/java/org/custommonkey/xmlunit/test_DoctypeInputStream.java (rev 0) +++ trunk/xmlunit/tests/java/org/custommonkey/xmlunit/test_DoctypeInputStream.java 2007-03-28 16:19:23 UTC (rev 161) @@ -0,0 +1,142 @@ +/* +****************************************************************** +Copyright (c) 200, Jeff Martin, Tim Bacon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the xmlunit.sourceforge.net nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +****************************************************************** +*/ + +package org.custommonkey.xmlunit; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * JUnit test for DoctypeInputStream + */ +public class test_DoctypeInputStream extends TestCase { + + private static final String NEWLINE = System.getProperty("line.separator"); + private static final String NO_DTD = "<document><element>one</element></document>"; + private File testFile; + + public void tearDown() { + if (testFile != null) { + testFile.delete(); + } + } + + private FileInputStream testDocument(String content) + throws IOException { + testFile = File.createTempFile("xmlunit_", ".xml"); + FileOutputStream fos = new FileOutputStream(testFile); + OutputStreamWriter w = new OutputStreamWriter(fos, "ISO-8859-1"); + w.write(content); + w.close(); + + return new FileInputStream(testFile); + } + + private static String readFully(DoctypeInputStream dis) + throws IOException { + StringBuffer buf = new StringBuffer(); + char[] ch = new char[1024]; + int numChars; + InputStreamReader reader = + new InputStreamReader(dis, "ISO-8859-1"); + while ((numChars = reader.read(ch))!=-1) { + buf.append(ch, 0, numChars); + } + return buf.toString(); + } + + private void assertEquals(String expected, String input, String docType, + String systemId) throws IOException { + FileInputStream fis = null; + try { + fis = testDocument(input); + DoctypeInputStream doctypeInputStream = + new DoctypeInputStream(fis, docType, systemId); + + assertEquals(expected, readFully(doctypeInputStream)); + } finally { + if (fis != null) { + fis.close(); + } + } + } + + public void testRead() throws IOException { + String oz = "Chirurgische Verbesserungen sind g\u00fcnstig"; + assertEquals("<!DOCTYPE Kylie SYSTEM \"bumJob\">" + oz, + oz, "Kylie", "bumJob"); + } + + public void testReplaceDoctypeInternalDTD() throws IOException { + assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">", + test_Constants.CHUCK_JONES_RIP_DTD_DECL, "ni", + "shrubbery"); + } + + public void XtestReplaceDoctypeExternalDTD() throws IOException { + assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">", + "<! DOCTYPE PUBLIC \"yak\" SYSTEM \"llama\">", "ni", + "shrubbery"); + } + + public void testReplaceDoctypeNoDTD() throws IOException { + assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">" + NO_DTD, + NO_DTD, "ni", "shrubbery"); + } + + public void testReplaceDoctypeNoDTDButXMLDecl() throws IOException { + assertEquals(test_Constants.XML_DECLARATION + + "<!DOCTYPE ni SYSTEM \"shrubbery\">" + NO_DTD, + test_Constants.XML_DECLARATION + NO_DTD, + "ni", "shrubbery"); + } + + public test_DoctypeInputStream(String name) { + super(name); + } + + public static TestSuite suite() { + return new TestSuite(test_DoctypeInputStream.class); + } +} + Property changes on: trunk/xmlunit/tests/java/org/custommonkey/xmlunit/test_DoctypeInputStream.java ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |