package gnu.xml.aelfred2;
import gnu.java.security.action.GetPropertyAction;
import java.io.BufferedInputStream;
import java.io.CharConversionException;
import java.io.EOFException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessController;
import java.util.Iterator;
import java.util.HashMap;
import java.util.LinkedList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
final class XmlParser
{
private final static boolean USE_CHEATS = true;
public final static int CONTENT_UNDECLARED = 0;
public final static int CONTENT_ANY = 1;
public final static int CONTENT_EMPTY = 2;
public final static int CONTENT_MIXED = 3;
public final static int CONTENT_ELEMENTS = 4;
public final static int ENTITY_UNDECLARED = 0;
public final static int ENTITY_INTERNAL = 1;
public final static int ENTITY_NDATA = 2;
public final static int ENTITY_TEXT = 3;
private final static int ENCODING_EXTERNAL = 0;
private final static int ENCODING_UTF_8 = 1;
private final static int ENCODING_ISO_8859_1 = 2;
private final static int ENCODING_UCS_2_12 = 3;
private final static int ENCODING_UCS_2_21 = 4;
private final static int ENCODING_UCS_4_1234 = 5;
private final static int ENCODING_UCS_4_4321 = 6;
private final static int ENCODING_UCS_4_2143 = 7;
private final static int ENCODING_UCS_4_3412 = 8;
private final static int ENCODING_ASCII = 9;
public final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30;
public final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31;
public final static int ATTRIBUTE_DEFAULT_IMPLIED = 32;
public final static int ATTRIBUTE_DEFAULT_REQUIRED = 33;
public final static int ATTRIBUTE_DEFAULT_FIXED = 34;
private final static int INPUT_NONE = 0;
private final static int INPUT_INTERNAL = 1;
private final static int INPUT_STREAM = 3;
private final static int INPUT_READER = 5;
private final static int LIT_ENTITY_REF = 2;
private final static int LIT_NORMALIZE = 4;
private final static int LIT_ATTRIBUTE = 8;
private final static int LIT_DISABLE_PE = 16;
private final static int LIT_DISABLE_CREF = 32;
private final static int LIT_DISABLE_EREF = 64;
private final static int LIT_PUBID = 256;
private final static int CONTEXT_NORMAL = 0;
private final static int CONTEXT_LITERAL = 1;
static boolean uriWarnings;
static
{
String key = "gnu.xml.aelfred2.XmlParser.uriWarnings";
GetPropertyAction a = new GetPropertyAction(key);
uriWarnings = "true".equals(AccessController.doPrivileged(a));
}
private SAXDriver handler;
private Reader reader; private InputStream is; private int line; private int column; private int sourceType; private LinkedList inputStack; private URLConnection externalEntity; private int encoding; private int currentByteCount; private InputSource scratch;
private char[] readBuffer;
private int readBufferPos;
private int readBufferLength;
private int readBufferOverflow;
private final static int READ_BUFFER_MAX = 16384;
private byte[] rawReadBuffer;
private static int DATA_BUFFER_INITIAL = 4096;
private char[] dataBuffer;
private int dataBufferPos;
private static int NAME_BUFFER_INITIAL = 1024;
private char[] nameBuffer;
private int nameBufferPos;
private boolean docIsStandalone;
private HashMap elementInfo;
private HashMap entityInfo;
private HashMap notationInfo;
private boolean skippedPE;
private String currentElement;
private int currentElementContent;
private LinkedList entityStack;
private boolean inLiteral;
private boolean expandPE;
private boolean peIsError;
private boolean doReport;
private final static int SYMBOL_TABLE_LENGTH = 2039;
private Object[][] symbolTable;
private String[] tagAttributes;
private int tagAttributePos;
private boolean sawCR;
private boolean inCDATA;
private static final int XML_10 = 0;
private static final int XML_11 = 1;
private int xmlVersion = XML_10;
XmlParser()
{
}
void setHandler(SAXDriver handler)
{
this.handler = handler;
}
void doParse(String systemId, String publicId, Reader reader,
InputStream stream, String encoding)
throws Exception
{
if (handler == null)
{
throw new IllegalStateException("no callback handler");
}
initializeVariables();
setInternalEntity("amp", "&");
setInternalEntity("lt", "<");
setInternalEntity("gt", ">");
setInternalEntity("apos", "'");
setInternalEntity("quot", """);
try
{
handler.startDocument();
pushURL(false, "[document]",
new ExternalIdentifiers(publicId, systemId, null),
reader, stream, encoding, false);
parseDocument();
}
catch (EOFException e)
{
error("empty document, with no root element.");
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException e)
{
}
}
if (stream != null)
{
try
{
stream.close();
}
catch (IOException e)
{
}
}
if (is != null)
{
try
{
is.close();
}
catch (IOException e)
{
}
}
scratch = null;
}
}
private void error(String message, String textFound, String textExpected)
throws SAXException
{
if (textFound != null)
{
message = message + " (found \"" + textFound + "\")";
}
if (textExpected != null)
{
message = message + " (expected \"" + textExpected + "\")";
}
handler.fatal(message);
throw new SAXException(message);
}
private void error(String message, char textFound, String textExpected)
throws SAXException
{
error(message, new Character(textFound).toString(), textExpected);
}
private void error(String message)
throws SAXException
{
handler.fatal(message);
}
private void parseDocument()
throws Exception
{
try
{ boolean sawDTD = parseProlog();
require('<');
parseElement(!sawDTD);
}
catch (EOFException ee)
{ error("premature end of file", "[EOF]", null);
}
try
{
parseMisc(); char c = readCh(); error("unexpected characters after document end", c, null);
}
catch (EOFException e)
{
return;
}
}
static final char[] startDelimComment = { '<', '!', '-', '-' };
static final char[] endDelimComment = { '-', '-' };
private void parseComment()
throws Exception
{
char c;
boolean saved = expandPE;
expandPE = false;
parseUntil(endDelimComment);
require('>');
expandPE = saved;
handler.comment(dataBuffer, 0, dataBufferPos);
dataBufferPos = 0;
}
static final char[] startDelimPI = { '<', '?' };
static final char[] endDelimPI = { '?', '>' };
private void parsePI()
throws SAXException, IOException
{
String name;
boolean saved = expandPE;
expandPE = false;
name = readNmtoken(true);
if (name.indexOf(':') >= 0)
{
error("Illegal character(':') in processing instruction name ",
name, null);
}
if ("xml".equalsIgnoreCase(name))
{
error("Illegal processing instruction target", name, null);
}
if (!tryRead(endDelimPI))
{
requireWhitespace();
parseUntil(endDelimPI);
}
expandPE = saved;
handler.processingInstruction(name, dataBufferToString());
}
static final char[] endDelimCDATA = { ']', ']', '>' };
private boolean isDirtyCurrentElement;
private void parseCDSect()
throws Exception
{
parseUntil(endDelimCDATA);
dataBufferFlush();
}
private boolean parseProlog()
throws Exception
{
parseMisc();
if (tryRead("<!DOCTYPE"))
{
parseDoctypedecl();
parseMisc();
return true;
}
return false;
}
private void checkLegalVersion(String version)
throws SAXException
{
int len = version.length();
for (int i = 0; i < len; i++)
{
char c = version.charAt(i);
if ('0' <= c && c <= '9')
{
continue;
}
if (c == '_' || c == '.' || c == ':' || c == '-')
{
continue;
}
if ('a' <= c && c <= 'z')
{
continue;
}
if ('A' <= c && c <= 'Z')
{
continue;
}
error ("illegal character in version", version, "1.0");
}
}
private String parseXMLDecl(boolean ignoreEncoding)
throws SAXException, IOException
{
String version;
String encodingName = null;
String standalone = null;
int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
String inputEncoding = null;
switch (this.encoding)
{
case ENCODING_EXTERNAL:
case ENCODING_UTF_8:
inputEncoding = "UTF-8";
break;
case ENCODING_ISO_8859_1:
inputEncoding = "ISO-8859-1";
break;
case ENCODING_UCS_2_12:
inputEncoding = "UTF-16BE";
break;
case ENCODING_UCS_2_21:
inputEncoding = "UTF-16LE";
break;
}
require("version");
parseEq();
checkLegalVersion(version = readLiteral(flags));
if (!version.equals("1.0"))
{
if (version.equals("1.1"))
{
handler.warn("expected XML version 1.0, not: " + version);
xmlVersion = XML_11;
}
else
{
error("illegal XML version", version, "1.0 or 1.1");
}
}
else
{
xmlVersion = XML_10;
}
boolean white = tryWhitespace();
if (tryRead("encoding"))
{
if (!white)
{
error("whitespace required before 'encoding='");
}
parseEq();
encodingName = readLiteral(flags);
if (!ignoreEncoding)
{
setupDecoding(encodingName);
}
}
if (encodingName != null)
{
white = tryWhitespace();
}
if (tryRead("standalone"))
{
if (!white)
{
error("whitespace required before 'standalone='");
}
parseEq();
standalone = readLiteral(flags);
if ("yes".equals(standalone))
{
docIsStandalone = true;
}
else if (!"no".equals(standalone))
{
error("standalone flag must be 'yes' or 'no'");
}
}
skipWhitespace();
require("?>");
if (inputEncoding == null)
{
inputEncoding = encodingName;
}
handler.xmlDecl(version, encodingName, docIsStandalone,
inputEncoding);
return encodingName;
}
private String parseTextDecl(boolean ignoreEncoding)
throws SAXException, IOException
{
String encodingName = null;
int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
if (tryRead ("version"))
{
String version;
parseEq();
checkLegalVersion(version = readLiteral(flags));
if (version.equals("1.1"))
{
if (xmlVersion == XML_10)
{
error("external subset has later version number.", "1.0",
version);
}
handler.warn("expected XML version 1.0, not: " + version);
xmlVersion = XML_11;
}
else if (!version.equals("1.0"))
{
error("illegal XML version", version, "1.0 or 1.1");
}
requireWhitespace();
}
require("encoding");
parseEq();
encodingName = readLiteral(flags);
if (!ignoreEncoding)
{
setupDecoding(encodingName);
}
skipWhitespace();
require("?>");
return encodingName;
}
private void setupDecoding(String encodingName)
throws SAXException, IOException
{
encodingName = encodingName.toUpperCase();
if (encoding == ENCODING_UTF_8 || encoding == ENCODING_EXTERNAL)
{
if (encodingName.equals("ISO-8859-1")
|| encodingName.equals("8859_1")
|| encodingName.equals("ISO8859_1"))
{
encoding = ENCODING_ISO_8859_1;
return;
}
else if (encodingName.equals("US-ASCII")
|| encodingName.equals("ASCII"))
{
encoding = ENCODING_ASCII;
return;
}
else if (encodingName.equals("UTF-8")
|| encodingName.equals("UTF8"))
{
encoding = ENCODING_UTF_8;
return;
}
else if (encoding != ENCODING_EXTERNAL)
{
throw new UnsupportedEncodingException(encodingName);
}
}
if (encoding == ENCODING_UCS_2_12 || encoding == ENCODING_UCS_2_21)
{
if (!(encodingName.equals("ISO-10646-UCS-2")
|| encodingName.equals("UTF-16")
|| encodingName.equals("UTF-16BE")
|| encodingName.equals("UTF-16LE")))
{
error("unsupported Unicode encoding", encodingName, "UTF-16");
}
return;
}
if (encoding == ENCODING_UCS_4_1234
|| encoding == ENCODING_UCS_4_4321
|| encoding == ENCODING_UCS_4_2143
|| encoding == ENCODING_UCS_4_3412)
{
if (!encodingName.equals("ISO-10646-UCS-4"))
{
error("unsupported 32-bit encoding", encodingName,
"ISO-10646-UCS-4");
}
return;
}
if (encodingName.equals("UTF-16BE"))
{
encoding = ENCODING_UCS_2_12;
return;
}
if (encodingName.equals("UTF-16LE"))
{
encoding = ENCODING_UCS_2_21;
return;
}
if (encodingName.equals("UTF-16")
|| encodingName.equals("ISO-10646-UCS-2"))
{
encodingName = "Unicode";
}
reader = new InputStreamReader(is, encodingName);
sourceType = INPUT_READER;
}
private void parseMisc()
throws Exception
{
while (true)
{
skipWhitespace();
if (tryRead(startDelimPI))
{
parsePI();
}
else if (tryRead(startDelimComment))
{
parseComment();
}
else
{
return;
}
}
}
private void parseDoctypedecl()
throws Exception
{
String rootName;
ExternalIdentifiers ids;
requireWhitespace();
rootName = readNmtoken(true);
skipWhitespace();
ids = readExternalIds(false, true);
handler.doctypeDecl(rootName, ids.publicId, ids.systemId);
skipWhitespace();
if (tryRead('['))
{
while (true)
{
doReport = expandPE = true;
skipWhitespace();
doReport = expandPE = false;
if (tryRead(']'))
{
break; }
else
{
peIsError = expandPE = true;
parseMarkupdecl();
peIsError = expandPE = false;
}
}
}
skipWhitespace();
require('>');
InputSource subset;
if (ids.systemId == null)
{
subset = handler.getExternalSubset(rootName,
handler.getSystemId());
}
else
{
subset = null;
}
if (ids.systemId != null || subset != null)
{
pushString(null, ">");
if (ids.systemId != null)
{
pushURL(true, "[dtd]", ids, null, null, null, true);
}
else
{
handler.warn("modifying document by adding external subset");
pushURL(true, "[dtd]",
new ExternalIdentifiers(subset.getPublicId(),
subset.getSystemId(),
null),
subset.getCharacterStream(),
subset.getByteStream(),
subset.getEncoding(),
false);
}
while (true)
{
doReport = expandPE = true;
skipWhitespace();
doReport = expandPE = false;
if (tryRead('>'))
{
break;
}
else
{
expandPE = true;
parseMarkupdecl();
expandPE = false;
}
}
if (inputStack.size() != 1)
{
error("external subset has unmatched '>'");
}
}
handler.endDoctype();
expandPE = false;
doReport = true;
}
private void parseMarkupdecl()
throws Exception
{
char[] saved = null;
boolean savedPE = expandPE;
require('<');
unread('<');
expandPE = false;
if (tryRead("<!ELEMENT"))
{
saved = readBuffer;
expandPE = savedPE;
parseElementDecl();
}
else if (tryRead("<!ATTLIST"))
{
saved = readBuffer;
expandPE = savedPE;
parseAttlistDecl();
}
else if (tryRead("<!ENTITY"))
{
saved = readBuffer;
expandPE = savedPE;
parseEntityDecl();
}
else if (tryRead("<!NOTATION"))
{
saved = readBuffer;
expandPE = savedPE;
parseNotationDecl();
}
else if (tryRead(startDelimPI))
{
saved = readBuffer;
expandPE = savedPE;
parsePI();
}
else if (tryRead(startDelimComment))
{
saved = readBuffer;
expandPE = savedPE;
parseComment();
}
else if (tryRead("<!["))
{
saved = readBuffer;
expandPE = savedPE;
if (inputStack.size() > 0)
{
parseConditionalSect(saved);
}
else
{
error("conditional sections illegal in internal subset");
}
}
else
{
error("expected markup declaration");
}
if (readBuffer != saved)
{
handler.verror("Illegal Declaration/PE nesting");
}
}
private void parseElement(boolean maybeGetSubset)
throws Exception
{
String gi;
char c;
int oldElementContent = currentElementContent;
String oldElement = currentElement;
ElementDecl element;
tagAttributePos = 0;
gi = readNmtoken(true);
if (maybeGetSubset)
{
InputSource subset = handler.getExternalSubset(gi,
handler.getSystemId());
if (subset != null)
{
String publicId = subset.getPublicId();
String systemId = subset.getSystemId();
handler.warn("modifying document by adding DTD");
handler.doctypeDecl(gi, publicId, systemId);
pushString(null, ">");
pushURL(true, "[dtd]",
new ExternalIdentifiers(publicId, systemId, null),
subset.getCharacterStream(),
subset.getByteStream(),
subset.getEncoding(),
false);
while (true)
{
doReport = expandPE = true;
skipWhitespace();
doReport = expandPE = false;
if (tryRead('>'))
{
break;
}
else
{
expandPE = true;
parseMarkupdecl();
expandPE = false;
}
}
if (inputStack.size() != 1)
{
error("external subset has unmatched '>'");
}
handler.endDoctype();
}
}
currentElement = gi;
element = (ElementDecl) elementInfo.get(gi);
currentElementContent = getContentType(element, CONTENT_ANY);
boolean white = tryWhitespace();
c = readCh();
while (c != '/' && c != '>')
{
unread(c);
if (!white)
{
error("need whitespace between attributes");
}
parseAttribute(gi);
white = tryWhitespace();
c = readCh();
}
Iterator atts = declaredAttributes(element);
if (atts != null)
{
String aname;
loop:
while (atts.hasNext())
{
aname = (String) atts.next();
for (int i = 0; i < tagAttributePos; i++)
{
if (tagAttributes[i] == aname)
{
continue loop;
}
}
String value = getAttributeDefaultValue(gi, aname);
if (value == null)
{
continue;
}
handler.attribute(aname, value, false);
}
}
switch (c)
{
case '>':
handler.startElement(gi);
parseContent();
break;
case '/':
require('>');
handler.startElement(gi);
handler.endElement(gi);
break;
}
currentElement = oldElement;
currentElementContent = oldElementContent;
}
private void parseAttribute(String name)
throws Exception
{
String aname;
String type;
String value;
int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF;
aname = readNmtoken(true);
type = getAttributeType(name, aname);
parseEq();
if (handler.stringInterning)
{
if (type == "CDATA" || type == null)
{
value = readLiteral(flags);
}
else
{
value = readLiteral(flags | LIT_NORMALIZE);
}
}
else
{
if (type.equals("CDATA") || type == null)
{
value = readLiteral(flags);
}
else
{
value = readLiteral(flags | LIT_NORMALIZE);
}
}
for (int i = 0; i < tagAttributePos; i++)
{
if (aname.equals(tagAttributes [i]))
{
error("duplicate attribute", aname, null);
}
}
handler.attribute(aname, value, true);
dataBufferPos = 0;
if (tagAttributePos == tagAttributes.length)
{
String newAttrib[] = new String[tagAttributes.length * 2];
System.arraycopy(tagAttributes, 0, newAttrib, 0, tagAttributePos);
tagAttributes = newAttrib;
}
tagAttributes[tagAttributePos++] = aname;
}
private void parseEq()
throws SAXException, IOException
{
skipWhitespace();
require('=');
skipWhitespace();
}
private void parseETag()
throws Exception
{
require(currentElement);
skipWhitespace();
require('>');
handler.endElement(currentElement);
}
private void parseContent()
throws Exception
{
char c;
while (true)
{
parseCharData();
c = readCh();
switch (c)
{
case '&': c = readCh();
if (c == '#')
{
parseCharRef();
}
else
{
unread(c);
parseEntityRef(true);
}
isDirtyCurrentElement = true;
break;
case '<': dataBufferFlush();
c = readCh();
switch (c)
{
case '!': c = readCh();
switch (c)
{
case '-': require('-');
isDirtyCurrentElement = false;
parseComment();
break;
case '[': isDirtyCurrentElement = false;
require("CDATA[");
handler.startCDATA();
inCDATA = true;
parseCDSect();
inCDATA = false;
handler.endCDATA();
break;
default:
error("expected comment or CDATA section", c, null);
break;
}
break;
case '?': isDirtyCurrentElement = false;
parsePI();
break;
case '/': isDirtyCurrentElement = false;
parseETag();
return;
default: isDirtyCurrentElement = false;
unread(c);
parseElement(false);
break;
}
}
}
}
private void parseElementDecl()
throws Exception
{
String name;
requireWhitespace();
name = readNmtoken(true);
requireWhitespace();
parseContentspec(name);
skipWhitespace();
require('>');
}
private void parseContentspec(String name)
throws Exception
{
if (tryRead("EMPTY"))
{
setElement(name, CONTENT_EMPTY, null, null);
if (!skippedPE)
{
handler.getDeclHandler().elementDecl(name, "EMPTY");
}
return;
}
else if (tryRead("ANY"))
{
setElement(name, CONTENT_ANY, null, null);
if (!skippedPE)
{
handler.getDeclHandler().elementDecl(name, "ANY");
}
return;
}
else
{
String model;
char[] saved;
require('(');
saved = readBuffer;
dataBufferAppend('(');
skipWhitespace();
if (tryRead("#PCDATA"))
{
dataBufferAppend("#PCDATA");
parseMixed(saved);
model = dataBufferToString();
setElement(name, CONTENT_MIXED, model, null);
}
else
{
parseElements(saved);
model = dataBufferToString();
setElement(name, CONTENT_ELEMENTS, model, null);
}
if (!skippedPE)
{
handler.getDeclHandler().elementDecl(name, model);
}
}
}
private void parseElements(char[] saved)
throws Exception
{
char c;
char sep;
skipWhitespace();
parseCp();
skipWhitespace();
c = readCh();
switch (c)
{
case ')':
if (readBuffer != saved)
{
handler.verror("Illegal Group/PE nesting");
}
dataBufferAppend(')');
c = readCh();
switch (c)
{
case '*':
case '+':
case '?':
dataBufferAppend(c);
break;
default:
unread(c);
}
return;
case ',': case '|':
sep = c;
dataBufferAppend(c);
break;
default:
error("bad separator in content model", c, null);
return;
}
while (true)
{
skipWhitespace();
parseCp();
skipWhitespace();
c = readCh();
if (c == ')')
{
if (readBuffer != saved)
{
handler.verror("Illegal Group/PE nesting");
}
dataBufferAppend(')');
break;
}
else if (c != sep)
{
error("bad separator in content model", c, null);
return;
}
else
{
dataBufferAppend(c);
}
}
c = readCh();
switch (c)
{
case '?':
case '*':
case '+':
dataBufferAppend(c);
return;
default:
unread(c);
return;
}
}
private void parseCp()
throws Exception
{
if (tryRead('('))
{
dataBufferAppend('(');
parseElements(readBuffer);
}
else
{
dataBufferAppend(readNmtoken(true));
char c = readCh();
switch (c)
{
case '?':
case '*':
case '+':
dataBufferAppend(c);
break;
default:
unread(c);
break;
}
}
}
private void parseMixed(char[] saved)
throws Exception
{
skipWhitespace();
if (tryRead(')'))
{
if (readBuffer != saved)
{
handler.verror("Illegal Group/PE nesting");
}
dataBufferAppend(")*");
tryRead('*');
return;
}
skipWhitespace();
while (!tryRead(")"))
{
require('|');
dataBufferAppend('|');
skipWhitespace();
dataBufferAppend(readNmtoken(true));
skipWhitespace();
}
if (readBuffer != saved)
{
handler.verror("Illegal Group/PE nesting");
}
require('*');
dataBufferAppend(")*");
}
private void parseAttlistDecl()
throws Exception
{
String elementName;
requireWhitespace();
elementName = readNmtoken(true);
boolean white = tryWhitespace();
while (!tryRead('>'))
{
if (!white)
{
error("whitespace required before attribute definition");
}
parseAttDef(elementName);
white = tryWhitespace();
}
}
private void parseAttDef(String elementName)
throws Exception
{
String name;
String type;
String enumer = null;
name = readNmtoken(true);
requireWhitespace();
type = readAttType();
if (handler.stringInterning)
{
if ("ENUMERATION" == type || "NOTATION" == type)
{
enumer = dataBufferToString();
}
}
else
{
if ("ENUMERATION".equals(type) || "NOTATION".equals(type))
{
enumer = dataBufferToString();
}
}
requireWhitespace();
parseDefault(elementName, name, type, enumer);
}
private String readAttType()
throws Exception
{
if (tryRead('('))
{
parseEnumeration(false);
return "ENUMERATION";
}
else
{
String typeString = readNmtoken(true);
if (handler.stringInterning)
{
if ("NOTATION" == typeString)
{
parseNotationType();
return typeString;
}
else if ("CDATA" == typeString
|| "ID" == typeString
|| "IDREF" == typeString
|| "IDREFS" == typeString
|| "ENTITY" == typeString
|| "ENTITIES" == typeString
|| "NMTOKEN" == typeString
|| "NMTOKENS" == typeString)
{
return typeString;
}
}
else
{
if ("NOTATION".equals(typeString))
{
parseNotationType();
return typeString;
}
else if ("CDATA".equals(typeString)
|| "ID".equals(typeString)
|| "IDREF".equals(typeString)
|| "IDREFS".equals(typeString)
|| "ENTITY".equals(typeString)
|| "ENTITIES".equals(typeString)
|| "NMTOKEN".equals(typeString)
|| "NMTOKENS".equals(typeString))
{
return typeString;
}
}
error("illegal attribute type", typeString, null);
return null;
}
}
private void parseEnumeration(boolean isNames)
throws Exception
{
dataBufferAppend('(');
skipWhitespace();
dataBufferAppend(readNmtoken(isNames));
skipWhitespace();
while (!tryRead(')'))
{
require('|');
dataBufferAppend('|');
skipWhitespace();
dataBufferAppend(readNmtoken (isNames));
skipWhitespace();
}
dataBufferAppend(')');
}
private void parseNotationType()
throws Exception
{
requireWhitespace();
require('(');
parseEnumeration(true);
}
private void parseDefault(String elementName, String name,
String type, String enumer)
throws Exception
{
int valueType = ATTRIBUTE_DEFAULT_SPECIFIED;
String value = null;
int flags = LIT_ATTRIBUTE;
boolean saved = expandPE;
String defaultType = null;
if (!skippedPE)
{
flags |= LIT_ENTITY_REF;
if (handler.stringInterning)
{
if ("CDATA" != type)
{
flags |= LIT_NORMALIZE;
}
}
else
{
if (!"CDATA".equals(type))
{
flags |= LIT_NORMALIZE;
}
}
}
expandPE = false;
if (tryRead('#'))
{
if (tryRead("FIXED"))
{
defaultType = "#FIXED";
valueType = ATTRIBUTE_DEFAULT_FIXED;
requireWhitespace();
value = readLiteral(flags);
}
else if (tryRead("REQUIRED"))
{
defaultType = "#REQUIRED";
valueType = ATTRIBUTE_DEFAULT_REQUIRED;
}
else if (tryRead("IMPLIED"))
{
defaultType = "#IMPLIED";
valueType = ATTRIBUTE_DEFAULT_IMPLIED;
}
else
{
error("illegal keyword for attribute default value");
}
}
else
{
value = readLiteral(flags);
}
expandPE = saved;
setAttribute(elementName, name, type, enumer, value, valueType);
if (handler.stringInterning)
{
if ("ENUMERATION" == type)
{
type = enumer;
}
else if ("NOTATION" == type)
{
type = "NOTATION " + enumer;
}
}
else
{
if ("ENUMERATION".equals(type))
{
type = enumer;
}
else if ("NOTATION".equals(type))
{
type = "NOTATION " + enumer;
}
}
if (!skippedPE)
{
handler.getDeclHandler().attributeDecl(elementName, name, type,
defaultType, value);
}
}
private void parseConditionalSect(char[] saved)
throws Exception
{
skipWhitespace();
if (tryRead("INCLUDE"))
{
skipWhitespace();
require('[');
if (readBuffer != saved)
{
handler.verror("Illegal Conditional Section/PE nesting");
}
skipWhitespace();
while (!tryRead("]]>"))
{
parseMarkupdecl();
skipWhitespace();
}
}
else if (tryRead("IGNORE"))
{
skipWhitespace();
require('[');
if (readBuffer != saved)
{
handler.verror("Illegal Conditional Section/PE nesting");
}
int nesting = 1;
char c;
expandPE = false;
for (int nest = 1; nest > 0; )
{
c = readCh();
switch (c)
{
case '<':
if (tryRead("!["))
{
nest++;
}
case ']':
if (tryRead("]>"))
{
nest--;
}
}
}
expandPE = true;
}
else
{
error("conditional section must begin with INCLUDE or IGNORE");
}
}
private void parseCharRef()
throws SAXException, IOException
{
parseCharRef(true );
}
private void tryReadCharRef()
throws SAXException, IOException
{
int value = 0;
char c;
if (tryRead('x'))
{
loop1:
while (true)
{
c = readCh();
if (c == ';')
{
break loop1;
}
else
{
int n = Character.digit(c, 16);
if (n == -1)
{
error("illegal character in character reference", c, null);
break loop1;
}
value *= 16;
value += n;
}
}
}
else
{
loop2:
while (true)
{
c = readCh();
if (c == ';')
{
break loop2;
}
else
{
int n = Character.digit(c, 10);
if (n == -1)
{
error("illegal character in character reference", c, null);
break loop2;
}
value *= 10;
value += n;
}
}
}
if ((value < 0x0020
&& ! (value == '\n' || value == '\t' || value == '\r'))
|| (value >= 0xD800 && value <= 0xDFFF)
|| value == 0xFFFE || value == 0xFFFF
|| value > 0x0010ffff)
{
error("illegal XML character reference U+"
+ Integer.toHexString(value));
}
if (value > 0x0010ffff)
{
error("character reference " + value + " is too large for UTF-16",
new Integer(value).toString(), null);
}
}
private void parseCharRef(boolean doFlush)
throws SAXException, IOException
{
int value = 0;
char c;
if (tryRead('x'))
{
loop1:
while (true)
{
c = readCh();
if (c == ';')
{
break loop1;
}
else
{
int n = Character.digit(c, 16);
if (n == -1)
{
error("illegal character in character reference", c, null);
break loop1;
}
value *= 16;
value += n;
}
}
}
else
{
loop2:
while (true)
{
c = readCh();
if (c == ';')
{
break loop2;
}
else
{
int n = Character.digit(c, 10);
if (n == -1)
{
error("illegal character in character reference", c, null);
break loop2;
}
value *= 10;
value += c - '0';
}
}
}
if ((value < 0x0020
&& ! (value == '\n' || value == '\t' || value == '\r'))
|| (value >= 0xD800 && value <= 0xDFFF)
|| value == 0xFFFE || value == 0xFFFF
|| value > 0x0010ffff)
{
error("illegal XML character reference U+"
+ Integer.toHexString(value));
}
if (value <= 0x0000ffff)
{
dataBufferAppend((char) value);
}
else if (value <= 0x0010ffff)
{
value -= 0x10000;
dataBufferAppend((char) (0xd800 | (value >> 10)));
dataBufferAppend((char) (0xdc00 | (value & 0x0003ff)));
}
else
{
error("character reference " + value + " is too large for UTF-16",
new Integer(value).toString(), null);
}
if (doFlush)
{
dataBufferFlush();
}
}
private void parseEntityRef(boolean externalAllowed)
throws SAXException, IOException
{
String name;
name = readNmtoken(true);
require(';');
switch (getEntityType(name))
{
case ENTITY_UNDECLARED:
String message;
message = "reference to undeclared general entity " + name;
if (skippedPE && !docIsStandalone)
{
handler.verror(message);
if (externalAllowed)
{
handler.skippedEntity(name);
}
}
else
{
error(message);
}
break;
case ENTITY_INTERNAL:
pushString(name, getEntityValue(name));
char t = readCh();
unread(t);
int bufferPosMark = readBufferPos;
int end = readBufferPos + getEntityValue(name).length();
for (int k = readBufferPos; k < end; k++)
{
t = readCh();
if (t == '&')
{
t = readCh();
if (t == '#')
{
tryReadCharRef();
if (readBufferPos >= end)
{
break;
}
k = readBufferPos;
continue;
}
else if (Character.isLetter(t))
{
unread(t);
readNmtoken(true);
require(';');
if (readBufferPos >= end)
{
break;
}
k = readBufferPos;
continue;
}
error(" malformed entity reference");
}
}
readBufferPos = bufferPosMark;
break;
case ENTITY_TEXT:
if (externalAllowed)
{
pushURL(false, name, getEntityIds(name),
null, null, null, true);
}
else
{
error("reference to external entity in attribute value.",
name, null);
}
break;
case ENTITY_NDATA:
if (externalAllowed)
{
error("unparsed entity reference in content", name, null);
}
else
{
error("reference to external entity in attribute value.",
name, null);
}
break;
default:
throw new RuntimeException();
}
}
private void parsePEReference()
throws SAXException, IOException
{
String name;
name = "%" + readNmtoken(true);
require(';');
switch (getEntityType(name))
{
case ENTITY_UNDECLARED:
handler.verror("reference to undeclared parameter entity " + name);
break;
case ENTITY_INTERNAL:
if (inLiteral)
{
pushString(name, getEntityValue(name));
}
else
{
pushString(name, ' ' + getEntityValue(name) + ' ');
}
break;
case ENTITY_TEXT:
if (!inLiteral)
{
pushString(null, " ");
}
pushURL(true, name, getEntityIds(name), null, null, null, true);
if (!inLiteral)
{
pushString(null, " ");
}
break;
}
}
private void parseEntityDecl()
throws Exception
{
boolean peFlag = false;
int flags = 0;
expandPE = false;
requireWhitespace();
if (tryRead('%'))
{
peFlag = true;
requireWhitespace();
}
expandPE = true;
String name = readNmtoken(true);
if (name.indexOf(':') >= 0)
{
error("Illegal character(':') in entity name ", name, null);
}
if (peFlag)
{
name = "%" + name;
}
requireWhitespace();
char c = readCh();
unread (c);
if (c == '"' || c == '\'')
{
String value = readLiteral(flags);
setInternalEntity(name, value);
}
else
{
ExternalIdentifiers ids = readExternalIds(false, false);
boolean white = tryWhitespace();
if (!peFlag && tryRead("NDATA"))
{
if (!white)
{
error("whitespace required before NDATA");
}
requireWhitespace();
String notationName = readNmtoken(true);
if (!skippedPE)
{
setExternalEntity(name, ENTITY_NDATA, ids, notationName);
handler.unparsedEntityDecl(name, ids.publicId, ids.systemId,
ids.baseUri, notationName);
}
}
else if (!skippedPE)
{
setExternalEntity(name, ENTITY_TEXT, ids, null);
handler.getDeclHandler()
.externalEntityDecl(name, ids.publicId,
handler.resolveURIs()
? handler.absolutize(ids.baseUri,
ids.systemId,
false)
: ids.systemId);
}
}
skipWhitespace();
require('>');
}
private void parseNotationDecl()
throws Exception
{
String nname;
ExternalIdentifiers ids;
requireWhitespace();
nname = readNmtoken(true);
if (nname.indexOf(':') >= 0)
{
error("Illegal character(':') in notation name ", nname, null);
}
requireWhitespace();
ids = readExternalIds(true, false);
setNotation(nname, ids);
skipWhitespace();
require('>');
}
private void parseCharData()
throws Exception
{
char c;
int state = 0;
boolean pureWhite = false;
if ((currentElementContent == CONTENT_ELEMENTS) && !isDirtyCurrentElement)
{
pureWhite = true;
}
while (true)
{
int lineAugment = 0;
int columnAugment = 0;
int i;
loop:
for (i = readBufferPos; i < readBufferLength; i++)
{
switch (c = readBuffer[i])
{
case '\n':
lineAugment++;
columnAugment = 0;
break;
case '\r': case '\t':
case ' ':
columnAugment++;
break;
case '&':
case '<':
columnAugment++;
state = 1;
break loop;
case ']':
pureWhite = false;
if ((i + 2) < readBufferLength)
{
if (readBuffer [i + 1] == ']'
&& readBuffer [i + 2] == '>')
{
state = 2;
break loop;
}
}
else
{
}
columnAugment++;
break;
default:
if ((c < 0x0020 || c > 0xFFFD)
|| ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085)
&& xmlVersion == XML_11))
{
error("illegal XML character U+"
+ Integer.toHexString(c));
}
pureWhite = false;
columnAugment++;
}
}
if (lineAugment > 0)
{
line += lineAugment;
column = columnAugment;
}
else
{
column += columnAugment;
}
int length = i - readBufferPos;
if (length != 0)
{
if (pureWhite)
{
handler.ignorableWhitespace(readBuffer,
readBufferPos, length);
}
else
{
handler.charData(readBuffer, readBufferPos, length);
}
readBufferPos = i;
}
if (state != 0)
{
break;
}
unread(readCh());
}
if (!pureWhite)
{
isDirtyCurrentElement = true;
}
if (state != 1) {
error("character data may not contain ']]>'");
}
}
private void requireWhitespace()
throws SAXException, IOException
{
char c = readCh();
if (isWhitespace(c))
{
skipWhitespace();
}
else
{
error("whitespace required", c, null);
}
}
private void skipWhitespace()
throws SAXException, IOException
{
if (USE_CHEATS)
{
int lineAugment = 0;
int columnAugment = 0;
loop:
for (int i = readBufferPos; i < readBufferLength; i++)
{
switch (readBuffer[i])
{
case ' ':
case '\t':
case '\r':
columnAugment++;
break;
case '\n':
lineAugment++;
columnAugment = 0;
break;
case '%':
if (expandPE)
{
break loop;
}
default:
readBufferPos = i;
if (lineAugment > 0)
{
line += lineAugment;
column = columnAugment;
}
else
{
column += columnAugment;
}
return;
}
}
}
char c = readCh ();
while (isWhitespace(c))
{
c = readCh();
}
unread(c);
}
private String readNmtoken(boolean isName)
throws SAXException, IOException
{
char c;
if (USE_CHEATS)
{
loop:
for (int i = readBufferPos; i < readBufferLength; i++)
{
c = readBuffer[i];
switch (c)
{
case '%':
if (expandPE)
{
break loop;
}
case '<': case '>': case '&':
case ',': case '|': case '*': case '+': case '?':
case ')':
case '=':
case '\'': case '"':
case '[':
case ' ': case '\t': case '\r': case '\n':
case ';':
case '/':
int start = readBufferPos;
if (i == start)
{
error("name expected", readBuffer[i], null);
}
readBufferPos = i;
return intern(readBuffer, start, i - start);
default:
if (isName && i == readBufferPos)
{
char c2 = (char) (c & 0x00f0);
switch (c & 0xff00)
{
case 0x0100:
switch (c2)
{
case 0x0030:
if (c == 0x0132 || c == 0x0133 || c == 0x013f)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x0040:
if (c == 0x0140 || c == 0x0149)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x00c0:
if (c == 0x01c4 || c == 0x01cc)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x00f0:
if (c == 0x01f1 || c == 0x01f3)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x00b0:
if (c == 0x01f1 || c == 0x01f3)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
default:
if (c == 0x017f)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
}
break;
case 0x1100:
switch (c2)
{
case 0x0000:
if (c == 0x1104 || c == 0x1108 ||
c == 0x110a || c == 0x110d)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x0030:
if (c == 0x113b || c == 0x113f)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x0040:
if (c == 0x1141 || c == 0x114d
|| c == 0x114f )
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x0050:
if (c == 0x1151 || c == 0x1156)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x0060:
if (c == 0x1162 || c == 0x1164
|| c == 0x1166 || c == 0x116b
|| c == 0x116f)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
case 0x00b0:
if (c == 0x11b6 || c == 0x11b9
|| c == 0x11bb || c == 0x116f)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
break;
default:
if (c == 0x1174 || c == 0x119f
|| c == 0x11ac || c == 0x11c3
|| c == 0x11f1)
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
}
break;
default:
if (c == 0x0e46 || c == 0x1011
|| c == 0x212f || c == 0x0587
|| c == 0x0230 )
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
}
}
if (i == readBufferPos && isName)
{
if (!Character.isUnicodeIdentifierStart(c)
&& c != ':' && c != '_')
{
error("Not a name start character, U+"
+ Integer.toHexString(c));
}
}
else if (!Character.isUnicodeIdentifierPart(c)
&& c != '-' && c != ':' && c != '_' && c != '.'
&& !isExtender(c))
{
error("Not a name character, U+"
+ Integer.toHexString(c));
}
}
}
}
nameBufferPos = 0;
loop:
while (true)
{
c = readCh();
switch (c)
{
case '%':
case '<': case '>': case '&':
case ',': case '|': case '*': case '+': case '?':
case ')':
case '=':
case '\'': case '"':
case '[':
case ' ': case '\t': case '\n': case '\r':
case ';':
case '/':
unread(c);
if (nameBufferPos == 0)
{
error ("name expected");
}
if (isName
&& !Character.isUnicodeIdentifierStart(nameBuffer[0])
&& ":_".indexOf(nameBuffer[0]) == -1)
{
error("Not a name start character, U+"
+ Integer.toHexString(nameBuffer[0]));
}
String s = intern(nameBuffer, 0, nameBufferPos);
nameBufferPos = 0;
return s;
default:
if ((nameBufferPos != 0 || !isName)
&& !Character.isUnicodeIdentifierPart(c)
&& ":-_.".indexOf(c) == -1
&& !isExtender(c))
{
error("Not a name character, U+"
+ Integer.toHexString(c));
}
if (nameBufferPos >= nameBuffer.length)
{
nameBuffer =
(char[]) extendArray(nameBuffer,
nameBuffer.length, nameBufferPos);
}
nameBuffer[nameBufferPos++] = c;
}
}
}
private static boolean isExtender(char c)
{
return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387
|| c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005
|| (c >= 0x3031 && c <= 0x3035)
|| (c >= 0x309d && c <= 0x309e)
|| (c >= 0x30fc && c <= 0x30fe);
}
private String readLiteral(int flags)
throws SAXException, IOException
{
char delim, c;
int startLine = line;
boolean saved = expandPE;
boolean savedReport = doReport;
delim = readCh();
if (delim != '"' && delim != '\'')
{
error("expected '\"' or \"'\"", delim, null);
return null;
}
inLiteral = true;
if ((flags & LIT_DISABLE_PE) != 0)
{
expandPE = false;
}
doReport = false;
char[] ourBuf = readBuffer;
try
{
c = readCh();
boolean ampRead = false;
loop:
while (! (c == delim && readBuffer == ourBuf))
{
switch (c)
{
case '\n':
case '\r':
if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0)
{
c = ' ';
}
break;
case '\t':
if ((flags & LIT_ATTRIBUTE) != 0)
{
c = ' ';
}
break;
case '&':
c = readCh();
if (c == '#')
{
if ((flags & LIT_DISABLE_CREF) != 0)
{
dataBufferAppend('&');
break;
}
parseCharRef(false );
}
else
{
unread(c);
if ((flags & LIT_ENTITY_REF) > 0)
{
parseEntityRef(false);
if (String.valueOf(readBuffer).equals("&"))
{
ampRead = true;
}
}
else if ((flags & LIT_DISABLE_EREF) != 0)
{
dataBufferAppend('&');
}
else
{
String name = readNmtoken(true);
require(';');
dataBufferAppend('&');
dataBufferAppend(name);
dataBufferAppend(';');
}
}
c = readCh();
continue loop;
case '<':
if ((flags & LIT_ATTRIBUTE) != 0)
{
error("attribute values may not contain '<'");
}
break;
default:
break;
}
dataBufferAppend(c);
c = readCh();
}
}
catch (EOFException e)
{
error("end of input while looking for delimiter (started on line "
+ startLine + ')', null, new Character(delim).toString());
}
inLiteral = false;
expandPE = saved;
doReport = savedReport;
if ((flags & LIT_NORMALIZE) > 0)
{
dataBufferNormalize();
}
return dataBufferToString();
}
private ExternalIdentifiers readExternalIds(boolean inNotation,
boolean isSubset)
throws Exception
{
char c;
ExternalIdentifiers ids = new ExternalIdentifiers();
int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
if (tryRead("PUBLIC"))
{
requireWhitespace();
ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags);
if (inNotation)
{
skipWhitespace();
c = readCh();
unread(c);
if (c == '"' || c == '\'')
{
ids.systemId = readLiteral(flags);
}
}
else
{
requireWhitespace();
ids.systemId = readLiteral(flags);
}
for (int i = 0; i < ids.publicId.length(); i++)
{
c = ids.publicId.charAt(i);
if (c >= 'a' && c <= 'z')
{
continue;
}
if (c >= 'A' && c <= 'Z')
{
continue;
}
if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(c) != -1)
{
continue;
}
error("illegal PUBLIC id character U+"
+ Integer.toHexString(c));
}
}
else if (tryRead("SYSTEM"))
{
requireWhitespace();
ids.systemId = readLiteral(flags);
}
else if (!isSubset)
{
error("missing SYSTEM or PUBLIC keyword");
}
if (ids.systemId != null)
{
if (ids.systemId.indexOf('#') != -1)
{
handler.verror("SYSTEM id has an URI fragment: " + ids.systemId);
}
ids.baseUri = handler.getSystemId();
if (ids.baseUri == null && uriWarnings)
{
handler.warn("No base URI; hope URI is absolute: "
+ ids.systemId);
}
}
return ids;
}
private final boolean isWhitespace(char c)
{
if (c > 0x20)
{
return false;
}
if (c == 0x20 || c == 0x0a || c == 0x09 || c == 0x0d)
{
return true;
}
return false; }
private void dataBufferAppend(char c)
{
if (dataBufferPos >= dataBuffer.length)
{
dataBuffer = (char[]) extendArray(dataBuffer,
dataBuffer.length, dataBufferPos);
}
dataBuffer[dataBufferPos++] = c;
}
private void dataBufferAppend(String s)
{
dataBufferAppend(s.toCharArray(), 0, s.length());
}
private void dataBufferAppend(char[] ch, int start, int length)
{
dataBuffer = (char[]) extendArray(dataBuffer, dataBuffer.length,
dataBufferPos + length);
System.arraycopy(ch, start, dataBuffer, dataBufferPos, length);
dataBufferPos += length;
}
private void dataBufferNormalize()
{
int i = 0;
int j = 0;
int end = dataBufferPos;
while (j < end && dataBuffer[j] == ' ')
{
j++;
}
while (end > j && dataBuffer[end - 1] == ' ')
{
end --;
}
while (j < end)
{
char c = dataBuffer[j++];
if (c == ' ')
{
while (j < end && dataBuffer[j++] == ' ')
{
continue;
}
dataBuffer[i++] = ' ';
dataBuffer[i++] = dataBuffer[j - 1];
}
else
{
dataBuffer[i++] = c;
}
}
dataBufferPos = i;
}
private String dataBufferToString()
{
String s = new String(dataBuffer, 0, dataBufferPos);
dataBufferPos = 0;
return s;
}
private void dataBufferFlush()
throws SAXException
{
if (currentElementContent == CONTENT_ELEMENTS
&& dataBufferPos > 0
&& !inCDATA)
{
for (int i = 0; i < dataBufferPos; i++)
{
if (!isWhitespace(dataBuffer[i]))
{
handler.charData(dataBuffer, 0, dataBufferPos);
dataBufferPos = 0;
}
}
if (dataBufferPos > 0)
{
handler.ignorableWhitespace(dataBuffer, 0, dataBufferPos);
dataBufferPos = 0;
}
}
else if (dataBufferPos > 0)
{
handler.charData(dataBuffer, 0, dataBufferPos);
dataBufferPos = 0;
}
}
private void require(String delim)
throws SAXException, IOException
{
int length = delim.length();
char[] ch;
if (length < dataBuffer.length)
{
ch = dataBuffer;
delim.getChars(0, length, ch, 0);
}
else
{
ch = delim.toCharArray();
}
if (USE_CHEATS && length <= (readBufferLength - readBufferPos))
{
int offset = readBufferPos;
for (int i = 0; i < length; i++, offset++)
{
if (ch[i] != readBuffer[offset])
{
error ("required string", null, delim);
}
}
readBufferPos = offset;
}
else
{
for (int i = 0; i < length; i++)
{
require(ch[i]);
}
}
}
private void require(char delim)
throws SAXException, IOException
{
char c = readCh();
if (c != delim)
{
error("required character", c, new Character(delim).toString());
}
}
public String intern(char[] ch, int start, int length)
{
int index = 0;
int hash = 0;
Object[] bucket;
for (int i = start; i < start + length; i++)
{
hash = 31 * hash + ch[i];
}
hash = (hash & 0x7fffffff) % SYMBOL_TABLE_LENGTH;
if ((bucket = symbolTable[hash]) == null)
{
bucket = new Object[8];
}
else
{
while (index < bucket.length)
{
char[] chFound = (char[]) bucket[index];
if (chFound == null)
{
break;
}
if (chFound.length == length)
{
for (int i = 0; i < chFound.length; i++)
{
if (ch[start + i] != chFound[i])
{
break;
}
else if (i == length - 1)
{
return (String) bucket[index + 1];
}
}
}
index += 2;
}
bucket = (Object[]) extendArray(bucket, bucket.length, index);
}
symbolTable[hash] = bucket;
String s = new String(ch, start, length).intern();
bucket[index] = s.toCharArray();
bucket[index + 1] = s;
return s;
}
private Object extendArray(Object array, int currentSize, int requiredSize)
{
if (requiredSize < currentSize)
{
return array;
}
else
{
Object newArray = null;
int newSize = currentSize * 2;
if (newSize <= requiredSize)
{
newSize = requiredSize + 1;
}
if (array instanceof char[])
{
newArray = new char[newSize];
}
else if (array instanceof Object[])
{
newArray = new Object[newSize];
}
else
{
throw new RuntimeException();
}
System.arraycopy(array, 0, newArray, 0, currentSize);
return newArray;
}
}
boolean isStandalone()
{
return docIsStandalone;
}
private int getContentType(ElementDecl element, int defaultType)
{
int retval;
if (element == null)
{
return defaultType;
}
retval = element.contentType;
if (retval == CONTENT_UNDECLARED)
{
retval = defaultType;
}
return retval;
}
public int getElementContentType(String name)
{
ElementDecl element = (ElementDecl) elementInfo.get(name);
return getContentType(element, CONTENT_UNDECLARED);
}
private void setElement(String name, int contentType,
String contentModel, HashMap attributes)
throws SAXException
{
if (skippedPE)
{
return;
}
ElementDecl element = (ElementDecl) elementInfo.get(name);
if (element == null)
{
element = new ElementDecl();
element.contentType = contentType;
element.contentModel = contentModel;
element.attributes = attributes;
elementInfo.put(name, element);
return;
}
if (contentType != CONTENT_UNDECLARED)
{
if (element.contentType == CONTENT_UNDECLARED)
{
element.contentType = contentType;
element.contentModel = contentModel;
}
else
{
handler.verror("multiple declarations for element type: "
+ name);
}
}
else if (attributes != null)
{
element.attributes = attributes;
}
}
private HashMap getElementAttributes(String name)
{
ElementDecl element = (ElementDecl) elementInfo.get(name);
return (element == null) ? null : element.attributes;
}
private Iterator declaredAttributes(ElementDecl element)
{
HashMap attlist;
if (element == null)
{
return null;
}
if ((attlist = element.attributes) == null)
{
return null;
}
return attlist.keySet().iterator();
}
public Iterator declaredAttributes(String elname)
{
return declaredAttributes((ElementDecl) elementInfo.get(elname));
}
public String getAttributeType(String name, String aname)
{
AttributeDecl attribute = getAttribute(name, aname);
return (attribute == null) ? null : attribute.type;
}
public String getAttributeEnumeration(String name, String aname)
{
AttributeDecl attribute = getAttribute(name, aname);
return (attribute == null) ? null : attribute.enumeration;
}
public String getAttributeDefaultValue(String name, String aname)
{
AttributeDecl attribute = getAttribute(name, aname);
return (attribute == null) ? null : attribute.value;
}
public int getAttributeDefaultValueType(String name, String aname)
{
AttributeDecl attribute = getAttribute(name, aname);
return (attribute == null) ? ATTRIBUTE_DEFAULT_UNDECLARED :
attribute.valueType;
}
private void setAttribute(String elName, String name, String type,
String enumeration, String value, int valueType)
throws Exception
{
HashMap attlist;
if (skippedPE)
{
return;
}
attlist = getElementAttributes(elName);
if (attlist == null)
{
attlist = new HashMap();
}
if (attlist.get(name) != null)
{
return;
}
else
{
AttributeDecl attribute = new AttributeDecl();
attribute.type = type;
attribute.value = value;
attribute.valueType = valueType;
attribute.enumeration = enumeration;
attlist.put(name, attribute);
setElement(elName, CONTENT_UNDECLARED, null, attlist);
}
}
private AttributeDecl getAttribute(String elName, String name)
{
HashMap attlist = getElementAttributes(elName);
return (attlist == null) ? null : (AttributeDecl) attlist.get(name);
}
public int getEntityType(String ename)
{
EntityInfo entity = (EntityInfo) entityInfo.get(ename);
return (entity == null) ? ENTITY_UNDECLARED : entity.type;
}
public ExternalIdentifiers getEntityIds(String ename)
{
EntityInfo entity = (EntityInfo) entityInfo.get(ename);
return (entity == null) ? null : entity.ids;
}
public String getEntityValue(String ename)
{
EntityInfo entity = (EntityInfo) entityInfo.get(ename);
return (entity == null) ? null : entity.value;
}
private void setInternalEntity(String eName, String value)
throws SAXException
{
if (skippedPE)
{
return;
}
if (entityInfo.get(eName) == null)
{
EntityInfo entity = new EntityInfo();
entity.type = ENTITY_INTERNAL;
entity.value = value;
entityInfo.put(eName, entity);
}
if (handler.stringInterning)
{
if ("lt" == eName || "gt" == eName || "quot" == eName
|| "apos" == eName || "amp" == eName)
{
return;
}
}
else
{
if ("lt".equals(eName) || "gt".equals(eName) || "quot".equals(eName)
|| "apos".equals(eName) || "amp".equals(eName))
{
return;
}
}
handler.getDeclHandler().internalEntityDecl(eName, value);
}
private void setExternalEntity(String eName, int eClass,
ExternalIdentifiers ids, String nName)
{
if (entityInfo.get(eName) == null)
{
EntityInfo entity = new EntityInfo();
entity.type = eClass;
entity.ids = ids;
entity.notationName = nName;
entityInfo.put(eName, entity);
}
}
private void setNotation(String nname, ExternalIdentifiers ids)
throws SAXException
{
if (skippedPE)
{
return;
}
handler.notationDecl(nname, ids.publicId, ids.systemId, ids.baseUri);
if (notationInfo.get(nname) == null)
{
notationInfo.put(nname, nname);
}
else
{
handler.verror("Duplicate notation name decl: " + nname);
}
}
public int getLineNumber()
{
return line;
}
public int getColumnNumber()
{
return column;
}
private char readCh()
throws SAXException, IOException
{
while (readBufferPos >= readBufferLength)
{
switch (sourceType)
{
case INPUT_READER:
case INPUT_STREAM:
readDataChunk();
while (readBufferLength < 1)
{
popInput();
if (readBufferLength < 1)
{
readDataChunk();
}
}
break;
default:
popInput();
break;
}
}
char c = readBuffer[readBufferPos++];
if (c == '\n')
{
line++;
column = 0;
}
else
{
if (c == '<')
{
}
else if (((c < 0x0020 && (c != '\t') && (c != '\r')) || c > 0xFFFD)
|| ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085)
&& xmlVersion == XML_11))
{
error("illegal XML character U+" + Integer.toHexString(c));
}
else if (c == '%' && expandPE)
{
if (peIsError)
{
error("PE reference within decl in internal subset.");
}
parsePEReference();
return readCh();
}
column++;
}
return c;
}
private void unread(char c)
throws SAXException
{
if (c == '\n')
{
line--;
column = -1;
}
if (readBufferPos > 0)
{
readBuffer[--readBufferPos] = c;
}
else
{
pushString(null, new Character(c).toString());
}
}
private void unread(char[] ch, int length)
throws SAXException
{
for (int i = 0; i < length; i++)
{
if (ch[i] == '\n')
{
line--;
column = -1;
}
}
if (length < readBufferPos)
{
readBufferPos -= length;
}
else
{
pushCharArray(null, ch, 0, length);
}
}
private void pushURL(boolean isPE,
String ename,
ExternalIdentifiers ids,
Reader reader,
InputStream stream,
String encoding,
boolean doResolve)
throws SAXException, IOException
{
boolean ignoreEncoding;
String systemId;
InputSource source;
if (!isPE)
{
dataBufferFlush();
}
scratch.setPublicId(ids.publicId);
scratch.setSystemId(ids.systemId);
if (doResolve)
{
source = handler.resolveEntity(isPE, ename, scratch, ids.baseUri);
if (source == null)
{
handler.warn("skipping entity: " + ename);
handler.skippedEntity(ename);
if (isPE)
{
skippedPE = true;
}
return;
}
systemId = source.getSystemId();
}
else
{
scratch.setCharacterStream(reader);
scratch.setByteStream(stream);
scratch.setEncoding(encoding);
source = scratch;
systemId = ids.systemId;
if (handler.stringInterning)
{
handler.startExternalEntity(ename, systemId,
"[document]" == ename);
}
else
{
handler.startExternalEntity(ename, systemId,
"[document]".equals(ename));
}
}
if (source.getCharacterStream() != null)
{
if (source.getByteStream() != null)
error("InputSource has two streams!");
reader = source.getCharacterStream();
}
else if (source.getByteStream() != null)
{
encoding = source.getEncoding();
if (encoding == null)
{
stream = source.getByteStream();
}
else
{
try
{
reader = new InputStreamReader(source.getByteStream(),
encoding);
}
catch (IOException e)
{
stream = source.getByteStream();
}
}
}
else if (systemId == null)
{
error("InputSource has no URI!");
}
scratch.setCharacterStream(null);
scratch.setByteStream(null);
scratch.setEncoding(null);
pushInput(ename);
readBuffer = new char[READ_BUFFER_MAX + 4];
readBufferPos = 0;
readBufferLength = 0;
readBufferOverflow = -1;
is = null;
line = 1;
column = 0;
currentByteCount = 0;
if (reader != null)
{
sourceType = INPUT_READER;
this.reader = reader;
tryEncodingDecl(true);
return;
}
sourceType = INPUT_STREAM;
if (stream != null)
{
is = stream;
}
else
{
URL url = new URL(systemId);
externalEntity = url.openConnection();
externalEntity.connect();
is = externalEntity.getInputStream();
}
if (!is.markSupported())
{
is = new BufferedInputStream(is);
}
if (encoding == null && externalEntity != null)
{
if (!"file".equals(externalEntity.getURL().getProtocol()))
{
int temp;
encoding = externalEntity.getContentType();
if (encoding == null)
{
temp = -1;
}
else
{
temp = encoding.indexOf("charset");
}
if (temp < 0)
{
encoding = null; }
else
{
if ((temp = encoding.indexOf(';')) > 0)
{
encoding = encoding.substring(0, temp);
}
if ((temp = encoding.indexOf('=', temp + 7)) > 0)
{
encoding = encoding.substring(temp + 1);
if ((temp = encoding.indexOf('(')) > 0)
{
encoding = encoding.substring(0, temp);
}
if ((temp = encoding.indexOf('"')) > 0)
{
encoding =
encoding.substring(temp + 1,
encoding.indexOf('"', temp + 2));
}
encoding.trim();
}
else
{
handler.warn("ignoring illegal MIME attribute: "
+ encoding);
encoding = null;
}
}
}
}
if (encoding != null)
{
this.encoding = ENCODING_EXTERNAL;
setupDecoding(encoding);
ignoreEncoding = true;
}
else
{
detectEncoding();
ignoreEncoding = false;
}
try
{
tryEncodingDecl(ignoreEncoding);
}
catch (UnsupportedEncodingException x)
{
encoding = x.getMessage();
try
{
if (sourceType != INPUT_STREAM)
{
throw x;
}
is.reset();
readBufferPos = 0;
readBufferLength = 0;
readBufferOverflow = -1;
line = 1;
currentByteCount = column = 0;
sourceType = INPUT_READER;
this.reader = new InputStreamReader(is, encoding);
is = null;
tryEncodingDecl(true);
}
catch (IOException e)
{
error("unsupported text encoding",
encoding,
null);
}
}
}
private String tryEncodingDecl(boolean ignoreEncoding)
throws SAXException, IOException
{
if (tryRead("<?xml"))
{
if (tryWhitespace())
{
if (inputStack.size() > 0)
{
return parseTextDecl(ignoreEncoding);
}
else
{
return parseXMLDecl(ignoreEncoding);
}
}
else
{
unread('l');
unread('m');
unread('x');
unread('?');
unread('<');
}
}
return null;
}
private void detectEncoding()
throws SAXException, IOException
{
byte[] signature = new byte[4];
is.mark(4);
is.read(signature);
is.reset();
if (tryEncoding(signature, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x3c))
{
encoding = ENCODING_UCS_4_1234;
}
else if (tryEncoding(signature, (byte) 0x3c, (byte) 0x00,
(byte) 0x00, (byte) 0x00))
{
encoding = ENCODING_UCS_4_4321;
}
else if (tryEncoding(signature, (byte) 0x00, (byte) 0x00,
(byte) 0x3c, (byte) 0x00))
{
encoding = ENCODING_UCS_4_2143;
}
else if (tryEncoding(signature, (byte) 0x00, (byte) 0x3c,
(byte) 0x00, (byte) 0x00))
{
encoding = ENCODING_UCS_4_3412;
}
else if (tryEncoding(signature, (byte) 0xfe, (byte) 0xff))
{
encoding = ENCODING_UCS_2_12;
is.read(); is.read();
}
else if (tryEncoding(signature, (byte) 0xff, (byte) 0xfe))
{
encoding = ENCODING_UCS_2_21;
is.read(); is.read();
}
else if (tryEncoding(signature, (byte) 0x00, (byte) 0x3c,
(byte) 0x00, (byte) 0x3f))
{
encoding = ENCODING_UCS_2_12;
error("no byte-order mark for UCS-2 entity");
}
else if (tryEncoding(signature, (byte) 0x3c, (byte) 0x00,
(byte) 0x3f, (byte) 0x00))
{
encoding = ENCODING_UCS_2_21;
error("no byte-order mark for UCS-2 entity");
}
else if (tryEncoding(signature, (byte) 0x3c, (byte) 0x3f,
(byte) 0x78, (byte) 0x6d))
{
encoding = ENCODING_UTF_8;
prefetchASCIIEncodingDecl();
}
else if (signature[0] == (byte) 0xef
&& signature[1] == (byte) 0xbb
&& signature[2] == (byte) 0xbf)
{
encoding = ENCODING_UTF_8;
is.read(); is.read(); is.read();
}
else
{
encoding = ENCODING_UTF_8;
}
}
private static boolean tryEncoding(byte[] sig, byte b1, byte b2,
byte b3, byte b4)
{
return (sig[0] == b1 && sig[1] == b2
&& sig[2] == b3 && sig[3] == b4);
}
private static boolean tryEncoding(byte[] sig, byte b1, byte b2)
{
return ((sig[0] == b1) && (sig[1] == b2));
}
private void pushString(String ename, String s)
throws SAXException
{
char[] ch = s.toCharArray();
pushCharArray(ename, ch, 0, ch.length);
}
private void pushCharArray(String ename, char[] ch, int start, int length)
throws SAXException
{
pushInput(ename);
if (ename != null && doReport)
{
dataBufferFlush();
handler.startInternalEntity(ename);
}
sourceType = INPUT_INTERNAL;
readBuffer = ch;
readBufferPos = start;
readBufferLength = length;
readBufferOverflow = -1;
}
private void pushInput(String ename)
throws SAXException
{
if (ename != null)
{
Iterator entities = entityStack.iterator();
while (entities.hasNext())
{
String e = (String) entities.next();
if (e != null && e == ename)
{
error("recursive reference to entity", ename, null);
}
}
}
entityStack.addLast(ename);
if (sourceType == INPUT_NONE)
{
return;
}
Input input = new Input();
input.sourceType = sourceType;
input.externalEntity = externalEntity;
input.readBuffer = readBuffer;
input.readBufferPos = readBufferPos;
input.readBufferLength = readBufferLength;
input.line = line;
input.encoding = encoding;
input.readBufferOverflow = readBufferOverflow;
input.is = is;
input.currentByteCount = currentByteCount;
input.column = column;
input.reader = reader;
inputStack.addLast(input);
}
private void popInput()
throws SAXException, IOException
{
String ename = (String) entityStack.removeLast();
if (ename != null && doReport)
{
dataBufferFlush();
}
switch (sourceType)
{
case INPUT_STREAM:
handler.endExternalEntity(ename);
is.close();
break;
case INPUT_READER:
handler.endExternalEntity(ename);
reader.close();
break;
case INPUT_INTERNAL:
if (ename != null && doReport)
{
handler.endInternalEntity(ename);
}
break;
}
if (inputStack.isEmpty())
{
throw new EOFException("no more input");
}
Input input = (Input) inputStack.removeLast();
sourceType = input.sourceType;
externalEntity = input.externalEntity;
readBuffer = input.readBuffer;
readBufferPos = input.readBufferPos;
readBufferLength = input.readBufferLength;
line = input.line;
encoding = input.encoding;
readBufferOverflow = input.readBufferOverflow;
is = input.is;
currentByteCount = input.currentByteCount;
column = input.column;
reader = input.reader;
}
private boolean tryRead(char delim)
throws SAXException, IOException
{
char c;
c = readCh();
if (c == delim)
{
return true;
}
else
{
unread(c);
return false;
}
}
private boolean tryRead(String delim)
throws SAXException, IOException
{
return tryRead(delim.toCharArray());
}
private boolean tryRead(char[] ch)
throws SAXException, IOException
{
char c;
for (int i = 0; i < ch.length; i++)
{
c = readCh();
if (c != ch[i])
{
unread(c);
if (i != 0)
{
unread(ch, i);
}
return false;
}
}
return true;
}
private boolean tryWhitespace()
throws SAXException, IOException
{
char c;
c = readCh();
if (isWhitespace(c))
{
skipWhitespace();
return true;
}
else
{
unread(c);
return false;
}
}
private void parseUntil(String delim)
throws SAXException, IOException
{
parseUntil(delim.toCharArray());
}
private void parseUntil(char[] delim)
throws SAXException, IOException
{
char c;
int startLine = line;
try
{
while (!tryRead(delim))
{
c = readCh();
dataBufferAppend(c);
}
}
catch (EOFException e)
{
error("end of input while looking for delimiter "
+ "(started on line " + startLine
+ ')', null, new String(delim));
}
}
private void prefetchASCIIEncodingDecl()
throws SAXException, IOException
{
int ch;
readBufferPos = readBufferLength = 0;
is.mark(readBuffer.length);
while (true)
{
ch = is.read();
readBuffer[readBufferLength++] = (char) ch;
switch (ch)
{
case (int) '>':
return;
case -1:
error("file ends before end of XML or encoding declaration.",
null, "?>");
}
if (readBuffer.length == readBufferLength)
{
error("unfinished XML or encoding declaration");
}
}
}
private void readDataChunk()
throws SAXException, IOException
{
int count;
if (readBufferOverflow > -1)
{
readBuffer[0] = (char) readBufferOverflow;
readBufferOverflow = -1;
readBufferPos = 1;
sawCR = true;
}
else
{
readBufferPos = 0;
sawCR = false;
}
if (sourceType == INPUT_READER)
{
count = reader.read(readBuffer,
readBufferPos, READ_BUFFER_MAX - readBufferPos);
if (count < 0)
{
readBufferLength = readBufferPos;
}
else
{
readBufferLength = readBufferPos + count;
}
if (readBufferLength > 0)
{
filterCR(count >= 0);
}
sawCR = false;
return;
}
count = is.read(rawReadBuffer, 0, READ_BUFFER_MAX);
if (count > 0)
{
switch (encoding)
{
case ENCODING_ASCII:
copyIso8859_1ReadBuffer(count, (char) 0x0080);
break;
case ENCODING_UTF_8:
copyUtf8ReadBuffer(count);
break;
case ENCODING_ISO_8859_1:
copyIso8859_1ReadBuffer(count, (char) 0);
break;
case ENCODING_UCS_2_12:
copyUcs2ReadBuffer(count, 8, 0);
break;
case ENCODING_UCS_2_21:
copyUcs2ReadBuffer(count, 0, 8);
break;
case ENCODING_UCS_4_1234:
copyUcs4ReadBuffer(count, 24, 16, 8, 0);
break;
case ENCODING_UCS_4_4321:
copyUcs4ReadBuffer(count, 0, 8, 16, 24);
break;
case ENCODING_UCS_4_2143:
copyUcs4ReadBuffer(count, 16, 24, 0, 8);
break;
case ENCODING_UCS_4_3412:
copyUcs4ReadBuffer(count, 8, 0, 24, 16);
break;
}
}
else
{
readBufferLength = readBufferPos;
}
readBufferPos = 0;
if (sawCR)
{
filterCR(count >= 0);
sawCR = false;
if (readBufferLength == 0 && count >= 0)
{
readDataChunk();
}
}
if (count > 0)
{
currentByteCount += count;
}
}
private void filterCR(boolean moreData)
{
int i, j;
readBufferOverflow = -1;
loop:
for (i = j = readBufferPos; j < readBufferLength; i++, j++)
{
switch (readBuffer[j])
{
case '\r':
if (j == readBufferLength - 1)
{
if (moreData)
{
readBufferOverflow = '\r';
readBufferLength--;
}
else {
readBuffer[i++] = '\n';
}
break loop;
}
else if (readBuffer[j + 1] == '\n')
{
j++;
}
readBuffer[i] = '\n';
break;
case '\n':
default:
readBuffer[i] = readBuffer[j];
break;
}
}
readBufferLength = i;
}
private void copyUtf8ReadBuffer(int count)
throws SAXException, IOException
{
int i = 0;
int j = readBufferPos;
int b1;
char c = 0;
while (i < count)
{
b1 = rawReadBuffer[i++];
if (b1 < 0)
{
if ((b1 & 0xe0) == 0xc0)
{
c = (char) (((b1 & 0x1f) << 6)
| getNextUtf8Byte(i++, count));
if (c < 0x0080)
{
encodingError("Illegal two byte UTF-8 sequence",
c, 0);
}
if ((c == 0x0085 || c == 0x000a) && sawCR)
{
continue;
}
if (c == 0x0085 && xmlVersion == XML_11)
{
readBuffer[j++] = '\r';
}
}
else if ((b1 & 0xf0) == 0xe0)
{
c = (char) (((b1 & 0x0f) << 12) |
(getNextUtf8Byte(i++, count) << 6) |
getNextUtf8Byte(i++, count));
if (c == 0x2028 && xmlVersion == XML_11)
{
readBuffer[j++] = '\r';
sawCR = true;
continue;
}
if (c < 0x0800 || (c >= 0xd800 && c <= 0xdfff))
{
encodingError("Illegal three byte UTF-8 sequence",
c, 0);
}
}
else if ((b1 & 0xf8) == 0xf0)
{
int iso646 = b1 & 07;
iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count);
iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count);
iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count);
if (iso646 <= 0xffff)
{
encodingError("Illegal four byte UTF-8 sequence",
iso646, 0);
}
else
{
if (iso646 > 0x0010ffff)
{
encodingError("UTF-8 value out of range for Unicode",
iso646, 0);
}
iso646 -= 0x010000;
readBuffer[j++] = (char) (0xd800 | (iso646 >> 10));
readBuffer[j++] = (char) (0xdc00 | (iso646 & 0x03ff));
continue;
}
}
else
{
encodingError("unsupported five or six byte UTF-8 sequence",
0xff & b1, i);
c = 0;
}
}
else
{
c = (char) b1;
}
readBuffer[j++] = c;
if (c == '\r')
{
sawCR = true;
}
}
readBufferLength = j;
}
private int getNextUtf8Byte(int pos, int count)
throws SAXException, IOException
{
int val;
if (pos < count)
{
val = rawReadBuffer[pos];
}
else
{
val = is.read();
if (val == -1)
{
encodingError("unfinished multi-byte UTF-8 sequence at EOF",
-1, pos);
}
}
if ((val & 0xc0) != 0x80)
{
encodingError("bad continuation of multi-byte UTF-8 sequence",
val, pos + 1);
}
return (val & 0x3f);
}
private void copyIso8859_1ReadBuffer(int count, char mask)
throws IOException
{
int i, j;
for (i = 0, j = readBufferPos; i < count; i++, j++)
{
char c = (char) (rawReadBuffer[i] & 0xff);
if ((c & mask) != 0)
{
throw new CharConversionException("non-ASCII character U+"
+ Integer.toHexString(c));
}
if (c == 0x0085 && xmlVersion == XML_11)
{
c = '\r';
}
readBuffer[j] = c;
if (c == '\r')
{
sawCR = true;
}
}
readBufferLength = j;
}
private void copyUcs2ReadBuffer(int count, int shift1, int shift2)
throws SAXException
{
int j = readBufferPos;
if (count > 0 && (count % 2) != 0)
{
encodingError("odd number of bytes in UCS-2 encoding", -1, count);
}
if (shift1 == 0)
{ for (int i = 0; i < count; i += 2)
{
char c = (char) (rawReadBuffer[i + 1] << 8);
c |= 0xff & rawReadBuffer[i];
readBuffer[j++] = c;
if (c == '\r')
{
sawCR = true;
}
}
}
else
{ for (int i = 0; i < count; i += 2)
{
char c = (char) (rawReadBuffer[i] << 8);
c |= 0xff & rawReadBuffer[i + 1];
readBuffer[j++] = c;
if (c == '\r')
{
sawCR = true;
}
}
}
readBufferLength = j;
}
private void copyUcs4ReadBuffer(int count, int shift1, int shift2,
int shift3, int shift4)
throws SAXException
{
int j = readBufferPos;
if (count > 0 && (count % 4) != 0)
{
encodingError("number of bytes in UCS-4 encoding " +
"not divisible by 4",
-1, count);
}
for (int i = 0; i < count; i += 4)
{
int value = (((rawReadBuffer [i] & 0xff) << shift1) |
((rawReadBuffer [i + 1] & 0xff) << shift2) |
((rawReadBuffer [i + 2] & 0xff) << shift3) |
((rawReadBuffer [i + 3] & 0xff) << shift4));
if (value < 0x0000ffff)
{
readBuffer [j++] = (char) value;
if (value == (int) '\r')
{
sawCR = true;
}
}
else if (value < 0x0010ffff)
{
value -= 0x010000;
readBuffer[j++] = (char) (0xd8 | ((value >> 10) & 0x03ff));
readBuffer[j++] = (char) (0xdc | (value & 0x03ff));
}
else
{
encodingError("UCS-4 value out of range for Unicode",
value, i);
}
}
readBufferLength = j;
}
private void encodingError(String message, int value, int offset)
throws SAXException
{
if (value != -1)
{
message = message + " (character code: 0x" +
Integer.toHexString(value) + ')';
error(message);
}
}
private void initializeVariables()
{
line = 1;
column = 0;
dataBufferPos = 0;
dataBuffer = new char[DATA_BUFFER_INITIAL];
nameBufferPos = 0;
nameBuffer = new char[NAME_BUFFER_INITIAL];
elementInfo = new HashMap();
entityInfo = new HashMap();
notationInfo = new HashMap();
skippedPE = false;
currentElement = null;
currentElementContent = CONTENT_UNDECLARED;
sourceType = INPUT_NONE;
inputStack = new LinkedList();
entityStack = new LinkedList();
externalEntity = null;
tagAttributePos = 0;
tagAttributes = new String[100];
rawReadBuffer = new byte[READ_BUFFER_MAX];
readBufferOverflow = -1;
scratch = new InputSource();
inLiteral = false;
expandPE = false;
peIsError = false;
doReport = false;
inCDATA = false;
symbolTable = new Object[SYMBOL_TABLE_LENGTH][];
}
static class ExternalIdentifiers
{
String publicId;
String systemId;
String baseUri;
ExternalIdentifiers()
{
}
ExternalIdentifiers(String publicId, String systemId, String baseUri)
{
this.publicId = publicId;
this.systemId = systemId;
this.baseUri = baseUri;
}
}
static class EntityInfo
{
int type;
ExternalIdentifiers ids;
String value;
String notationName;
}
static class AttributeDecl
{
String type;
String value;
int valueType;
String enumeration;
String defaultValue;
}
static class ElementDecl
{
int contentType;
String contentModel;
HashMap attributes;
}
static class Input
{
int sourceType;
URLConnection externalEntity;
char[] readBuffer;
int readBufferPos;
int readBufferLength;
int line;
int encoding;
int readBufferOverflow;
InputStream is;
int currentByteCount;
int column;
Reader reader;
}
}