diff --git a/xml/src/processing/xml/CDATAReader.java b/xml/src/processing/xml/CDATAReader.java
new file mode 100644
index 000000000..11b6849a7
--- /dev/null
+++ b/xml/src/processing/xml/CDATAReader.java
@@ -0,0 +1,193 @@
+/* CDATAReader.java NanoXML/Java
+ *
+ * $Revision: 1.3 $
+ * $Date: 2002/01/04 21:03:28 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+import java.io.Reader;
+import java.io.IOException;
+
+
+/**
+ * This reader reads data from another reader until the end of a CDATA section
+ * (]]>) has been encountered.
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
+ */
+class CDATAReader
+ extends Reader
+{
+
+ /**
+ * The encapsulated reader.
+ */
+ private StdXMLReader reader;
+
+
+ /**
+ * Saved char.
+ */
+ private char savedChar;
+
+
+ /**
+ * True if the end of the stream has been reached.
+ */
+ private boolean atEndOfData;
+
+
+ /**
+ * Creates the reader.
+ *
+ * @param reader the encapsulated reader
+ */
+ CDATAReader(StdXMLReader reader)
+ {
+ this.reader = reader;
+ this.savedChar = 0;
+ this.atEndOfData = false;
+ }
+
+
+ /**
+ * Cleans up the object when it's destroyed.
+ */
+ protected void finalize()
+ throws Throwable
+ {
+ this.reader = null;
+ super.finalize();
+ }
+
+
+ /**
+ * Reads a block of data.
+ *
+ * @param buffer where to put the read data
+ * @param offset first position in buffer to put the data
+ * @param size maximum number of chars to read
+ *
+ * @return the number of chars read, or -1 if at EOF
+ *
+ * @throws java.io.IOException
+ * if an error occurred reading the data
+ */
+ public int read(char[] buffer,
+ int offset,
+ int size)
+ throws IOException
+ {
+ int charsRead = 0;
+
+ if (this.atEndOfData) {
+ return -1;
+ }
+
+ if ((offset + size) > buffer.length) {
+ size = buffer.length - offset;
+ }
+
+ while (charsRead < size) {
+ char ch = this.savedChar;
+
+ if (ch == 0) {
+ ch = this.reader.read();
+ } else {
+ this.savedChar = 0;
+ }
+
+ if (ch == ']') {
+ char ch2 = this.reader.read();
+
+ if (ch2 == ']') {
+ char ch3 = this.reader.read();
+
+ if (ch3 == '>') {
+ this.atEndOfData = true;
+ break;
+ }
+
+ this.savedChar = ch2;
+ this.reader.unread(ch3);
+ } else {
+ this.reader.unread(ch2);
+ }
+ }
+ buffer[charsRead] = ch;
+ charsRead++;
+ }
+
+ if (charsRead == 0) {
+ charsRead = -1;
+ }
+
+ return charsRead;
+ }
+
+
+ /**
+ * Skips remaining data and closes the stream.
+ *
+ * @throws java.io.IOException
+ * if an error occurred reading the data
+ */
+ public void close()
+ throws IOException
+ {
+ while (! this.atEndOfData) {
+ char ch = this.savedChar;
+
+ if (ch == 0) {
+ ch = this.reader.read();
+ } else {
+ this.savedChar = 0;
+ }
+
+ if (ch == ']') {
+ char ch2 = this.reader.read();
+
+ if (ch2 == ']') {
+ char ch3 = this.reader.read();
+
+ if (ch3 == '>') {
+ break;
+ }
+
+ this.savedChar = ch2;
+ this.reader.unread(ch3);
+ } else {
+ this.reader.unread(ch2);
+ }
+ }
+ }
+
+ this.atEndOfData = true;
+ }
+
+}
diff --git a/xml/src/processing/xml/ContentReader.java b/xml/src/processing/xml/ContentReader.java
new file mode 100644
index 000000000..66430c06b
--- /dev/null
+++ b/xml/src/processing/xml/ContentReader.java
@@ -0,0 +1,212 @@
+/* ContentReader.java NanoXML/Java
+ *
+ * $Revision: 1.4 $
+ * $Date: 2002/01/04 21:03:28 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+import java.io.Reader;
+import java.io.IOException;
+
+
+/**
+ * This reader reads data from another reader until a new element has
+ * been encountered.
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
+ */
+class ContentReader
+ extends Reader
+{
+
+ /**
+ * The encapsulated reader.
+ */
+ private StdXMLReader reader;
+
+
+ /**
+ * Buffer.
+ */
+ private String buffer;
+
+
+ /**
+ * Pointer into the buffer.
+ */
+ private int bufferIndex;
+
+
+ /**
+ * The entity resolver.
+ */
+ private XMLEntityResolver resolver;
+
+
+ /**
+ * Creates the reader.
+ *
+ * @param reader the encapsulated reader
+ * @param resolver the entity resolver
+ * @param buffer data that has already been read from reader
+ */
+ ContentReader(StdXMLReader reader,
+ XMLEntityResolver resolver,
+ String buffer)
+ {
+ this.reader = reader;
+ this.resolver = resolver;
+ this.buffer = buffer;
+ this.bufferIndex = 0;
+ }
+
+
+ /**
+ * Cleans up the object when it's destroyed.
+ */
+ protected void finalize()
+ throws Throwable
+ {
+ this.reader = null;
+ this.resolver = null;
+ this.buffer = null;
+ super.finalize();
+ }
+
+
+ /**
+ * Reads a block of data.
+ *
+ * @param outputBuffer where to put the read data
+ * @param offset first position in buffer to put the data
+ * @param size maximum number of chars to read
+ *
+ * @return the number of chars read, or -1 if at EOF
+ *
+ * @throws java.io.IOException
+ * if an error occurred reading the data
+ */
+ public int read(char[] outputBuffer,
+ int offset,
+ int size)
+ throws IOException
+ {
+ try {
+ int charsRead = 0;
+ int bufferLength = this.buffer.length();
+
+ if ((offset + size) > outputBuffer.length) {
+ size = outputBuffer.length - offset;
+ }
+
+ while (charsRead < size) {
+ String str = "";
+ char ch;
+
+ if (this.bufferIndex >= bufferLength) {
+ str = XMLUtil.read(this.reader, '&');
+ ch = str.charAt(0);
+ } else {
+ ch = this.buffer.charAt(this.bufferIndex);
+ this.bufferIndex++;
+ outputBuffer[charsRead] = ch;
+ charsRead++;
+ continue; // don't interprete chars in the buffer
+ }
+
+ if (ch == '<') {
+ this.reader.unread(ch);
+ break;
+ }
+
+ if ((ch == '&') && (str.length() > 1)) {
+ if (str.charAt(1) == '#') {
+ ch = XMLUtil.processCharLiteral(str);
+ } else {
+ XMLUtil.processEntity(str, this.reader, this.resolver);
+ continue;
+ }
+ }
+
+ outputBuffer[charsRead] = ch;
+ charsRead++;
+ }
+
+ if (charsRead == 0) {
+ charsRead = -1;
+ }
+
+ return charsRead;
+ } catch (XMLParseException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+
+ /**
+ * Skips remaining data and closes the stream.
+ *
+ * @throws java.io.IOException
+ * if an error occurred reading the data
+ */
+ public void close()
+ throws IOException
+ {
+ try {
+ int bufferLength = this.buffer.length();
+
+ for (;;) {
+ String str = "";
+ char ch;
+
+ if (this.bufferIndex >= bufferLength) {
+ str = XMLUtil.read(this.reader, '&');
+ ch = str.charAt(0);
+ } else {
+ ch = this.buffer.charAt(this.bufferIndex);
+ this.bufferIndex++;
+ continue; // don't interprete chars in the buffer
+ }
+
+ if (ch == '<') {
+ this.reader.unread(ch);
+ break;
+ }
+
+ if ((ch == '&') && (str.length() > 1)) {
+ if (str.charAt(1) != '#') {
+ XMLUtil.processEntity(str, this.reader, this.resolver);
+ }
+ }
+ }
+ } catch (XMLParseException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+}
diff --git a/xml/src/processing/xml/PIReader.java b/xml/src/processing/xml/PIReader.java
new file mode 100644
index 000000000..d6a2bf298
--- /dev/null
+++ b/xml/src/processing/xml/PIReader.java
@@ -0,0 +1,157 @@
+/* PIReader.java NanoXML/Java
+ *
+ * $Revision: 1.3 $
+ * $Date: 2002/01/04 21:03:28 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+import java.io.Reader;
+import java.io.IOException;
+
+
+/**
+ * This reader reads data from another reader until the end of a processing
+ * instruction (?>) has been encountered.
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
+ */
+class PIReader
+ extends Reader
+{
+
+ /**
+ * The encapsulated reader.
+ */
+ private StdXMLReader reader;
+
+
+ /**
+ * True if the end of the stream has been reached.
+ */
+ private boolean atEndOfData;
+
+
+ /**
+ * Creates the reader.
+ *
+ * @param reader the encapsulated reader
+ */
+ PIReader(StdXMLReader reader)
+ {
+ this.reader = reader;
+ this.atEndOfData = false;
+ }
+
+
+ /**
+ * Cleans up the object when it's destroyed.
+ */
+ protected void finalize()
+ throws Throwable
+ {
+ this.reader = null;
+ super.finalize();
+ }
+
+
+ /**
+ * Reads a block of data.
+ *
+ * @param buffer where to put the read data
+ * @param offset first position in buffer to put the data
+ * @param size maximum number of chars to read
+ *
+ * @return the number of chars read, or -1 if at EOF
+ *
+ * @throws java.io.IOException
+ * if an error occurred reading the data
+ */
+ public int read(char[] buffer,
+ int offset,
+ int size)
+ throws IOException
+ {
+ if (this.atEndOfData) {
+ return -1;
+ }
+
+ int charsRead = 0;
+
+ if ((offset + size) > buffer.length) {
+ size = buffer.length - offset;
+ }
+
+ while (charsRead < size) {
+ char ch = this.reader.read();
+
+ if (ch == '?') {
+ char ch2 = this.reader.read();
+
+ if (ch2 == '>') {
+ this.atEndOfData = true;
+ break;
+ }
+
+ this.reader.unread(ch2);
+ }
+
+ buffer[charsRead] = ch;
+ charsRead++;
+ }
+
+ if (charsRead == 0) {
+ charsRead = -1;
+ }
+
+ return charsRead;
+ }
+
+
+ /**
+ * Skips remaining data and closes the stream.
+ *
+ * @throws java.io.IOException
+ * if an error occurred reading the data
+ */
+ public void close()
+ throws IOException
+ {
+ while (! this.atEndOfData) {
+ char ch = this.reader.read();
+
+ if (ch == '?') {
+ char ch2 = this.reader.read();
+
+ if (ch2 == '>') {
+ this.atEndOfData = true;
+ }
+ }
+ }
+ }
+
+}
diff --git a/xml/src/processing/xml/StdXMLBuilder.java b/xml/src/processing/xml/StdXMLBuilder.java
new file mode 100644
index 000000000..2fb848994
--- /dev/null
+++ b/xml/src/processing/xml/StdXMLBuilder.java
@@ -0,0 +1,358 @@
+/* StdXMLBuilder.java NanoXML/Java
+ *
+ * $Revision: 1.3 $
+ * $Date: 2002/01/04 21:03:28 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Stack;
+
+
+/**
+ * StdXMLBuilder is a concrete implementation of IXMLBuilder which creates a
+ * tree of IXMLElement from an XML data source.
+ *
+ * @see net.n3.nanoxml.XMLElement
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
+ */
+public class StdXMLBuilder
+{
+
+ /**
+ * This stack contains the current element and its parents.
+ */
+ private Stack stack;
+
+
+ /**
+ * The root element of the parsed XML tree.
+ */
+ private XMLElement root;
+
+ private XMLElement parent;
+
+ /**
+ * Prototype element for creating the tree.
+ */
+ //private XMLElement prototype;
+
+
+ /**
+ * Creates the builder.
+ */
+ public StdXMLBuilder()
+ {
+ this.stack = null;
+ this.root = null;
+ //this(new XMLElement());
+ }
+
+
+ public StdXMLBuilder(XMLElement parent)
+ {
+ this.parent = parent;
+ }
+
+
+ /**
+ * Creates the builder.
+ *
+ * @param prototype the prototype to use when building the tree.
+ */
+// public StdXMLBuilder(XMLElement prototype)
+// {
+// this.stack = null;
+// this.root = null;
+// this.prototype = prototype;
+// }
+
+
+ /**
+ * Cleans up the object when it's destroyed.
+ */
+ protected void finalize()
+ throws Throwable
+ {
+ //this.prototype = null;
+ this.root = null;
+ this.stack.clear();
+ this.stack = null;
+ super.finalize();
+ }
+
+
+ /**
+ * This method is called before the parser starts processing its input.
+ *
+ * @param systemID the system ID of the XML data source.
+ * @param lineNr the line on which the parsing starts.
+ */
+ public void startBuilding(String systemID,
+ int lineNr)
+ {
+ this.stack = new Stack();
+ this.root = null;
+ }
+
+
+ /**
+ * This method is called when a processing instruction is encountered.
+ * PIs with target "xml" are handled by the parser.
+ *
+ * @param target the PI target.
+ * @param reader to read the data from the PI.
+ */
+ public void newProcessingInstruction(String target,
+ Reader reader)
+ {
+ // nothing to do
+ }
+
+
+ /**
+ * This method is called when a new XML element is encountered.
+ *
+ * @see #endElement
+ *
+ * @param name the name of the element.
+ * @param nsPrefix the prefix used to identify the namespace. If no
+ * namespace has been specified, this parameter is null.
+ * @param nsURI the URI associated with the namespace. If no
+ * namespace has been specified, or no URI is
+ * associated with nsPrefix, this parameter is null.
+ * @param systemID the system ID of the XML data source.
+ * @param lineNr the line in the source where the element starts.
+ */
+ public void startElement(String name,
+ String nsPrefix,
+ String nsURI,
+ String systemID,
+ int lineNr)
+ {
+ String fullName = name;
+
+ if (nsPrefix != null) {
+ fullName = nsPrefix + ':' + name;
+ }
+
+ //XMLElement elt = this.prototype.createElement(fullName, nsURI,
+ // systemID, lineNr);
+
+// XMLElement elt = new XMLElement(fullName, nsURI, systemID, lineNr);
+//
+// if (this.stack.empty()) {
+// this.root = elt;
+// } else {
+// XMLElement top = (XMLElement) this.stack.peek();
+// top.addChild(elt);
+// }
+// stack.push(elt);
+
+ if (this.stack.empty()) {
+ //System.out.println("setting root");
+ parent.set(fullName, nsURI, systemID, lineNr);
+ stack.push(parent);
+ root = parent;
+ } else {
+ XMLElement top = (XMLElement) this.stack.peek();
+ //System.out.println("stack has " + top.getName());
+ XMLElement elt = new XMLElement(fullName, nsURI, systemID, lineNr);
+ top.addChild(elt);
+ stack.push(elt);
+ }
+ }
+
+
+ /**
+ * This method is called when the attributes of an XML element have been
+ * processed.
+ *
+ * @see #startElement
+ * @see #addAttribute
+ *
+ * @param name the name of the element.
+ * @param nsPrefix the prefix used to identify the namespace. If no
+ * namespace has been specified, this parameter is null.
+ * @param nsURI the URI associated with the namespace. If no
+ * namespace has been specified, or no URI is
+ * associated with nsPrefix, this parameter is null.
+ */
+ public void elementAttributesProcessed(String name,
+ String nsPrefix,
+ String nsURI)
+ {
+ // nothing to do
+ }
+
+
+ /**
+ * This method is called when the end of an XML elemnt is encountered.
+ *
+ * @see #startElement
+ *
+ * @param name the name of the element.
+ * @param nsPrefix the prefix used to identify the namespace. If no
+ * namespace has been specified, this parameter is null.
+ * @param nsURI the URI associated with the namespace. If no
+ * namespace has been specified, or no URI is
+ * associated with nsPrefix, this parameter is null.
+ */
+ public void endElement(String name,
+ String nsPrefix,
+ String nsURI)
+ {
+ XMLElement elt = (XMLElement) this.stack.pop();
+
+ if (elt.getChildCount() == 1) {
+ XMLElement child = elt.getChildAtIndex(0);
+
+ if (child.getName() == null) {
+ elt.setContent(child.getContent());
+ elt.removeChildAtIndex(0);
+ }
+ }
+ }
+
+
+ /**
+ * This method is called when a new attribute of an XML element is
+ * encountered.
+ *
+ * @param key the key (name) of the attribute.
+ * @param nsPrefix the prefix used to identify the namespace. If no
+ * namespace has been specified, this parameter is null.
+ * @param nsURI the URI associated with the namespace. If no
+ * namespace has been specified, or no URI is
+ * associated with nsPrefix, this parameter is null.
+ * @param value the value of the attribute.
+ * @param type the type of the attribute. If no type is known,
+ * "CDATA" is returned.
+ *
+ * @throws java.lang.Exception
+ * If an exception occurred while processing the event.
+ */
+ public void addAttribute(String key,
+ String nsPrefix,
+ String nsURI,
+ String value,
+ String type)
+ throws Exception
+ {
+ String fullName = key;
+
+ if (nsPrefix != null) {
+ fullName = nsPrefix + ':' + key;
+ }
+
+ XMLElement top = (XMLElement) this.stack.peek();
+
+ if (top.hasAttribute(fullName)) {
+ throw new XMLParseException(top.getSystemID(),
+ top.getLineNr(),
+ "Duplicate attribute: " + key);
+ }
+
+ if (nsPrefix != null) {
+ top.setAttribute(fullName, nsURI, value);
+ } else {
+ top.setAttribute(fullName, value);
+ }
+ }
+
+
+ /**
+ * This method is called when a PCDATA element is encountered. A Java
+ * reader is supplied from which you can read the data. The reader will
+ * only read the data of the element. You don't need to check for
+ * boundaries. If you don't read the full element, the rest of the data
+ * is skipped. You also don't have to care about entities; they are
+ * resolved by the parser.
+ *
+ * @param reader the Java reader from which you can retrieve the data.
+ * @param systemID the system ID of the XML data source.
+ * @param lineNr the line in the source where the element starts.
+ */
+ public void addPCData(Reader reader,
+ String systemID,
+ int lineNr)
+ {
+ int bufSize = 2048;
+ int sizeRead = 0;
+ StringBuffer str = new StringBuffer(bufSize);
+ char[] buf = new char[bufSize];
+
+ for (;;) {
+ if (sizeRead >= bufSize) {
+ bufSize *= 2;
+ str.ensureCapacity(bufSize);
+ }
+
+ int size;
+
+ try {
+ size = reader.read(buf);
+ } catch (IOException e) {
+ break;
+ }
+
+ if (size < 0) {
+ break;
+ }
+
+ str.append(buf, 0, size);
+ sizeRead += size;
+ }
+
+ //XMLElement elt = this.prototype.createElement(null, systemID, lineNr);
+ XMLElement elt = new XMLElement(null, null, systemID, lineNr);
+ elt.setContent(str.toString());
+
+ if (! this.stack.empty()) {
+ XMLElement top = (XMLElement) this.stack.peek();
+ top.addChild(elt);
+ }
+ }
+
+
+ /**
+ * Returns the result of the building process. This method is called just
+ * before the parse method of IXMLParser returns.
+ *
+ * @see net.n3.nanoxml.IXMLParser#parse
+ *
+ * @return the result of the building process.
+ */
+ public Object getResult()
+ {
+ return this.root;
+ }
+
+}
diff --git a/xml/src/processing/xml/StdXMLParser.java b/xml/src/processing/xml/StdXMLParser.java
new file mode 100644
index 000000000..c286a0b9d
--- /dev/null
+++ b/xml/src/processing/xml/StdXMLParser.java
@@ -0,0 +1,684 @@
+/* StdXMLParser.java NanoXML/Java
+ *
+ * $Revision: 1.5 $
+ * $Date: 2002/03/24 11:37:00 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+import java.io.Reader;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Vector;
+
+
+/**
+ * StdXMLParser is the core parser of NanoXML.
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
+ */
+public class StdXMLParser {
+
+ /**
+ * The builder which creates the logical structure of the XML data.
+ */
+ private StdXMLBuilder builder;
+
+
+ /**
+ * The reader from which the parser retrieves its data.
+ */
+ private StdXMLReader reader;
+
+
+ /**
+ * The entity resolver.
+ */
+ private XMLEntityResolver entityResolver;
+
+
+ /**
+ * The validator that will process entity references and validate the XML
+ * data.
+ */
+ private XMLValidator validator;
+
+
+ /**
+ * Creates a new parser.
+ */
+ public StdXMLParser()
+ {
+ this.builder = null;
+ this.validator = null;
+ this.reader = null;
+ this.entityResolver = new XMLEntityResolver();
+ }
+
+
+ /**
+ * Cleans up the object when it's destroyed.
+ */
+ protected void finalize()
+ throws Throwable
+ {
+ this.builder = null;
+ this.reader = null;
+ this.entityResolver = null;
+ this.validator = null;
+ super.finalize();
+ }
+
+
+ /**
+ * Sets the builder which creates the logical structure of the XML data.
+ *
+ * @param builder the non-null builder
+ */
+ public void setBuilder(StdXMLBuilder builder)
+ {
+ this.builder = builder;
+ }
+
+
+ /**
+ * Returns the builder which creates the logical structure of the XML data.
+ *
+ * @return the builder
+ */
+ public StdXMLBuilder getBuilder()
+ {
+ return this.builder;
+ }
+
+
+ /**
+ * Sets the validator that validates the XML data.
+ *
+ * @param validator the non-null validator
+ */
+ public void setValidator(XMLValidator validator)
+ {
+ this.validator = validator;
+ }
+
+
+ /**
+ * Returns the validator that validates the XML data.
+ *
+ * @return the validator
+ */
+ public XMLValidator getValidator()
+ {
+ return this.validator;
+ }
+
+
+ /**
+ * Sets the entity resolver.
+ *
+ * @param resolver the non-null resolver
+ */
+ public void setResolver(XMLEntityResolver resolver)
+ {
+ this.entityResolver = resolver;
+ }
+
+
+ /**
+ * Returns the entity resolver.
+ *
+ * @return the non-null resolver
+ */
+ public XMLEntityResolver getResolver()
+ {
+ return this.entityResolver;
+ }
+
+
+ /**
+ * Sets the reader from which the parser retrieves its data.
+ *
+ * @param reader the reader
+ */
+ public void setReader(StdXMLReader reader)
+ {
+ this.reader = reader;
+ }
+
+
+ /**
+ * Returns the reader from which the parser retrieves its data.
+ *
+ * @return the reader
+ */
+ public StdXMLReader getReader()
+ {
+ return this.reader;
+ }
+
+
+ /**
+ * Parses the data and lets the builder create the logical data structure.
+ *
+ * @return the logical structure built by the builder
+ *
+ * @throws net.n3.nanoxml.XMLException
+ * if an error occurred reading or parsing the data
+ */
+ public Object parse()
+ throws XMLException
+ {
+ try {
+ this.builder.startBuilding(this.reader.getSystemID(),
+ this.reader.getLineNr());
+ this.scanData();
+ return this.builder.getResult();
+ } catch (XMLException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new XMLException(e);
+ }
+ }
+
+
+ /**
+ * Scans the XML data for elements.
+ *
+ * @throws java.lang.Exception
+ * if something went wrong
+ */
+ protected void scanData() throws Exception {
+ while ((! this.reader.atEOF()) && (this.builder.getResult() == null)) {
+ String str = XMLUtil.read(this.reader, '&');
+ char ch = str.charAt(0);
+ if (ch == '&') {
+ XMLUtil.processEntity(str, this.reader, this.entityResolver);
+ continue;
+ }
+
+ switch (ch) {
+ case '<':
+ this.scanSomeTag(false, // don't allow CDATA
+ null, // no default namespace
+ new Properties());
+ break;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ // skip whitespace
+ break;
+
+ default:
+ XMLUtil.errorInvalidInput(reader.getSystemID(),
+ reader.getLineNr(),
+ "`" + ch + "' (0x"
+ + Integer.toHexString((int) ch)
+ + ')');
+ }
+ }
+ }
+
+
+ /**
+ * Scans an XML tag.
+ *
+ * @param allowCDATA true if CDATA sections are allowed at this point
+ * @param defaultNamespace the default namespace URI (or null)
+ * @param namespaces list of defined namespaces
+ *
+ * @throws java.lang.Exception
+ * if something went wrong
+ */
+ protected void scanSomeTag(boolean allowCDATA,
+ String defaultNamespace,
+ Properties namespaces)
+ throws Exception
+ {
+ String str = XMLUtil.read(this.reader, '&');
+ char ch = str.charAt(0);
+
+ if (ch == '&') {
+ XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
+ reader.getLineNr(),
+ str);
+ }
+
+ switch (ch) {
+ case '?':
+ this.processPI();
+ break;
+
+ case '!':
+ this.processSpecialTag(allowCDATA);
+ break;
+
+ default:
+ this.reader.unread(ch);
+ this.processElement(defaultNamespace, namespaces);
+ }
+ }
+
+
+ /**
+ * Processes a "processing instruction".
+ *
+ * @throws java.lang.Exception
+ * if something went wrong
+ */
+ protected void processPI()
+ throws Exception
+ {
+ XMLUtil.skipWhitespace(this.reader, null);
+ String target = XMLUtil.scanIdentifier(this.reader);
+ XMLUtil.skipWhitespace(this.reader, null);
+ Reader reader = new PIReader(this.reader);
+
+ if (! target.equalsIgnoreCase("xml")) {
+ this.builder.newProcessingInstruction(target, reader);
+ }
+
+ reader.close();
+ }
+
+
+ /**
+ * Processes a tag that starts with a bang (<!...>).
+ *
+ * @param allowCDATA true if CDATA sections are allowed at this point
+ *
+ * @throws java.lang.Exception
+ * if something went wrong
+ */
+ protected void processSpecialTag(boolean allowCDATA)
+ throws Exception
+ {
+ String str = XMLUtil.read(this.reader, '&');
+ char ch = str.charAt(0);
+
+ if (ch == '&') {
+ XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
+ reader.getLineNr(),
+ str);
+ }
+
+ switch (ch) {
+ case '[':
+ if (allowCDATA) {
+ this.processCDATA();
+ } else {
+ XMLUtil.errorUnexpectedCDATA(reader.getSystemID(),
+ reader.getLineNr());
+ }
+
+ return;
+
+ case 'D':
+ this.processDocType();
+ return;
+
+ case '-':
+ XMLUtil.skipComment(this.reader);
+ return;
+ }
+ }
+
+
+ /**
+ * Processes a CDATA section.
+ *
+ * @throws java.lang.Exception
+ * if something went wrong
+ */
+ protected void processCDATA()
+ throws Exception
+ {
+ if (! XMLUtil.checkLiteral(this.reader, "CDATA[")) {
+ XMLUtil.errorExpectedInput(reader.getSystemID(),
+ reader.getLineNr(),
+ "') {
+ XMLUtil.errorExpectedInput(reader.getSystemID(),
+ reader.getLineNr(),
+ "`>'");
+ }
+
+ if (false) { // TODO currently disabled
+ if (systemID != null) {
+ Reader reader = this.reader.openStream(publicID.toString(),
+ systemID);
+ this.reader.startNewStream(reader);
+ this.reader.setSystemID(systemID);
+ this.reader.setPublicID(publicID.toString());
+ this.validator.parseDTD(publicID.toString(),
+ this.reader,
+ this.entityResolver,
+ true);
+ }
+ }
+ }
+
+
+ /**
+ * Processes a regular element.
+ *
+ * @param defaultNamespace the default namespace URI (or null)
+ * @param namespaces list of defined namespaces
+ *
+ * @throws java.lang.Exception
+ * if something went wrong
+ */
+ protected void processElement(String defaultNamespace,
+ Properties namespaces)
+ throws Exception
+ {
+ String fullName = XMLUtil.scanIdentifier(this.reader);
+ String name = fullName;
+ XMLUtil.skipWhitespace(this.reader, null);
+ String prefix = null;
+ int colonIndex = name.indexOf(':');
+
+ if (colonIndex > 0) {
+ prefix = name.substring(0, colonIndex);
+ name = name.substring(colonIndex + 1);
+ }
+
+ Vector attrNames = new Vector();
+ Vector attrValues = new Vector();
+ Vector attrTypes = new Vector();
+
+ this.validator.elementStarted(fullName,
+ this.reader.getSystemID(),
+ this.reader.getLineNr());
+ char ch;
+
+ for (;;) {
+ ch = this.reader.read();
+
+ if ((ch == '/') || (ch == '>')) {
+ break;
+ }
+
+ this.reader.unread(ch);
+ this.processAttribute(attrNames, attrValues, attrTypes);
+ XMLUtil.skipWhitespace(this.reader, null);
+ }
+
+ Properties extraAttributes = new Properties();
+ this.validator.elementAttributesProcessed(fullName,
+ extraAttributes,
+ this.reader.getSystemID(),
+ this.reader.getLineNr());
+ Enumeration en = extraAttributes.keys();
+
+ while (en.hasMoreElements()) {
+ String key = (String) en.nextElement();
+ String value = extraAttributes.getProperty(key);
+ attrNames.addElement(key);
+ attrValues.addElement(value);
+ attrTypes.addElement("CDATA");
+ }
+
+ for (int i = 0; i < attrNames.size(); i++) {
+ String key = (String) attrNames.elementAt(i);
+ String value = (String) attrValues.elementAt(i);
+ //String type = (String) attrTypes.elementAt(i);
+
+ if (key.equals("xmlns")) {
+ defaultNamespace = value;
+ } else if (key.startsWith("xmlns:")) {
+ namespaces.put(key.substring(6), value);
+ }
+ }
+
+ if (prefix == null) {
+ this.builder.startElement(name, prefix, defaultNamespace,
+ this.reader.getSystemID(),
+ this.reader.getLineNr());
+ } else {
+ this.builder.startElement(name, prefix,
+ namespaces.getProperty(prefix),
+ this.reader.getSystemID(),
+ this.reader.getLineNr());
+ }
+
+ for (int i = 0; i < attrNames.size(); i++) {
+ String key = (String) attrNames.elementAt(i);
+
+ if (key.startsWith("xmlns")) {
+ continue;
+ }
+
+ String value = (String) attrValues.elementAt(i);
+ String type = (String) attrTypes.elementAt(i);
+ colonIndex = key.indexOf(':');
+
+ if (colonIndex > 0) {
+ String attPrefix = key.substring(0, colonIndex);
+ key = key.substring(colonIndex + 1);
+ this.builder.addAttribute(key, attPrefix,
+ namespaces.getProperty(attPrefix),
+ value, type);
+ } else {
+ this.builder.addAttribute(key, null, null, value, type);
+ }
+ }
+
+ if (prefix == null) {
+ this.builder.elementAttributesProcessed(name, prefix,
+ defaultNamespace);
+ } else {
+ this.builder.elementAttributesProcessed(name, prefix,
+ namespaces
+ .getProperty(prefix));
+ }
+
+ if (ch == '/') {
+ if (this.reader.read() != '>') {
+ XMLUtil.errorExpectedInput(reader.getSystemID(),
+ reader.getLineNr(),
+ "`>'");
+ }
+
+ this.validator.elementEnded(name,
+ this.reader.getSystemID(),
+ this.reader.getLineNr());
+
+ if (prefix == null) {
+ this.builder.endElement(name, prefix, defaultNamespace);
+ } else {
+ this.builder.endElement(name, prefix,
+ namespaces.getProperty(prefix));
+ }
+
+ return;
+ }
+
+ StringBuffer buffer = new StringBuffer(16);
+
+ for (;;) {
+ buffer.setLength(0);
+ String str;
+
+ for (;;) {
+ XMLUtil.skipWhitespace(this.reader, buffer);
+ str = XMLUtil.read(this.reader, '&');
+
+ if ((str.charAt(0) == '&') && (str.charAt(1) != '#')) {
+ XMLUtil.processEntity(str, this.reader,
+ this.entityResolver);
+ } else {
+ break;
+ }
+ }
+
+ if (str.charAt(0) == '<') {
+ str = XMLUtil.read(this.reader, '\0');
+
+ if (str.charAt(0) == '/') {
+ XMLUtil.skipWhitespace(this.reader, null);
+ str = XMLUtil.scanIdentifier(this.reader);
+
+ if (! str.equals(fullName)) {
+ XMLUtil.errorWrongClosingTag(reader.getSystemID(),
+ reader.getLineNr(),
+ name, str);
+ }
+
+ XMLUtil.skipWhitespace(this.reader, null);
+
+ if (this.reader.read() != '>') {
+ XMLUtil.errorClosingTagNotEmpty(reader.getSystemID(),
+ reader.getLineNr());
+ }
+
+ this.validator.elementEnded(fullName,
+ this.reader.getSystemID(),
+ this.reader.getLineNr());
+ if (prefix == null) {
+ this.builder.endElement(name, prefix, defaultNamespace);
+ } else {
+ this.builder.endElement(name, prefix,
+ namespaces.getProperty(prefix));
+ }
+ break;
+ } else { // <[^/]
+ this.reader.unread(str.charAt(0));
+ this.scanSomeTag(true, //CDATA allowed
+ defaultNamespace,
+ (Properties) namespaces.clone());
+ }
+ } else { // [^<]
+ if (str.charAt(0) == '&') {
+ ch = XMLUtil.processCharLiteral(str);
+ buffer.append(ch);
+ } else {
+ reader.unread(str.charAt(0));
+ }
+ this.validator.PCDataAdded(this.reader.getSystemID(),
+ this.reader.getLineNr());
+ Reader r = new ContentReader(this.reader,
+ this.entityResolver,
+ buffer.toString());
+ this.builder.addPCData(r, this.reader.getSystemID(),
+ this.reader.getLineNr());
+ r.close();
+ }
+ }
+ }
+
+
+ /**
+ * Processes an attribute of an element.
+ *
+ * @param attrNames contains the names of the attributes.
+ * @param attrValues contains the values of the attributes.
+ * @param attrTypes contains the types of the attributes.
+ *
+ * @throws java.lang.Exception
+ * if something went wrong
+ */
+ protected void processAttribute(Vector attrNames,
+ Vector attrValues,
+ Vector attrTypes)
+ throws Exception
+ {
+ String key = XMLUtil.scanIdentifier(this.reader);
+ XMLUtil.skipWhitespace(this.reader, null);
+
+ if (! XMLUtil.read(this.reader, '&').equals("=")) {
+ XMLUtil.errorExpectedInput(reader.getSystemID(),
+ reader.getLineNr(),
+ "`='");
+ }
+
+ XMLUtil.skipWhitespace(this.reader, null);
+ String value = XMLUtil.scanString(this.reader, '&',
+ this.entityResolver);
+ attrNames.addElement(key);
+ attrValues.addElement(value);
+ attrTypes.addElement("CDATA");
+ this.validator.attributeAdded(key, value,
+ this.reader.getSystemID(),
+ this.reader.getLineNr());
+ }
+
+}
diff --git a/xml/src/processing/xml/StdXMLReader.java b/xml/src/processing/xml/StdXMLReader.java
new file mode 100644
index 000000000..9914cee49
--- /dev/null
+++ b/xml/src/processing/xml/StdXMLReader.java
@@ -0,0 +1,626 @@
+/* StdXMLReader.java NanoXML/Java
+ *
+ * $Revision: 1.4 $
+ * $Date: 2002/01/04 21:03:28 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+//import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.LineNumberReader;
+import java.io.PushbackReader;
+import java.io.PushbackInputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Stack;
+
+
+/**
+ * StdXMLReader reads the data to be parsed.
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
+ */
+public class StdXMLReader
+{
+
+ /**
+ * A stacked reader.
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
+ */
+ private class StackedReader
+ {
+
+ PushbackReader pbReader;
+
+ LineNumberReader lineReader;
+
+ URL systemId;
+
+ String publicId;
+
+ }
+
+
+ /**
+ * The stack of readers.
+ */
+ private Stack readers;
+
+
+ /**
+ * The current push-back reader.
+ */
+ private StackedReader currentReader;
+
+
+ /**
+ * Creates a new reader using a string as input.
+ *
+ * @param str the string containing the XML data
+ */
+ public static StdXMLReader stringReader(String str)
+ {
+ return new StdXMLReader(new StringReader(str));
+ }
+
+
+ /**
+ * Creates a new reader using a file as input.
+ *
+ * @param filename the name of the file containing the XML data
+ *
+ * @throws java.io.FileNotFoundException
+ * if the file could not be found
+ * @throws java.io.IOException
+ * if an I/O error occurred
+ */
+ public static StdXMLReader fileReader(String filename)
+ throws FileNotFoundException,
+ IOException
+ {
+ StdXMLReader r = new StdXMLReader(new FileInputStream(filename));
+ r.setSystemID(filename);
+
+ for (int i = 0; i < r.readers.size(); i++) {
+ StackedReader sr = (StackedReader) r.readers.elementAt(i);
+ sr.systemId = r.currentReader.systemId;
+ }
+
+ return r;
+ }
+
+
+ /**
+ * Initializes the reader from a system and public ID.
+ *
+ * @param publicID the public ID which may be null.
+ * @param systemID the non-null system ID.
+ *
+ * @throws MalformedURLException
+ * if the system ID does not contain a valid URL
+ * @throws FileNotFoundException
+ * if the system ID refers to a local file which does not exist
+ * @throws IOException
+ * if an error occurred opening the stream
+ */
+ public StdXMLReader(String publicID,
+ String systemID)
+ throws MalformedURLException,
+ FileNotFoundException,
+ IOException
+ {
+ URL systemIDasURL = null;
+
+ try {
+ systemIDasURL = new URL(systemID);
+ } catch (MalformedURLException e) {
+ systemID = "file:" + systemID;
+
+ try {
+ systemIDasURL = new URL(systemID);
+ } catch (MalformedURLException e2) {
+ throw e;
+ }
+ }
+
+ this.currentReader = new StackedReader();
+ this.readers = new Stack();
+ Reader reader = this.openStream(publicID, systemIDasURL.toString());
+ this.currentReader.lineReader = new LineNumberReader(reader);
+ this.currentReader.pbReader
+ = new PushbackReader(this.currentReader.lineReader, 2);
+ }
+
+
+ /**
+ * Initializes the XML reader.
+ *
+ * @param reader the input for the XML data.
+ */
+ public StdXMLReader(Reader reader)
+ {
+ this.currentReader = new StackedReader();
+ this.readers = new Stack();
+ this.currentReader.lineReader = new LineNumberReader(reader);
+ this.currentReader.pbReader
+ = new PushbackReader(this.currentReader.lineReader, 2);
+ this.currentReader.publicId = "";
+
+ try {
+ this.currentReader.systemId = new URL("file:.");
+ } catch (MalformedURLException e) {
+ // never happens
+ }
+ }
+
+
+ /**
+ * Cleans up the object when it's destroyed.
+ */
+ protected void finalize()
+ throws Throwable
+ {
+ this.currentReader.lineReader = null;
+ this.currentReader.pbReader = null;
+ this.currentReader.systemId = null;
+ this.currentReader.publicId = null;
+ this.currentReader = null;
+ this.readers.clear();
+ super.finalize();
+ }
+
+
+ /**
+ * Scans the encoding from an <?xml...?> tag.
+ *
+ * @param str the first tag in the XML data.
+ *
+ * @return the encoding, or null if no encoding has been specified.
+ */
+ protected String getEncoding(String str)
+ {
+ if (! str.startsWith("= 'a')
+ && (str.charAt(index) <= 'z')) {
+ key.append(str.charAt(index));
+ index++;
+ }
+
+ while ((index < str.length()) && (str.charAt(index) <= ' ')) {
+ index++;
+ }
+
+ if ((index >= str.length()) || (str.charAt(index) != '=')) {
+ break;
+ }
+
+ while ((index < str.length()) && (str.charAt(index) != '\'')
+ && (str.charAt(index) != '"')) {
+ index++;
+ }
+
+ if (index >= str.length()) {
+ break;
+ }
+
+ char delimiter = str.charAt(index);
+ index++;
+ int index2 = str.indexOf(delimiter, index);
+
+ if (index2 < 0) {
+ break;
+ }
+
+ if (key.toString().equals("encoding")) {
+ return str.substring(index, index2);
+ }
+
+ index = index2 + 1;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Converts a stream to a reader while detecting the encoding.
+ *
+ * @param stream the input for the XML data.
+ * @param charsRead buffer where to put characters that have been read
+ *
+ * @throws java.io.IOException
+ * if an I/O error occurred
+ */
+ protected Reader stream2reader(InputStream stream,
+ StringBuffer charsRead)
+ throws IOException
+ {
+ PushbackInputStream pbstream = new PushbackInputStream(stream);
+ int b = pbstream.read();
+
+ switch (b) {
+ case 0x00:
+ case 0xFE:
+ case 0xFF:
+ pbstream.unread(b);
+ return new InputStreamReader(pbstream, "UTF-16");
+
+ case 0xEF:
+ for (int i = 0; i < 2; i++) {
+ pbstream.read();
+ }
+
+ return new InputStreamReader(pbstream, "UTF-8");
+
+ case 0x3C:
+ b = pbstream.read();
+ charsRead.append('<');
+
+ while ((b > 0) && (b != 0x3E)) {
+ charsRead.append((char) b);
+ b = pbstream.read();
+ }
+
+ if (b > 0) {
+ charsRead.append((char) b);
+ }
+
+ String encoding = this.getEncoding(charsRead.toString());
+
+ if (encoding == null) {
+ return new InputStreamReader(pbstream, "UTF-8");
+ }
+
+ charsRead.setLength(0);
+
+ try {
+ return new InputStreamReader(pbstream, encoding);
+ } catch (UnsupportedEncodingException e) {
+ return new InputStreamReader(pbstream, "UTF-8");
+ }
+
+ default:
+ charsRead.append((char) b);
+ return new InputStreamReader(pbstream, "UTF-8");
+ }
+ }
+
+
+ /**
+ * Initializes the XML reader.
+ *
+ * @param stream the input for the XML data.
+ *
+ * @throws java.io.IOException
+ * if an I/O error occurred
+ */
+ public StdXMLReader(InputStream stream)
+ throws IOException
+ {
+ // unused?
+ //PushbackInputStream pbstream = new PushbackInputStream(stream);
+ StringBuffer charsRead = new StringBuffer();
+ Reader reader = this.stream2reader(stream, charsRead);
+ this.currentReader = new StackedReader();
+ this.readers = new Stack();
+ this.currentReader.lineReader = new LineNumberReader(reader);
+ this.currentReader.pbReader
+ = new PushbackReader(this.currentReader.lineReader, 2);
+ this.currentReader.publicId = "";
+
+ try {
+ this.currentReader.systemId = new URL("file:.");
+ } catch (MalformedURLException e) {
+ // never happens
+ }
+
+ this.startNewStream(new StringReader(charsRead.toString()));
+ }
+
+
+ /**
+ * Reads a character.
+ *
+ * @return the character
+ *
+ * @throws java.io.IOException
+ * if no character could be read
+ */
+ public char read()
+ throws IOException
+ {
+ int ch = this.currentReader.pbReader.read();
+
+ while (ch < 0) {
+ if (this.readers.empty()) {
+ throw new IOException("Unexpected EOF");
+ }
+
+ this.currentReader.pbReader.close();
+ this.currentReader = (StackedReader) this.readers.pop();
+ ch = this.currentReader.pbReader.read();
+ }
+
+ return (char) ch;
+ }
+
+
+ /**
+ * Returns true if the current stream has no more characters left to be
+ * read.
+ *
+ * @throws java.io.IOException
+ * if an I/O error occurred
+ */
+ public boolean atEOFOfCurrentStream()
+ throws IOException
+ {
+ int ch = this.currentReader.pbReader.read();
+
+ if (ch < 0) {
+ return true;
+ } else {
+ this.currentReader.pbReader.unread(ch);
+ return false;
+ }
+ }
+
+
+ /**
+ * Returns true if there are no more characters left to be read.
+ *
+ * @throws java.io.IOException
+ * if an I/O error occurred
+ */
+ public boolean atEOF()
+ throws IOException
+ {
+ int ch = this.currentReader.pbReader.read();
+
+ while (ch < 0) {
+ if (this.readers.empty()) {
+ return true;
+ }
+
+ this.currentReader.pbReader.close();
+ this.currentReader = (StackedReader) this.readers.pop();
+ ch = this.currentReader.pbReader.read();
+ }
+
+ this.currentReader.pbReader.unread(ch);
+ return false;
+ }
+
+
+ /**
+ * Pushes the last character read back to the stream.
+ *
+ * @param ch the character to push back.
+ *
+ * @throws java.io.IOException
+ * if an I/O error occurred
+ */
+ public void unread(char ch)
+ throws IOException
+ {
+ this.currentReader.pbReader.unread(ch);
+ }
+
+
+ /**
+ * Opens a stream from a public and system ID.
+ *
+ * @param publicID the public ID, which may be null
+ * @param systemID the system ID, which is never null
+ *
+ * @throws java.net.MalformedURLException
+ * if the system ID does not contain a valid URL
+ * @throws java.io.FileNotFoundException
+ * if the system ID refers to a local file which does not exist
+ * @throws java.io.IOException
+ * if an error occurred opening the stream
+ */
+ public Reader openStream(String publicID,
+ String systemID)
+ throws MalformedURLException,
+ FileNotFoundException,
+ IOException
+ {
+ URL url = new URL(this.currentReader.systemId, systemID);
+
+ if (url.getRef() != null) {
+ String ref = url.getRef();
+
+ if (url.getFile().length() > 0) {
+ url = new URL(url.getProtocol(), url.getHost(), url.getPort(),
+ url.getFile());
+ url = new URL("jar:" + url + '!' + ref);
+ } else {
+ url = StdXMLReader.class.getResource(ref);
+ }
+ }
+
+ this.currentReader.publicId = publicID;
+ this.currentReader.systemId = url;
+ StringBuffer charsRead = new StringBuffer();
+ Reader reader = this.stream2reader(url.openStream(), charsRead);
+
+ if (charsRead.length() == 0) {
+ return reader;
+ }
+
+ String charsReadStr = charsRead.toString();
+ PushbackReader pbreader = new PushbackReader(reader,
+ charsReadStr.length());
+
+ for (int i = charsReadStr.length() - 1; i >= 0; i--) {
+ pbreader.unread(charsReadStr.charAt(i));
+ }
+
+ return pbreader;
+ }
+
+
+ /**
+ * Starts a new stream from a Java reader. The new stream is used
+ * temporary to read data from. If that stream is exhausted, control
+ * returns to the parent stream.
+ *
+ * @param reader the non-null reader to read the new data from
+ */
+ public void startNewStream(Reader reader)
+ {
+ this.startNewStream(reader, false);
+ }
+
+
+ /**
+ * Starts a new stream from a Java reader. The new stream is used
+ * temporary to read data from. If that stream is exhausted, control
+ * returns to the parent stream.
+ *
+ * @param reader the non-null reader to read the new data from
+ * @param isInternalEntity true if the reader is produced by resolving
+ * an internal entity
+ */
+ public void startNewStream(Reader reader,
+ boolean isInternalEntity)
+ {
+ StackedReader oldReader = this.currentReader;
+ this.readers.push(this.currentReader);
+ this.currentReader = new StackedReader();
+
+ if (isInternalEntity) {
+ this.currentReader.lineReader = null;
+ this.currentReader.pbReader = new PushbackReader(reader, 2);
+ } else {
+ this.currentReader.lineReader = new LineNumberReader(reader);
+ this.currentReader.pbReader
+ = new PushbackReader(this.currentReader.lineReader, 2);
+ }
+
+ this.currentReader.systemId = oldReader.systemId;
+ this.currentReader.publicId = oldReader.publicId;
+ }
+
+
+ /**
+ * Returns the current "level" of the stream on the stack of streams.
+ */
+ public int getStreamLevel()
+ {
+ return this.readers.size();
+ }
+
+
+ /**
+ * Returns the line number of the data in the current stream.
+ */
+ public int getLineNr()
+ {
+ if (this.currentReader.lineReader == null) {
+ StackedReader sr = (StackedReader) this.readers.peek();
+
+ if (sr.lineReader == null) {
+ return 0;
+ } else {
+ return sr.lineReader.getLineNumber() + 1;
+ }
+ }
+
+ return this.currentReader.lineReader.getLineNumber() + 1;
+ }
+
+
+ /**
+ * Sets the system ID of the current stream.
+ *
+ * @param systemID the system ID
+ *
+ * @throws java.net.MalformedURLException
+ * if the system ID does not contain a valid URL
+ */
+ public void setSystemID(String systemID)
+ throws MalformedURLException
+ {
+ this.currentReader.systemId = new URL(this.currentReader.systemId,
+ systemID);
+ }
+
+
+ /**
+ * Sets the public ID of the current stream.
+ *
+ * @param publicID the public ID
+ */
+ public void setPublicID(String publicID)
+ {
+ this.currentReader.publicId = publicID;
+ }
+
+
+ /**
+ * Returns the current system ID.
+ */
+ public String getSystemID()
+ {
+ return this.currentReader.systemId.toString();
+ }
+
+
+ /**
+ * Returns the current public ID.
+ */
+ public String getPublicID()
+ {
+ return this.currentReader.publicId;
+ }
+
+}
diff --git a/xml/src/processing/xml/XMLAttribute.java b/xml/src/processing/xml/XMLAttribute.java
new file mode 100644
index 000000000..759dd47fc
--- /dev/null
+++ b/xml/src/processing/xml/XMLAttribute.java
@@ -0,0 +1,153 @@
+/* XMLAttribute.java NanoXML/Java
+ *
+ * $Revision: 1.4 $
+ * $Date: 2002/01/04 21:03:29 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+/**
+ * An attribute in an XML element. This is an internal class.
+ *
+ * @see net.n3.nanoxml.XMLElement
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
+ */
+class XMLAttribute
+{
+
+ /**
+ * The full name of the attribute.
+ */
+ private String fullName;
+
+
+ /**
+ * The short name of the attribute.
+ */
+ private String name;
+
+
+ /**
+ * The namespace URI of the attribute.
+ */
+ private String namespace;
+
+
+ /**
+ * The value of the attribute.
+ */
+ private String value;
+
+
+ /**
+ * The type of the attribute.
+ */
+ private String type;
+
+
+ /**
+ * Creates a new attribute.
+ *
+ * @param fullName the non-null full name
+ * @param name the non-null short name
+ * @param namespace the namespace URI, which may be null
+ * @param value the value of the attribute
+ * @param type the type of the attribute
+ */
+ XMLAttribute(String fullName,
+ String name,
+ String namespace,
+ String value,
+ String type)
+ {
+ this.fullName = fullName;
+ this.name = name;
+ this.namespace = namespace;
+ this.value = value;
+ this.type = type;
+ }
+
+
+ /**
+ * Returns the full name of the attribute.
+ */
+ String getFullName()
+ {
+ return this.fullName;
+ }
+
+
+ /**
+ * Returns the short name of the attribute.
+ */
+ String getName()
+ {
+ return this.name;
+ }
+
+
+ /**
+ * Returns the namespace of the attribute.
+ */
+ String getNamespace()
+ {
+ return this.namespace;
+ }
+
+
+ /**
+ * Returns the value of the attribute.
+ */
+ String getValue()
+ {
+ return this.value;
+ }
+
+
+ /**
+ * Sets the value of the attribute.
+ *
+ * @param value the new value.
+ */
+ void setValue(String value)
+ {
+ this.value = value;
+ }
+
+
+ /**
+ * Returns the type of the attribute.
+ *
+ * @param type the new type.
+ */
+ String getType()
+ {
+ return this.type;
+ }
+
+}
diff --git a/xml/src/processing/xml/XMLElement.java b/xml/src/processing/xml/XMLElement.java
index 568ec7c58..64245521f 100644
--- a/xml/src/processing/xml/XMLElement.java
+++ b/xml/src/processing/xml/XMLElement.java
@@ -1,471 +1,220 @@
-/*
- This code is from NanoXML 2.2.3 Lite
- Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
-
- Additional modifications Copyright (c) 2006 Ben Fry and Casey Reas
- to make the code better-suited for use with Processing.
-
- Original license notice from Marc De Scheemaecker:
-
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from the
- use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software in
- a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any source distribution.
-*/
+/* XMLElement.java NanoXML/Java
+ *
+ * $Revision: 1.5 $
+ * $Date: 2002/02/06 18:50:12 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
package processing.xml;
+//import java.io.IOException;
import java.io.ByteArrayOutputStream;
-import java.io.CharArrayReader;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
+import java.io.Serializable;
import java.io.StringReader;
-import java.io.Writer;
import java.util.Enumeration;
-import java.util.Hashtable;
+import java.util.Properties;
import java.util.Vector;
import processing.core.PApplet;
/**
- * XMLElement is a representation of an XML object. The object is able to parse
- * XML code.
- *
- * The code is from NanoXML 2.2.3 Lite from Marc De Scheemaecker. His project is - * online at http://nanoxml.cyberelf.be/. - * Some interfaces to the code have been changed, and the package naming has been - * altered, however it should be clear that this code is almost entirely his - * work, with no connection to the Processing project. - *
- * Alterations/additions for the Processing library:
- * The encoding parameter inside XML files is ignored, all files are
- * parsed with UTF-8 encoding (as of release 0134).
- *
- * import processing.xml.*;
+ * XMLElement is an XML element. The standard NanoXML builder generates a
+ * tree of such elements.
+ *
+ * @see net.n3.nanoxml.StdXMLBuilder
*
- * XMLElement xml = new XMLElement(this, "filename.xml");
- * int childCount = xml.getChildCount();
- * for (int i = 0; i < childCount; i++) {
- * XMLElement kid = xml.getChild(i);
- * float attr = kid.getFloatAttribute("some-attribute");
- * println("some-attribute is " + attr);
- * }
- *
* @author Marc De Scheemaecker
- * @author Ben Fry
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
*/
-public class XMLElement
-{
- static final boolean DEBUG = false;
-
+public class XMLElement implements Serializable {
/**
- * The attributes given to the element.
- *
- *
null.
- * null.
- * XMLElement
- * or a subclass of XMLElement.
- * null iff the element is not
- * initialized by either parse or setName.
- * null, it's not empty.
- * null, it contains a valid
- * XML identifier.
- * null iff the element is not a
- * #PCDATA element.
- * null.
- * lineNumber >= 0
- * true if the case of the element and attribute names
- * are case insensitive.
- */
- private boolean ignoreCase;
-
-
- /**
- * true if the leading and trailing whitespace of #PCDATA
- * sections have to be ignored.
- */
- private boolean ignoreWhitespace;
-
-
- /**
- * Character read too much.
- * This character provides push-back functionality to the input reader
- * without having to use a PushbackReader.
- * If there is no such character, this field is '\0'.
- */
- private char charReadTooMuch;
-
-
- /**
- * The reader provided by the caller of the parse method.
- *
- * null while the parse method
- * is running.
- * new XMLElement(new Hashtable(), false, true)
- * new XMLElement(entities, false, true)
- * entities != null
- * new XMLElement(new Hashtable(), skipLeadingWhitespace, true)
- * true if leading and trailing whitespace in PCDATA
- * content has to be removed.
- *
- * new XMLElement(entities, skipLeadingWhitespace, true)
- * true if leading and trailing whitespace in PCDATA
- * content has to be removed.
- *
- * entities != null
- * true if leading and trailing whitespace in PCDATA
- * content has to be removed.
- * @param ignoreCase
- * true if the case of element and attribute names have
- * to be ignored.
- *
- * entities != null
- *
- * This constructor should only be called from
- * {@link #createAnotherElement() createAnotherElement}
- * to create child elements.
- *
- * @param entities
- * The entity conversion table.
- * @param skipLeadingWhitespace
- * true if leading and trailing whitespace in PCDATA
- * content has to be removed.
- * @param fillBasicConversionTable
- * true if the basic entities need to be added to
- * the entity list.
- * @param ignoreCase
- * true if the case of element and attribute names have
- * to be ignored.
- *
- *
entities != null
- * fillBasicConversionTable == false
- * then entities contains at least the following
- * entries: amp, lt, gt,
- * apos and quot
- * child != null
- * child.getName() != null
- * child does not have a parent element
- * name != null
- * name is a valid XML identifier
- * value != null
- * name != null
- * name is a valid XML identifier
- * name != null
- * name is a valid XML identifier
- * result != null
- * result != null
- * result != null
- * null is returned.
+ * Returns a vector of all child elements named name.
*
- * @see processing.xml.XMLElement#setContent(java.lang.String)
- * setContent(String)
+ * @param name the full name of the children to search for.
+ *
+ * @return the non-null vector of child elements.
*/
- public String getContent()
- {
- return this.content;
- }
+// public Vector getChildrenNamed(String name) {
+// Vector result = new Vector(this.children.size());
+// Enumeration enum = this.children.elements();
+// while (enum.hasMoreElements()) {
+// XMLElement child = (XMLElement) enum.nextElement();
+// String childName = child.getFullName();
+// if ((childName != null) && childName.equals(name)) {
+// result.addElement(child);
+// }
+// }
+// return result;
+// }
/**
- * Returns the line Number in the source data on which the element is found.
- * This method returns 0 there is no associated source data.
+ * Returns a vector of all child elements named name.
*
- * result >= 0
- * null is returned.
- *
- * @param name The name of the attribute.
- *
- * name != null
- * name is a valid XML identifier
- * defaultValue is returned.
- *
- * @param aname The name of the attribute.
- * @param defaultValue Key to use if the attribute is missing.
- *
- * name != null
- * name is a valid XML identifier
- *
- * As an example, if valueSet contains the mapping "one" =>
- * "1"
- * and the element contains the attribute attr="one", then
- * getAttribute("attr", mapping, defaultKey, false) returns
- * "1".
+ * Searches an attribute.
*
- * @param name
- * The name of the attribute.
- * @param valueSet
- * Hashtable mapping keys to values.
- * @param defaultKey
- * Key to use if the attribute is missing.
- * @param allowLiterals
- * true if literals are valid.
+ * @param name the non-null short name of the attribute.
+ * @param namespace the name space, which may be null.
*
- *
name != null
- * name is a valid XML identifier
- * valueSet != null
- * valueSet are strings
- * null is returned.
+ * Returns the system ID of the data where the element started.
*
- * @param name The name of the attribute.
+ * @return the system ID, or null if unknown.
*
- * name != null
- * name is a valid XML identifier
- * defaultValue is returned.
+ * Returns the line number in the data where the element started.
*
- * @param name The name of the attribute.
- * @param defaultValue Key to use if the attribute is missing.
+ * @return the line number, or NO_LINE if unknown.
*
- * name != null
- * name is a valid XML identifier
- *
- * As an example, if valueSet contains the mapping "one" =>
- * "1"
- * and the element contains the attribute attr="one", then
- * getAttribute("attr", mapping, defaultKey, false) returns
- * "1".
+ * Return the #PCDATA content of the element. If the element has a
+ * combination of #PCDATA content and child elements, the #PCDATA
+ * sections can be retrieved as unnamed child objects. In this case,
+ * this method returns null.
*
- * @param name
- * The name of the attribute.
- * @param valueSet
- * Hashtable mapping keys to values.
- * @param defaultKey
- * Key to use if the attribute is missing.
- * @param allowLiterals
- * true if literals are valid.
- *
- *
name != null
- * name is a valid XML identifier
- * valueSet != null
- * valueSet are strings
- * valueSet are strings
- * 0 is returned.
+ * Sets the #PCDATA content. It is an error to call this method with a
+ * non-null value if there are child objects.
*
- * @param name The name of the attribute.
- *
- * name != null
- * name is a valid XML identifier
- * defaultValue is returned.
- *
- * @param name The name of the attribute.
- * @param defaultValue Key to use if the attribute is missing.
- *
- * name != null
- * name is a valid XML identifier
- *
- * As an example, if valueSet contains the mapping "one" => 1
- * and the element contains the attribute attr="one", then
- * getIntAttribute("attr", mapping, defaultKey, false) returns
- * 1.
- *
- * @param name
- * The name of the attribute.
- * @param valueSet
- * Hashtable mapping keys to values.
- * @param defaultKey
- * Key to use if the attribute is missing.
- * @param allowLiteralNumbers
- * true if literal numbers are valid.
- *
- *
name != null
- * name is a valid XML identifier
- * valueSet != null
- * valueSet are strings
- * valueSet are Integer objects
- * defaultKey is either null, a
- * key in valueSet or an integer.
- * 0.0 is returned.
- *
- * @param name The name of the attribute.
- *
- * name != null
- * name is a valid XML identifier
- * defaultValue is returned.
- *
- * @param name The name of the attribute.
- * @param defaultValue Key to use if the attribute is missing.
- *
- * name != null
- * name is a valid XML identifier
- *
- * As an example, if valueSet contains the mapping "one" =>
- * 1.0
- * and the element contains the attribute attr="one", then
- * getDoubleAttribute("attr", mapping, defaultKey, false)
- * returns 1.0.
- *
- * @param name
- * The name of the attribute.
- * @param valueSet
- * Hashtable mapping keys to values.
- * @param defaultKey
- * Key to use if the attribute is missing.
- * @param allowLiteralNumbers
- * true if literal numbers are valid.
- *
- *
name != null
- * name is a valid XML identifier
- * valueSet != null
- * valueSet are strings
- * valueSet are Double objects
- * defaultKey is either null, a
- * key in valueSet or a double.
- * defaultValue is returned.
- * If the value of the attribute is equal to trueValue,
- * true is returned.
- * If the value of the attribute is equal to falseValue,
- * false is returned.
- * If the value doesn't match trueValue or
- * falseValue, an exception is thrown.
- *
- * @param name The name of the attribute.
- * @param trueValue The value associated with true.
- * @param falseValue The value associated with true.
- * @param defaultValue Value to use if the attribute is missing.
- *
- * name != null
- * name is a valid XML identifier
- * trueValue and falseValue
- * are different strings.
- * reader != null
- * reader is not closed
- * reader != null
- * reader is not closed
- * string != null
- * string.length() > 0
- * string to scan.
- *
- * string != null
- * offset < string.length()
- * offset >= 0
- * string to scan.
- * @param end
- * The character where to stop scanning.
- * This character is not scanned.
- *
- * string != null
- * end <= string.length()
- * offset < end
- * offset >= 0
- * string to scan.
- * @param end
- * The character where to stop scanning.
- * This character is not scanned.
- * @param startingLineNumber
- * The line number of the first line in the data.
- *
- * string != null
- * end <= string.length()
- * offset < end
- * offset >= 0
- * string to scan.
- * @param end
- * The character where to stop scanning.
- * This character is not scanned.
- *
- * input != null
- * end <= input.length
- * offset < end
- * offset >= 0
- * string to scan.
- * @param end
- * The character where to stop scanning.
- * This character is not scanned.
- * @param startingLineNumber
- * The line number of the first line in the data.
- *
- * input != null
- * end <= input.length
- * offset < end
- * offset >= 0
- * child != null
- * child is a child element of the receiver
- * name != null
- * name is a valid XML identifier
- * null
- * - * You should override this method when subclassing XMLElement. - */ - protected XMLElement createAnotherElement() - { - return new XMLElement(this.entities, - this.ignoreWhitespace, - false, - this.ignoreCase); - } - - - /** - * Changes the content string. - * - * @param content - * The new content string. - */ - public void setContent(String content) - { + public void setContent(String content) { this.content = content; } /** - * Changes the name of the element. + * Returns true if the element equals another element. * - * @param name - * The new name. - * - *
name != null
- * name is a valid XML identifier
- * writer != null
- * writer is not closed
- * writer != null
- * writer is not closed
- * str != null
- * result.
- *
- * @param result
- * The buffer in which the scanned identifier will be put.
- *
- * result != null
- * result.
- *
- * @return the next character following the whitespace.
- *
- * result != null
- * string.
- *
- * string != null
- * data.
- *
- * data != null
- * buf.
- *
- * buf != null
- * bracketLevel >= 0
- * literal != null
- * elt != null
- * buf.
- *
- * @param buf Where to put the entity value.
- *
- * buf != null
- * ch != '\0'
- * name != null
- * name != null
- * value != null
- * context != null
- * context.length() > 0
- * charSet != null
- * charSet.length() > 0
- * name != null
- * name.length() > 0
- * NO_LINE if the line number is unknown.
- *
- * lineNumber > 0 || lineNumber == NO_LINE
- * message != null
- * message != null
- * lineNumber > 0
- * NO_LINE if the line number is
- * unknown.
- *
- * @see processing.xml.XMLParseException#NO_LINE
- */
- public int getLineNumber()
- {
- return this.lineNumber;
- }
+ /**
+ * Creates a new exception.
+ *
+ * @param systemID the system ID from where the data came
+ * @param lineNr the line number in the XML data where the exception
+ * occurred.
+ * @param msg the message of the exception.
+ */
+ public XMLParseException(String systemID,
+ int lineNr,
+ String msg)
+ {
+ super(systemID, lineNr, null, msg, true);
+ }
}
diff --git a/xml/src/processing/xml/XMLUtil.java b/xml/src/processing/xml/XMLUtil.java
new file mode 100644
index 000000000..261019b13
--- /dev/null
+++ b/xml/src/processing/xml/XMLUtil.java
@@ -0,0 +1,756 @@
+/* XMLUtil.java NanoXML/Java
+ *
+ * $Revision: 1.5 $
+ * $Date: 2002/02/03 21:19:38 $
+ * $Name: RELEASE_2_2_1 $
+ *
+ * This file is part of NanoXML 2 for Java.
+ * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from the
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+package processing.xml;
+
+
+import java.io.IOException;
+import java.io.Reader;
+
+
+/**
+ * Utility methods for NanoXML.
+ *
+ * @author Marc De Scheemaecker
+ * @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
+ */
+class XMLUtil
+{
+
+ /**
+ * Skips the remainder of a comment.
+ * It is assumed that <!- is already read.
+ *
+ * @param reader the reader
+ *
+ * @throws java.io.IOException
+ * if an error occurred reading the data
+ */
+ static void skipComment(StdXMLReader reader)
+ throws IOException,
+ XMLParseException
+ {
+ if (reader.read() != '-') {
+ XMLUtil.errorExpectedInput(reader.getSystemID(),
+ reader.getLineNr(),
+ "