parser2.java
来自「java jdk 1.4的源码」· Java 代码 · 共 1,790 行 · 第 1/5 页
JAVA
1,790 行
// XXX we can marginally speed PE handling, and certainly // be cleaner (hence potentially more correct), by using // the observations that expanded PEs only start and stop // where whitespace is allowed. getc wouldn't need any // "lexical" PE expansion logic, and no other method needs // to handle termination of PEs. (parsing of literals would // still need to pop entities, but not parsing of references // in content.) char c = getc(); boolean saw = false; while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { 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; } private String maybeGetName () throws IOException, SAXException { NameCacheEntry entry = maybeGetNameCacheEntry (); return (entry == null) ? null : entry.name; } private NameCacheEntry maybeGetNameCacheEntry () throws IOException, SAXException { // [5] Name ::= (Letter|'_'|':') (Namechar)* char c = getc (); if (!XmlChars.isLetter (c) && c != ':' && c != '_') { ungetc (); return null; } return nameCharString (c); } // Used when parsing enumerations private String getNmtoken () throws SAXException, IOException { // [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; } return nameCache.lookupEntry (nameTmp, i); } // // much similarity between parsing entity values in DTD // and attribute values (in DTD or content) ... both follow // literal parsing rules, newline canonicalization, etc // // 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). // private void parseLiteral (boolean isEntityValue) throws IOException, SAXException { // [9] EntityValue ::= // '"' ([^"&%] | Reference | PEReference)* '"' // | "'" ([^'&%] | Reference | PEReference)* "'" // [10] AttValue ::= // '"' ([^"&] | Reference )* '"' // | "'" ([^'&] | Reference )* "'" // Only expand PEs in getc() when processing entity value literals // and do not expand when processing AttValue. Save state of // doLexicalPE and restore it before returning. boolean savedLexicalPE = doLexicalPE;// doLexicalPE = isEntityValue; char quote = getc (); char c; InputEntity source = in; if (quote != '\'' && quote != '"') fatal ("P-007"); // don't report entity expansions within attributes, // they're reported "fully expanded" via SAX isInAttribute = !isEntityValue; // 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; } if ((c = getc ()) == quote && in == source) break; // // Basically the "reference in attribute value" // row of the chart in section 4.4 of the spec // if (c == '&') { String entityName = maybeGetName (); if (entityName != null) { nextChar (';', "F-020", entityName); // 4.4 says: bypass these here ... we'll catch // forbidden refs to unparsed entities on use if (isEntityValue) { strTmp.append ('&'); strTmp.append (entityName); 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 if (c == '%' && isEntityValue) { String entityName = maybeGetName (); if (entityName != null) { nextChar (';', "F-021", entityName); if (inExternalPE) expandEntityInLiteral (entityName, params, isEntityValue); else fatal ("P-010", new Object [] { entityName }); 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;// doLexicalPE = savedLexicalPE; } // does a SINGLE expansion of the entity (often reparsed later) private void expandEntityInLiteral ( String name, SimpleHashtable table, boolean isEntityValue ) throws SAXException, IOException { Object entity = table.get (name); //throw fatal error when entity expansion count reaches the limit set by application //if we don't want to have any costraint on number of entity that can be expanaded //set the DEFAULT_ENTITY_EXPANSION_LIMIT to -1. if( entityExpansionLimit != -1 && entityExpansionCount++ >= entityExpansionLimit){ fatal ("P-086", new Object[] {new Integer(entityExpansionLimit)}); }; // // Note: if entity is a PE (value.isPE) there is an XML // requirement that the content be "markkupdecl", but that error // is ignored here (as permitted by the XML spec). // if (entity instanceof InternalEntity) { InternalEntity value = (InternalEntity) entity; if (supportValidation && isValidating && isStandalone && !value.isFromInternalSubset) error ("V-002", new Object [] { name }); 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) { // // Note: much confusion about whether spec requires such // errors to be fatal in many cases, but none about whether // it allows "normal" errors to be unrecoverable! // fatal ( (table == params) ? "V-022" : "P-014", new Object [] { name }); } } // [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; doLexicalPE = false; boolean saveCommentText = lexicalHandler != nullHandler; 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 // infer by being an internal entity outside an element. // if (inExternalPE || (!donePrologue && in.isInternal ())) { if (supportValidation && isValidating) error ("V-021", null); in = in.pop (); continue; } fatal ("P-017"); } } doLexicalPE = savedLexicalPE; if (saveCommentText) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?