mirror of
https://github.com/esp8266/Arduino.git
synced 2025-08-12 20:49:16 +03:00
632 lines
18 KiB
Java
632 lines
18 KiB
Java
/* NonValidator.java NanoXML/Java
|
|
*
|
|
* $Revision: 1.4 $
|
|
* $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.Reader;
|
|
import java.io.StringReader;
|
|
import java.util.Enumeration;
|
|
import java.util.Hashtable;
|
|
import java.util.Properties;
|
|
import java.util.Stack;
|
|
|
|
|
|
/**
|
|
* XMLValidator implementation based on NonValidator (which implemented
|
|
* IXMLValidator in the original NanoXML).
|
|
* This implementation processes the DTD and handles entity definitions.
|
|
* It does not do any validation itself.
|
|
*
|
|
* @author Marc De Scheemaecker
|
|
* @author processing.org
|
|
*/
|
|
public class XMLValidator
|
|
{
|
|
|
|
/**
|
|
* The parameter entity resolver.
|
|
*/
|
|
protected XMLEntityResolver parameterEntityResolver;
|
|
|
|
|
|
/**
|
|
* Contains the default values for attributes for the different element
|
|
* types.
|
|
*/
|
|
protected Hashtable<String, Properties> attributeDefaultValues;
|
|
|
|
|
|
/**
|
|
* The stack of elements to be processed.
|
|
*/
|
|
protected Stack<Properties> currentElements;
|
|
|
|
|
|
/**
|
|
* Creates the "validator".
|
|
*/
|
|
public XMLValidator()
|
|
{
|
|
this.attributeDefaultValues = new Hashtable<String, Properties>();
|
|
this.currentElements = new Stack<Properties>();
|
|
this.parameterEntityResolver = new XMLEntityResolver();
|
|
}
|
|
|
|
|
|
/**
|
|
* Cleans up the object when it's destroyed.
|
|
*/
|
|
protected void finalize()
|
|
throws Throwable
|
|
{
|
|
this.parameterEntityResolver = null;
|
|
this.attributeDefaultValues.clear();
|
|
this.attributeDefaultValues = null;
|
|
this.currentElements.clear();
|
|
this.currentElements = null;
|
|
super.finalize();
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the parameter entity resolver.
|
|
*
|
|
* @param resolver the entity resolver.
|
|
*/
|
|
public void setParameterEntityResolver(XMLEntityResolver resolver)
|
|
{
|
|
this.parameterEntityResolver = resolver;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the parameter entity resolver.
|
|
*
|
|
* @return the entity resolver.
|
|
*/
|
|
public XMLEntityResolver getParameterEntityResolver()
|
|
{
|
|
return this.parameterEntityResolver;
|
|
}
|
|
|
|
|
|
/**
|
|
* Parses the DTD. The validator object is responsible for reading the
|
|
* full DTD.
|
|
*
|
|
* @param publicID the public ID, which may be null.
|
|
* @param reader the reader to read the DTD from.
|
|
* @param entityResolver the entity resolver.
|
|
* @param external true if the DTD is external.
|
|
*
|
|
* @throws java.lang.Exception
|
|
* If something went wrong.
|
|
*/
|
|
public void parseDTD(String publicID,
|
|
StdXMLReader reader,
|
|
XMLEntityResolver entityResolver,
|
|
boolean external)
|
|
throws Exception
|
|
{
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
int origLevel = reader.getStreamLevel();
|
|
|
|
for (;;) {
|
|
String str = XMLUtil.read(reader, '%');
|
|
char ch = str.charAt(0);
|
|
|
|
if (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
continue;
|
|
} else if (ch == '<') {
|
|
this.processElement(reader, entityResolver);
|
|
} else if (ch == ']') {
|
|
return; // end internal DTD
|
|
} else {
|
|
XMLUtil.errorInvalidInput(reader.getSystemID(),
|
|
reader.getLineNr(),
|
|
str);
|
|
}
|
|
|
|
do {
|
|
ch = reader.read();
|
|
|
|
if (external && (reader.getStreamLevel() < origLevel)) {
|
|
reader.unread(ch);
|
|
return; // end external DTD
|
|
}
|
|
} while ((ch == ' ') || (ch == '\t') || (ch == '\n')
|
|
|| (ch == '\r'));
|
|
|
|
reader.unread(ch);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Processes an element in the DTD.
|
|
*
|
|
* @param reader the reader to read data from.
|
|
* @param entityResolver the entity resolver.
|
|
*
|
|
* @throws java.lang.Exception
|
|
* If something went wrong.
|
|
*/
|
|
protected void processElement(StdXMLReader reader,
|
|
XMLEntityResolver entityResolver)
|
|
throws Exception
|
|
{
|
|
String str = XMLUtil.read(reader, '%');
|
|
char ch = str.charAt(0);
|
|
|
|
if (ch != '!') {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
|
|
switch (ch) {
|
|
case '-':
|
|
XMLUtil.skipComment(reader);
|
|
break;
|
|
|
|
case '[':
|
|
this.processConditionalSection(reader, entityResolver);
|
|
break;
|
|
|
|
case 'E':
|
|
this.processEntity(reader, entityResolver);
|
|
break;
|
|
|
|
case 'A':
|
|
this.processAttList(reader, entityResolver);
|
|
break;
|
|
|
|
default:
|
|
XMLUtil.skipTag(reader);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Processes a conditional section.
|
|
*
|
|
* @param reader the reader to read data from.
|
|
* @param entityResolver the entity resolver.
|
|
*
|
|
* @throws java.lang.Exception
|
|
* If something went wrong.
|
|
*/
|
|
protected void processConditionalSection(StdXMLReader reader,
|
|
XMLEntityResolver entityResolver)
|
|
throws Exception
|
|
{
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
|
|
String str = XMLUtil.read(reader, '%');
|
|
char ch = str.charAt(0);
|
|
|
|
if (ch != 'I') {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
|
|
switch (ch) {
|
|
case 'G':
|
|
this.processIgnoreSection(reader, entityResolver);
|
|
return;
|
|
|
|
case 'N':
|
|
break;
|
|
|
|
default:
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
if (! XMLUtil.checkLiteral(reader, "CLUDE")) {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
|
|
if (ch != '[') {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
Reader subreader = new CDATAReader(reader);
|
|
StringBuffer buf = new StringBuffer(1024);
|
|
|
|
for (;;) {
|
|
int ch2 = subreader.read();
|
|
|
|
if (ch2 < 0) {
|
|
break;
|
|
}
|
|
|
|
buf.append((char) ch2);
|
|
}
|
|
|
|
subreader.close();
|
|
reader.startNewStream(new StringReader(buf.toString()));
|
|
}
|
|
|
|
|
|
/**
|
|
* Processes an ignore section.
|
|
*
|
|
* @param reader the reader to read data from.
|
|
* @param entityResolver the entity resolver.
|
|
*
|
|
* @throws java.lang.Exception
|
|
* If something went wrong.
|
|
*/
|
|
protected void processIgnoreSection(StdXMLReader reader,
|
|
XMLEntityResolver entityResolver)
|
|
throws Exception
|
|
{
|
|
if (! XMLUtil.checkLiteral(reader, "NORE")) {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
|
|
String str = XMLUtil.read(reader, '%');
|
|
char ch = str.charAt(0);
|
|
|
|
if (ch != '[') {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
Reader subreader = new CDATAReader(reader);
|
|
subreader.close();
|
|
}
|
|
|
|
|
|
/**
|
|
* Processes an ATTLIST element.
|
|
*
|
|
* @param reader the reader to read data from.
|
|
* @param entityResolver the entity resolver.
|
|
*
|
|
* @throws java.lang.Exception
|
|
* If something went wrong.
|
|
*/
|
|
protected void processAttList(StdXMLReader reader,
|
|
XMLEntityResolver entityResolver)
|
|
throws Exception
|
|
{
|
|
if (! XMLUtil.checkLiteral(reader, "TTLIST")) {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
String str = XMLUtil.read(reader, '%');
|
|
char ch = str.charAt(0);
|
|
while (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
}
|
|
reader.unread(ch);
|
|
String elementName = XMLUtil.scanIdentifier(reader);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
while (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
}
|
|
|
|
Properties props = new Properties();
|
|
|
|
while (ch != '>') {
|
|
reader.unread(ch);
|
|
String attName = XMLUtil.scanIdentifier(reader);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
while (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
}
|
|
|
|
if (ch == '(') {
|
|
while (ch != ')') {
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
while (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
}
|
|
}
|
|
} else {
|
|
reader.unread(ch);
|
|
XMLUtil.scanIdentifier(reader);
|
|
}
|
|
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
while (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
}
|
|
|
|
if (ch == '#') {
|
|
str = XMLUtil.scanIdentifier(reader);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
|
|
if (! str.equals("FIXED")) {
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
while (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
} else {
|
|
reader.unread(ch);
|
|
}
|
|
|
|
String value = XMLUtil.scanString(reader, '%',
|
|
this.parameterEntityResolver);
|
|
props.put(attName, value);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
while (ch == '%') {
|
|
XMLUtil.processEntity(str, reader,
|
|
this.parameterEntityResolver);
|
|
str = XMLUtil.read(reader, '%');
|
|
ch = str.charAt(0);
|
|
}
|
|
}
|
|
|
|
if (! props.isEmpty()) {
|
|
this.attributeDefaultValues.put(elementName, props);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Processes an ENTITY element.
|
|
*
|
|
* @param reader the reader to read data from.
|
|
* @param entityResolver the entity resolver.
|
|
*
|
|
* @throws java.lang.Exception
|
|
* If something went wrong.
|
|
*/
|
|
protected void processEntity(StdXMLReader reader,
|
|
XMLEntityResolver entityResolver)
|
|
throws Exception
|
|
{
|
|
if (! XMLUtil.checkLiteral(reader, "NTITY")) {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
char ch = XMLUtil.readChar(reader, '\0');
|
|
|
|
if (ch == '%') {
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
entityResolver = this.parameterEntityResolver;
|
|
} else {
|
|
reader.unread(ch);
|
|
}
|
|
|
|
String key = XMLUtil.scanIdentifier(reader);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
ch = XMLUtil.readChar(reader, '%');
|
|
String systemID = null;
|
|
String publicID = null;
|
|
|
|
switch (ch) {
|
|
case 'P':
|
|
if (! XMLUtil.checkLiteral(reader, "UBLIC")) {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
publicID = XMLUtil.scanString(reader, '%',
|
|
this.parameterEntityResolver);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
systemID = XMLUtil.scanString(reader, '%',
|
|
this.parameterEntityResolver);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
XMLUtil.readChar(reader, '%');
|
|
break;
|
|
|
|
case 'S':
|
|
if (! XMLUtil.checkLiteral(reader, "YSTEM")) {
|
|
XMLUtil.skipTag(reader);
|
|
return;
|
|
}
|
|
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
systemID = XMLUtil.scanString(reader, '%',
|
|
this.parameterEntityResolver);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
XMLUtil.readChar(reader, '%');
|
|
break;
|
|
|
|
case '"':
|
|
case '\'':
|
|
reader.unread(ch);
|
|
String value = XMLUtil.scanString(reader, '%',
|
|
this.parameterEntityResolver);
|
|
entityResolver.addInternalEntity(key, value);
|
|
XMLUtil.skipWhitespace(reader, null);
|
|
XMLUtil.readChar(reader, '%');
|
|
break;
|
|
|
|
default:
|
|
XMLUtil.skipTag(reader);
|
|
}
|
|
|
|
if (systemID != null) {
|
|
entityResolver.addExternalEntity(key, publicID, systemID);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Indicates that an element has been started.
|
|
*
|
|
* @param name the name of the element.
|
|
* @param systemId the system ID of the XML data of the element.
|
|
* @param lineNr the line number in the XML data of the element.
|
|
*/
|
|
public void elementStarted(String name,
|
|
String systemId,
|
|
int lineNr)
|
|
{
|
|
Properties attribs
|
|
= (Properties) this.attributeDefaultValues.get(name);
|
|
|
|
if (attribs == null) {
|
|
attribs = new Properties();
|
|
} else {
|
|
attribs = (Properties) attribs.clone();
|
|
}
|
|
|
|
this.currentElements.push(attribs);
|
|
}
|
|
|
|
|
|
/**
|
|
* Indicates that the current element has ended.
|
|
*
|
|
* @param name the name of the element.
|
|
* @param systemId the system ID of the XML data of the element.
|
|
* @param lineNr the line number in the XML data of the element.
|
|
*/
|
|
public void elementEnded(String name,
|
|
String systemId,
|
|
int lineNr)
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
|
|
/**
|
|
* This method is called when the attributes of an XML element have been
|
|
* processed.
|
|
* If there are attributes with a default value which have not been
|
|
* specified yet, they have to be put into <I>extraAttributes</I>.
|
|
*
|
|
* @param name the name of the element.
|
|
* @param extraAttributes where to put extra attributes.
|
|
* @param systemId the system ID of the XML data of the element.
|
|
* @param lineNr the line number in the XML data of the element.
|
|
*/
|
|
public void elementAttributesProcessed(String name,
|
|
Properties extraAttributes,
|
|
String systemId,
|
|
int lineNr)
|
|
{
|
|
Properties props = (Properties) this.currentElements.pop();
|
|
Enumeration<?> en = props.keys();
|
|
|
|
while (en.hasMoreElements()) {
|
|
String key = (String) en.nextElement();
|
|
extraAttributes.put(key, props.get(key));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Indicates that an attribute has been added to the current element.
|
|
*
|
|
* @param key the name of the attribute.
|
|
* @param value the value of the attribute.
|
|
* @param systemId the system ID of the XML data of the element.
|
|
* @param lineNr the line number in the XML data of the element.
|
|
*/
|
|
public void attributeAdded(String key,
|
|
String value,
|
|
String systemId,
|
|
int lineNr)
|
|
{
|
|
Properties props = (Properties) this.currentElements.peek();
|
|
|
|
if (props.containsKey(key)) {
|
|
props.remove(key);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Indicates that a new #PCDATA element has been encountered.
|
|
*
|
|
* @param systemId the system ID of the XML data of the element.
|
|
* @param lineNr the line number in the XML data of the element.
|
|
*/
|
|
public void PCDataAdded(String systemId,
|
|
int lineNr)
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
}
|