< prev index next >
src/jdk.xml.bind/share/classes/com/sun/xml/internal/dtdparser/DTDParser.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 36,118 ****
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Set;
import java.util.Vector;
/**
* This implements parsing of XML 1.0 DTDs.
! * <p/>
! * This conforms to the portion of the XML 1.0 specification related
! * to the external DTD subset.
! * <p/>
! * For multi-language applications (such as web servers using XML
! * processing to create dynamic content), a method supports choosing
! * a locale for parser diagnostics which is both understood by the
! * message recipient and supported by the parser.
! * <p/>
! * This parser produces a stream of parse events. It supports some
! * features (exposing comments, CDATA sections, and entity references)
! * which are not required to be reported by conformant XML processors.
*
* @author David Brownell
* @author Janet Koenig
* @author Kohsuke KAWAGUCHI
! * @version $Id: DTDParser.java,v 1.2 2009/04/16 15:25:49 snajper Exp $
*/
public class DTDParser {
public final static String TYPE_CDATA = "CDATA";
public final static String TYPE_ID = "ID";
public final static String TYPE_IDREF = "IDREF";
public final static String TYPE_IDREFS = "IDREFS";
public final static String TYPE_ENTITY = "ENTITY";
public final static String TYPE_ENTITIES = "ENTITIES";
public final static String TYPE_NMTOKEN = "NMTOKEN";
public final static String TYPE_NMTOKENS = "NMTOKENS";
public final static String TYPE_NOTATION = "NOTATION";
public final static String TYPE_ENUMERATION = "ENUMERATION";
-
-
// stack of input entities being merged
private InputEntity in;
-
// temporaries reused during parsing
private StringBuffer strTmp;
! private char nameTmp [];
private NameCache nameCache;
! private char charTmp [] = new char[2];
!
// temporary DTD parsing state
private boolean doLexicalPE;
-
// DTD state, used during parsing
// private SimpleHashtable elements = new SimpleHashtable (47);
protected final Set declaredElements = new java.util.HashSet();
private SimpleHashtable params = new SimpleHashtable(7);
-
// exposed to package-private subclass
Hashtable notations = new Hashtable(7);
SimpleHashtable entities = new SimpleHashtable(17);
-
private SimpleHashtable ids = new SimpleHashtable();
-
// listeners for DTD parsing events
private DTDEventListener dtdHandler;
-
private EntityResolver resolver;
private Locale locale;
-
// string constants -- use these copies so "==" works
// package private
static final String strANY = "ANY";
static final String strEMPTY = "EMPTY";
/**
* Used by applications to request locale for diagnostics.
*
! * @param l The locale to use, or null to use system defaults
! * (which may include only message IDs).
*/
public void setLocale(Locale l) throws SAXException {
if (l != null && !messages.isLocaleSupported(l.toString())) {
throw new SAXException(messages.getMessage(locale,
--- 36,113 ----
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Set;
import java.util.Vector;
+ import java.util.logging.Level;
+ import java.util.logging.Logger;
/**
* This implements parsing of XML 1.0 DTDs.
! * <p>
! * This conforms to the portion of the XML 1.0 specification related to the
! * external DTD subset.
! * <p>
! * For multi-language applications (such as web servers using XML processing to
! * create dynamic content), a method supports choosing a locale for parser
! * diagnostics which is both understood by the message recipient and supported
! * by the parser.
! * <p>
! * This parser produces a stream of parse events. It supports some features
! * (exposing comments, CDATA sections, and entity references) which are not
! * required to be reported by conformant XML processors.
*
* @author David Brownell
* @author Janet Koenig
* @author Kohsuke KAWAGUCHI
! * @version $Id: DTDParser.java,v 1.2 2009-04-16 15:25:49 snajper Exp $
*/
public class DTDParser {
+
public final static String TYPE_CDATA = "CDATA";
public final static String TYPE_ID = "ID";
public final static String TYPE_IDREF = "IDREF";
public final static String TYPE_IDREFS = "IDREFS";
public final static String TYPE_ENTITY = "ENTITY";
public final static String TYPE_ENTITIES = "ENTITIES";
public final static String TYPE_NMTOKEN = "NMTOKEN";
public final static String TYPE_NMTOKENS = "NMTOKENS";
public final static String TYPE_NOTATION = "NOTATION";
public final static String TYPE_ENUMERATION = "ENUMERATION";
// stack of input entities being merged
private InputEntity in;
// temporaries reused during parsing
private StringBuffer strTmp;
! private char nameTmp[];
private NameCache nameCache;
! private char charTmp[] = new char[2];
// temporary DTD parsing state
private boolean doLexicalPE;
// DTD state, used during parsing
// private SimpleHashtable elements = new SimpleHashtable (47);
protected final Set declaredElements = new java.util.HashSet();
private SimpleHashtable params = new SimpleHashtable(7);
// exposed to package-private subclass
Hashtable notations = new Hashtable(7);
SimpleHashtable entities = new SimpleHashtable(17);
private SimpleHashtable ids = new SimpleHashtable();
// listeners for DTD parsing events
private DTDEventListener dtdHandler;
private EntityResolver resolver;
private Locale locale;
// string constants -- use these copies so "==" works
// package private
static final String strANY = "ANY";
static final String strEMPTY = "EMPTY";
+ private static final Logger LOGGER = Logger.getLogger(DTDParser.class.getName());
+
/**
* Used by applications to request locale for diagnostics.
*
! * @param l The locale to use, or null to use system defaults (which may
! * include only message IDs).
*/
public void setLocale(Locale l) throws SAXException {
if (l != null && !messages.isLocaleSupported(l.toString())) {
throw new SAXException(messages.getMessage(locale,
*** 127,150 ****
public Locale getLocale() {
return locale;
}
/**
! * Chooses a client locale to use for diagnostics, using the first
! * language specified in the list that is supported by this parser.
! * That locale is then set using <a href="#setLocale(java.util.Locale)">
! * setLocale()</a>. Such a list could be provided by a variety of user
! * preference mechanisms, including the HTTP <em>Accept-Language</em>
! * header field.
*
* @param languages Array of language specifiers, ordered with the most
! * preferable one at the front. For example, "en-ca" then "fr-ca",
! * followed by "zh_CN". Both RFC 1766 and Java styles are supported.
* @return The chosen locale, or null.
* @see MessageCatalog
*/
! public Locale chooseLocale(String languages [])
throws SAXException {
Locale l = messages.chooseLocale(languages);
if (l != null) {
--- 122,144 ----
public Locale getLocale() {
return locale;
}
/**
! * Chooses a client locale to use for diagnostics, using the first language
! * specified in the list that is supported by this parser. That locale is
! * then set using <a href="#setLocale(java.util.Locale)"> setLocale()</a>.
! * Such a list could be provided by a variety of user preference mechanisms,
! * including the HTTP <em>Accept-Language</em> header field.
*
* @param languages Array of language specifiers, ordered with the most
! * preferable one at the front. For example, "en-ca" then "fr-ca", followed
! * by "zh_CN". Both RFC 1766 and Java styles are supported.
* @return The chosen locale, or null.
* @see MessageCatalog
*/
! public Locale chooseLocale(String languages[])
throws SAXException {
Locale l = messages.chooseLocale(languages);
if (l != null) {
*** 172,200 ****
/**
* Used by applications to set handling of DTD parsing events.
*/
public void setDtdHandler(DTDEventListener handler) {
dtdHandler = handler;
! if (handler != null)
handler.setDocumentLocator(new Locator() {
public String getPublicId() {
return DTDParser.this.getPublicId();
}
public String getSystemId() {
return DTDParser.this.getSystemId();
}
public int getLineNumber() {
return DTDParser.this.getLineNumber();
}
public int getColumnNumber() {
return DTDParser.this.getColumnNumber();
}
});
}
/**
* Returns the handler used to for DTD parsing events.
*/
public DTDEventListener getDtdHandler() {
--- 166,199 ----
/**
* Used by applications to set handling of DTD parsing events.
*/
public void setDtdHandler(DTDEventListener handler) {
dtdHandler = handler;
! if (handler != null) {
handler.setDocumentLocator(new Locator() {
+ @Override
public String getPublicId() {
return DTDParser.this.getPublicId();
}
+ @Override
public String getSystemId() {
return DTDParser.this.getSystemId();
}
+ @Override
public int getLineNumber() {
return DTDParser.this.getLineNumber();
}
+ @Override
public int getColumnNumber() {
return DTDParser.this.getColumnNumber();
}
});
}
+ }
/**
* Returns the handler used to for DTD parsing events.
*/
public DTDEventListener getDtdHandler() {
*** 213,241 ****
/**
* Parse a DTD.
*/
public void parse(String uri)
throws IOException, SAXException {
! InputSource in;
init();
// System.out.println ("parse (\"" + uri + "\")");
! in = resolver.resolveEntity(null, uri);
// If custom resolver punts resolution to parser, handle it ...
! if (in == null) {
! in = Resolver.createInputSource(new java.net.URL(uri), false);
// ... or if custom resolver doesn't correctly construct the
// input entity, patch it up enough so relative URIs work, and
// issue a warning to minimize later confusion.
! } else if (in.getSystemId() == null) {
warning("P-065", null);
! in.setSystemId(uri);
}
! parseInternal(in);
}
// makes sure the parser is reset to "before a document"
private void init() {
in = null;
--- 212,240 ----
/**
* Parse a DTD.
*/
public void parse(String uri)
throws IOException, SAXException {
! InputSource inSource;
init();
// System.out.println ("parse (\"" + uri + "\")");
! inSource = resolver.resolveEntity(null, uri);
// If custom resolver punts resolution to parser, handle it ...
! if (inSource == null) {
! inSource = Resolver.createInputSource(new java.net.URL(uri), false);
// ... or if custom resolver doesn't correctly construct the
// input entity, patch it up enough so relative URIs work, and
// issue a warning to minimize later confusion.
! } else if (inSource.getSystemId() == null) {
warning("P-065", null);
! inSource.setSystemId(uri);
}
! parseInternal(inSource);
}
// makes sure the parser is reset to "before a document"
private void init() {
in = null;
*** 261,285 ****
builtin("lt", "<");
builtin("gt", ">");
builtin("quot", "\"");
builtin("apos", "'");
! if (locale == null)
locale = Locale.getDefault();
! if (resolver == null)
resolver = new Resolver();
! if (dtdHandler == null)
dtdHandler = new DTDHandlerBase();
}
private void builtin(String entityName, String entityValue) {
InternalEntity entity;
entity = new InternalEntity(entityName, entityValue.toCharArray());
entities.put(entityName, entity);
}
-
////////////////////////////////////////////////////////////////
//
// parsing is by recursive descent, code roughly
// following the BNF rules except tweaked for simple
// lookahead. rules are more or less in numeric order,
--- 260,286 ----
builtin("lt", "<");
builtin("gt", ">");
builtin("quot", "\"");
builtin("apos", "'");
! if (locale == null) {
locale = Locale.getDefault();
! }
! if (resolver == null) {
resolver = new Resolver();
! }
! if (dtdHandler == null) {
dtdHandler = new DTDHandlerBase();
}
+ }
private void builtin(String entityName, String entityValue) {
InternalEntity entity;
entity = new InternalEntity(entityName, entityValue.toCharArray());
entities.put(entityName, entity);
}
////////////////////////////////////////////////////////////////
//
// parsing is by recursive descent, code roughly
// following the BNF rules except tweaked for simple
// lookahead. rules are more or less in numeric order,
*** 287,303 ****
//
// a classic benefit of recursive descent parsers: it's
// relatively easy to get diagnostics that make sense.
//
////////////////////////////////////////////////////////////////
!
!
private void parseInternal(InputSource input)
throws IOException, SAXException {
! if (input == null)
fatal("P-000");
try {
in = InputEntity.getInputEntity(dtdHandler, locale);
in.init(input, null, null, false);
--- 288,304 ----
//
// a classic benefit of recursive descent parsers: it's
// relatively easy to get diagnostics that make sense.
//
////////////////////////////////////////////////////////////////
! @SuppressWarnings("CallToThreadDumpStack")
private void parseInternal(InputSource input)
throws IOException, SAXException {
! if (input == null) {
fatal("P-000");
+ }
try {
in = InputEntity.getInputEntity(dtdHandler, locale);
in.init(input, null, null, false);
*** 310,321 ****
ExternalEntity externalSubset = new ExternalEntity(in);
externalParameterEntity(externalSubset);
if (!in.isEOF()) {
! fatal("P-001", new Object[]
! {Integer.toHexString(((int) getc()))});
}
afterRoot();
dtdHandler.endDTD();
} catch (EndOfInputException e) {
--- 311,321 ----
ExternalEntity externalSubset = new ExternalEntity(in);
externalParameterEntity(externalSubset);
if (!in.isEOF()) {
! fatal("P-001", new Object[]{Integer.toHexString(((int) getc()))});
}
afterRoot();
dtdHandler.endDTD();
} catch (EndOfInputException e) {
*** 327,340 ****
fatal("P-002", new Object[]{name});
} else {
fatal("P-003", null);
}
} catch (RuntimeException e) {
! // Don't discard location that triggered the exception
! // ## Should properly wrap exception
! System.err.print("Internal DTD parser error: "); // ##
! e.printStackTrace();
throw new SAXParseException(e.getMessage() != null
? e.getMessage() : e.getClass().getName(),
getPublicId(), getSystemId(),
getLineNumber(), getColumnNumber());
--- 327,337 ----
fatal("P-002", new Object[]{name});
} else {
fatal("P-003", null);
}
} catch (RuntimeException e) {
! LOGGER.log(Level.SEVERE, "Internal DTD parser error.", e);
throw new SAXParseException(e.getMessage() != null
? e.getMessage() : e.getClass().getName(),
getPublicId(), getSystemId(),
getLineNumber(), getColumnNumber());
*** 366,402 ****
// Make sure all IDREFs match declared ID attributes. We scan
// after the document element is parsed, since XML allows forward
// references, and only now can we know if they're all resolved.
for (Enumeration e = ids.keys();
! e.hasMoreElements();
! ) {
String id = (String) e.nextElement();
Boolean value = (Boolean) ids.get(id);
! if (Boolean.FALSE == value)
error("V-024", new Object[]{id});
}
}
!
// role is for diagnostics
private void whitespace(String roleId)
throws IOException, SAXException {
// [3] S ::= (#x20 | #x9 | #xd | #xa)+
if (!maybeWhitespace()) {
! fatal("P-004", new Object[]
! {messages.getMessage(locale, roleId)});
}
}
// S?
private boolean maybeWhitespace()
throws IOException, SAXException {
! if (!doLexicalPE)
return in.maybeWhitespace();
// see getc() for the PE logic -- this lets us splice
// expansions of PEs in "anywhere". getc() has smarts,
// so for external PEs we don't bypass it.
--- 363,398 ----
// Make sure all IDREFs match declared ID attributes. We scan
// after the document element is parsed, since XML allows forward
// references, and only now can we know if they're all resolved.
for (Enumeration e = ids.keys();
! e.hasMoreElements();) {
String id = (String) e.nextElement();
Boolean value = (Boolean) ids.get(id);
! if (Boolean.FALSE.equals(value)) {
error("V-024", new Object[]{id});
}
}
! }
// role is for diagnostics
private void whitespace(String roleId)
throws IOException, SAXException {
// [3] S ::= (#x20 | #x9 | #xd | #xa)+
if (!maybeWhitespace()) {
! fatal("P-004", new Object[]{messages.getMessage(locale, roleId)});
}
}
// S?
private boolean maybeWhitespace()
throws IOException, SAXException {
! if (!doLexicalPE) {
return in.maybeWhitespace();
+ }
// see getc() for the PE logic -- this lets us splice
// expansions of PEs in "anywhere". getc() has smarts,
// so for external PEs we don't bypass it.
*** 416,427 ****
saw = true;
// this gracefully ends things when we stop playing
// with internal parameters. caller should have a
// grammar rule allowing whitespace at end of entity.
! if (in.isEOF() && !in.isInternal())
return saw;
c = getc();
}
ungetc();
return saw;
}
--- 412,424 ----
saw = true;
// this gracefully ends things when we stop playing
// with internal parameters. caller should have a
// grammar rule allowing whitespace at end of entity.
! if (in.isEOF() && !in.isInternal()) {
return saw;
+ }
c = getc();
}
ungetc();
return saw;
}
*** 450,480 ****
private String getNmtoken()
throws IOException, SAXException {
// [7] Nmtoken ::= (Namechar)+
char c = getc();
! if (!XmlChars.isNameChar(c))
! fatal("P-006", new Object[]{new Character(c)});
return nameCharString(c).name;
}
// n.b. this gets used when parsing attribute values (for
// internal references) so we can't use strTmp; it's also
// a hotspot for CPU and memory in the parser (called at least
// once for each element) so this has been optimized a bit.
-
private NameCacheEntry nameCharString(char c)
throws IOException, SAXException {
int i = 1;
nameTmp[0] = c;
! for (; ;) {
! if ((c = in.getNameChar()) == 0)
break;
if (i >= nameTmp.length) {
! char tmp [] = new char[nameTmp.length + 10];
System.arraycopy(nameTmp, 0, tmp, 0, nameTmp.length);
nameTmp = tmp;
}
nameTmp[i++] = c;
}
--- 447,478 ----
private String getNmtoken()
throws IOException, SAXException {
// [7] Nmtoken ::= (Namechar)+
char c = getc();
! if (!XmlChars.isNameChar(c)) {
! fatal("P-006", new Object[]{Character.valueOf(c)});
! }
return nameCharString(c).name;
}
// n.b. this gets used when parsing attribute values (for
// internal references) so we can't use strTmp; it's also
// a hotspot for CPU and memory in the parser (called at least
// once for each element) so this has been optimized a bit.
private NameCacheEntry nameCharString(char c)
throws IOException, SAXException {
int i = 1;
nameTmp[0] = c;
! for (;;) {
! if ((c = in.getNameChar()) == 0) {
break;
+ }
if (i >= nameTmp.length) {
! char tmp[] = new char[nameTmp.length + 10];
System.arraycopy(nameTmp, 0, tmp, 0, nameTmp.length);
nameTmp = tmp;
}
nameTmp[i++] = c;
}
*** 488,497 ****
--- 486,496 ----
//
// leaves value in 'strTmp' ... either a "replacement text" (4.5),
// or else partially normalized attribute value (the first bit
// of 3.3.3's spec, without the "if not CDATA" bits).
//
+ @SuppressWarnings("UnusedAssignment")
private void parseLiteral(boolean isEntityValue)
throws IOException, SAXException {
// [9] EntityValue ::=
// '"' ([^"&%] | Reference | PEReference)* '"'
*** 514,524 ****
// get value into strTmp
strTmp = new StringBuffer();
// scan, allowing entity push/pop wherever ...
// expanded entities can't terminate the literal!
! for (; ;) {
if (in != source && in.isEOF()) {
// we don't report end of parsed entities
// within attributes (no SAX hooks)
in = in.pop();
continue;
--- 513,523 ----
// get value into strTmp
strTmp = new StringBuffer();
// scan, allowing entity push/pop wherever ...
// expanded entities can't terminate the literal!
! for (;;) {
if (in != source && in.isEOF()) {
// we don't report end of parsed entities
// within attributes (no SAX hooks)
in = in.pop();
continue;
*** 545,568 ****
strTmp.append(';');
continue;
}
expandEntityInLiteral(entityName, entities, isEntityValue);
-
// character references are always included immediately
! } else if ((c = getc()) == '#') {
int tmp = parseCharNumber();
if (tmp > 0xffff) {
tmp = surrogatesToCharTmp(tmp);
strTmp.append(charTmp[0]);
! if (tmp == 2)
strTmp.append(charTmp[1]);
! } else
strTmp.append((char) tmp);
! } else
fatal("P-009");
continue;
}
// expand parameter entities only within entity value literals
--- 544,569 ----
strTmp.append(';');
continue;
}
expandEntityInLiteral(entityName, entities, isEntityValue);
// character references are always included immediately
! } else if ((getc()) == '#') {
int tmp = parseCharNumber();
if (tmp > 0xffff) {
tmp = surrogatesToCharTmp(tmp);
strTmp.append(charTmp[0]);
! if (tmp == 2) {
strTmp.append(charTmp[1]);
! }
! } else {
strTmp.append((char) tmp);
! }
! } else {
fatal("P-009");
+ }
continue;
}
// expand parameter entities only within entity value literals
*** 571,596 ****
if (entityName != null) {
nextChar(';', "F-021", entityName);
expandEntityInLiteral(entityName, params, isEntityValue);
continue;
! } else
fatal("P-011");
}
// For attribute values ...
if (!isEntityValue) {
// 3.3.3 says whitespace normalizes to space...
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
strTmp.append(' ');
continue;
}
// "<" not legal in parsed literals ...
! if (c == '<')
fatal("P-012");
}
strTmp.append(c);
}
// isInAttribute = false;
}
--- 572,599 ----
if (entityName != null) {
nextChar(';', "F-021", entityName);
expandEntityInLiteral(entityName, params, isEntityValue);
continue;
! } else {
fatal("P-011");
}
+ }
// For attribute values ...
if (!isEntityValue) {
// 3.3.3 says whitespace normalizes to space...
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
strTmp.append(' ');
continue;
}
// "<" not legal in parsed literals ...
! if (c == '<') {
fatal("P-012");
}
+ }
strTmp.append(c);
}
// isInAttribute = false;
}
*** 606,616 ****
--- 609,621 ----
InternalEntity value = (InternalEntity) entity;
pushReader(value.buf, name, !value.isPE);
} else if (entity instanceof ExternalEntity) {
if (!isEntityValue) // must be a PE ...
+ {
fatal("P-013", new Object[]{name});
+ }
// XXX if this returns false ...
pushReader((ExternalEntity) entity);
} else if (entity == null) {
//
*** 623,716 ****
}
}
// [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
// for PUBLIC and SYSTEM literals, also "<?xml ...type='literal'?>'
-
// NOTE: XML spec should explicitly say that PE ref syntax is
// ignored in PIs, comments, SystemLiterals, and Pubid Literal
// values ... can't process the XML spec's own DTD without doing
// that for comments.
-
private String getQuotedString(String type, String extra)
throws IOException, SAXException {
// use in.getc to bypass PE processing
char quote = in.getc();
! if (quote != '\'' && quote != '"')
fatal("P-015", new Object[]{
messages.getMessage(locale, type, new Object[]{extra})
});
char c;
strTmp = new StringBuffer();
! while ((c = in.getc()) != quote)
strTmp.append((char) c);
return strTmp.toString();
}
-
private String parsePublicId() throws IOException, SAXException {
// [12] PubidLiteral ::= ('"' PubidChar* '"') | ("'" PubidChar* "'")
// [13] PubidChar ::= #x20|#xd|#xa|[a-zA-Z0-9]|[-'()+,./:=?;!*#@$_%]
String retval = getQuotedString("F-033", null);
for (int i = 0; i < retval.length(); i++) {
char c = retval.charAt(i);
if (" \r\n-'()+,./:=?;!*#@$_%0123456789".indexOf(c) == -1
&& !(c >= 'A' && c <= 'Z')
! && !(c >= 'a' && c <= 'z'))
! fatal("P-016", new Object[]{new Character(c)});
}
strTmp = new StringBuffer();
strTmp.append(retval);
return normalize(false);
}
// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
// handled by: InputEntity.parsedContent()
-
private boolean maybeComment(boolean skipStart)
throws IOException, SAXException {
// [15] Comment ::= '<!--'
// ( (Char - '-') | ('-' (Char - '-'))*
// '-->'
! if (!in.peek(skipStart ? "!--" : "<!--", null))
return false;
boolean savedLexicalPE = doLexicalPE;
boolean saveCommentText;
doLexicalPE = false;
saveCommentText = false;
! if (saveCommentText)
strTmp = new StringBuffer();
oneComment:
! for (; ;) {
try {
// bypass PE expansion, but permit PEs
// to complete ... valid docs won't care.
! for (; ;) {
int c = getc();
if (c == '-') {
c = getc();
if (c != '-') {
! if (saveCommentText)
strTmp.append('-');
ungetc();
continue;
}
nextChar('>', "F-022", null);
break oneComment;
}
! if (saveCommentText)
strTmp.append((char) c);
}
} catch (EndOfInputException e) {
//
// This is fatal EXCEPT when we're processing a PE...
// in which case a validating processor reports an error.
// External PEs are easy to detect; internal ones we
--- 628,724 ----
}
}
// [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
// for PUBLIC and SYSTEM literals, also "<?xml ...type='literal'?>'
// NOTE: XML spec should explicitly say that PE ref syntax is
// ignored in PIs, comments, SystemLiterals, and Pubid Literal
// values ... can't process the XML spec's own DTD without doing
// that for comments.
private String getQuotedString(String type, String extra)
throws IOException, SAXException {
// use in.getc to bypass PE processing
char quote = in.getc();
! if (quote != '\'' && quote != '"') {
fatal("P-015", new Object[]{
messages.getMessage(locale, type, new Object[]{extra})
});
+ }
char c;
strTmp = new StringBuffer();
! while ((c = in.getc()) != quote) {
strTmp.append((char) c);
+ }
return strTmp.toString();
}
private String parsePublicId() throws IOException, SAXException {
// [12] PubidLiteral ::= ('"' PubidChar* '"') | ("'" PubidChar* "'")
// [13] PubidChar ::= #x20|#xd|#xa|[a-zA-Z0-9]|[-'()+,./:=?;!*#@$_%]
String retval = getQuotedString("F-033", null);
for (int i = 0; i < retval.length(); i++) {
char c = retval.charAt(i);
if (" \r\n-'()+,./:=?;!*#@$_%0123456789".indexOf(c) == -1
&& !(c >= 'A' && c <= 'Z')
! && !(c >= 'a' && c <= 'z')) {
! fatal("P-016", new Object[]{Character.valueOf(c)});
! }
}
strTmp = new StringBuffer();
strTmp.append(retval);
return normalize(false);
}
// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
// handled by: InputEntity.parsedContent()
private boolean maybeComment(boolean skipStart)
throws IOException, SAXException {
// [15] Comment ::= '<!--'
// ( (Char - '-') | ('-' (Char - '-'))*
// '-->'
! if (!in.peek(skipStart ? "!--" : "<!--", null)) {
return false;
+ }
boolean savedLexicalPE = doLexicalPE;
boolean saveCommentText;
doLexicalPE = false;
saveCommentText = false;
! if (saveCommentText) {
strTmp = new StringBuffer();
+ }
oneComment:
! for (;;) {
try {
// bypass PE expansion, but permit PEs
// to complete ... valid docs won't care.
! for (;;) {
int c = getc();
if (c == '-') {
c = getc();
if (c != '-') {
! if (saveCommentText) {
strTmp.append('-');
+ }
ungetc();
continue;
}
nextChar('>', "F-022", null);
break oneComment;
}
! if (saveCommentText) {
strTmp.append((char) c);
}
+ }
} catch (EndOfInputException e) {
//
// This is fatal EXCEPT when we're processing a PE...
// in which case a validating processor reports an error.
// External PEs are easy to detect; internal ones we
*** 721,732 ****
}
fatal("P-017");
}
}
doLexicalPE = savedLexicalPE;
! if (saveCommentText)
dtdHandler.comment(strTmp.toString());
return true;
}
private boolean maybePI(boolean skipStart)
throws IOException, SAXException {
--- 729,741 ----
}
fatal("P-017");
}
}
doLexicalPE = savedLexicalPE;
! if (saveCommentText) {
dtdHandler.comment(strTmp.toString());
+ }
return true;
}
private boolean maybePI(boolean skipStart)
throws IOException, SAXException {
*** 735,746 ****
// (S (Char* - (Char* '?>' Char*)))?
// '?>'
// [17] PITarget ::= Name - (('X'|'x')('M'|'m')('L'|'l')
boolean savedLexicalPE = doLexicalPE;
! if (!in.peek(skipStart ? "?" : "<?", null))
return false;
doLexicalPE = false;
String target = maybeGetName();
if (target == null) {
--- 744,756 ----
// (S (Char* - (Char* '?>' Char*)))?
// '?>'
// [17] PITarget ::= Name - (('X'|'x')('M'|'m')('L'|'l')
boolean savedLexicalPE = doLexicalPE;
! if (!in.peek(skipStart ? "?" : "<?", null)) {
return false;
+ }
doLexicalPE = false;
String target = maybeGetName();
if (target == null) {
*** 754,769 ****
}
if (maybeWhitespace()) {
strTmp = new StringBuffer();
try {
! for (; ;) {
// use in.getc to bypass PE processing
char c = in.getc();
//Reached the end of PI.
! if (c == '?' && in.peekc('>'))
break;
strTmp.append(c);
}
} catch (EndOfInputException e) {
fatal("P-021");
}
--- 764,780 ----
}
if (maybeWhitespace()) {
strTmp = new StringBuffer();
try {
! for (;;) {
// use in.getc to bypass PE processing
char c = in.getc();
//Reached the end of PI.
! if (c == '?' && in.peekc('>')) {
break;
+ }
strTmp.append(c);
}
} catch (EndOfInputException e) {
fatal("P-021");
}
*** 783,793 ****
// [19] CDStart ::= '<![CDATA['
// [20] CData ::= (Char* - (Char* ']]>' Char*))
// [21] CDEnd ::= ']]>'
//
// ... handled by InputEntity.unparsedContent()
-
// collapsing several rules together ...
// simpler than attribute literals -- no reference parsing!
private String maybeReadAttribute(String name, boolean must)
throws IOException, SAXException {
--- 794,803 ----
*** 827,867 ****
String value = maybeReadAttribute("version", must);
// [26] versionNum ::= ([a-zA-Z0-9_.:]| '-')+
! if (must && value == null)
fatal("P-025", new Object[]{versionNum});
if (value != null) {
int length = value.length();
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
if (!((c >= '0' && c <= '9')
|| c == '_' || c == '.'
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
! || c == ':' || c == '-')
! )
fatal("P-026", new Object[]{value});
}
}
! if (value != null && !value.equals(versionNum))
error("P-027", new Object[]{versionNum, value});
}
// common code used by most markup declarations
// ... S (Q)Name ...
private String getMarkupDeclname(String roleId, boolean qname)
throws IOException, SAXException {
String name;
whitespace(roleId);
name = maybeGetName();
! if (name == null)
! fatal("P-005", new Object[]
! {messages.getMessage(locale, roleId)});
return name;
}
private boolean maybeMarkupDecl()
throws IOException, SAXException {
--- 837,879 ----
String value = maybeReadAttribute("version", must);
// [26] versionNum ::= ([a-zA-Z0-9_.:]| '-')+
! if (must && value == null) {
fatal("P-025", new Object[]{versionNum});
+ }
if (value != null) {
int length = value.length();
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
if (!((c >= '0' && c <= '9')
|| c == '_' || c == '.'
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
! || c == ':' || c == '-')) {
fatal("P-026", new Object[]{value});
}
}
! }
! if (value != null && !value.equals(versionNum)) {
error("P-027", new Object[]{versionNum, value});
}
+ }
// common code used by most markup declarations
// ... S (Q)Name ...
private String getMarkupDeclname(String roleId, boolean qname)
throws IOException, SAXException {
String name;
whitespace(roleId);
name = maybeGetName();
! if (name == null) {
! fatal("P-005", new Object[]{messages.getMessage(locale, roleId)});
! }
return name;
}
private boolean maybeMarkupDecl()
throws IOException, SAXException {
*** 873,883 ****
|| maybeEntityDecl()
|| maybeNotationDecl()
|| maybePI(false)
|| maybeComment(false);
}
-
private static final String XmlLang = "xml:lang";
private boolean isXmlLang(String value) {
// [33] LanguageId ::= Langcode ('-' Subcode)*
--- 885,894 ----
*** 891,950 ****
// but that's neither a WF nor a validity constraint.
int nextSuffix;
char c;
! if (value.length() < 2)
return false;
c = value.charAt(1);
if (c == '-') { // IANA, or user, code
c = value.charAt(0);
! if (!(c == 'i' || c == 'I' || c == 'x' || c == 'X'))
return false;
nextSuffix = 1;
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
// 2 letter ISO code, or error
c = value.charAt(0);
! if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
return false;
nextSuffix = 2;
! } else
return false;
// here "suffix" ::= '-' [a-zA-Z]+ suffix*
while (nextSuffix < value.length()) {
c = value.charAt(nextSuffix);
! if (c != '-')
break;
while (++nextSuffix < value.length()) {
c = value.charAt(nextSuffix);
! if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
break;
}
}
return value.length() == nextSuffix && c != '-';
}
-
//
// CHAPTER 3: Logical Structures
//
-
/**
! * To validate, subclassers should at this time make sure that
! * values are of the declared types:<UL>
! * <LI> ID and IDREF(S) values are Names
! * <LI> NMTOKEN(S) are Nmtokens
! * <LI> ENUMERATION values match one of the tokens
! * <LI> NOTATION values match a notation name
! * <LI> ENTITIY(IES) values match an unparsed external entity
! * </UL>
! * <p/>
! * <P> Separately, make sure IDREF values match some ID
! * provided in the document (in the afterRoot method).
*/
! /* void validateAttributeSyntax (Attribute attr, String value)
throws DTDParseException {
// ID, IDREF(S) ... values are Names
if (Attribute.ID == attr.type()) {
if (!XmlNames.isName (value))
error ("V-025", new Object [] { value });
--- 902,962 ----
// but that's neither a WF nor a validity constraint.
int nextSuffix;
char c;
! if (value.length() < 2) {
return false;
+ }
c = value.charAt(1);
if (c == '-') { // IANA, or user, code
c = value.charAt(0);
! if (!(c == 'i' || c == 'I' || c == 'x' || c == 'X')) {
return false;
+ }
nextSuffix = 1;
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
// 2 letter ISO code, or error
c = value.charAt(0);
! if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
return false;
+ }
nextSuffix = 2;
! } else {
return false;
+ }
// here "suffix" ::= '-' [a-zA-Z]+ suffix*
while (nextSuffix < value.length()) {
c = value.charAt(nextSuffix);
! if (c != '-') {
break;
+ }
while (++nextSuffix < value.length()) {
c = value.charAt(nextSuffix);
! if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
break;
}
}
+ }
return value.length() == nextSuffix && c != '-';
}
//
// CHAPTER 3: Logical Structures
//
/**
! * To validate, subclassers should at this time make sure that values are of
! * the declared types:<UL> <LI> ID and IDREF(S) values are Names <LI>
! * NMTOKEN(S) are Nmtokens <LI> ENUMERATION values match one of the tokens
! * <LI> NOTATION values match a notation name <LI> ENTITIY(IES) values match
! * an unparsed external entity </UL>
! * <p>
! * <P> Separately, make sure IDREF values match some ID provided in the
! * document (in the afterRoot method).
*/
! /* void validateAttributeSyntax (Attribute attr, String value)
throws DTDParseException {
// ID, IDREF(S) ... values are Names
if (Attribute.ID == attr.type()) {
if (!XmlNames.isName (value))
error ("V-025", new Object [] { value });
*** 1043,1092 ****
error ("V-040", null);
} else if (Attribute.CDATA != attr.type())
throw new InternalError (attr.type());
}
! */
! /*
private boolean isUnparsedEntity (String name)
{
Object e = entities.getNonInterned (name);
if (e == null || !(e instanceof ExternalEntity))
return false;
return ((ExternalEntity)e).notation != null;
}
! */
private boolean maybeElementDecl()
throws IOException, SAXException {
// [45] elementDecl ::= '<!ELEMENT' S Name S contentspec S? '>'
// [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
InputEntity start = peekDeclaration("!ELEMENT");
! if (start == null)
return false;
// n.b. for content models where inter-element whitespace is
// ignorable, we mark that fact here.
String name = getMarkupDeclname("F-015", true);
// Element element = (Element) elements.get (name);
// boolean declEffective = false;
! /*
if (element != null) {
if (element.contentModel() != null) {
error ("V-012", new Object [] { name });
} // else <!ATTLIST name ...> came first
} else {
element = new Element(name);
elements.put (element.name(), element);
declEffective = true;
}
! */
! if (declaredElements.contains(name))
error("V-012", new Object[]{name});
! else {
declaredElements.add(name);
// declEffective = true;
}
short modelType;
--- 1055,1105 ----
error ("V-040", null);
} else if (Attribute.CDATA != attr.type())
throw new InternalError (attr.type());
}
! */
! /*
private boolean isUnparsedEntity (String name)
{
Object e = entities.getNonInterned (name);
if (e == null || !(e instanceof ExternalEntity))
return false;
return ((ExternalEntity)e).notation != null;
}
! */
private boolean maybeElementDecl()
throws IOException, SAXException {
// [45] elementDecl ::= '<!ELEMENT' S Name S contentspec S? '>'
// [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
InputEntity start = peekDeclaration("!ELEMENT");
! if (start == null) {
return false;
+ }
// n.b. for content models where inter-element whitespace is
// ignorable, we mark that fact here.
String name = getMarkupDeclname("F-015", true);
// Element element = (Element) elements.get (name);
// boolean declEffective = false;
! /*
if (element != null) {
if (element.contentModel() != null) {
error ("V-012", new Object [] { name });
} // else <!ATTLIST name ...> came first
} else {
element = new Element(name);
elements.put (element.name(), element);
declEffective = true;
}
! */
! if (declaredElements.contains(name)) {
error("V-012", new Object[]{name});
! } else {
declaredElements.add(name);
// declEffective = true;
}
short modelType;
*** 1103,1127 ****
dtdHandler.endContentModel(name, modelType);
maybeWhitespace();
char c = getc();
! if (c != '>')
! fatal("P-036", new Object[]{name, new Character(c)});
! if (start != in)
error("V-013", null);
/// dtdHandler.elementDecl(element);
return true;
}
// We're leaving the content model as a regular expression;
// it's an efficient natural way to express such things, and
// libraries often interpret them. No whitespace in the
// model we store, though!
-
/**
* returns content model type.
*/
private short getMixedOrChildren(String elementName/*Element element*/)
throws IOException, SAXException {
--- 1116,1141 ----
dtdHandler.endContentModel(name, modelType);
maybeWhitespace();
char c = getc();
! if (c != '>') {
! fatal("P-036", new Object[]{name, Character.valueOf(c)});
! }
! if (start != in) {
error("V-013", null);
+ }
/// dtdHandler.elementDecl(element);
return true;
}
// We're leaving the content model as a regular expression;
// it's an efficient natural way to express such things, and
// libraries often interpret them. No whitespace in the
// model we store, though!
/**
* returns content model type.
*/
private short getMixedOrChildren(String elementName/*Element element*/)
throws IOException, SAXException {
*** 1184,1197 ****
// getFrequency(temp);
///->
getcps(elementName, next);
/// getFrequency(); <- this looks like a bug
///<-
! } else
! fatal((type == 0) ? "P-039" :
! ((type == ',') ? "P-037" : "P-038"),
! new Object[]{new Character(getc())});
maybeWhitespace();
if (decided) {
char c = getc();
--- 1198,1212 ----
// getFrequency(temp);
///->
getcps(elementName, next);
/// getFrequency(); <- this looks like a bug
///<-
! } else {
! fatal((type == 0) ? "P-039"
! : ((type == ',') ? "P-037" : "P-038"),
! new Object[]{Character.valueOf(getc())});
! }
maybeWhitespace();
if (decided) {
char c = getc();
*** 1207,1218 ****
ungetc();
continue;
} else {
fatal((type == 0) ? "P-041" : "P-040",
new Object[]{
! new Character(c),
! new Character(type)
});
}
} else {
type = getc();
switch (type) {
--- 1222,1233 ----
ungetc();
continue;
} else {
fatal((type == 0) ? "P-041" : "P-040",
new Object[]{
! Character.valueOf(c),
! Character.valueOf(type)
});
}
} else {
type = getc();
switch (type) {
*** 1231,1242 ****
strTmp.append(type);
}
maybeWhitespace();
} while (!peek(")"));
! if (in != start)
error("V-014", new Object[]{elementName});
strTmp.append(')');
dtdHandler.endModelGroup(getFrequency());
// return retval;
}
--- 1246,1258 ----
strTmp.append(type);
}
maybeWhitespace();
} while (!peek(")"));
! if (in != start) {
error("V-014", new Object[]{elementName});
+ }
strTmp.append(')');
dtdHandler.endModelGroup(getFrequency());
// return retval;
}
*** 1284,1295 ****
// [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
// | '(' S? '#PCDATA' S? ')'
maybeWhitespace();
if (peek("\u0029*") || peek("\u0029")) {
! if (in != start)
error("V-014", new Object[]{elementName});
strTmp.append(')');
// element.setContentModel(new StringModel(StringModelType.PCDATA));
return;
}
--- 1300,1312 ----
// [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
// | '(' S? '#PCDATA' S? ')'
maybeWhitespace();
if (peek("\u0029*") || peek("\u0029")) {
! if (in != start) {
error("V-014", new Object[]{elementName});
+ }
strTmp.append(')');
// element.setContentModel(new StringModel(StringModelType.PCDATA));
return;
}
*** 1303,1315 ****
strTmp.append('|');
maybeWhitespace();
doLexicalPE = true;
name = maybeGetName();
! if (name == null)
! fatal("P-042", new Object[]
! {elementName, Integer.toHexString(getc())});
if (l.contains(name)) {
error("V-015", new Object[]{name});
} else {
l.add(name);
dtdHandler.mixedElement(name);
--- 1320,1332 ----
strTmp.append('|');
maybeWhitespace();
doLexicalPE = true;
name = maybeGetName();
! if (name == null) {
! fatal("P-042", new Object[]{elementName, Integer.toHexString(getc())});
! }
if (l.contains(name)) {
error("V-015", new Object[]{name});
} else {
l.add(name);
dtdHandler.mixedElement(name);
*** 1317,1330 ****
strTmp.append(name);
maybeWhitespace();
}
if (!peek("\u0029*")) // right paren
! fatal("P-043", new Object[]
! {elementName, new Character(getc())});
! if (in != start)
error("V-014", new Object[]{elementName});
strTmp.append(')');
// ChoiceModel cm = new ChoiceModel((Collection)l);
// cm.setRepeat(Repeat.ZERO_OR_MORE);
// element.setContentModel(cm);
}
--- 1334,1349 ----
strTmp.append(name);
maybeWhitespace();
}
if (!peek("\u0029*")) // right paren
! {
! fatal("P-043", new Object[]{elementName, Character.valueOf(getc())});
! }
! if (in != start) {
error("V-014", new Object[]{elementName});
+ }
strTmp.append(')');
// ChoiceModel cm = new ChoiceModel((Collection)l);
// cm.setRepeat(Repeat.ZERO_OR_MORE);
// element.setContentModel(cm);
}
*** 1333,1344 ****
throws IOException, SAXException {
// [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
InputEntity start = peekDeclaration("!ATTLIST");
! if (start == null)
return false;
String elementName = getMarkupDeclname("F-016", true);
// Element element = (Element) elements.get (name);
// if (element == null) {
--- 1352,1364 ----
throws IOException, SAXException {
// [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
InputEntity start = peekDeclaration("!ATTLIST");
! if (start == null) {
return false;
+ }
String elementName = getMarkupDeclname("F-016", true);
// Element element = (Element) elements.get (name);
// if (element == null) {
*** 1359,1377 ****
String entityName = maybeGetName();
if (entityName != null) {
nextChar(';', "F-021", entityName);
whitespace("F-021");
continue;
! } else
fatal("P-011");
}
ungetc();
// look for attribute name otherwise
String attName = maybeGetName();
if (attName == null) {
! fatal("P-044", new Object[]{new Character(getc())});
}
whitespace("F-001");
/// Attribute a = new Attribute (name);
--- 1379,1398 ----
String entityName = maybeGetName();
if (entityName != null) {
nextChar(';', "F-021", entityName);
whitespace("F-021");
continue;
! } else {
fatal("P-011");
}
+ }
ungetc();
// look for attribute name otherwise
String attName = maybeGetName();
if (attName == null) {
! fatal("P-044", new Object[]{Character.valueOf(getc())});
}
whitespace("F-001");
/// Attribute a = new Attribute (name);
*** 1380,1419 ****
// Note: use the type constants from Attribute
// so that "==" may be used (faster)
// [55] StringType ::= 'CDATA'
! if (peek(TYPE_CDATA))
! /// a.setType(Attribute.CDATA);
typeName = TYPE_CDATA;
!
! // [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS'
// | 'ENTITY' | 'ENTITIES'
// | 'NMTOKEN' | 'NMTOKENS'
// n.b. if "IDREFS" is there, both "ID" and "IDREF"
// match peekahead ... so this order matters!
! else if (peek(TYPE_IDREFS))
typeName = TYPE_IDREFS;
! else if (peek(TYPE_IDREF))
typeName = TYPE_IDREF;
! else if (peek(TYPE_ID)) {
typeName = TYPE_ID;
// TODO: should implement this error check?
/// if (element.id() != null) {
/// error ("V-016", new Object [] { element.id() });
/// } else
/// element.setId(name);
! } else if (peek(TYPE_ENTITY))
typeName = TYPE_ENTITY;
! else if (peek(TYPE_ENTITIES))
typeName = TYPE_ENTITIES;
! else if (peek(TYPE_NMTOKENS))
typeName = TYPE_NMTOKENS;
! else if (peek(TYPE_NMTOKEN))
typeName = TYPE_NMTOKEN;
!
! // [57] EnumeratedType ::= NotationType | Enumeration
// [58] NotationType ::= 'NOTATION' S '(' S? Name
// (S? '|' S? Name)* S? ')'
else if (peek(TYPE_NOTATION)) {
typeName = TYPE_NOTATION;
whitespace("F-002");
--- 1401,1438 ----
// Note: use the type constants from Attribute
// so that "==" may be used (faster)
// [55] StringType ::= 'CDATA'
! if (peek(TYPE_CDATA)) /// a.setType(Attribute.CDATA);
! {
typeName = TYPE_CDATA;
! } // [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS'
// | 'ENTITY' | 'ENTITIES'
// | 'NMTOKEN' | 'NMTOKENS'
// n.b. if "IDREFS" is there, both "ID" and "IDREF"
// match peekahead ... so this order matters!
! else if (peek(TYPE_IDREFS)) {
typeName = TYPE_IDREFS;
! } else if (peek(TYPE_IDREF)) {
typeName = TYPE_IDREF;
! } else if (peek(TYPE_ID)) {
typeName = TYPE_ID;
// TODO: should implement this error check?
/// if (element.id() != null) {
/// error ("V-016", new Object [] { element.id() });
/// } else
/// element.setId(name);
! } else if (peek(TYPE_ENTITY)) {
typeName = TYPE_ENTITY;
! } else if (peek(TYPE_ENTITIES)) {
typeName = TYPE_ENTITIES;
! } else if (peek(TYPE_NMTOKENS)) {
typeName = TYPE_NMTOKENS;
! } else if (peek(TYPE_NMTOKEN)) {
typeName = TYPE_NMTOKEN;
! } // [57] EnumeratedType ::= NotationType | Enumeration
// [58] NotationType ::= 'NOTATION' S '(' S? Name
// (S? '|' S? Name)* S? ')'
else if (peek(TYPE_NOTATION)) {
typeName = TYPE_NOTATION;
whitespace("F-002");
*** 1421,1439 ****
maybeWhitespace();
values = new Vector();
do {
String name;
! if ((name = maybeGetName()) == null)
fatal("P-068");
// permit deferred declarations
! if (notations.get(name) == null)
notations.put(name, name);
values.addElement(name);
maybeWhitespace();
! if (peek("|"))
maybeWhitespace();
} while (!peek(")"));
/// a.setValues(new String [v.size ()]);
/// for (int i = 0; i < v.size (); i++)
/// a.setValue(i, (String)v.elementAt(i));
--- 1440,1461 ----
maybeWhitespace();
values = new Vector();
do {
String name;
! if ((name = maybeGetName()) == null) {
fatal("P-068");
+ }
// permit deferred declarations
! if (notations.get(name) == null) {
notations.put(name, name);
+ }
values.addElement(name);
maybeWhitespace();
! if (peek("|")) {
maybeWhitespace();
+ }
} while (!peek(")"));
/// a.setValues(new String [v.size ()]);
/// for (int i = 0; i < v.size (); i++)
/// a.setValue(i, (String)v.elementAt(i));
*** 1449,1515 ****
do {
String name = getNmtoken();
/// v.addElement (name);
values.addElement(name);
maybeWhitespace();
! if (peek("|"))
maybeWhitespace();
} while (!peek(")"));
/// a.setValues(new String [v.size ()]);
/// for (int i = 0; i < v.size (); i++)
/// a.setValue(i, (String)v.elementAt(i));
} else {
fatal("P-045",
! new Object[]{attName, new Character(getc())});
typeName = null;
}
short attributeUse;
String defaultValue = null;
// [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED'
// | (('#FIXED' S)? AttValue)
whitespace("F-003");
! if (peek("#REQUIRED"))
attributeUse = DTDEventListener.USE_REQUIRED;
! /// a.setIsRequired(true);
else if (peek("#FIXED")) {
/// if (a.type() == Attribute.ID)
! if (typeName == TYPE_ID)
error("V-017", new Object[]{attName});
/// a.setIsFixed(true);
attributeUse = DTDEventListener.USE_FIXED;
whitespace("F-004");
parseLiteral(false);
/// if (a.type() != Attribute.CDATA)
/// a.setDefaultValue(normalize(false));
/// else
/// a.setDefaultValue(strTmp.toString());
! if (typeName == TYPE_CDATA)
defaultValue = normalize(false);
! else
defaultValue = strTmp.toString();
// TODO: implement this check
/// if (a.type() != Attribute.CDATA)
/// validateAttributeSyntax (a, a.defaultValue());
} else if (!peek("#IMPLIED")) {
attributeUse = DTDEventListener.USE_IMPLIED;
/// if (a.type() == Attribute.ID)
! if (typeName == TYPE_ID)
error("V-018", new Object[]{attName});
parseLiteral(false);
/// if (a.type() != Attribute.CDATA)
/// a.setDefaultValue(normalize(false));
/// else
/// a.setDefaultValue(strTmp.toString());
! if (typeName == TYPE_CDATA)
defaultValue = normalize(false);
! else
defaultValue = strTmp.toString();
// TODO: implement this check
/// if (a.type() != Attribute.CDATA)
/// validateAttributeSyntax (a, a.defaultValue());
} else {
--- 1471,1542 ----
do {
String name = getNmtoken();
/// v.addElement (name);
values.addElement(name);
maybeWhitespace();
! if (peek("|")) {
maybeWhitespace();
+ }
} while (!peek(")"));
/// a.setValues(new String [v.size ()]);
/// for (int i = 0; i < v.size (); i++)
/// a.setValue(i, (String)v.elementAt(i));
} else {
fatal("P-045",
! new Object[]{attName, Character.valueOf(getc())});
typeName = null;
}
short attributeUse;
String defaultValue = null;
// [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED'
// | (('#FIXED' S)? AttValue)
whitespace("F-003");
! if (peek("#REQUIRED")) {
attributeUse = DTDEventListener.USE_REQUIRED;
! } /// a.setIsRequired(true);
else if (peek("#FIXED")) {
/// if (a.type() == Attribute.ID)
! if (typeName == TYPE_ID) {
error("V-017", new Object[]{attName});
+ }
/// a.setIsFixed(true);
attributeUse = DTDEventListener.USE_FIXED;
whitespace("F-004");
parseLiteral(false);
/// if (a.type() != Attribute.CDATA)
/// a.setDefaultValue(normalize(false));
/// else
/// a.setDefaultValue(strTmp.toString());
! if (typeName == TYPE_CDATA) {
defaultValue = normalize(false);
! } else {
defaultValue = strTmp.toString();
+ }
// TODO: implement this check
/// if (a.type() != Attribute.CDATA)
/// validateAttributeSyntax (a, a.defaultValue());
} else if (!peek("#IMPLIED")) {
attributeUse = DTDEventListener.USE_IMPLIED;
/// if (a.type() == Attribute.ID)
! if (typeName == TYPE_ID) {
error("V-018", new Object[]{attName});
+ }
parseLiteral(false);
/// if (a.type() != Attribute.CDATA)
/// a.setDefaultValue(normalize(false));
/// else
/// a.setDefaultValue(strTmp.toString());
! if (typeName == TYPE_CDATA) {
defaultValue = normalize(false);
! } else {
defaultValue = strTmp.toString();
+ }
// TODO: implement this check
/// if (a.type() != Attribute.CDATA)
/// validateAttributeSyntax (a, a.defaultValue());
} else {
*** 1517,1541 ****
attributeUse = DTDEventListener.USE_NORMAL;
}
if (XmlLang.equals(attName)
&& defaultValue/* a.defaultValue()*/ != null
! && !isXmlLang(defaultValue/*a.defaultValue()*/))
error("P-033", new Object[]{defaultValue /*a.defaultValue()*/});
// TODO: isn't it an error to specify the same attribute twice?
/// if (!element.attributes().contains(a)) {
/// element.addAttribute(a);
/// dtdHandler.attributeDecl(a);
/// }
! String[] v = (values != null) ? (String[]) values.toArray(new String[0]) : null;
dtdHandler.attributeDecl(elementName, attName, typeName, v, attributeUse, defaultValue);
maybeWhitespace();
}
! if (start != in)
error("V-013", null);
return true;
}
// used when parsing literal attribute values,
// or public identifiers.
--- 1544,1570 ----
attributeUse = DTDEventListener.USE_NORMAL;
}
if (XmlLang.equals(attName)
&& defaultValue/* a.defaultValue()*/ != null
! && !isXmlLang(defaultValue/*a.defaultValue()*/)) {
error("P-033", new Object[]{defaultValue /*a.defaultValue()*/});
+ }
// TODO: isn't it an error to specify the same attribute twice?
/// if (!element.attributes().contains(a)) {
/// element.addAttribute(a);
/// dtdHandler.attributeDecl(a);
/// }
! String[] v = (values != null) ? (String[]) values.toArray(new String[values.size()]) : null;
dtdHandler.attributeDecl(elementName, attName, typeName, v, attributeUse, defaultValue);
maybeWhitespace();
}
! if (start != in) {
error("V-013", null);
+ }
return true;
}
// used when parsing literal attribute values,
// or public identifiers.
*** 1549,1617 ****
String s2 = s.trim();
boolean didStrip = false;
if (s != s2) {
s = s2;
- s2 = null;
didStrip = true;
}
strTmp = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (!XmlChars.isSpace(c)) {
strTmp.append(c);
continue;
}
strTmp.append(' ');
! while (++i < s.length() && XmlChars.isSpace(s.charAt(i)))
didStrip = true;
i--;
}
! if (didStrip)
return strTmp.toString();
! else
return s;
}
private boolean maybeConditionalSect()
throws IOException, SAXException {
// [61] conditionalSect ::= includeSect | ignoreSect
! if (!peek("<!["))
return false;
String keyword;
InputEntity start = in;
maybeWhitespace();
! if ((keyword = maybeGetName()) == null)
fatal("P-046");
maybeWhitespace();
nextChar('[', "F-030", null);
// [62] includeSect ::= '<![' S? 'INCLUDE' S? '['
// extSubsetDecl ']]>'
if ("INCLUDE".equals(keyword)) {
! for (; ;) {
! while (in.isEOF() && in != start)
in = in.pop();
if (in.isEOF()) {
error("V-020", null);
}
! if (peek("]]>"))
break;
doLexicalPE = false;
! if (maybeWhitespace())
continue;
! if (maybePEReference())
continue;
doLexicalPE = true;
! if (maybeMarkupDecl() || maybeConditionalSect())
continue;
fatal("P-047");
}
// [63] ignoreSect ::= '<![' S? 'IGNORE' S? '['
--- 1578,1654 ----
String s2 = s.trim();
boolean didStrip = false;
if (s != s2) {
s = s2;
didStrip = true;
}
strTmp = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (!XmlChars.isSpace(c)) {
strTmp.append(c);
continue;
}
strTmp.append(' ');
! while (++i < s.length() && XmlChars.isSpace(s.charAt(i))) {
didStrip = true;
+ }
i--;
}
! if (didStrip) {
return strTmp.toString();
! } else {
return s;
}
+ }
private boolean maybeConditionalSect()
throws IOException, SAXException {
// [61] conditionalSect ::= includeSect | ignoreSect
! if (!peek("<![")) {
return false;
+ }
String keyword;
InputEntity start = in;
maybeWhitespace();
! if ((keyword = maybeGetName()) == null) {
fatal("P-046");
+ }
maybeWhitespace();
nextChar('[', "F-030", null);
// [62] includeSect ::= '<![' S? 'INCLUDE' S? '['
// extSubsetDecl ']]>'
if ("INCLUDE".equals(keyword)) {
! for (;;) {
! while (in.isEOF() && in != start) {
in = in.pop();
+ }
if (in.isEOF()) {
error("V-020", null);
}
! if (peek("]]>")) {
break;
+ }
doLexicalPE = false;
! if (maybeWhitespace()) {
continue;
! }
! if (maybePEReference()) {
continue;
+ }
doLexicalPE = true;
! if (maybeMarkupDecl() || maybeConditionalSect()) {
continue;
+ }
fatal("P-047");
}
// [63] ignoreSect ::= '<![' S? 'IGNORE' S? '['
*** 1624,1674 ****
// ignoreSectcontents
doLexicalPE = false;
while (nestlevel > 0) {
char c = getc(); // will pop input entities
if (c == '<') {
! if (peek("!["))
nestlevel++;
} else if (c == ']') {
! if (peek("]>"))
nestlevel--;
! } else
continue;
}
! } else
fatal("P-048", new Object[]{keyword});
return true;
}
-
//
// CHAPTER 4: Physical Structures
//
-
// parse decimal or hex numeric character reference
private int parseCharNumber()
throws IOException, SAXException {
char c;
int retval = 0;
// n.b. we ignore overflow ...
if (getc() != 'x') {
ungetc();
! for (; ;) {
c = getc();
if (c >= '0' && c <= '9') {
retval *= 10;
retval += (c - '0');
continue;
}
! if (c == ';')
return retval;
fatal("P-049");
}
! } else
! for (; ;) {
c = getc();
if (c >= '0' && c <= '9') {
retval <<= 4;
retval += (c - '0');
continue;
--- 1661,1714 ----
// ignoreSectcontents
doLexicalPE = false;
while (nestlevel > 0) {
char c = getc(); // will pop input entities
if (c == '<') {
! if (peek("![")) {
nestlevel++;
+ }
} else if (c == ']') {
! if (peek("]>")) {
nestlevel--;
! }
! } else {
continue;
}
! }
! } else {
fatal("P-048", new Object[]{keyword});
+ }
return true;
}
//
// CHAPTER 4: Physical Structures
//
// parse decimal or hex numeric character reference
private int parseCharNumber()
throws IOException, SAXException {
char c;
int retval = 0;
// n.b. we ignore overflow ...
if (getc() != 'x') {
ungetc();
! for (;;) {
c = getc();
if (c >= '0' && c <= '9') {
retval *= 10;
retval += (c - '0');
continue;
}
! if (c == ';') {
return retval;
+ }
fatal("P-049");
}
! } else {
! for (;;) {
c = getc();
if (c >= '0' && c <= '9') {
retval <<= 4;
retval += (c - '0');
continue;
*** 1681,1695 ****
if (c >= 'A' && c <= 'F') {
retval <<= 4;
retval += 10 + (c - 'A');
continue;
}
! if (c == ';')
return retval;
fatal("P-050");
}
}
// parameter is a UCS-4 character ... i.e. not just 16 bit UNICODE,
// though still subject to the 'Char' construct in XML
private int surrogatesToCharTmp(int ucs4)
throws SAXException {
--- 1721,1737 ----
if (c >= 'A' && c <= 'F') {
retval <<= 4;
retval += 10 + (c - 'A');
continue;
}
! if (c == ';') {
return retval;
+ }
fatal("P-050");
}
}
+ }
// parameter is a UCS-4 character ... i.e. not just 16 bit UNICODE,
// though still subject to the 'Char' construct in XML
private int surrogatesToCharTmp(int ucs4)
throws SAXException {
*** 1717,1734 ****
// This is the SYNTACTIC version of this construct.
// When processing external entities, there is also
// a LEXICAL version; see getc() and doLexicalPE.
// [69] PEReference ::= '%' Name ';'
! if (!in.peekc('%'))
return false;
String name = maybeGetName();
Object entity;
! if (name == null)
fatal("P-011");
nextChar(';', "F-021", name);
entity = params.get(name);
if (entity instanceof InternalEntity) {
InternalEntity value = (InternalEntity) entity;
--- 1759,1778 ----
// This is the SYNTACTIC version of this construct.
// When processing external entities, there is also
// a LEXICAL version; see getc() and doLexicalPE.
// [69] PEReference ::= '%' Name ';'
! if (!in.peekc('%')) {
return false;
+ }
String name = maybeGetName();
Object entity;
! if (name == null) {
fatal("P-011");
+ }
nextChar(';', "F-021", name);
entity = params.get(name);
if (entity instanceof InternalEntity) {
InternalEntity value = (InternalEntity) entity;
*** 1753,1764 ****
// [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
// [74] PEDef ::= EntityValue | ExternalID
//
InputEntity start = peekDeclaration("!ENTITY");
! if (start == null)
return false;
String entityName;
SimpleHashtable defns;
ExternalEntity externalId;
boolean doStore;
--- 1797,1809 ----
// [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
// [74] PEDef ::= EntityValue | ExternalID
//
InputEntity start = peekDeclaration("!ENTITY");
! if (start == null) {
return false;
+ }
String entityName;
SimpleHashtable defns;
ExternalEntity externalId;
boolean doStore;
*** 1773,1784 ****
doLexicalPE = false;
whitespace("F-005");
if (in.peekc('%')) {
whitespace("F-006");
defns = params;
! } else
defns = entities;
ungetc(); // leave some whitespace
doLexicalPE = true;
entityName = getMarkupDeclname("F-017", false);
whitespace("F-007");
--- 1818,1830 ----
doLexicalPE = false;
whitespace("F-005");
if (in.peekc('%')) {
whitespace("F-006");
defns = params;
! } else {
defns = entities;
+ }
ungetc(); // leave some whitespace
doLexicalPE = true;
entityName = getMarkupDeclname("F-017", false);
whitespace("F-007");
*** 1790,1853 ****
// redefine builtin internal entities, but since reporting such
// errors is optional we only give warnings ("just in case") for
// non-parameter entities.
//
doStore = (defns.get(entityName) == null);
! if (!doStore && defns == entities)
warning("P-054", new Object[]{entityName});
// internal entities
if (externalId == null) {
! char value [];
InternalEntity entity;
doLexicalPE = false; // "ab%bar;cd" -maybe-> "abcd"
parseLiteral(true);
doLexicalPE = true;
if (doStore) {
value = new char[strTmp.length()];
! if (value.length != 0)
strTmp.getChars(0, value.length, value, 0);
entity = new InternalEntity(entityName, value);
entity.isPE = (defns == params);
- entity.isFromInternalSubset = false;
defns.put(entityName, entity);
! if (defns == entities)
dtdHandler.internalGeneralEntityDecl(entityName,
new String(value));
}
// external entities (including unparsed)
} else {
// [76] NDataDecl ::= S 'NDATA' S Name
if (defns == entities && maybeWhitespace()
&& peek("NDATA")) {
externalId.notation = getMarkupDeclname("F-018", false);
// flag undeclared notation for checking after
// the DTD is fully processed
! if (notations.get(externalId.notation) == null)
notations.put(externalId.notation, Boolean.TRUE);
}
externalId.name = entityName;
externalId.isPE = (defns == params);
- externalId.isFromInternalSubset = false;
if (doStore) {
defns.put(entityName, externalId);
! if (externalId.notation != null)
dtdHandler.unparsedEntityDecl(entityName,
externalId.publicId, externalId.systemId,
externalId.notation);
! else if (defns == entities)
dtdHandler.externalGeneralEntityDecl(entityName,
externalId.publicId, externalId.systemId);
}
}
maybeWhitespace();
nextChar('>', "F-031", entityName);
! if (start != in)
error("V-013", null);
return true;
}
private ExternalEntity maybeExternalID()
throws IOException, SAXException {
--- 1836,1903 ----
// redefine builtin internal entities, but since reporting such
// errors is optional we only give warnings ("just in case") for
// non-parameter entities.
//
doStore = (defns.get(entityName) == null);
! if (!doStore && defns == entities) {
warning("P-054", new Object[]{entityName});
+ }
// internal entities
if (externalId == null) {
! char value[];
InternalEntity entity;
doLexicalPE = false; // "ab%bar;cd" -maybe-> "abcd"
parseLiteral(true);
doLexicalPE = true;
if (doStore) {
value = new char[strTmp.length()];
! if (value.length != 0) {
strTmp.getChars(0, value.length, value, 0);
+ }
entity = new InternalEntity(entityName, value);
entity.isPE = (defns == params);
defns.put(entityName, entity);
! if (defns == entities) {
dtdHandler.internalGeneralEntityDecl(entityName,
new String(value));
}
+ }
// external entities (including unparsed)
} else {
// [76] NDataDecl ::= S 'NDATA' S Name
if (defns == entities && maybeWhitespace()
&& peek("NDATA")) {
externalId.notation = getMarkupDeclname("F-018", false);
// flag undeclared notation for checking after
// the DTD is fully processed
! if (notations.get(externalId.notation) == null) {
notations.put(externalId.notation, Boolean.TRUE);
}
+ }
externalId.name = entityName;
externalId.isPE = (defns == params);
if (doStore) {
defns.put(entityName, externalId);
! if (externalId.notation != null) {
dtdHandler.unparsedEntityDecl(entityName,
externalId.publicId, externalId.systemId,
externalId.notation);
! } else if (defns == entities) {
dtdHandler.externalGeneralEntityDecl(entityName,
externalId.publicId, externalId.systemId);
}
}
+ }
maybeWhitespace();
nextChar('>', "F-031", entityName);
! if (start != in) {
error("V-013", null);
+ }
return true;
}
private ExternalEntity maybeExternalID()
throws IOException, SAXException {
*** 1858,1869 ****
ExternalEntity retval;
if (peek("PUBLIC")) {
whitespace("F-009");
temp = parsePublicId();
! } else if (!peek("SYSTEM"))
return null;
retval = new ExternalEntity(in);
retval.publicId = temp;
whitespace("F-008");
retval.systemId = parseSystemId();
--- 1908,1920 ----
ExternalEntity retval;
if (peek("PUBLIC")) {
whitespace("F-009");
temp = parsePublicId();
! } else if (!peek("SYSTEM")) {
return null;
+ }
retval = new ExternalEntity(in);
retval.publicId = temp;
whitespace("F-008");
retval.systemId = parseSystemId();
*** 1885,1913 ****
// not URLs, so we pass URIs through with scheme intact
if (temp == -1 || uri.indexOf('/') < temp) {
String baseURI;
baseURI = in.getSystemId();
! if (baseURI == null)
fatal("P-055", new Object[]{uri});
! if (uri.length() == 0)
uri = ".";
baseURI = baseURI.substring(0, baseURI.lastIndexOf('/') + 1);
! if (uri.charAt(0) != '/')
uri = baseURI + uri;
! else {
// XXX slashes at the beginning of a relative URI are
// a special case we don't handle.
throw new InternalError();
}
// letting other code map any "/xxx/../" or "/./" to "/",
// since all URIs must handle it the same.
}
// check for fragment ID in URI
! if (uri.indexOf('#') != -1)
error("P-056", new Object[]{uri});
return uri;
}
private void maybeTextDecl()
throws IOException, SAXException {
--- 1936,1967 ----
// not URLs, so we pass URIs through with scheme intact
if (temp == -1 || uri.indexOf('/') < temp) {
String baseURI;
baseURI = in.getSystemId();
! if (baseURI == null) {
fatal("P-055", new Object[]{uri});
! }
! if (uri.length() == 0) {
uri = ".";
+ }
baseURI = baseURI.substring(0, baseURI.lastIndexOf('/') + 1);
! if (uri.charAt(0) != '/') {
uri = baseURI + uri;
! } else {
// XXX slashes at the beginning of a relative URI are
// a special case we don't handle.
throw new InternalError();
}
// letting other code map any "/xxx/../" or "/./" to "/",
// since all URIs must handle it the same.
}
// check for fragment ID in URI
! if (uri.indexOf('#') != -1) {
error("P-056", new Object[]{uri});
+ }
return uri;
}
private void maybeTextDecl()
throws IOException, SAXException {
*** 1915,1928 ****
// [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
if (peek("<?xml")) {
readVersion(false, "1.0");
readEncoding(true);
maybeWhitespace();
! if (!peek("?>"))
fatal("P-057");
}
}
private void externalParameterEntity(ExternalEntity next)
throws IOException, SAXException {
//
--- 1969,1983 ----
// [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
if (peek("<?xml")) {
readVersion(false, "1.0");
readEncoding(true);
maybeWhitespace();
! if (!peek("?>")) {
fatal("P-057");
}
}
+ }
private void externalParameterEntity(ExternalEntity next)
throws IOException, SAXException {
//
*** 1950,1994 ****
if (in.isEOF()) {
in = in.pop();
continue;
}
doLexicalPE = false;
! if (maybeWhitespace())
continue;
! if (maybePEReference())
continue;
doLexicalPE = true;
! if (maybeMarkupDecl() || maybeConditionalSect())
continue;
break;
}
// if (in != pe) throw new InternalError("who popped my PE?");
! if (!pe.isEOF())
fatal("P-059", new Object[]{in.getName()});
}
private void readEncoding(boolean must)
throws IOException, SAXException {
// [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
String name = maybeReadAttribute("encoding", must);
! if (name == null)
return;
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if ((c >= 'A' && c <= 'Z')
! || (c >= 'a' && c <= 'z'))
continue;
if (i != 0
&& ((c >= '0' && c <= '9')
|| c == '-'
|| c == '_'
! || c == '.'
! ))
continue;
! fatal("P-060", new Object[]{new Character(c)});
}
//
// This should be the encoding in use, and it's even an error for
// it to be anything else (in certain cases that are impractical to
--- 2005,2055 ----
if (in.isEOF()) {
in = in.pop();
continue;
}
doLexicalPE = false;
! if (maybeWhitespace()) {
continue;
! }
! if (maybePEReference()) {
continue;
+ }
doLexicalPE = true;
! if (maybeMarkupDecl() || maybeConditionalSect()) {
continue;
+ }
break;
}
// if (in != pe) throw new InternalError("who popped my PE?");
! if (!pe.isEOF()) {
fatal("P-059", new Object[]{in.getName()});
}
+ }
private void readEncoding(boolean must)
throws IOException, SAXException {
// [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
String name = maybeReadAttribute("encoding", must);
! if (name == null) {
return;
+ }
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if ((c >= 'A' && c <= 'Z')
! || (c >= 'a' && c <= 'z')) {
continue;
+ }
if (i != 0
&& ((c >= '0' && c <= '9')
|| c == '-'
|| c == '_'
! || c == '.')) {
continue;
! }
! fatal("P-060", new Object[]{Character.valueOf(c)});
}
//
// This should be the encoding in use, and it's even an error for
// it to be anything else (in certain cases that are impractical to
*** 1999,2067 ****
// such "errors" not to be reported at all.
//
String currentEncoding = in.getEncoding();
if (currentEncoding != null
! && !name.equalsIgnoreCase(currentEncoding))
warning("P-061", new Object[]{name, currentEncoding});
}
private boolean maybeNotationDecl()
throws IOException, SAXException {
// [82] NotationDecl ::= '<!NOTATION' S Name S
// (ExternalID | PublicID) S? '>'
// [83] PublicID ::= 'PUBLIC' S PubidLiteral
InputEntity start = peekDeclaration("!NOTATION");
! if (start == null)
return false;
String name = getMarkupDeclname("F-019", false);
ExternalEntity entity = new ExternalEntity(in);
whitespace("F-011");
if (peek("PUBLIC")) {
whitespace("F-009");
entity.publicId = parsePublicId();
if (maybeWhitespace()) {
! if (!peek(">"))
entity.systemId = parseSystemId();
! else
ungetc();
}
} else if (peek("SYSTEM")) {
whitespace("F-008");
entity.systemId = parseSystemId();
! } else
fatal("P-062");
maybeWhitespace();
nextChar('>', "F-032", name);
! if (start != in)
error("V-013", null);
! if (entity.systemId != null && entity.systemId.indexOf('#') != -1)
error("P-056", new Object[]{entity.systemId});
Object value = notations.get(name);
! if (value != null && value instanceof ExternalEntity)
warning("P-063", new Object[]{name});
!
! else {
notations.put(name, entity);
dtdHandler.notationDecl(name, entity.publicId,
entity.systemId);
}
return true;
}
-
////////////////////////////////////////////////////////////////
//
// UTILITIES
//
////////////////////////////////////////////////////////////////
-
private char getc() throws IOException, SAXException {
if (!doLexicalPE) {
char c = in.getc();
return c;
--- 2060,2131 ----
// such "errors" not to be reported at all.
//
String currentEncoding = in.getEncoding();
if (currentEncoding != null
! && !name.equalsIgnoreCase(currentEncoding)) {
warning("P-061", new Object[]{name, currentEncoding});
}
+ }
private boolean maybeNotationDecl()
throws IOException, SAXException {
// [82] NotationDecl ::= '<!NOTATION' S Name S
// (ExternalID | PublicID) S? '>'
// [83] PublicID ::= 'PUBLIC' S PubidLiteral
InputEntity start = peekDeclaration("!NOTATION");
! if (start == null) {
return false;
+ }
String name = getMarkupDeclname("F-019", false);
ExternalEntity entity = new ExternalEntity(in);
whitespace("F-011");
if (peek("PUBLIC")) {
whitespace("F-009");
entity.publicId = parsePublicId();
if (maybeWhitespace()) {
! if (!peek(">")) {
entity.systemId = parseSystemId();
! } else {
ungetc();
}
+ }
} else if (peek("SYSTEM")) {
whitespace("F-008");
entity.systemId = parseSystemId();
! } else {
fatal("P-062");
+ }
maybeWhitespace();
nextChar('>', "F-032", name);
! if (start != in) {
error("V-013", null);
! }
! if (entity.systemId != null && entity.systemId.indexOf('#') != -1) {
error("P-056", new Object[]{entity.systemId});
+ }
Object value = notations.get(name);
! if (value != null && value instanceof ExternalEntity) {
warning("P-063", new Object[]{name});
! } else {
notations.put(name, entity);
dtdHandler.notationDecl(name, entity.publicId,
entity.systemId);
}
return true;
}
////////////////////////////////////////////////////////////////
//
// UTILITIES
//
////////////////////////////////////////////////////////////////
private char getc() throws IOException, SAXException {
if (!doLexicalPE) {
char c = in.getc();
return c;
*** 2084,2123 ****
// Also, there are some validity constraints in this area.
//
char c;
while (in.isEOF()) {
! if (in.isInternal() || (doLexicalPE && !in.isDocument()))
in = in.pop();
! else {
fatal("P-064", new Object[]{in.getName()});
}
}
if ((c = in.getc()) == '%' && doLexicalPE) {
// PE ref ::= '%' name ';'
String name = maybeGetName();
Object entity;
! if (name == null)
fatal("P-011");
nextChar(';', "F-021", name);
entity = params.get(name);
// push a magic "entity" before and after the
// real one, so ungetc() behaves uniformly
pushReader(" ".toCharArray(), null, false);
! if (entity instanceof InternalEntity)
pushReader(((InternalEntity) entity).buf, name, false);
! else if (entity instanceof ExternalEntity)
! // PEs can't be unparsed!
// XXX if this returns false ...
pushReader((ExternalEntity) entity);
! else if (entity == null)
! // see note in maybePEReference re making this be nonfatal.
fatal("V-022");
! else
throw new InternalError();
pushReader(" ".toCharArray(), null, false);
return in.getc();
}
return c;
}
--- 2148,2189 ----
// Also, there are some validity constraints in this area.
//
char c;
while (in.isEOF()) {
! if (in.isInternal() || (doLexicalPE && !in.isDocument())) {
in = in.pop();
! } else {
fatal("P-064", new Object[]{in.getName()});
}
}
if ((c = in.getc()) == '%' && doLexicalPE) {
// PE ref ::= '%' name ';'
String name = maybeGetName();
Object entity;
! if (name == null) {
fatal("P-011");
+ }
nextChar(';', "F-021", name);
entity = params.get(name);
// push a magic "entity" before and after the
// real one, so ungetc() behaves uniformly
pushReader(" ".toCharArray(), null, false);
! if (entity instanceof InternalEntity) {
pushReader(((InternalEntity) entity).buf, name, false);
! } else if (entity instanceof ExternalEntity) // PEs can't be unparsed!
// XXX if this returns false ...
+ {
pushReader((ExternalEntity) entity);
! } else if (entity == null) // see note in maybePEReference re making this be nonfatal.
! {
fatal("V-022");
! } else {
throw new InternalError();
+ }
pushReader(" ".toCharArray(), null, false);
return in.getc();
}
return c;
}
*** 2133,2171 ****
return in.peek(s, null);
}
// Return the entity starting the specified declaration
// (for validating declaration nesting) else null.
-
private InputEntity peekDeclaration(String s)
throws IOException, SAXException {
InputEntity start;
! if (!in.peekc('<'))
return null;
start = in;
! if (in.peek(s, null))
return start;
in.ungetc();
return null;
}
private void nextChar(char c, String location, String near)
throws IOException, SAXException {
! while (in.isEOF() && !in.isDocument())
in = in.pop();
! if (!in.peekc(c))
! fatal("P-008", new Object[]
! {new Character(c),
messages.getMessage(locale, location),
(near == null ? "" : ('"' + near + '"'))});
}
!
! private void pushReader(char buf [], String name, boolean isGeneral)
throws SAXException {
InputEntity r = InputEntity.getInputEntity(dtdHandler, locale);
r.init(buf, name, in, !isGeneral);
in = r;
--- 2199,2238 ----
return in.peek(s, null);
}
// Return the entity starting the specified declaration
// (for validating declaration nesting) else null.
private InputEntity peekDeclaration(String s)
throws IOException, SAXException {
InputEntity start;
! if (!in.peekc('<')) {
return null;
+ }
start = in;
! if (in.peek(s, null)) {
return start;
+ }
in.ungetc();
return null;
}
private void nextChar(char c, String location, String near)
throws IOException, SAXException {
! while (in.isEOF() && !in.isDocument()) {
in = in.pop();
! }
! if (!in.peekc(c)) {
! fatal("P-008", new Object[]{Character.valueOf(c),
messages.getMessage(locale, location),
(near == null ? "" : ('"' + near + '"'))});
}
+ }
! private void pushReader(char buf[], String name, boolean isGeneral)
throws SAXException {
InputEntity r = InputEntity.getInputEntity(dtdHandler, locale);
r.init(buf, name, in, !isGeneral);
in = r;
*** 2179,2190 ****
try {
s = next.getInputSource(resolver);
} catch (IOException e) {
String msg =
"unable to open the external entity from :" + next.systemId;
! if (next.publicId != null)
msg += " (public id:" + next.publicId + ")";
SAXParseException spe = new SAXParseException(msg,
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber(), e);
dtdHandler.fatalError(spe);
throw e;
--- 2246,2258 ----
try {
s = next.getInputSource(resolver);
} catch (IOException e) {
String msg =
"unable to open the external entity from :" + next.systemId;
! if (next.publicId != null) {
msg += " (public id:" + next.publicId + ")";
+ }
SAXParseException spe = new SAXParseException(msg,
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber(), e);
dtdHandler.fatalError(spe);
throw e;
*** 2214,2234 ****
return (in == null) ? -1 : in.getColumnNumber();
}
// error handling convenience routines
!
! private void warning(String messageId, Object parameters [])
throws SAXException {
SAXParseException e = new SAXParseException(messages.getMessage(locale, messageId, parameters),
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber());
dtdHandler.warning(e);
}
! void error(String messageId, Object parameters [])
throws SAXException {
SAXParseException e = new SAXParseException(messages.getMessage(locale, messageId, parameters),
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber());
--- 2282,2301 ----
return (in == null) ? -1 : in.getColumnNumber();
}
// error handling convenience routines
! private void warning(String messageId, Object parameters[])
throws SAXException {
SAXParseException e = new SAXParseException(messages.getMessage(locale, messageId, parameters),
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber());
dtdHandler.warning(e);
}
! void error(String messageId, Object parameters[])
throws SAXException {
SAXParseException e = new SAXParseException(messages.getMessage(locale, messageId, parameters),
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber());
*** 2238,2248 ****
private void fatal(String messageId) throws SAXException {
fatal(messageId, null);
}
! private void fatal(String messageId, Object parameters [])
throws SAXException {
SAXParseException e = new SAXParseException(messages.getMessage(locale, messageId, parameters),
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber());
--- 2305,2315 ----
private void fatal(String messageId) throws SAXException {
fatal(messageId, null);
}
! private void fatal(String messageId, Object parameters[])
throws SAXException {
SAXParseException e = new SAXParseException(messages.getMessage(locale, messageId, parameters),
getPublicId(), getSystemId(), getLineNumber(), getColumnNumber());
*** 2265,2307 ****
// Unless we auto-grow this, the default size should be a
// reasonable bit larger than needed for most XML files
// we've yet seen (and be prime). If it's too small, the
// penalty is just excess cache collisions.
//
! NameCacheEntry hashtable [] = new NameCacheEntry[541];
//
// Usually we just want to get the 'symbol' for these chars
//
! String lookup(char value [], int len) {
return lookupEntry(value, len).name;
}
//
// Sometimes we need to scan the chars in the resulting
// string, so there's an accessor which exposes them.
// (Mostly for element end tags.)
//
! NameCacheEntry lookupEntry(char value [], int len) {
int index = 0;
NameCacheEntry entry;
// hashing to get index
! for (int i = 0; i < len; i++)
index = index * 31 + value[i];
index &= 0x7fffffff;
index %= hashtable.length;
// return entry if one's there ...
for (entry = hashtable[index];
entry != null;
entry = entry.next) {
! if (entry.matches(value, len))
return entry;
}
// else create new one
entry = new NameCacheEntry();
entry.chars = new char[len];
System.arraycopy(value, 0, entry.chars, 0, len);
--- 2332,2377 ----
// Unless we auto-grow this, the default size should be a
// reasonable bit larger than needed for most XML files
// we've yet seen (and be prime). If it's too small, the
// penalty is just excess cache collisions.
//
!
! NameCacheEntry hashtable[] = new NameCacheEntry[541];
//
// Usually we just want to get the 'symbol' for these chars
//
! String lookup(char value[], int len) {
return lookupEntry(value, len).name;
}
//
// Sometimes we need to scan the chars in the resulting
// string, so there's an accessor which exposes them.
// (Mostly for element end tags.)
//
! NameCacheEntry lookupEntry(char value[], int len) {
int index = 0;
NameCacheEntry entry;
// hashing to get index
! for (int i = 0; i < len; i++) {
index = index * 31 + value[i];
+ }
index &= 0x7fffffff;
index %= hashtable.length;
// return entry if one's there ...
for (entry = hashtable[index];
entry != null;
entry = entry.next) {
! if (entry.matches(value, len)) {
return entry;
}
+ }
// else create new one
entry = new NameCacheEntry();
entry.chars = new char[len];
System.arraycopy(value, 0, entry.chars, 0, len);
*** 2319,2338 ****
}
static class NameCacheEntry {
String name;
! char chars [];
NameCacheEntry next;
! boolean matches(char value [], int len) {
!
! if (chars.length != len)
return false;
! for (int i = 0; i < len; i++)
! if (value[i] != chars[i])
return false;
return true;
}
}
//
--- 2389,2410 ----
}
static class NameCacheEntry {
String name;
! char chars[];
NameCacheEntry next;
! boolean matches(char value[], int len) {
! if (chars == null || chars.length != len) {
return false;
! }
! for (int i = 0; i < len; i++) {
! if (value[i] != chars[i]) {
return false;
+ }
+ }
return true;
}
}
//
*** 2344,2350 ****
Catalog() {
super(DTDParser.class);
}
}
-
}
--- 2416,2421 ----
< prev index next >