--- old/src/jdk.xml.bind/share/classes/com/sun/xml/internal/dtdparser/DTDParser.java 2015-10-22 23:51:07.000000000 +0200 +++ new/src/jdk.xml.bind/share/classes/com/sun/xml/internal/dtdparser/DTDParser.java 2015-10-22 23:51:06.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,28 +38,31 @@ 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. - *

- * This conforms to the portion of the XML 1.0 specification related - * to the external DTD subset. - *

- * 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. - *

- * 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. + *

+ * This conforms to the portion of the XML 1.0 specification related to the + * external DTD subset. + *

+ * 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. + *

+ * 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 $ + * @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"; @@ -70,47 +73,39 @@ 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 char nameTmp[]; private NameCache nameCache; - private char charTmp [] = new char[2]; - + 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). + * @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 { @@ -129,20 +124,19 @@ } /** - * 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 - * setLocale(). Such a list could be provided by a variety of user - * preference mechanisms, including the HTTP Accept-Language - * header field. + * 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 setLocale(). + * Such a list could be provided by a variety of user preference mechanisms, + * including the HTTP Accept-Language 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. + * 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 []) + public Locale chooseLocale(String languages[]) throws SAXException { Locale l = messages.chooseLocale(languages); @@ -174,24 +168,29 @@ */ public void setDtdHandler(DTDEventListener handler) { dtdHandler = handler; - if (handler != null) + 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(); } }); + } } /** @@ -215,25 +214,25 @@ */ public void parse(String uri) throws IOException, SAXException { - InputSource in; + InputSource inSource; init(); // System.out.println ("parse (\"" + uri + "\")"); - in = resolver.resolveEntity(null, uri); + inSource = 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); + 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 (in.getSystemId() == null) { + } else if (inSource.getSystemId() == null) { warning("P-065", null); - in.setSystemId(uri); + inSource.setSystemId(uri); } - parseInternal(in); + parseInternal(inSource); } // makes sure the parser is reset to "before a document" @@ -263,12 +262,15 @@ builtin("quot", "\""); builtin("apos", "'"); - if (locale == null) + if (locale == null) { locale = Locale.getDefault(); - if (resolver == null) + } + if (resolver == null) { resolver = new Resolver(); - if (dtdHandler == null) + } + if (dtdHandler == null) { dtdHandler = new DTDHandlerBase(); + } } private void builtin(String entityName, String entityValue) { @@ -277,7 +279,6 @@ entities.put(entityName, entity); } - //////////////////////////////////////////////////////////////// // // parsing is by recursive descent, code roughly @@ -289,13 +290,13 @@ // relatively easy to get diagnostics that make sense. // //////////////////////////////////////////////////////////////// - - + @SuppressWarnings("CallToThreadDumpStack") private void parseInternal(InputSource input) throws IOException, SAXException { - if (input == null) + if (input == null) { fatal("P-000"); + } try { in = InputEntity.getInputEntity(dtdHandler, locale); @@ -312,8 +313,7 @@ externalParameterEntity(externalSubset); if (!in.isEOF()) { - fatal("P-001", new Object[] - {Integer.toHexString(((int) getc()))}); + fatal("P-001", new Object[]{Integer.toHexString(((int) getc()))}); } afterRoot(); dtdHandler.endDTD(); @@ -329,10 +329,7 @@ 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(); + LOGGER.log(Level.SEVERE, "Internal DTD parser error.", e); throw new SAXParseException(e.getMessage() != null ? e.getMessage() : e.getClass().getName(), getPublicId(), getSystemId(), @@ -368,24 +365,22 @@ // references, and only now can we know if they're all resolved. for (Enumeration e = ids.keys(); - e.hasMoreElements(); - ) { + e.hasMoreElements();) { String id = (String) e.nextElement(); Boolean value = (Boolean) ids.get(id); - if (Boolean.FALSE == value) + 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)}); + fatal("P-004", new Object[]{messages.getMessage(locale, roleId)}); } } @@ -393,8 +388,9 @@ private boolean maybeWhitespace() throws IOException, SAXException { - if (!doLexicalPE) + if (!doLexicalPE) { return in.maybeWhitespace(); + } // see getc() for the PE logic -- this lets us splice // expansions of PEs in "anywhere". getc() has smarts, @@ -418,8 +414,9 @@ // 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()) + if (in.isEOF() && !in.isInternal()) { return saw; + } c = getc(); } ungetc(); @@ -452,8 +449,9 @@ // [7] Nmtoken ::= (Namechar)+ char c = getc(); - if (!XmlChars.isNameChar(c)) - fatal("P-006", new Object[]{new Character(c)}); + if (!XmlChars.isNameChar(c)) { + fatal("P-006", new Object[]{Character.valueOf(c)}); + } return nameCharString(c).name; } @@ -461,18 +459,18 @@ // 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) + for (;;) { + if ((c = in.getNameChar()) == 0) { break; + } if (i >= nameTmp.length) { - char tmp [] = new char[nameTmp.length + 10]; + char tmp[] = new char[nameTmp.length + 10]; System.arraycopy(nameTmp, 0, tmp, 0, nameTmp.length); nameTmp = tmp; } @@ -490,6 +488,7 @@ // 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 { @@ -516,7 +515,7 @@ // scan, allowing entity push/pop wherever ... // expanded entities can't terminate the literal! - for (; ;) { + for (;;) { if (in != source && in.isEOF()) { // we don't report end of parsed entities // within attributes (no SAX hooks) @@ -547,20 +546,22 @@ } expandEntityInLiteral(entityName, entities, isEntityValue); - // character references are always included immediately - } else if ((c = getc()) == '#') { + } else if ((getc()) == '#') { int tmp = parseCharNumber(); if (tmp > 0xffff) { tmp = surrogatesToCharTmp(tmp); strTmp.append(charTmp[0]); - if (tmp == 2) + if (tmp == 2) { strTmp.append(charTmp[1]); - } else + } + } else { strTmp.append((char) tmp); - } else + } + } else { fatal("P-009"); + } continue; } @@ -573,8 +574,9 @@ nextChar(';', "F-021", entityName); expandEntityInLiteral(entityName, params, isEntityValue); continue; - } else + } else { fatal("P-011"); + } } // For attribute values ... @@ -586,8 +588,9 @@ } // "<" not legal in parsed literals ... - if (c == '<') + if (c == '<') { fatal("P-012"); + } } strTmp.append(c); @@ -597,7 +600,7 @@ // does a SINGLE expansion of the entity (often reparsed later) private void expandEntityInLiteral(String name, SimpleHashtable table, - boolean isEntityValue) + boolean isEntityValue) throws IOException, SAXException { Object entity = table.get(name); @@ -607,8 +610,10 @@ pushReader(value.buf, name, !value.isPE); } else if (entity instanceof ExternalEntity) { - if (!isEntityValue) // must be a PE ... + if (!isEntityValue) // must be a PE ... + { fatal("P-013", new Object[]{name}); + } // XXX if this returns false ... pushReader((ExternalEntity) entity); @@ -625,32 +630,31 @@ // [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") // for PUBLIC and SYSTEM literals, also "' - // 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 != '"') + if (quote != '\'' && quote != '"') { fatal("P-015", new Object[]{ - messages.getMessage(locale, type, new Object[]{extra}) - }); + messages.getMessage(locale, type, new Object[]{extra}) + }); + } char c; strTmp = new StringBuffer(); - while ((c = in.getc()) != quote) + while ((c = in.getc()) != quote) { strTmp.append((char) c); + } return strTmp.toString(); } - private String parsePublicId() throws IOException, SAXException { // [12] PubidLiteral ::= ('"' PubidChar* '"') | ("'" PubidChar* "'") @@ -660,8 +664,9 @@ 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)}); + && !(c >= 'a' && c <= 'z')) { + fatal("P-016", new Object[]{Character.valueOf(c)}); + } } strTmp = new StringBuffer(); strTmp.append(retval); @@ -670,44 +675,47 @@ // [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) // handled by: InputEntity.parsedContent() - private boolean maybeComment(boolean skipStart) throws IOException, SAXException { // [15] Comment ::= '' - if (!in.peek(skipStart ? "!--" : "