diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-11-04 13:31:30 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-11-04 13:31:30 +0100 |
commit | c5c44d12073791bb1150445ce48bc57fccbb544d (patch) | |
tree | 9d7704d17cb06f886b0943d1508c9ff08f4b9570 /parser/html/javasrc/TreeBuilder.java | |
parent | a63272b5303b7aef467e974c630f745146fb983a (diff) | |
parent | bbc2206a0fda053a6f5071b457bd209dab9ed268 (diff) | |
download | UXP-c5c44d12073791bb1150445ce48bc57fccbb544d.tar UXP-c5c44d12073791bb1150445ce48bc57fccbb544d.tar.gz UXP-c5c44d12073791bb1150445ce48bc57fccbb544d.tar.lz UXP-c5c44d12073791bb1150445ce48bc57fccbb544d.tar.xz UXP-c5c44d12073791bb1150445ce48bc57fccbb544d.zip |
Merge branch 'master' into certexception-work
Diffstat (limited to 'parser/html/javasrc/TreeBuilder.java')
-rw-r--r-- | parser/html/javasrc/TreeBuilder.java | 6558 |
1 files changed, 0 insertions, 6558 deletions
diff --git a/parser/html/javasrc/TreeBuilder.java b/parser/html/javasrc/TreeBuilder.java deleted file mode 100644 index 5e83d1847..000000000 --- a/parser/html/javasrc/TreeBuilder.java +++ /dev/null @@ -1,6558 +0,0 @@ -/* - * Copyright (c) 2007 Henri Sivonen - * Copyright (c) 2007-2015 Mozilla Foundation - * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla - * Foundation, and Opera Software ASA. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* - * The comments following this one that use the same comment syntax as this - * comment are quotes from the WHATWG HTML 5 spec as of 27 June 2007 - * amended as of June 28 2007. - * That document came with this statement: - * "© Copyright 2004-2007 Apple Computer, Inc., Mozilla Foundation, and - * Opera Software ASA. You are granted a license to use, reproduce and - * create derivative works of this document." - */ - -package nu.validator.htmlparser.impl; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import org.xml.sax.ErrorHandler; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import nu.validator.htmlparser.annotation.Auto; -import nu.validator.htmlparser.annotation.Const; -import nu.validator.htmlparser.annotation.IdType; -import nu.validator.htmlparser.annotation.Inline; -import nu.validator.htmlparser.annotation.Literal; -import nu.validator.htmlparser.annotation.Local; -import nu.validator.htmlparser.annotation.NoLength; -import nu.validator.htmlparser.annotation.NsUri; -import nu.validator.htmlparser.common.DoctypeExpectation; -import nu.validator.htmlparser.common.DocumentMode; -import nu.validator.htmlparser.common.DocumentModeHandler; -import nu.validator.htmlparser.common.Interner; -import nu.validator.htmlparser.common.TokenHandler; -import nu.validator.htmlparser.common.XmlViolationPolicy; - -public abstract class TreeBuilder<T> implements TokenHandler, - TreeBuilderState<T> { - - /** - * Array version of U+FFFD. - */ - private static final @NoLength char[] REPLACEMENT_CHARACTER = { '\uFFFD' }; - - // Start dispatch groups - - final static int OTHER = 0; - - final static int A = 1; - - final static int BASE = 2; - - final static int BODY = 3; - - final static int BR = 4; - - final static int BUTTON = 5; - - final static int CAPTION = 6; - - final static int COL = 7; - - final static int COLGROUP = 8; - - final static int FORM = 9; - - final static int FRAME = 10; - - final static int FRAMESET = 11; - - final static int IMAGE = 12; - - final static int INPUT = 13; - - final static int ISINDEX = 14; - - final static int LI = 15; - - final static int LINK_OR_BASEFONT_OR_BGSOUND = 16; - - final static int MATH = 17; - - final static int META = 18; - - final static int SVG = 19; - - final static int HEAD = 20; - - final static int HR = 22; - - final static int HTML = 23; - - final static int NOBR = 24; - - final static int NOFRAMES = 25; - - final static int NOSCRIPT = 26; - - final static int OPTGROUP = 27; - - final static int OPTION = 28; - - final static int P = 29; - - final static int PLAINTEXT = 30; - - final static int SCRIPT = 31; - - final static int SELECT = 32; - - final static int STYLE = 33; - - final static int TABLE = 34; - - final static int TEXTAREA = 35; - - final static int TITLE = 36; - - final static int TR = 37; - - final static int XMP = 38; - - final static int TBODY_OR_THEAD_OR_TFOOT = 39; - - final static int TD_OR_TH = 40; - - final static int DD_OR_DT = 41; - - final static int H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6 = 42; - - final static int MARQUEE_OR_APPLET = 43; - - final static int PRE_OR_LISTING = 44; - - final static int B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U = 45; - - final static int UL_OR_OL_OR_DL = 46; - - final static int IFRAME = 47; - - final static int EMBED = 48; - - final static int AREA_OR_WBR = 49; - - final static int DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU = 50; - - final static int ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY = 51; - - final static int RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR = 52; - - final static int RB_OR_RTC = 53; - - final static int PARAM_OR_SOURCE_OR_TRACK = 55; - - final static int MGLYPH_OR_MALIGNMARK = 56; - - final static int MI_MO_MN_MS_MTEXT = 57; - - final static int ANNOTATION_XML = 58; - - final static int FOREIGNOBJECT_OR_DESC = 59; - - final static int NOEMBED = 60; - - final static int FIELDSET = 61; - - final static int OUTPUT = 62; - - final static int OBJECT = 63; - - final static int FONT = 64; - - final static int KEYGEN = 65; - - final static int MENUITEM = 66; - - final static int TEMPLATE = 67; - - final static int IMG = 68; - - final static int RT_OR_RP = 69; - - // start insertion modes - - private static final int IN_ROW = 0; - - private static final int IN_TABLE_BODY = 1; - - private static final int IN_TABLE = 2; - - private static final int IN_CAPTION = 3; - - private static final int IN_CELL = 4; - - private static final int FRAMESET_OK = 5; - - private static final int IN_BODY = 6; - - private static final int IN_HEAD = 7; - - private static final int IN_HEAD_NOSCRIPT = 8; - - // no fall-through - - private static final int IN_COLUMN_GROUP = 9; - - // no fall-through - - private static final int IN_SELECT_IN_TABLE = 10; - - private static final int IN_SELECT = 11; - - // no fall-through - - private static final int AFTER_BODY = 12; - - // no fall-through - - private static final int IN_FRAMESET = 13; - - private static final int AFTER_FRAMESET = 14; - - // no fall-through - - private static final int INITIAL = 15; - - // could add fall-through - - private static final int BEFORE_HTML = 16; - - // could add fall-through - - private static final int BEFORE_HEAD = 17; - - // no fall-through - - private static final int AFTER_HEAD = 18; - - // no fall-through - - private static final int AFTER_AFTER_BODY = 19; - - // no fall-through - - private static final int AFTER_AFTER_FRAMESET = 20; - - // no fall-through - - private static final int TEXT = 21; - - private static final int IN_TEMPLATE = 22; - - // start charset states - - private static final int CHARSET_INITIAL = 0; - - private static final int CHARSET_C = 1; - - private static final int CHARSET_H = 2; - - private static final int CHARSET_A = 3; - - private static final int CHARSET_R = 4; - - private static final int CHARSET_S = 5; - - private static final int CHARSET_E = 6; - - private static final int CHARSET_T = 7; - - private static final int CHARSET_EQUALS = 8; - - private static final int CHARSET_SINGLE_QUOTED = 9; - - private static final int CHARSET_DOUBLE_QUOTED = 10; - - private static final int CHARSET_UNQUOTED = 11; - - // end pseudo enums - - // [NOCPP[ - - private final static String[] HTML4_PUBLIC_IDS = { - "-//W3C//DTD HTML 4.0 Frameset//EN", - "-//W3C//DTD HTML 4.0 Transitional//EN", - "-//W3C//DTD HTML 4.0//EN", "-//W3C//DTD HTML 4.01 Frameset//EN", - "-//W3C//DTD HTML 4.01 Transitional//EN", - "-//W3C//DTD HTML 4.01//EN" }; - - // ]NOCPP] - - @Literal private final static String[] QUIRKY_PUBLIC_IDS = { - "+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", - "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//" }; - - private static final int NOT_FOUND_ON_STACK = Integer.MAX_VALUE; - - // [NOCPP[ - - private static final @Local String HTML_LOCAL = "html"; - - // ]NOCPP] - - private int mode = INITIAL; - - private int originalMode = INITIAL; - - /** - * Used only when moving back to IN_BODY. - */ - private boolean framesetOk = true; - - protected Tokenizer tokenizer; - - // [NOCPP[ - - protected ErrorHandler errorHandler; - - private DocumentModeHandler documentModeHandler; - - private DoctypeExpectation doctypeExpectation = DoctypeExpectation.HTML; - - private LocatorImpl firstCommentLocation; - - // ]NOCPP] - - private boolean scriptingEnabled = false; - - private boolean needToDropLF; - - // [NOCPP[ - - private boolean wantingComments; - - // ]NOCPP] - - private boolean fragment; - - private @Local String contextName; - - private @NsUri String contextNamespace; - - private T contextNode; - - /** - * Stack of template insertion modes - */ - private @Auto int[] templateModeStack; - - /** - * Current template mode stack pointer. - */ - private int templateModePtr = -1; - - private @Auto StackNode<T>[] stack; - - private int currentPtr = -1; - - private @Auto StackNode<T>[] listOfActiveFormattingElements; - - private int listPtr = -1; - - private T formPointer; - - private T headPointer; - - /** - * Used to work around Gecko limitations. Not used in Java. - */ - private T deepTreeSurrogateParent; - - protected @Auto char[] charBuffer; - - protected int charBufferLen = 0; - - private boolean quirks = false; - - private boolean isSrcdocDocument = false; - - // [NOCPP[ - - private boolean reportingDoctype = true; - - private XmlViolationPolicy namePolicy = XmlViolationPolicy.ALTER_INFOSET; - - private final Map<String, LocatorImpl> idLocations = new HashMap<String, LocatorImpl>(); - - private boolean html4; - - // ]NOCPP] - - protected TreeBuilder() { - fragment = false; - } - - /** - * Reports an condition that would make the infoset incompatible with XML - * 1.0 as fatal. - * - * @throws SAXException - * @throws SAXParseException - */ - protected void fatal() throws SAXException { - } - - // [NOCPP[ - - protected final void fatal(Exception e) throws SAXException { - SAXParseException spe = new SAXParseException(e.getMessage(), - tokenizer, e); - if (errorHandler != null) { - errorHandler.fatalError(spe); - } - throw spe; - } - - final void fatal(String s) throws SAXException { - SAXParseException spe = new SAXParseException(s, tokenizer); - if (errorHandler != null) { - errorHandler.fatalError(spe); - } - throw spe; - } - - /** - * Reports a Parse Error. - * - * @param message - * the message - * @throws SAXException - */ - final void err(String message) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck(message); - } - - /** - * Reports a Parse Error without checking if an error handler is present. - * - * @param message - * the message - * @throws SAXException - */ - final void errNoCheck(String message) throws SAXException { - SAXParseException spe = new SAXParseException(message, tokenizer); - errorHandler.error(spe); - } - - private void errListUnclosedStartTags(int eltPos) throws SAXException { - if (currentPtr != -1) { - for (int i = currentPtr; i > eltPos; i--) { - reportUnclosedElementNameAndLocation(i); - } - } - } - - /** - * Reports the name and location of an unclosed element. - * - * @throws SAXException - */ - private final void reportUnclosedElementNameAndLocation(int pos) throws SAXException { - StackNode<T> node = stack[pos]; - if (node.isOptionalEndTag()) { - return; - } - TaintableLocatorImpl locator = node.getLocator(); - if (locator.isTainted()) { - return; - } - locator.markTainted(); - SAXParseException spe = new SAXParseException( - "Unclosed element \u201C" + node.popName + "\u201D.", locator); - errorHandler.error(spe); - } - - /** - * Reports a warning - * - * @param message - * the message - * @throws SAXException - */ - final void warn(String message) throws SAXException { - if (errorHandler == null) { - return; - } - SAXParseException spe = new SAXParseException(message, tokenizer); - errorHandler.warning(spe); - } - - /** - * Reports a warning with an explicit locator - * - * @param message - * the message - * @throws SAXException - */ - final void warn(String message, Locator locator) throws SAXException { - if (errorHandler == null) { - return; - } - SAXParseException spe = new SAXParseException(message, locator); - errorHandler.warning(spe); - } - - // ]NOCPP] - - @SuppressWarnings("unchecked") public final void startTokenization(Tokenizer self) throws SAXException { - tokenizer = self; - stack = new StackNode[64]; - templateModeStack = new int[64]; - listOfActiveFormattingElements = new StackNode[64]; - needToDropLF = false; - originalMode = INITIAL; - templateModePtr = -1; - currentPtr = -1; - listPtr = -1; - formPointer = null; - headPointer = null; - deepTreeSurrogateParent = null; - // [NOCPP[ - html4 = false; - idLocations.clear(); - wantingComments = wantsComments(); - firstCommentLocation = null; - // ]NOCPP] - start(fragment); - charBufferLen = 0; - charBuffer = null; - framesetOk = true; - if (fragment) { - T elt; - if (contextNode != null) { - elt = contextNode; - } else { - elt = createHtmlElementSetAsRoot(tokenizer.emptyAttributes()); - } - // When the context node is not in the HTML namespace, contrary - // to the spec, the first node on the stack is not set to "html" - // in the HTML namespace. Instead, it is set to a node that has - // the characteristics of the appropriate "adjusted current node". - // This way, there is no need to perform "adjusted current node" - // checks during tree construction. Instead, it's sufficient to - // just look at the current node. However, this also means that it - // is not safe to treat "html" in the HTML namespace as a sentinel - // that ends stack popping. Instead, stack popping loops that are - // meant not to pop the first element on the stack need to check - // for currentPos becoming zero. - if (contextNamespace == "http://www.w3.org/2000/svg") { - ElementName elementName = ElementName.SVG; - if ("title" == contextName || "desc" == contextName - || "foreignObject" == contextName) { - // These elements are all alike and we don't care about - // the exact name. - elementName = ElementName.FOREIGNOBJECT; - } - // This is the SVG variant of the StackNode constructor. - StackNode<T> node = new StackNode<T>(elementName, - elementName.camelCaseName, elt - // [NOCPP[ - , errorHandler == null ? null - : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - currentPtr++; - stack[currentPtr] = node; - tokenizer.setStateAndEndTagExpectation(Tokenizer.DATA, - contextName); - // The frameset-ok flag is set even though <frameset> never - // ends up being allowed as HTML frameset in the fragment case. - mode = FRAMESET_OK; - } else if (contextNamespace == "http://www.w3.org/1998/Math/MathML") { - ElementName elementName = ElementName.MATH; - if ("mi" == contextName || "mo" == contextName - || "mn" == contextName || "ms" == contextName - || "mtext" == contextName) { - // These elements are all alike and we don't care about - // the exact name. - elementName = ElementName.MTEXT; - } else if ("annotation-xml" == contextName) { - elementName = ElementName.ANNOTATION_XML; - // Blink does not check the encoding attribute of the - // annotation-xml element innerHTML is being set on. - // Let's do the same at least until - // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26783 - // is resolved. - } - // This is the MathML variant of the StackNode constructor. - StackNode<T> node = new StackNode<T>(elementName, elt, - elementName.name, false - // [NOCPP[ - , errorHandler == null ? null - : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - currentPtr++; - stack[currentPtr] = node; - tokenizer.setStateAndEndTagExpectation(Tokenizer.DATA, - contextName); - // The frameset-ok flag is set even though <frameset> never - // ends up being allowed as HTML frameset in the fragment case. - mode = FRAMESET_OK; - } else { // html - StackNode<T> node = new StackNode<T>(ElementName.HTML, elt - // [NOCPP[ - , errorHandler == null ? null - : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - currentPtr++; - stack[currentPtr] = node; - if ("template" == contextName) { - pushTemplateMode(IN_TEMPLATE); - } - resetTheInsertionMode(); - formPointer = getFormPointerForContext(contextNode); - if ("title" == contextName || "textarea" == contextName) { - tokenizer.setStateAndEndTagExpectation(Tokenizer.RCDATA, - contextName); - } else if ("style" == contextName || "xmp" == contextName - || "iframe" == contextName || "noembed" == contextName - || "noframes" == contextName - || (scriptingEnabled && "noscript" == contextName)) { - tokenizer.setStateAndEndTagExpectation(Tokenizer.RAWTEXT, - contextName); - } else if ("plaintext" == contextName) { - tokenizer.setStateAndEndTagExpectation(Tokenizer.PLAINTEXT, - contextName); - } else if ("script" == contextName) { - tokenizer.setStateAndEndTagExpectation( - Tokenizer.SCRIPT_DATA, contextName); - } else { - tokenizer.setStateAndEndTagExpectation(Tokenizer.DATA, - contextName); - } - } - contextName = null; - contextNode = null; - } else { - mode = INITIAL; - // If we are viewing XML source, put a foreign element permanently - // on the stack so that cdataSectionAllowed() returns true. - // CPPONLY: if (tokenizer.isViewingXmlSource()) { - // CPPONLY: T elt = createElement("http://www.w3.org/2000/svg", - // CPPONLY: "svg", - // CPPONLY: tokenizer.emptyAttributes(), null); - // CPPONLY: StackNode<T> node = new StackNode<T>(ElementName.SVG, - // CPPONLY: "svg", - // CPPONLY: elt); - // CPPONLY: currentPtr++; - // CPPONLY: stack[currentPtr] = node; - // CPPONLY: } - } - } - - public final void doctype(@Local String name, String publicIdentifier, - String systemIdentifier, boolean forceQuirks) throws SAXException { - needToDropLF = false; - if (!isInForeign() && mode == INITIAL) { - // [NOCPP[ - if (reportingDoctype) { - // ]NOCPP] - String emptyString = Portability.newEmptyString(); - appendDoctypeToDocument(name == null ? "" : name, - publicIdentifier == null ? emptyString - : publicIdentifier, - systemIdentifier == null ? emptyString - : systemIdentifier); - Portability.releaseString(emptyString); - // [NOCPP[ - } - switch (doctypeExpectation) { - case HTML: - // ]NOCPP] - if (isQuirky(name, publicIdentifier, systemIdentifier, - forceQuirks)) { - errQuirkyDoctype(); - documentModeInternal(DocumentMode.QUIRKS_MODE, - publicIdentifier, systemIdentifier, false); - } else if (isAlmostStandards(publicIdentifier, - systemIdentifier)) { - // [NOCPP[ - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - // ]NOCPP] - errAlmostStandardsDoctype(); - documentModeInternal( - DocumentMode.ALMOST_STANDARDS_MODE, - publicIdentifier, systemIdentifier, false); - } else { - // [NOCPP[ - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - if ((Portability.literalEqualsString( - "-//W3C//DTD HTML 4.0//EN", publicIdentifier) && (systemIdentifier == null || Portability.literalEqualsString( - "http://www.w3.org/TR/REC-html40/strict.dtd", - systemIdentifier))) - || (Portability.literalEqualsString( - "-//W3C//DTD HTML 4.01//EN", - publicIdentifier) && (systemIdentifier == null || Portability.literalEqualsString( - "http://www.w3.org/TR/html4/strict.dtd", - systemIdentifier))) - || (Portability.literalEqualsString( - "-//W3C//DTD XHTML 1.0 Strict//EN", - publicIdentifier) && Portability.literalEqualsString( - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", - systemIdentifier)) - || (Portability.literalEqualsString( - "-//W3C//DTD XHTML 1.1//EN", - publicIdentifier) && Portability.literalEqualsString( - "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd", - systemIdentifier)) - - ) { - warn("Obsolete doctype. Expected \u201C<!DOCTYPE html>\u201D."); - } else if (!((systemIdentifier == null || Portability.literalEqualsString( - "about:legacy-compat", systemIdentifier)) && publicIdentifier == null)) { - err("Legacy doctype. Expected \u201C<!DOCTYPE html>\u201D."); - } - // ]NOCPP] - documentModeInternal(DocumentMode.STANDARDS_MODE, - publicIdentifier, systemIdentifier, false); - } - // [NOCPP[ - break; - case HTML401_STRICT: - html4 = true; - tokenizer.turnOnAdditionalHtml4Errors(); - if (isQuirky(name, publicIdentifier, systemIdentifier, - forceQuirks)) { - err("Quirky doctype. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - documentModeInternal(DocumentMode.QUIRKS_MODE, - publicIdentifier, systemIdentifier, true); - } else if (isAlmostStandards(publicIdentifier, - systemIdentifier)) { - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - err("Almost standards mode doctype. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - documentModeInternal( - DocumentMode.ALMOST_STANDARDS_MODE, - publicIdentifier, systemIdentifier, true); - } else { - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - if ("-//W3C//DTD HTML 4.01//EN".equals(publicIdentifier)) { - if (!"http://www.w3.org/TR/html4/strict.dtd".equals(systemIdentifier)) { - warn("The doctype did not contain the system identifier prescribed by the HTML 4.01 specification. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - } - } else { - err("The doctype was not the HTML 4.01 Strict doctype. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - } - documentModeInternal(DocumentMode.STANDARDS_MODE, - publicIdentifier, systemIdentifier, true); - } - break; - case HTML401_TRANSITIONAL: - html4 = true; - tokenizer.turnOnAdditionalHtml4Errors(); - if (isQuirky(name, publicIdentifier, systemIdentifier, - forceQuirks)) { - err("Quirky doctype. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - documentModeInternal(DocumentMode.QUIRKS_MODE, - publicIdentifier, systemIdentifier, true); - } else if (isAlmostStandards(publicIdentifier, - systemIdentifier)) { - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - if ("-//W3C//DTD HTML 4.01 Transitional//EN".equals(publicIdentifier) - && systemIdentifier != null) { - if (!"http://www.w3.org/TR/html4/loose.dtd".equals(systemIdentifier)) { - warn("The doctype did not contain the system identifier prescribed by the HTML 4.01 specification. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - } - } else { - err("The doctype was not a non-quirky HTML 4.01 Transitional doctype. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - } - documentModeInternal( - DocumentMode.ALMOST_STANDARDS_MODE, - publicIdentifier, systemIdentifier, true); - } else { - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - err("The doctype was not the HTML 4.01 Transitional doctype. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - documentModeInternal(DocumentMode.STANDARDS_MODE, - publicIdentifier, systemIdentifier, true); - } - break; - case AUTO: - html4 = isHtml4Doctype(publicIdentifier); - if (html4) { - tokenizer.turnOnAdditionalHtml4Errors(); - } - if (isQuirky(name, publicIdentifier, systemIdentifier, - forceQuirks)) { - err("Quirky doctype. Expected e.g. \u201C<!DOCTYPE html>\u201D."); - documentModeInternal(DocumentMode.QUIRKS_MODE, - publicIdentifier, systemIdentifier, html4); - } else if (isAlmostStandards(publicIdentifier, - systemIdentifier)) { - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - if ("-//W3C//DTD HTML 4.01 Transitional//EN".equals(publicIdentifier)) { - if (!"http://www.w3.org/TR/html4/loose.dtd".equals(systemIdentifier)) { - warn("The doctype did not contain the system identifier prescribed by the HTML 4.01 specification. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - } - } else { - err("Almost standards mode doctype. Expected e.g. \u201C<!DOCTYPE html>\u201D."); - } - documentModeInternal( - DocumentMode.ALMOST_STANDARDS_MODE, - publicIdentifier, systemIdentifier, html4); - } else { - if (firstCommentLocation != null) { - warn("Comments seen before doctype. Internet Explorer will go into the quirks mode.", - firstCommentLocation); - } - if ("-//W3C//DTD HTML 4.01//EN".equals(publicIdentifier)) { - if (!"http://www.w3.org/TR/html4/strict.dtd".equals(systemIdentifier)) { - warn("The doctype did not contain the system identifier prescribed by the HTML 4.01 specification. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - } - } else if ("-//W3C//DTD XHTML 1.0 Strict//EN".equals(publicIdentifier)) { - if (!"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".equals(systemIdentifier)) { - warn("The doctype did not contain the system identifier prescribed by the XHTML 1.0 specification. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\u201D."); - } - } else if ("//W3C//DTD XHTML 1.1//EN".equals(publicIdentifier)) { - if (!"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd".equals(systemIdentifier)) { - warn("The doctype did not contain the system identifier prescribed by the XHTML 1.1 specification. Expected \u201C<!DOCTYPE HTML PUBLIC \"//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\u201D."); - } - } else if (!((systemIdentifier == null || Portability.literalEqualsString( - "about:legacy-compat", systemIdentifier)) && publicIdentifier == null)) { - err("Unexpected doctype. Expected, e.g., \u201C<!DOCTYPE html>\u201D."); - } - documentModeInternal(DocumentMode.STANDARDS_MODE, - publicIdentifier, systemIdentifier, html4); - } - break; - case NO_DOCTYPE_ERRORS: - if (isQuirky(name, publicIdentifier, systemIdentifier, - forceQuirks)) { - documentModeInternal(DocumentMode.QUIRKS_MODE, - publicIdentifier, systemIdentifier, false); - } else if (isAlmostStandards(publicIdentifier, - systemIdentifier)) { - documentModeInternal( - DocumentMode.ALMOST_STANDARDS_MODE, - publicIdentifier, systemIdentifier, false); - } else { - documentModeInternal(DocumentMode.STANDARDS_MODE, - publicIdentifier, systemIdentifier, false); - } - break; - } - // ]NOCPP] - - /* - * - * Then, switch to the root element mode of the tree construction - * stage. - */ - mode = BEFORE_HTML; - return; - } - /* - * A DOCTYPE token Parse error. - */ - errStrayDoctype(); - /* - * Ignore the token. - */ - return; - } - - // [NOCPP[ - - private boolean isHtml4Doctype(String publicIdentifier) { - if (publicIdentifier != null - && (Arrays.binarySearch(TreeBuilder.HTML4_PUBLIC_IDS, - publicIdentifier) > -1)) { - return true; - } - return false; - } - - // ]NOCPP] - - public final void comment(@NoLength char[] buf, int start, int length) - throws SAXException { - needToDropLF = false; - // [NOCPP[ - if (firstCommentLocation == null) { - firstCommentLocation = new LocatorImpl(tokenizer); - } - if (!wantingComments) { - return; - } - // ]NOCPP] - if (!isInForeign()) { - switch (mode) { - case INITIAL: - case BEFORE_HTML: - case AFTER_AFTER_BODY: - case AFTER_AFTER_FRAMESET: - /* - * A comment token Append a Comment node to the Document - * object with the data attribute set to the data given in - * the comment token. - */ - appendCommentToDocument(buf, start, length); - return; - case AFTER_BODY: - /* - * A comment token Append a Comment node to the first - * element in the stack of open elements (the html element), - * with the data attribute set to the data given in the - * comment token. - */ - flushCharacters(); - appendComment(stack[0].node, buf, start, length); - return; - default: - break; - } - } - /* - * A comment token Append a Comment node to the current node with the - * data attribute set to the data given in the comment token. - */ - flushCharacters(); - appendComment(stack[currentPtr].node, buf, start, length); - return; - } - - /** - * @see nu.validator.htmlparser.common.TokenHandler#characters(char[], int, - * int) - */ - public final void characters(@Const @NoLength char[] buf, int start, int length) - throws SAXException { - // Note: Can't attach error messages to EOF in C++ yet - - // CPPONLY: if (tokenizer.isViewingXmlSource()) { - // CPPONLY: return; - // CPPONLY: } - if (needToDropLF) { - needToDropLF = false; - if (buf[start] == '\n') { - start++; - length--; - if (length == 0) { - return; - } - } - } - - // optimize the most common case - switch (mode) { - case IN_BODY: - case IN_CELL: - case IN_CAPTION: - if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { - reconstructTheActiveFormattingElements(); - } - // fall through - case TEXT: - accumulateCharacters(buf, start, length); - return; - case IN_TABLE: - case IN_TABLE_BODY: - case IN_ROW: - accumulateCharactersForced(buf, start, length); - return; - default: - int end = start + length; - charactersloop: for (int i = start; i < end; i++) { - switch (buf[i]) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\u000C': - /* - * A character token that is one of one of U+0009 - * CHARACTER TABULATION, U+000A LINE FEED (LF), - * U+000C FORM FEED (FF), or U+0020 SPACE - */ - switch (mode) { - case INITIAL: - case BEFORE_HTML: - case BEFORE_HEAD: - /* - * Ignore the token. - */ - start = i + 1; - continue; - case IN_HEAD: - case IN_HEAD_NOSCRIPT: - case AFTER_HEAD: - case IN_COLUMN_GROUP: - case IN_FRAMESET: - case AFTER_FRAMESET: - /* - * Append the character to the current node. - */ - continue; - case FRAMESET_OK: - case IN_TEMPLATE: - case IN_BODY: - case IN_CELL: - case IN_CAPTION: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - - /* - * Reconstruct the active formatting - * elements, if any. - */ - if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { - flushCharacters(); - reconstructTheActiveFormattingElements(); - } - /* - * Append the token's character to the - * current node. - */ - break charactersloop; - case IN_SELECT: - case IN_SELECT_IN_TABLE: - break charactersloop; - case IN_TABLE: - case IN_TABLE_BODY: - case IN_ROW: - accumulateCharactersForced(buf, i, 1); - start = i + 1; - continue; - case AFTER_BODY: - case AFTER_AFTER_BODY: - case AFTER_AFTER_FRAMESET: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - /* - * Reconstruct the active formatting - * elements, if any. - */ - flushCharacters(); - reconstructTheActiveFormattingElements(); - /* - * Append the token's character to the - * current node. - */ - continue; - } - default: - /* - * A character token that is not one of one of - * U+0009 CHARACTER TABULATION, U+000A LINE FEED - * (LF), U+000C FORM FEED (FF), or U+0020 SPACE - */ - switch (mode) { - case INITIAL: - /* - * Parse error. - */ - // [NOCPP[ - switch (doctypeExpectation) { - case AUTO: - err("Non-space characters found without seeing a doctype first. Expected e.g. \u201C<!DOCTYPE html>\u201D."); - break; - case HTML: - // XXX figure out a way to report this in the Gecko View Source case - err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); - break; - case HTML401_STRICT: - err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - break; - case HTML401_TRANSITIONAL: - err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - break; - case NO_DOCTYPE_ERRORS: - } - // ]NOCPP] - /* - * - * Set the document to quirks mode. - */ - documentModeInternal( - DocumentMode.QUIRKS_MODE, null, - null, false); - /* - * Then, switch to the root element mode of - * the tree construction stage - */ - mode = BEFORE_HTML; - /* - * and reprocess the current token. - */ - i--; - continue; - case BEFORE_HTML: - /* - * Create an HTMLElement node with the tag - * name html, in the HTML namespace. Append - * it to the Document object. - */ - // No need to flush characters here, - // because there's nothing to flush. - appendHtmlElementToDocumentAndPush(); - /* Switch to the main mode */ - mode = BEFORE_HEAD; - /* - * reprocess the current token. - */ - i--; - continue; - case BEFORE_HEAD: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - /* - * /Act as if a start tag token with the tag - * name "head" and no attributes had been - * seen, - */ - flushCharacters(); - appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); - mode = IN_HEAD; - /* - * then reprocess the current token. - * - * This will result in an empty head element - * being generated, with the current token - * being reprocessed in the "after head" - * insertion mode. - */ - i--; - continue; - case IN_HEAD: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - /* - * Act as if an end tag token with the tag - * name "head" had been seen, - */ - flushCharacters(); - pop(); - mode = AFTER_HEAD; - /* - * and reprocess the current token. - */ - i--; - continue; - case IN_HEAD_NOSCRIPT: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - /* - * Parse error. Act as if an end tag with - * the tag name "noscript" had been seen - */ - errNonSpaceInNoscriptInHead(); - flushCharacters(); - pop(); - mode = IN_HEAD; - /* - * and reprocess the current token. - */ - i--; - continue; - case AFTER_HEAD: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - /* - * Act as if a start tag token with the tag - * name "body" and no attributes had been - * seen, - */ - flushCharacters(); - appendToCurrentNodeAndPushBodyElement(); - mode = FRAMESET_OK; - /* - * and then reprocess the current token. - */ - i--; - continue; - case FRAMESET_OK: - framesetOk = false; - mode = IN_BODY; - i--; - continue; - case IN_TEMPLATE: - case IN_BODY: - case IN_CELL: - case IN_CAPTION: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - /* - * Reconstruct the active formatting - * elements, if any. - */ - if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { - flushCharacters(); - reconstructTheActiveFormattingElements(); - } - /* - * Append the token's character to the - * current node. - */ - break charactersloop; - case IN_TABLE: - case IN_TABLE_BODY: - case IN_ROW: - accumulateCharactersForced(buf, i, 1); - start = i + 1; - continue; - case IN_COLUMN_GROUP: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - start = i; - } - /* - * Act as if an end tag with the tag name - * "colgroup" had been seen, and then, if - * that token wasn't ignored, reprocess the - * current token. - */ - if (currentPtr == 0 || stack[currentPtr].getGroup() == - TreeBuilder.TEMPLATE) { - errNonSpaceInColgroupInFragment(); - start = i + 1; - continue; - } - flushCharacters(); - pop(); - mode = IN_TABLE; - i--; - continue; - case IN_SELECT: - case IN_SELECT_IN_TABLE: - break charactersloop; - case AFTER_BODY: - errNonSpaceAfterBody(); - fatal(); - mode = framesetOk ? FRAMESET_OK : IN_BODY; - i--; - continue; - case IN_FRAMESET: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - // start index is adjusted below. - } - /* - * Parse error. - */ - errNonSpaceInFrameset(); - /* - * Ignore the token. - */ - start = i + 1; - continue; - case AFTER_FRAMESET: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - // start index is adjusted below. - } - /* - * Parse error. - */ - errNonSpaceAfterFrameset(); - /* - * Ignore the token. - */ - start = i + 1; - continue; - case AFTER_AFTER_BODY: - /* - * Parse error. - */ - errNonSpaceInTrailer(); - /* - * Switch back to the main mode and - * reprocess the token. - */ - mode = framesetOk ? FRAMESET_OK : IN_BODY; - i--; - continue; - case AFTER_AFTER_FRAMESET: - if (start < i) { - accumulateCharacters(buf, start, i - - start); - // start index is adjusted below. - } - /* - * Parse error. - */ - errNonSpaceInTrailer(); - /* - * Ignore the token. - */ - start = i + 1; - continue; - } - } - } - if (start < end) { - accumulateCharacters(buf, start, end - start); - } - } - } - - /** - * @see nu.validator.htmlparser.common.TokenHandler#zeroOriginatingReplacementCharacter() - */ - public void zeroOriginatingReplacementCharacter() throws SAXException { - if (mode == TEXT) { - accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1); - return; - } - if (currentPtr >= 0) { - if (isSpecialParentInForeign(stack[currentPtr])) { - return; - } - accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1); - } - } - - public final void eof() throws SAXException { - flushCharacters(); - // Note: Can't attach error messages to EOF in C++ yet - eofloop: for (;;) { - switch (mode) { - case INITIAL: - /* - * Parse error. - */ - // [NOCPP[ - switch (doctypeExpectation) { - case AUTO: - err("End of file seen without seeing a doctype first. Expected e.g. \u201C<!DOCTYPE html>\u201D."); - break; - case HTML: - err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); - break; - case HTML401_STRICT: - err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - break; - case HTML401_TRANSITIONAL: - err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - break; - case NO_DOCTYPE_ERRORS: - } - // ]NOCPP] - /* - * - * Set the document to quirks mode. - */ - documentModeInternal(DocumentMode.QUIRKS_MODE, null, null, - false); - /* - * Then, switch to the root element mode of the tree - * construction stage - */ - mode = BEFORE_HTML; - /* - * and reprocess the current token. - */ - continue; - case BEFORE_HTML: - /* - * Create an HTMLElement node with the tag name html, in the - * HTML namespace. Append it to the Document object. - */ - appendHtmlElementToDocumentAndPush(); - // XXX application cache manifest - /* Switch to the main mode */ - mode = BEFORE_HEAD; - /* - * reprocess the current token. - */ - continue; - case BEFORE_HEAD: - appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); - mode = IN_HEAD; - continue; - case IN_HEAD: - // [NOCPP[ - if (errorHandler != null && currentPtr > 1) { - errEofWithUnclosedElements(); - } - // ]NOCPP] - while (currentPtr > 0) { - popOnEof(); - } - mode = AFTER_HEAD; - continue; - case IN_HEAD_NOSCRIPT: - // [NOCPP[ - errEofWithUnclosedElements(); - // ]NOCPP] - while (currentPtr > 1) { - popOnEof(); - } - mode = IN_HEAD; - continue; - case AFTER_HEAD: - appendToCurrentNodeAndPushBodyElement(); - mode = IN_BODY; - continue; - case IN_TABLE_BODY: - case IN_ROW: - case IN_TABLE: - case IN_SELECT_IN_TABLE: - case IN_SELECT: - case IN_COLUMN_GROUP: - case FRAMESET_OK: - case IN_CAPTION: - case IN_CELL: - case IN_BODY: - // [NOCPP[ - // i > 0 to stop in time in the foreign fragment case. - openelementloop: for (int i = currentPtr; i > 0; i--) { - int group = stack[i].getGroup(); - switch (group) { - case DD_OR_DT: - case LI: - case P: - case TBODY_OR_THEAD_OR_TFOOT: - case TD_OR_TH: - case BODY: - case HTML: - break; - default: - errEofWithUnclosedElements(); - break openelementloop; - } - } - // ]NOCPP] - - if (isTemplateModeStackEmpty()) { - break eofloop; - } - - // fall through to IN_TEMPLATE - case IN_TEMPLATE: - int eltPos = findLast("template"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment; - break eofloop; - } - if (errorHandler != null) { - errUnclosedElements(eltPos, "template"); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - popTemplateMode(); - resetTheInsertionMode(); - - // Reprocess token. - continue; - case TEXT: - // [NOCPP[ - if (errorHandler != null) { - errNoCheck("End of file seen when expecting text or an end tag."); - errListUnclosedStartTags(0); - } - // ]NOCPP] - // XXX mark script as already executed - if (originalMode == AFTER_HEAD) { - popOnEof(); - } - popOnEof(); - mode = originalMode; - continue; - case IN_FRAMESET: - // [NOCPP[ - if (errorHandler != null && currentPtr > 0) { - errEofWithUnclosedElements(); - } - // ]NOCPP] - break eofloop; - case AFTER_BODY: - case AFTER_FRAMESET: - case AFTER_AFTER_BODY: - case AFTER_AFTER_FRAMESET: - default: - // [NOCPP[ - if (currentPtr == 0) { // This silliness is here to poison - // buggy compiler optimizations in - // GWT - System.currentTimeMillis(); - } - // ]NOCPP] - break eofloop; - } - } - while (currentPtr > 0) { - popOnEof(); - } - if (!fragment) { - popOnEof(); - } - /* Stop parsing. */ - } - - /** - * @see nu.validator.htmlparser.common.TokenHandler#endTokenization() - */ - public final void endTokenization() throws SAXException { - formPointer = null; - headPointer = null; - deepTreeSurrogateParent = null; - templateModeStack = null; - if (stack != null) { - while (currentPtr > -1) { - stack[currentPtr].release(); - currentPtr--; - } - stack = null; - } - if (listOfActiveFormattingElements != null) { - while (listPtr > -1) { - if (listOfActiveFormattingElements[listPtr] != null) { - listOfActiveFormattingElements[listPtr].release(); - } - listPtr--; - } - listOfActiveFormattingElements = null; - } - // [NOCPP[ - idLocations.clear(); - // ]NOCPP] - charBuffer = null; - end(); - } - - public final void startTag(ElementName elementName, - HtmlAttributes attributes, boolean selfClosing) throws SAXException { - flushCharacters(); - - // [NOCPP[ - if (errorHandler != null) { - // ID uniqueness - @IdType String id = attributes.getId(); - if (id != null) { - LocatorImpl oldLoc = idLocations.get(id); - if (oldLoc != null) { - err("Duplicate ID \u201C" + id + "\u201D."); - errorHandler.warning(new SAXParseException( - "The first occurrence of ID \u201C" + id - + "\u201D was here.", oldLoc)); - } else { - idLocations.put(id, new LocatorImpl(tokenizer)); - } - } - } - // ]NOCPP] - - int eltPos; - needToDropLF = false; - starttagloop: for (;;) { - int group = elementName.getGroup(); - @Local String name = elementName.name; - if (isInForeign()) { - StackNode<T> currentNode = stack[currentPtr]; - @NsUri String currNs = currentNode.ns; - if (!(currentNode.isHtmlIntegrationPoint() || (currNs == "http://www.w3.org/1998/Math/MathML" && ((currentNode.getGroup() == MI_MO_MN_MS_MTEXT && group != MGLYPH_OR_MALIGNMARK) || (currentNode.getGroup() == ANNOTATION_XML && group == SVG))))) { - switch (group) { - case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: - case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: - case BODY: - case BR: - case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR: - case DD_OR_DT: - case UL_OR_OL_OR_DL: - case EMBED: - case IMG: - case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: - case HEAD: - case HR: - case LI: - case META: - case NOBR: - case P: - case PRE_OR_LISTING: - case TABLE: - case FONT: - // re-check FONT to deal with the special case - if (!(group == FONT && !(attributes.contains(AttributeName.COLOR) - || attributes.contains(AttributeName.FACE) || attributes.contains(AttributeName.SIZE)))) { - errHtmlStartTagInForeignContext(name); - if (!fragment) { - while (!isSpecialParentInForeign(stack[currentPtr])) { - pop(); - } - continue starttagloop; - } // else fall thru - } - // else fall thru - default: - if ("http://www.w3.org/2000/svg" == currNs) { - attributes.adjustForSvg(); - if (selfClosing) { - appendVoidElementToCurrentMayFosterSVG( - elementName, attributes); - selfClosing = false; - } else { - appendToCurrentNodeAndPushElementMayFosterSVG( - elementName, attributes); - } - attributes = null; // CPP - break starttagloop; - } else { - attributes.adjustForMath(); - if (selfClosing) { - appendVoidElementToCurrentMayFosterMathML( - elementName, attributes); - selfClosing = false; - } else { - appendToCurrentNodeAndPushElementMayFosterMathML( - elementName, attributes); - } - attributes = null; // CPP - break starttagloop; - } - } // switch - } // foreignObject / annotation-xml - } - switch (mode) { - case IN_TEMPLATE: - switch (group) { - case COL: - popTemplateMode(); - pushTemplateMode(IN_COLUMN_GROUP); - mode = IN_COLUMN_GROUP; - // Reprocess token. - continue; - case CAPTION: - case COLGROUP: - case TBODY_OR_THEAD_OR_TFOOT: - popTemplateMode(); - pushTemplateMode(IN_TABLE); - mode = IN_TABLE; - // Reprocess token. - continue; - case TR: - popTemplateMode(); - pushTemplateMode(IN_TABLE_BODY); - mode = IN_TABLE_BODY; - // Reprocess token. - continue; - case TD_OR_TH: - popTemplateMode(); - pushTemplateMode(IN_ROW); - mode = IN_ROW; - // Reprocess token. - continue; - case META: - checkMetaCharset(attributes); - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case TITLE: - startTagTitleInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case BASE: - case LINK_OR_BASEFONT_OR_BGSOUND: - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case SCRIPT: - startTagScriptInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case NOFRAMES: - case STYLE: - startTagGenericRawText(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case TEMPLATE: - startTagTemplateInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - default: - popTemplateMode(); - pushTemplateMode(IN_BODY); - mode = IN_BODY; - // Reprocess token. - continue; - } - case IN_ROW: - switch (group) { - case TD_OR_TH: - clearStackBackTo(findLastOrRoot(TreeBuilder.TR)); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - mode = IN_CELL; - insertMarker(); - attributes = null; // CPP - break starttagloop; - case CAPTION: - case COL: - case COLGROUP: - case TBODY_OR_THEAD_OR_TFOOT: - case TR: - eltPos = findLastOrRoot(TreeBuilder.TR); - if (eltPos == 0) { - assert fragment || isTemplateContents(); - errNoTableRowToClose(); - break starttagloop; - } - clearStackBackTo(eltPos); - pop(); - mode = IN_TABLE_BODY; - continue; - default: - // fall through to IN_TABLE - } - case IN_TABLE_BODY: - switch (group) { - case TR: - clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot()); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - mode = IN_ROW; - attributes = null; // CPP - break starttagloop; - case TD_OR_TH: - errStartTagInTableBody(name); - clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot()); - appendToCurrentNodeAndPushElement( - ElementName.TR, - HtmlAttributes.EMPTY_ATTRIBUTES); - mode = IN_ROW; - continue; - case CAPTION: - case COL: - case COLGROUP: - case TBODY_OR_THEAD_OR_TFOOT: - eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); - if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) { - assert fragment || isTemplateContents(); - errStrayStartTag(name); - break starttagloop; - } else { - clearStackBackTo(eltPos); - pop(); - mode = IN_TABLE; - continue; - } - default: - // fall through to IN_TABLE - } - case IN_TABLE: - intableloop: for (;;) { - switch (group) { - case CAPTION: - clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); - insertMarker(); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - mode = IN_CAPTION; - attributes = null; // CPP - break starttagloop; - case COLGROUP: - clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - mode = IN_COLUMN_GROUP; - attributes = null; // CPP - break starttagloop; - case COL: - clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); - appendToCurrentNodeAndPushElement( - ElementName.COLGROUP, - HtmlAttributes.EMPTY_ATTRIBUTES); - mode = IN_COLUMN_GROUP; - continue starttagloop; - case TBODY_OR_THEAD_OR_TFOOT: - clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - mode = IN_TABLE_BODY; - attributes = null; // CPP - break starttagloop; - case TR: - case TD_OR_TH: - clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); - appendToCurrentNodeAndPushElement( - ElementName.TBODY, - HtmlAttributes.EMPTY_ATTRIBUTES); - mode = IN_TABLE_BODY; - continue starttagloop; - case TEMPLATE: - // fall through to IN_HEAD - break intableloop; - case TABLE: - errTableSeenWhileTableOpen(); - eltPos = findLastInTableScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment || isTemplateContents(); - break starttagloop; - } - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent("table")) { - errNoCheckUnclosedElementsOnStack(); - } - while (currentPtr >= eltPos) { - pop(); - } - resetTheInsertionMode(); - continue starttagloop; - case SCRIPT: - // XXX need to manage much more stuff - // here if - // supporting - // document.write() - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.SCRIPT_DATA, elementName); - attributes = null; // CPP - break starttagloop; - case STYLE: - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RAWTEXT, elementName); - attributes = null; // CPP - break starttagloop; - case INPUT: - errStartTagInTable(name); - if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "hidden", - attributes.getValue(AttributeName.TYPE))) { - break intableloop; - } - appendVoidElementToCurrent( - name, attributes, - formPointer); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case FORM: - if (formPointer != null || isTemplateContents()) { - errFormWhenFormOpen(); - break starttagloop; - } else { - errStartTagInTable(name); - appendVoidFormToCurrent(attributes); - attributes = null; // CPP - break starttagloop; - } - default: - errStartTagInTable(name); - // fall through to IN_BODY - break intableloop; - } - } - case IN_CAPTION: - switch (group) { - case CAPTION: - case COL: - case COLGROUP: - case TBODY_OR_THEAD_OR_TFOOT: - case TR: - case TD_OR_TH: - errStrayStartTag(name); - eltPos = findLastInTableScope("caption"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - break starttagloop; - } - generateImpliedEndTags(); - if (errorHandler != null && currentPtr != eltPos) { - errNoCheckUnclosedElementsOnStack(); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - mode = IN_TABLE; - continue; - default: - // fall through to IN_BODY - } - case IN_CELL: - switch (group) { - case CAPTION: - case COL: - case COLGROUP: - case TBODY_OR_THEAD_OR_TFOOT: - case TR: - case TD_OR_TH: - eltPos = findLastInTableScopeTdTh(); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errNoCellToClose(); - break starttagloop; - } else { - closeTheCell(eltPos); - continue; - } - default: - // fall through to IN_BODY - } - case FRAMESET_OK: - switch (group) { - case FRAMESET: - if (mode == FRAMESET_OK) { - if (currentPtr == 0 || stack[1].getGroup() != BODY) { - assert fragment || isTemplateContents(); - errStrayStartTag(name); - break starttagloop; - } else { - errFramesetStart(); - detachFromParent(stack[1].node); - while (currentPtr > 0) { - pop(); - } - appendToCurrentNodeAndPushElement( - elementName, - attributes); - mode = IN_FRAMESET; - attributes = null; // CPP - break starttagloop; - } - } else { - errStrayStartTag(name); - break starttagloop; - } - // NOT falling through! - case PRE_OR_LISTING: - case LI: - case DD_OR_DT: - case BUTTON: - case MARQUEE_OR_APPLET: - case OBJECT: - case TABLE: - case AREA_OR_WBR: - case BR: - case EMBED: - case IMG: - case INPUT: - case KEYGEN: - case HR: - case TEXTAREA: - case XMP: - case IFRAME: - case SELECT: - if (mode == FRAMESET_OK - && !(group == INPUT && Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "hidden", - attributes.getValue(AttributeName.TYPE)))) { - framesetOk = false; - mode = IN_BODY; - } - // fall through to IN_BODY - default: - // fall through to IN_BODY - } - case IN_BODY: - inbodyloop: for (;;) { - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case BASE: - case LINK_OR_BASEFONT_OR_BGSOUND: - case META: - case STYLE: - case SCRIPT: - case TITLE: - case TEMPLATE: - // Fall through to IN_HEAD - break inbodyloop; - case BODY: - if (currentPtr == 0 || stack[1].getGroup() != BODY || isTemplateContents()) { - assert fragment || isTemplateContents(); - errStrayStartTag(name); - break starttagloop; - } - errFooSeenWhenFooOpen(name); - framesetOk = false; - if (mode == FRAMESET_OK) { - mode = IN_BODY; - } - if (addAttributesToBody(attributes)) { - attributes = null; // CPP - } - break starttagloop; - case P: - case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: - case UL_OR_OL_OR_DL: - case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: - implicitlyCloseP(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: - implicitlyCloseP(); - if (stack[currentPtr].getGroup() == H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) { - errHeadingWhenHeadingOpen(); - pop(); - } - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case FIELDSET: - implicitlyCloseP(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes, formPointer); - attributes = null; // CPP - break starttagloop; - case PRE_OR_LISTING: - implicitlyCloseP(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - needToDropLF = true; - attributes = null; // CPP - break starttagloop; - case FORM: - if (formPointer != null && !isTemplateContents()) { - errFormWhenFormOpen(); - break starttagloop; - } else { - implicitlyCloseP(); - appendToCurrentNodeAndPushFormElementMayFoster(attributes); - attributes = null; // CPP - break starttagloop; - } - case LI: - case DD_OR_DT: - eltPos = currentPtr; - for (;;) { - StackNode<T> node = stack[eltPos]; // weak - // ref - if (node.getGroup() == group) { // LI or - // DD_OR_DT - generateImpliedEndTagsExceptFor(node.name); - if (errorHandler != null - && eltPos != currentPtr) { - errUnclosedElementsImplied(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - break; - } else if (eltPos == 0 || (node.isSpecial() - && (node.ns != "http://www.w3.org/1999/xhtml" - || (node.name != "p" - && node.name != "address" - && node.name != "div")))) { - break; - } - eltPos--; - } - implicitlyCloseP(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case PLAINTEXT: - implicitlyCloseP(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - tokenizer.setStateAndEndTagExpectation( - Tokenizer.PLAINTEXT, elementName); - attributes = null; // CPP - break starttagloop; - case A: - int activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker("a"); - if (activeAPos != -1) { - errFooSeenWhenFooOpen(name); - StackNode<T> activeA = listOfActiveFormattingElements[activeAPos]; - activeA.retain(); - adoptionAgencyEndTag("a"); - removeFromStack(activeA); - activeAPos = findInListOfActiveFormattingElements(activeA); - if (activeAPos != -1) { - removeFromListOfActiveFormattingElements(activeAPos); - } - activeA.release(); - } - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushFormattingElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: - case FONT: - reconstructTheActiveFormattingElements(); - maybeForgetEarlierDuplicateFormattingElement(elementName.name, attributes); - appendToCurrentNodeAndPushFormattingElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case NOBR: - reconstructTheActiveFormattingElements(); - if (TreeBuilder.NOT_FOUND_ON_STACK != findLastInScope("nobr")) { - errFooSeenWhenFooOpen(name); - adoptionAgencyEndTag("nobr"); - reconstructTheActiveFormattingElements(); - } - appendToCurrentNodeAndPushFormattingElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case BUTTON: - eltPos = findLastInScope(name); - if (eltPos != TreeBuilder.NOT_FOUND_ON_STACK) { - errFooSeenWhenFooOpen(name); - generateImpliedEndTags(); - if (errorHandler != null - && !isCurrent(name)) { - errUnclosedElementsImplied(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - continue starttagloop; - } else { - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes, formPointer); - attributes = null; // CPP - break starttagloop; - } - case OBJECT: - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes, formPointer); - insertMarker(); - attributes = null; // CPP - break starttagloop; - case MARQUEE_OR_APPLET: - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - insertMarker(); - attributes = null; // CPP - break starttagloop; - case TABLE: - // The only quirk. Blame Hixie and - // Acid2. - if (!quirks) { - implicitlyCloseP(); - } - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - mode = IN_TABLE; - attributes = null; // CPP - break starttagloop; - case BR: - case EMBED: - case AREA_OR_WBR: - reconstructTheActiveFormattingElements(); - // FALL THROUGH to PARAM_OR_SOURCE_OR_TRACK - // CPPONLY: case MENUITEM: - case PARAM_OR_SOURCE_OR_TRACK: - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case HR: - implicitlyCloseP(); - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case IMAGE: - errImage(); - elementName = ElementName.IMG; - continue starttagloop; - case IMG: - case KEYGEN: - case INPUT: - reconstructTheActiveFormattingElements(); - appendVoidElementToCurrentMayFoster( - name, attributes, - formPointer); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case ISINDEX: - errIsindex(); - if (formPointer != null && !isTemplateContents()) { - break starttagloop; - } - implicitlyCloseP(); - HtmlAttributes formAttrs = new HtmlAttributes(0); - int actionIndex = attributes.getIndex(AttributeName.ACTION); - if (actionIndex > -1) { - formAttrs.addAttribute( - AttributeName.ACTION, - attributes.getValueNoBoundsCheck(actionIndex) - // [NOCPP[ - , XmlViolationPolicy.ALLOW - // ]NOCPP] - // CPPONLY: , attributes.getLineNoBoundsCheck(actionIndex) - ); - } - appendToCurrentNodeAndPushFormElementMayFoster(formAttrs); - appendVoidElementToCurrentMayFoster( - ElementName.HR, - HtmlAttributes.EMPTY_ATTRIBUTES); - appendToCurrentNodeAndPushElementMayFoster( - ElementName.LABEL, - HtmlAttributes.EMPTY_ATTRIBUTES); - int promptIndex = attributes.getIndex(AttributeName.PROMPT); - if (promptIndex > -1) { - @Auto char[] prompt = Portability.newCharArrayFromString(attributes.getValueNoBoundsCheck(promptIndex)); - appendCharacters(stack[currentPtr].node, - prompt, 0, prompt.length); - } else { - appendIsindexPrompt(stack[currentPtr].node); - } - HtmlAttributes inputAttributes = new HtmlAttributes( - 0); - inputAttributes.addAttribute( - AttributeName.NAME, - Portability.newStringFromLiteral("isindex") - // [NOCPP[ - , XmlViolationPolicy.ALLOW - // ]NOCPP] - // CPPONLY: , tokenizer.getLineNumber() - ); - for (int i = 0; i < attributes.getLength(); i++) { - AttributeName attributeQName = attributes.getAttributeNameNoBoundsCheck(i); - if (AttributeName.NAME == attributeQName - || AttributeName.PROMPT == attributeQName) { - attributes.releaseValue(i); - } else if (AttributeName.ACTION != attributeQName) { - inputAttributes.addAttribute( - attributeQName, - attributes.getValueNoBoundsCheck(i) - // [NOCPP[ - , XmlViolationPolicy.ALLOW - // ]NOCPP] - // CPPONLY: , attributes.getLineNoBoundsCheck(i) - ); - } - } - attributes.clearWithoutReleasingContents(); - appendVoidElementToCurrentMayFoster( - "input", - inputAttributes, formPointer); - pop(); // label - appendVoidElementToCurrentMayFoster( - ElementName.HR, - HtmlAttributes.EMPTY_ATTRIBUTES); - pop(); // form - - if (!isTemplateContents()) { - formPointer = null; - } - - selfClosing = false; - // Portability.delete(formAttrs); - // Portability.delete(inputAttributes); - // Don't delete attributes, they are deleted - // later - break starttagloop; - case TEXTAREA: - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes, formPointer); - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RCDATA, elementName); - originalMode = mode; - mode = TEXT; - needToDropLF = true; - attributes = null; // CPP - break starttagloop; - case XMP: - implicitlyCloseP(); - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RAWTEXT, elementName); - attributes = null; // CPP - break starttagloop; - case NOSCRIPT: - if (!scriptingEnabled) { - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - } else { - // fall through - } - case NOFRAMES: - case IFRAME: - case NOEMBED: - startTagGenericRawText(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case SELECT: - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes, formPointer); - switch (mode) { - case IN_TABLE: - case IN_CAPTION: - case IN_COLUMN_GROUP: - case IN_TABLE_BODY: - case IN_ROW: - case IN_CELL: - mode = IN_SELECT_IN_TABLE; - break; - default: - mode = IN_SELECT; - break; - } - attributes = null; // CPP - break starttagloop; - case OPTGROUP: - case OPTION: - if (isCurrent("option")) { - pop(); - } - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case RB_OR_RTC: - eltPos = findLastInScope("ruby"); - if (eltPos != NOT_FOUND_ON_STACK) { - generateImpliedEndTags(); - } - if (eltPos != currentPtr) { - if (eltPos == NOT_FOUND_ON_STACK) { - errStartTagSeenWithoutRuby(name); - } else { - errUnclosedChildrenInRuby(); - } - } - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case RT_OR_RP: - eltPos = findLastInScope("ruby"); - if (eltPos != NOT_FOUND_ON_STACK) { - generateImpliedEndTagsExceptFor("rtc"); - } - if (eltPos != currentPtr) { - if (!isCurrent("rtc")) { - if (eltPos == NOT_FOUND_ON_STACK) { - errStartTagSeenWithoutRuby(name); - } else { - errUnclosedChildrenInRuby(); - } - } - } - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case MATH: - reconstructTheActiveFormattingElements(); - attributes.adjustForMath(); - if (selfClosing) { - appendVoidElementToCurrentMayFosterMathML( - elementName, attributes); - selfClosing = false; - } else { - appendToCurrentNodeAndPushElementMayFosterMathML( - elementName, attributes); - } - attributes = null; // CPP - break starttagloop; - case SVG: - reconstructTheActiveFormattingElements(); - attributes.adjustForSvg(); - if (selfClosing) { - appendVoidElementToCurrentMayFosterSVG( - elementName, - attributes); - selfClosing = false; - } else { - appendToCurrentNodeAndPushElementMayFosterSVG( - elementName, attributes); - } - attributes = null; // CPP - break starttagloop; - case CAPTION: - case COL: - case COLGROUP: - case TBODY_OR_THEAD_OR_TFOOT: - case TR: - case TD_OR_TH: - case FRAME: - case FRAMESET: - case HEAD: - errStrayStartTag(name); - break starttagloop; - case OUTPUT: - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes, formPointer); - attributes = null; // CPP - break starttagloop; - default: - reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - } - } - case IN_HEAD: - inheadloop: for (;;) { - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case BASE: - case LINK_OR_BASEFONT_OR_BGSOUND: - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case META: - // Fall through to IN_HEAD_NOSCRIPT - break inheadloop; - case TITLE: - startTagTitleInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case NOSCRIPT: - if (scriptingEnabled) { - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RAWTEXT, elementName); - } else { - appendToCurrentNodeAndPushElementMayFoster( - elementName, - attributes); - mode = IN_HEAD_NOSCRIPT; - } - attributes = null; // CPP - break starttagloop; - case SCRIPT: - startTagScriptInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case STYLE: - case NOFRAMES: - startTagGenericRawText(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case HEAD: - /* Parse error. */ - errFooSeenWhenFooOpen(name); - /* Ignore the token. */ - break starttagloop; - case TEMPLATE: - startTagTemplateInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - default: - pop(); - mode = AFTER_HEAD; - continue starttagloop; - } - } - case IN_HEAD_NOSCRIPT: - switch (group) { - case HTML: - // XXX did Hixie really mean to omit "base" - // here? - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case LINK_OR_BASEFONT_OR_BGSOUND: - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case META: - checkMetaCharset(attributes); - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case STYLE: - case NOFRAMES: - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RAWTEXT, elementName); - attributes = null; // CPP - break starttagloop; - case HEAD: - errFooSeenWhenFooOpen(name); - break starttagloop; - case NOSCRIPT: - errFooSeenWhenFooOpen(name); - break starttagloop; - default: - errBadStartTagInHead(name); - pop(); - mode = IN_HEAD; - continue; - } - case IN_COLUMN_GROUP: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case COL: - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - case TEMPLATE: - startTagTemplateInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - default: - if (currentPtr == 0 || stack[currentPtr].getGroup() == TEMPLATE) { - assert fragment || isTemplateContents(); - errGarbageInColgroup(); - break starttagloop; - } - pop(); - mode = IN_TABLE; - continue; - } - case IN_SELECT_IN_TABLE: - switch (group) { - case CAPTION: - case TBODY_OR_THEAD_OR_TFOOT: - case TR: - case TD_OR_TH: - case TABLE: - errStartTagWithSelectOpen(name); - eltPos = findLastInTableScope("select"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment; - break starttagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375 - } - while (currentPtr >= eltPos) { - pop(); - } - resetTheInsertionMode(); - continue; - default: - // fall through to IN_SELECT - } - case IN_SELECT: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case OPTION: - if (isCurrent("option")) { - pop(); - } - appendToCurrentNodeAndPushElement( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case OPTGROUP: - if (isCurrent("option")) { - pop(); - } - if (isCurrent("optgroup")) { - pop(); - } - appendToCurrentNodeAndPushElement( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case SELECT: - errStartSelectWhereEndSelectExpected(); - eltPos = findLastInTableScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment; - errNoSelectInTableScope(); - break starttagloop; - } else { - while (currentPtr >= eltPos) { - pop(); - } - resetTheInsertionMode(); - break starttagloop; - } - case INPUT: - case TEXTAREA: - case KEYGEN: - errStartTagWithSelectOpen(name); - eltPos = findLastInTableScope("select"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment; - break starttagloop; - } - while (currentPtr >= eltPos) { - pop(); - } - resetTheInsertionMode(); - continue; - case SCRIPT: - startTagScriptInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - case TEMPLATE: - startTagTemplateInHead(elementName, attributes); - attributes = null; // CPP - break starttagloop; - default: - errStrayStartTag(name); - break starttagloop; - } - case AFTER_BODY: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - default: - errStrayStartTag(name); - mode = framesetOk ? FRAMESET_OK : IN_BODY; - continue; - } - case IN_FRAMESET: - switch (group) { - case FRAMESET: - appendToCurrentNodeAndPushElement( - elementName, - attributes); - attributes = null; // CPP - break starttagloop; - case FRAME: - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - attributes = null; // CPP - break starttagloop; - default: - // fall through to AFTER_FRAMESET - } - case AFTER_FRAMESET: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case NOFRAMES: - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RAWTEXT, elementName); - attributes = null; // CPP - break starttagloop; - default: - errStrayStartTag(name); - break starttagloop; - } - case INITIAL: - /* - * Parse error. - */ - // [NOCPP[ - switch (doctypeExpectation) { - case AUTO: - err("Start tag seen without seeing a doctype first. Expected e.g. \u201C<!DOCTYPE html>\u201D."); - break; - case HTML: - // ]NOCPP] - errStartTagWithoutDoctype(); - // [NOCPP[ - break; - case HTML401_STRICT: - err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - break; - case HTML401_TRANSITIONAL: - err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - break; - case NO_DOCTYPE_ERRORS: - } - // ]NOCPP] - /* - * - * Set the document to quirks mode. - */ - documentModeInternal(DocumentMode.QUIRKS_MODE, null, null, - false); - /* - * Then, switch to the root element mode of the tree - * construction stage - */ - mode = BEFORE_HTML; - /* - * and reprocess the current token. - */ - continue; - case BEFORE_HTML: - switch (group) { - case HTML: - // optimize error check and streaming SAX by - // hoisting - // "html" handling here. - if (attributes == HtmlAttributes.EMPTY_ATTRIBUTES) { - // This has the right magic side effect - // that - // it - // makes attributes in SAX Tree mutable. - appendHtmlElementToDocumentAndPush(); - } else { - appendHtmlElementToDocumentAndPush(attributes); - } - // XXX application cache should fire here - mode = BEFORE_HEAD; - attributes = null; // CPP - break starttagloop; - default: - /* - * Create an HTMLElement node with the tag name - * html, in the HTML namespace. Append it to the - * Document object. - */ - appendHtmlElementToDocumentAndPush(); - /* Switch to the main mode */ - mode = BEFORE_HEAD; - /* - * reprocess the current token. - */ - continue; - } - case BEFORE_HEAD: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case HEAD: - /* - * A start tag whose tag name is "head" - * - * Create an element for the token. - * - * Set the head element pointer to this new element - * node. - * - * Append the new element to the current node and - * push it onto the stack of open elements. - */ - appendToCurrentNodeAndPushHeadElement(attributes); - /* - * Change the insertion mode to "in head". - */ - mode = IN_HEAD; - attributes = null; // CPP - break starttagloop; - default: - /* - * Any other start tag token - * - * Act as if a start tag token with the tag name - * "head" and no attributes had been seen, - */ - appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); - mode = IN_HEAD; - /* - * then reprocess the current token. - * - * This will result in an empty head element being - * generated, with the current token being - * reprocessed in the "after head" insertion mode. - */ - continue; - } - case AFTER_HEAD: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case BODY: - if (attributes.getLength() == 0) { - // This has the right magic side effect - // that - // it - // makes attributes in SAX Tree mutable. - appendToCurrentNodeAndPushBodyElement(); - } else { - appendToCurrentNodeAndPushBodyElement(attributes); - } - framesetOk = false; - mode = IN_BODY; - attributes = null; // CPP - break starttagloop; - case FRAMESET: - appendToCurrentNodeAndPushElement( - elementName, - attributes); - mode = IN_FRAMESET; - attributes = null; // CPP - break starttagloop; - case TEMPLATE: - errFooBetweenHeadAndBody(name); - pushHeadPointerOntoStack(); - StackNode<T> headOnStack = stack[currentPtr]; - startTagTemplateInHead(elementName, attributes); - removeFromStack(headOnStack); - attributes = null; // CPP - break starttagloop; - case BASE: - case LINK_OR_BASEFONT_OR_BGSOUND: - errFooBetweenHeadAndBody(name); - pushHeadPointerOntoStack(); - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - pop(); // head - attributes = null; // CPP - break starttagloop; - case META: - errFooBetweenHeadAndBody(name); - checkMetaCharset(attributes); - pushHeadPointerOntoStack(); - appendVoidElementToCurrentMayFoster( - elementName, - attributes); - selfClosing = false; - pop(); // head - attributes = null; // CPP - break starttagloop; - case SCRIPT: - errFooBetweenHeadAndBody(name); - pushHeadPointerOntoStack(); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.SCRIPT_DATA, elementName); - attributes = null; // CPP - break starttagloop; - case STYLE: - case NOFRAMES: - errFooBetweenHeadAndBody(name); - pushHeadPointerOntoStack(); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RAWTEXT, elementName); - attributes = null; // CPP - break starttagloop; - case TITLE: - errFooBetweenHeadAndBody(name); - pushHeadPointerOntoStack(); - appendToCurrentNodeAndPushElement( - elementName, - attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation( - Tokenizer.RCDATA, elementName); - attributes = null; // CPP - break starttagloop; - case HEAD: - errStrayStartTag(name); - break starttagloop; - default: - appendToCurrentNodeAndPushBodyElement(); - mode = FRAMESET_OK; - continue; - } - case AFTER_AFTER_BODY: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - default: - errStrayStartTag(name); - fatal(); - mode = framesetOk ? FRAMESET_OK : IN_BODY; - continue; - } - case AFTER_AFTER_FRAMESET: - switch (group) { - case HTML: - errStrayStartTag(name); - if (!fragment && !isTemplateContents()) { - addAttributesToHtml(attributes); - attributes = null; // CPP - } - break starttagloop; - case NOFRAMES: - startTagGenericRawText(elementName, attributes); - attributes = null; // CPP - break starttagloop; - default: - errStrayStartTag(name); - break starttagloop; - } - case TEXT: - assert false; - break starttagloop; // Avoid infinite loop if the assertion - // fails - } - } - if (selfClosing) { - errSelfClosing(); - } - // CPPONLY: if (mBuilder == null && attributes != HtmlAttributes.EMPTY_ATTRIBUTES) { - // CPPONLY: Portability.delete(attributes); - // CPPONLY: } - } - - private void startTagTitleInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException { - appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation(Tokenizer.RCDATA, elementName); - } - - private void startTagGenericRawText(ElementName elementName, HtmlAttributes attributes) throws SAXException { - appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation(Tokenizer.RAWTEXT, elementName); - } - - private void startTagScriptInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException { - // XXX need to manage much more stuff here if supporting document.write() - appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); - originalMode = mode; - mode = TEXT; - tokenizer.setStateAndEndTagExpectation(Tokenizer.SCRIPT_DATA, elementName); - } - - private void startTagTemplateInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException { - appendToCurrentNodeAndPushElement(elementName, attributes); - insertMarker(); - framesetOk = false; - originalMode = mode; - mode = IN_TEMPLATE; - pushTemplateMode(IN_TEMPLATE); - } - - private boolean isTemplateContents() { - return TreeBuilder.NOT_FOUND_ON_STACK != findLast("template"); - } - - private boolean isTemplateModeStackEmpty() { - return templateModePtr == -1; - } - - private boolean isSpecialParentInForeign(StackNode<T> stackNode) { - @NsUri String ns = stackNode.ns; - return ("http://www.w3.org/1999/xhtml" == ns) - || (stackNode.isHtmlIntegrationPoint()) - || (("http://www.w3.org/1998/Math/MathML" == ns) && (stackNode.getGroup() == MI_MO_MN_MS_MTEXT)); - } - - /** - * - * <p> - * C++ memory note: The return value must be released. - * - * @return - * @throws SAXException - * @throws StopSniffingException - */ - public static String extractCharsetFromContent(String attributeValue - // CPPONLY: , TreeBuilder tb - ) { - // This is a bit ugly. Converting the string to char array in order to - // make the portability layer smaller. - int charsetState = CHARSET_INITIAL; - int start = -1; - int end = -1; - @Auto char[] buffer = Portability.newCharArrayFromString(attributeValue); - - charsetloop: for (int i = 0; i < buffer.length; i++) { - char c = buffer[i]; - switch (charsetState) { - case CHARSET_INITIAL: - switch (c) { - case 'c': - case 'C': - charsetState = CHARSET_C; - continue; - default: - continue; - } - case CHARSET_C: - switch (c) { - case 'h': - case 'H': - charsetState = CHARSET_H; - continue; - default: - charsetState = CHARSET_INITIAL; - continue; - } - case CHARSET_H: - switch (c) { - case 'a': - case 'A': - charsetState = CHARSET_A; - continue; - default: - charsetState = CHARSET_INITIAL; - continue; - } - case CHARSET_A: - switch (c) { - case 'r': - case 'R': - charsetState = CHARSET_R; - continue; - default: - charsetState = CHARSET_INITIAL; - continue; - } - case CHARSET_R: - switch (c) { - case 's': - case 'S': - charsetState = CHARSET_S; - continue; - default: - charsetState = CHARSET_INITIAL; - continue; - } - case CHARSET_S: - switch (c) { - case 'e': - case 'E': - charsetState = CHARSET_E; - continue; - default: - charsetState = CHARSET_INITIAL; - continue; - } - case CHARSET_E: - switch (c) { - case 't': - case 'T': - charsetState = CHARSET_T; - continue; - default: - charsetState = CHARSET_INITIAL; - continue; - } - case CHARSET_T: - switch (c) { - case '\t': - case '\n': - case '\u000C': - case '\r': - case ' ': - continue; - case '=': - charsetState = CHARSET_EQUALS; - continue; - default: - return null; - } - case CHARSET_EQUALS: - switch (c) { - case '\t': - case '\n': - case '\u000C': - case '\r': - case ' ': - continue; - case '\'': - start = i + 1; - charsetState = CHARSET_SINGLE_QUOTED; - continue; - case '\"': - start = i + 1; - charsetState = CHARSET_DOUBLE_QUOTED; - continue; - default: - start = i; - charsetState = CHARSET_UNQUOTED; - continue; - } - case CHARSET_SINGLE_QUOTED: - switch (c) { - case '\'': - end = i; - break charsetloop; - default: - continue; - } - case CHARSET_DOUBLE_QUOTED: - switch (c) { - case '\"': - end = i; - break charsetloop; - default: - continue; - } - case CHARSET_UNQUOTED: - switch (c) { - case '\t': - case '\n': - case '\u000C': - case '\r': - case ' ': - case ';': - end = i; - break charsetloop; - default: - continue; - } - } - } - String charset = null; - if (start != -1) { - if (end == -1) { - end = buffer.length; - } - charset = Portability.newStringFromBuffer(buffer, start, end - - start - // CPPONLY: , tb - ); - } - return charset; - } - - private void checkMetaCharset(HtmlAttributes attributes) - throws SAXException { - String charset = attributes.getValue(AttributeName.CHARSET); - if (charset != null) { - if (tokenizer.internalEncodingDeclaration(charset)) { - requestSuspension(); - return; - } - return; - } - if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "content-type", - attributes.getValue(AttributeName.HTTP_EQUIV))) { - return; - } - String content = attributes.getValue(AttributeName.CONTENT); - if (content != null) { - String extract = TreeBuilder.extractCharsetFromContent(content - // CPPONLY: , this - ); - // remember not to return early without releasing the string - if (extract != null) { - if (tokenizer.internalEncodingDeclaration(extract)) { - requestSuspension(); - } - } - Portability.releaseString(extract); - } - } - - public final void endTag(ElementName elementName) throws SAXException { - flushCharacters(); - needToDropLF = false; - int eltPos; - int group = elementName.getGroup(); - @Local String name = elementName.name; - endtagloop: for (;;) { - if (isInForeign()) { - if (stack[currentPtr].name != name) { - if (currentPtr == 0) { - errStrayEndTag(name); - } else { - errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName); - } - } - eltPos = currentPtr; - for (;;) { - if (eltPos == 0) { - assert fragment: "We can get this close to the root of the stack in foreign content only in the fragment case."; - break endtagloop; - } - if (stack[eltPos].name == name) { - while (currentPtr >= eltPos) { - pop(); - } - break endtagloop; - } - if (stack[--eltPos].ns == "http://www.w3.org/1999/xhtml") { - break; - } - } - } - switch (mode) { - case IN_TEMPLATE: - switch (group) { - case TEMPLATE: - // fall through to IN_HEAD - break; - default: - errStrayEndTag(name); - break endtagloop; - } - case IN_ROW: - switch (group) { - case TR: - eltPos = findLastOrRoot(TreeBuilder.TR); - if (eltPos == 0) { - assert fragment || isTemplateContents(); - errNoTableRowToClose(); - break endtagloop; - } - clearStackBackTo(eltPos); - pop(); - mode = IN_TABLE_BODY; - break endtagloop; - case TABLE: - eltPos = findLastOrRoot(TreeBuilder.TR); - if (eltPos == 0) { - assert fragment || isTemplateContents(); - errNoTableRowToClose(); - break endtagloop; - } - clearStackBackTo(eltPos); - pop(); - mode = IN_TABLE_BODY; - continue; - case TBODY_OR_THEAD_OR_TFOOT: - if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag(name); - break endtagloop; - } - eltPos = findLastOrRoot(TreeBuilder.TR); - if (eltPos == 0) { - assert fragment || isTemplateContents(); - errNoTableRowToClose(); - break endtagloop; - } - clearStackBackTo(eltPos); - pop(); - mode = IN_TABLE_BODY; - continue; - case BODY: - case CAPTION: - case COL: - case COLGROUP: - case HTML: - case TD_OR_TH: - errStrayEndTag(name); - break endtagloop; - default: - // fall through to IN_TABLE - } - case IN_TABLE_BODY: - switch (group) { - case TBODY_OR_THEAD_OR_TFOOT: - eltPos = findLastOrRoot(name); - if (eltPos == 0) { - errStrayEndTag(name); - break endtagloop; - } - clearStackBackTo(eltPos); - pop(); - mode = IN_TABLE; - break endtagloop; - case TABLE: - eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); - if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) { - assert fragment || isTemplateContents(); - errStrayEndTag(name); - break endtagloop; - } - clearStackBackTo(eltPos); - pop(); - mode = IN_TABLE; - continue; - case BODY: - case CAPTION: - case COL: - case COLGROUP: - case HTML: - case TD_OR_TH: - case TR: - errStrayEndTag(name); - break endtagloop; - default: - // fall through to IN_TABLE - } - case IN_TABLE: - switch (group) { - case TABLE: - eltPos = findLast("table"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment || isTemplateContents(); - errStrayEndTag(name); - break endtagloop; - } - while (currentPtr >= eltPos) { - pop(); - } - resetTheInsertionMode(); - break endtagloop; - case BODY: - case CAPTION: - case COL: - case COLGROUP: - case HTML: - case TBODY_OR_THEAD_OR_TFOOT: - case TD_OR_TH: - case TR: - errStrayEndTag(name); - break endtagloop; - case TEMPLATE: - // fall through to IN_HEAD - break; - default: - errStrayEndTag(name); - // fall through to IN_BODY - } - case IN_CAPTION: - switch (group) { - case CAPTION: - eltPos = findLastInTableScope("caption"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - break endtagloop; - } - generateImpliedEndTags(); - if (errorHandler != null && currentPtr != eltPos) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - mode = IN_TABLE; - break endtagloop; - case TABLE: - errTableClosedWhileCaptionOpen(); - eltPos = findLastInTableScope("caption"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - break endtagloop; - } - generateImpliedEndTags(); - if (errorHandler != null && currentPtr != eltPos) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - mode = IN_TABLE; - continue; - case BODY: - case COL: - case COLGROUP: - case HTML: - case TBODY_OR_THEAD_OR_TFOOT: - case TD_OR_TH: - case TR: - errStrayEndTag(name); - break endtagloop; - default: - // fall through to IN_BODY - } - case IN_CELL: - switch (group) { - case TD_OR_TH: - eltPos = findLastInTableScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag(name); - break endtagloop; - } - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent(name)) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - mode = IN_ROW; - break endtagloop; - case TABLE: - case TBODY_OR_THEAD_OR_TFOOT: - case TR: - if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) { - assert name == "tbody" || name == "tfoot" || name == "thead" || fragment || isTemplateContents(); - errStrayEndTag(name); - break endtagloop; - } - closeTheCell(findLastInTableScopeTdTh()); - continue; - case BODY: - case CAPTION: - case COL: - case COLGROUP: - case HTML: - errStrayEndTag(name); - break endtagloop; - default: - // fall through to IN_BODY - } - case FRAMESET_OK: - case IN_BODY: - switch (group) { - case BODY: - if (!isSecondOnStackBody()) { - assert fragment || isTemplateContents(); - errStrayEndTag(name); - break endtagloop; - } - assert currentPtr >= 1; - if (errorHandler != null) { - uncloseloop1: for (int i = 2; i <= currentPtr; i++) { - switch (stack[i].getGroup()) { - case DD_OR_DT: - case LI: - case OPTGROUP: - case OPTION: // is this possible? - case P: - case RB_OR_RTC: - case RT_OR_RP: - case TD_OR_TH: - case TBODY_OR_THEAD_OR_TFOOT: - break; - default: - errEndWithUnclosedElements(name); - break uncloseloop1; - } - } - } - mode = AFTER_BODY; - break endtagloop; - case HTML: - if (!isSecondOnStackBody()) { - assert fragment || isTemplateContents(); - errStrayEndTag(name); - break endtagloop; - } - if (errorHandler != null) { - uncloseloop2: for (int i = 0; i <= currentPtr; i++) { - switch (stack[i].getGroup()) { - case DD_OR_DT: - case LI: - case P: - case RB_OR_RTC: - case RT_OR_RP: - case TBODY_OR_THEAD_OR_TFOOT: - case TD_OR_TH: - case BODY: - case HTML: - break; - default: - errEndWithUnclosedElements(name); - break uncloseloop2; - } - } - } - mode = AFTER_BODY; - continue; - case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: - case UL_OR_OL_OR_DL: - case PRE_OR_LISTING: - case FIELDSET: - case BUTTON: - case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: - eltPos = findLastInScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag(name); - } else { - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent(name)) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - } - break endtagloop; - case FORM: - if (!isTemplateContents()) { - if (formPointer == null) { - errStrayEndTag(name); - break endtagloop; - } - formPointer = null; - eltPos = findLastInScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag(name); - break endtagloop; - } - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent(name)) { - errUnclosedElements(eltPos, name); - } - removeFromStack(eltPos); - break endtagloop; - } else { - eltPos = findLastInScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag(name); - break endtagloop; - } - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent(name)) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - break endtagloop; - } - case P: - eltPos = findLastInButtonScope("p"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errNoElementToCloseButEndTagSeen("p"); - // XXX Can the 'in foreign' case happen anymore? - if (isInForeign()) { - errHtmlStartTagInForeignContext(name); - // Check for currentPtr for the fragment - // case. - while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") { - pop(); - } - } - appendVoidElementToCurrentMayFoster( - elementName, - HtmlAttributes.EMPTY_ATTRIBUTES); - break endtagloop; - } - generateImpliedEndTagsExceptFor("p"); - assert eltPos != TreeBuilder.NOT_FOUND_ON_STACK; - if (errorHandler != null && eltPos != currentPtr) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - break endtagloop; - case LI: - eltPos = findLastInListScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errNoElementToCloseButEndTagSeen(name); - } else { - generateImpliedEndTagsExceptFor(name); - if (errorHandler != null - && eltPos != currentPtr) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - } - break endtagloop; - case DD_OR_DT: - eltPos = findLastInScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errNoElementToCloseButEndTagSeen(name); - } else { - generateImpliedEndTagsExceptFor(name); - if (errorHandler != null - && eltPos != currentPtr) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - } - break endtagloop; - case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: - eltPos = findLastInScopeHn(); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag(name); - } else { - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent(name)) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - } - break endtagloop; - case OBJECT: - case MARQUEE_OR_APPLET: - eltPos = findLastInScope(name); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag(name); - } else { - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent(name)) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - } - break endtagloop; - case BR: - errEndTagBr(); - if (isInForeign()) { - // XXX can this happen anymore? - errHtmlStartTagInForeignContext(name); - // Check for currentPtr for the fragment - // case. - while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") { - pop(); - } - } - reconstructTheActiveFormattingElements(); - appendVoidElementToCurrentMayFoster( - elementName, - HtmlAttributes.EMPTY_ATTRIBUTES); - break endtagloop; - case TEMPLATE: - // fall through to IN_HEAD; - break; - case AREA_OR_WBR: - // CPPONLY: case MENUITEM: - case PARAM_OR_SOURCE_OR_TRACK: - case EMBED: - case IMG: - case IMAGE: - case INPUT: - case KEYGEN: // XXX?? - case HR: - case ISINDEX: - case IFRAME: - case NOEMBED: // XXX??? - case NOFRAMES: // XXX?? - case SELECT: - case TABLE: - case TEXTAREA: // XXX?? - errStrayEndTag(name); - break endtagloop; - case NOSCRIPT: - if (scriptingEnabled) { - errStrayEndTag(name); - break endtagloop; - } else { - // fall through - } - case A: - case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: - case FONT: - case NOBR: - if (adoptionAgencyEndTag(name)) { - break endtagloop; - } - // else handle like any other tag - default: - if (isCurrent(name)) { - pop(); - break endtagloop; - } - - eltPos = currentPtr; - for (;;) { - StackNode<T> node = stack[eltPos]; - if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) { - generateImpliedEndTags(); - if (errorHandler != null - && !isCurrent(name)) { - errUnclosedElements(eltPos, name); - } - while (currentPtr >= eltPos) { - pop(); - } - break endtagloop; - } else if (eltPos == 0 || node.isSpecial()) { - errStrayEndTag(name); - break endtagloop; - } - eltPos--; - } - } - case IN_HEAD: - switch (group) { - case HEAD: - pop(); - mode = AFTER_HEAD; - break endtagloop; - case BR: - case HTML: - case BODY: - pop(); - mode = AFTER_HEAD; - continue; - case TEMPLATE: - endTagTemplateInHead(); - break endtagloop; - default: - errStrayEndTag(name); - break endtagloop; - } - case IN_HEAD_NOSCRIPT: - switch (group) { - case NOSCRIPT: - pop(); - mode = IN_HEAD; - break endtagloop; - case BR: - errStrayEndTag(name); - pop(); - mode = IN_HEAD; - continue; - default: - errStrayEndTag(name); - break endtagloop; - } - case IN_COLUMN_GROUP: - switch (group) { - case COLGROUP: - if (currentPtr == 0 || stack[currentPtr].getGroup() == - TreeBuilder.TEMPLATE) { - assert fragment || isTemplateContents(); - errGarbageInColgroup(); - break endtagloop; - } - pop(); - mode = IN_TABLE; - break endtagloop; - case COL: - errStrayEndTag(name); - break endtagloop; - case TEMPLATE: - endTagTemplateInHead(); - break endtagloop; - default: - if (currentPtr == 0 || stack[currentPtr].getGroup() == - TreeBuilder.TEMPLATE) { - assert fragment || isTemplateContents(); - errGarbageInColgroup(); - break endtagloop; - } - pop(); - mode = IN_TABLE; - continue; - } - case IN_SELECT_IN_TABLE: - switch (group) { - case CAPTION: - case TABLE: - case TBODY_OR_THEAD_OR_TFOOT: - case TR: - case TD_OR_TH: - errEndTagSeenWithSelectOpen(name); - if (findLastInTableScope(name) != TreeBuilder.NOT_FOUND_ON_STACK) { - eltPos = findLastInTableScope("select"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment; - break endtagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375 - } - while (currentPtr >= eltPos) { - pop(); - } - resetTheInsertionMode(); - continue; - } else { - break endtagloop; - } - default: - // fall through to IN_SELECT - } - case IN_SELECT: - switch (group) { - case OPTION: - if (isCurrent("option")) { - pop(); - break endtagloop; - } else { - errStrayEndTag(name); - break endtagloop; - } - case OPTGROUP: - if (isCurrent("option") - && "optgroup" == stack[currentPtr - 1].name) { - pop(); - } - if (isCurrent("optgroup")) { - pop(); - } else { - errStrayEndTag(name); - } - break endtagloop; - case SELECT: - eltPos = findLastInTableScope("select"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - assert fragment; - errStrayEndTag(name); - break endtagloop; - } - while (currentPtr >= eltPos) { - pop(); - } - resetTheInsertionMode(); - break endtagloop; - case TEMPLATE: - endTagTemplateInHead(); - break endtagloop; - default: - errStrayEndTag(name); - break endtagloop; - } - case AFTER_BODY: - switch (group) { - case HTML: - if (fragment) { - errStrayEndTag(name); - break endtagloop; - } else { - mode = AFTER_AFTER_BODY; - break endtagloop; - } - default: - errEndTagAfterBody(); - mode = framesetOk ? FRAMESET_OK : IN_BODY; - continue; - } - case IN_FRAMESET: - switch (group) { - case FRAMESET: - if (currentPtr == 0) { - assert fragment; - errStrayEndTag(name); - break endtagloop; - } - pop(); - if ((!fragment) && !isCurrent("frameset")) { - mode = AFTER_FRAMESET; - } - break endtagloop; - default: - errStrayEndTag(name); - break endtagloop; - } - case AFTER_FRAMESET: - switch (group) { - case HTML: - mode = AFTER_AFTER_FRAMESET; - break endtagloop; - default: - errStrayEndTag(name); - break endtagloop; - } - case INITIAL: - /* - * Parse error. - */ - // [NOCPP[ - switch (doctypeExpectation) { - case AUTO: - err("End tag seen without seeing a doctype first. Expected e.g. \u201C<!DOCTYPE html>\u201D."); - break; - case HTML: - // ]NOCPP] - errEndTagSeenWithoutDoctype(); - // [NOCPP[ - break; - case HTML401_STRICT: - err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D."); - break; - case HTML401_TRANSITIONAL: - err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D."); - break; - case NO_DOCTYPE_ERRORS: - } - // ]NOCPP] - /* - * - * Set the document to quirks mode. - */ - documentModeInternal(DocumentMode.QUIRKS_MODE, null, null, - false); - /* - * Then, switch to the root element mode of the tree - * construction stage - */ - mode = BEFORE_HTML; - /* - * and reprocess the current token. - */ - continue; - case BEFORE_HTML: - switch (group) { - case HEAD: - case BR: - case HTML: - case BODY: - /* - * Create an HTMLElement node with the tag name - * html, in the HTML namespace. Append it to the - * Document object. - */ - appendHtmlElementToDocumentAndPush(); - /* Switch to the main mode */ - mode = BEFORE_HEAD; - /* - * reprocess the current token. - */ - continue; - default: - errStrayEndTag(name); - break endtagloop; - } - case BEFORE_HEAD: - switch (group) { - case HEAD: - case BR: - case HTML: - case BODY: - appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); - mode = IN_HEAD; - continue; - default: - errStrayEndTag(name); - break endtagloop; - } - case AFTER_HEAD: - switch (group) { - case TEMPLATE: - endTagTemplateInHead(); - break endtagloop; - case HTML: - case BODY: - case BR: - appendToCurrentNodeAndPushBodyElement(); - mode = FRAMESET_OK; - continue; - default: - errStrayEndTag(name); - break endtagloop; - } - case AFTER_AFTER_BODY: - errStrayEndTag(name); - mode = framesetOk ? FRAMESET_OK : IN_BODY; - continue; - case AFTER_AFTER_FRAMESET: - errStrayEndTag(name); - break endtagloop; - case TEXT: - // XXX need to manage insertion point here - pop(); - if (originalMode == AFTER_HEAD) { - silentPop(); - } - mode = originalMode; - break endtagloop; - } - } // endtagloop - } - - private void endTagTemplateInHead() throws SAXException { - int eltPos = findLast("template"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - errStrayEndTag("template"); - return; - } - generateImpliedEndTags(); - if (errorHandler != null && !isCurrent("template")) { - errUnclosedElements(eltPos, "template"); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - popTemplateMode(); - resetTheInsertionMode(); - } - - private int findLastInTableScopeOrRootTemplateTbodyTheadTfoot() { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].getGroup() == TreeBuilder.TBODY_OR_THEAD_OR_TFOOT || - stack[i].getGroup() == TreeBuilder.TEMPLATE) { - return i; - } - } - return 0; - } - - private int findLast(@Local String name) { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) { - return i; - } - } - return TreeBuilder.NOT_FOUND_ON_STACK; - } - - private int findLastInTableScope(@Local String name) { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].ns == "http://www.w3.org/1999/xhtml") { - if (stack[i].name == name) { - return i; - } else if (stack[i].name == "table" || stack[i].name == "template") { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - } - return TreeBuilder.NOT_FOUND_ON_STACK; - } - - private int findLastInButtonScope(@Local String name) { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].ns == "http://www.w3.org/1999/xhtml") { - if (stack[i].name == name) { - return i; - } else if (stack[i].name == "button") { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - - if (stack[i].isScoping()) { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - return TreeBuilder.NOT_FOUND_ON_STACK; - } - - private int findLastInScope(@Local String name) { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) { - return i; - } else if (stack[i].isScoping()) { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - return TreeBuilder.NOT_FOUND_ON_STACK; - } - - private int findLastInListScope(@Local String name) { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].ns == "http://www.w3.org/1999/xhtml") { - if (stack[i].name == name) { - return i; - } else if (stack[i].name == "ul" || stack[i].name == "ol") { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - - if (stack[i].isScoping()) { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - return TreeBuilder.NOT_FOUND_ON_STACK; - } - - private int findLastInScopeHn() { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].getGroup() == TreeBuilder.H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) { - return i; - } else if (stack[i].isScoping()) { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - return TreeBuilder.NOT_FOUND_ON_STACK; - } - - private void generateImpliedEndTagsExceptFor(@Local String name) - throws SAXException { - for (;;) { - StackNode<T> node = stack[currentPtr]; - switch (node.getGroup()) { - case P: - case LI: - case DD_OR_DT: - case OPTION: - case OPTGROUP: - case RB_OR_RTC: - case RT_OR_RP: - if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) { - return; - } - pop(); - continue; - default: - return; - } - } - } - - private void generateImpliedEndTags() throws SAXException { - for (;;) { - switch (stack[currentPtr].getGroup()) { - case P: - case LI: - case DD_OR_DT: - case OPTION: - case OPTGROUP: - case RB_OR_RTC: - case RT_OR_RP: - pop(); - continue; - default: - return; - } - } - } - - private boolean isSecondOnStackBody() { - return currentPtr >= 1 && stack[1].getGroup() == TreeBuilder.BODY; - } - - private void documentModeInternal(DocumentMode m, String publicIdentifier, - String systemIdentifier, boolean html4SpecificAdditionalErrorChecks) - throws SAXException { - - if (isSrcdocDocument) { - // Srcdoc documents are always rendered in standards mode. - quirks = false; - if (documentModeHandler != null) { - documentModeHandler.documentMode( - DocumentMode.STANDARDS_MODE - // [NOCPP[ - , null, null, false - // ]NOCPP] - ); - } - return; - } - - quirks = (m == DocumentMode.QUIRKS_MODE); - if (documentModeHandler != null) { - documentModeHandler.documentMode( - m - // [NOCPP[ - , publicIdentifier, systemIdentifier, - html4SpecificAdditionalErrorChecks - // ]NOCPP] - ); - } - // [NOCPP[ - documentMode(m, publicIdentifier, systemIdentifier, - html4SpecificAdditionalErrorChecks); - // ]NOCPP] - } - - private boolean isAlmostStandards(String publicIdentifier, - String systemIdentifier) { - if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-//w3c//dtd xhtml 1.0 transitional//en", publicIdentifier)) { - return true; - } - if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-//w3c//dtd xhtml 1.0 frameset//en", publicIdentifier)) { - return true; - } - if (systemIdentifier != null) { - if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-//w3c//dtd html 4.01 transitional//en", publicIdentifier)) { - return true; - } - if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-//w3c//dtd html 4.01 frameset//en", publicIdentifier)) { - return true; - } - } - return false; - } - - private boolean isQuirky(@Local String name, String publicIdentifier, - String systemIdentifier, boolean forceQuirks) { - if (forceQuirks) { - return true; - } - if (name != HTML_LOCAL) { - return true; - } - if (publicIdentifier != null) { - for (int i = 0; i < TreeBuilder.QUIRKY_PUBLIC_IDS.length; i++) { - if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( - TreeBuilder.QUIRKY_PUBLIC_IDS[i], publicIdentifier)) { - return true; - } - } - if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier) - || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-/w3c/dtd html 4.0 transitional/en", - publicIdentifier) - || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "html", publicIdentifier)) { - return true; - } - } - if (systemIdentifier == null) { - if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-//w3c//dtd html 4.01 transitional//en", publicIdentifier)) { - return true; - } else if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "-//w3c//dtd html 4.01 frameset//en", publicIdentifier)) { - return true; - } - } else if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd", - systemIdentifier)) { - return true; - } - return false; - } - - private void closeTheCell(int eltPos) throws SAXException { - generateImpliedEndTags(); - if (errorHandler != null && eltPos != currentPtr) { - errUnclosedElementsCell(eltPos); - } - while (currentPtr >= eltPos) { - pop(); - } - clearTheListOfActiveFormattingElementsUpToTheLastMarker(); - mode = IN_ROW; - return; - } - - private int findLastInTableScopeTdTh() { - for (int i = currentPtr; i > 0; i--) { - @Local String name = stack[i].name; - if (stack[i].ns == "http://www.w3.org/1999/xhtml") { - if ("td" == name || "th" == name) { - return i; - } else if (name == "table" || name == "template") { - return TreeBuilder.NOT_FOUND_ON_STACK; - } - } - } - return TreeBuilder.NOT_FOUND_ON_STACK; - } - - private void clearStackBackTo(int eltPos) throws SAXException { - int eltGroup = stack[eltPos].getGroup(); - while (currentPtr > eltPos) { // > not >= intentional - if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" - && stack[currentPtr].getGroup() == TEMPLATE - && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltPos == 0)) { - return; - } - pop(); - } - } - - private void resetTheInsertionMode() { - StackNode<T> node; - @Local String name; - @NsUri String ns; - for (int i = currentPtr; i >= 0; i--) { - node = stack[i]; - name = node.name; - ns = node.ns; - if (i == 0) { - if (!(contextNamespace == "http://www.w3.org/1999/xhtml" && (contextName == "td" || contextName == "th"))) { - if (fragment) { - // Make sure we are parsing a fragment otherwise the context element doesn't make sense. - name = contextName; - ns = contextNamespace; - } - } else { - mode = framesetOk ? FRAMESET_OK : IN_BODY; // XXX from Hixie's email - return; - } - } - if ("select" == name) { - int ancestorIndex = i; - while (ancestorIndex > 0) { - StackNode<T> ancestor = stack[ancestorIndex--]; - if ("http://www.w3.org/1999/xhtml" == ancestor.ns) { - if ("template" == ancestor.name) { - break; - } - if ("table" == ancestor.name) { - mode = IN_SELECT_IN_TABLE; - return; - } - } - } - mode = IN_SELECT; - return; - } else if ("td" == name || "th" == name) { - mode = IN_CELL; - return; - } else if ("tr" == name) { - mode = IN_ROW; - return; - } else if ("tbody" == name || "thead" == name || "tfoot" == name) { - mode = IN_TABLE_BODY; - return; - } else if ("caption" == name) { - mode = IN_CAPTION; - return; - } else if ("colgroup" == name) { - mode = IN_COLUMN_GROUP; - return; - } else if ("table" == name) { - mode = IN_TABLE; - return; - } else if ("http://www.w3.org/1999/xhtml" != ns) { - mode = framesetOk ? FRAMESET_OK : IN_BODY; - return; - } else if ("template" == name) { - assert templateModePtr >= 0; - mode = templateModeStack[templateModePtr]; - return; - } else if ("head" == name) { - if (name == contextName) { - mode = framesetOk ? FRAMESET_OK : IN_BODY; // really - } else { - mode = IN_HEAD; - } - return; - } else if ("body" == name) { - mode = framesetOk ? FRAMESET_OK : IN_BODY; - return; - } else if ("frameset" == name) { - // TODO: Fragment case. Add error reporting. - mode = IN_FRAMESET; - return; - } else if ("html" == name) { - if (headPointer == null) { - // TODO: Fragment case. Add error reporting. - mode = BEFORE_HEAD; - } else { - mode = AFTER_HEAD; - } - return; - } else if (i == 0) { - mode = framesetOk ? FRAMESET_OK : IN_BODY; - return; - } - } - } - - /** - * @throws SAXException - * - */ - private void implicitlyCloseP() throws SAXException { - int eltPos = findLastInButtonScope("p"); - if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - return; - } - generateImpliedEndTagsExceptFor("p"); - if (errorHandler != null && eltPos != currentPtr) { - errUnclosedElementsImplied(eltPos, "p"); - } - while (currentPtr >= eltPos) { - pop(); - } - } - - private boolean debugOnlyClearLastStackSlot() { - stack[currentPtr] = null; - return true; - } - - private boolean debugOnlyClearLastListSlot() { - listOfActiveFormattingElements[listPtr] = null; - return true; - } - - private void pushTemplateMode(int mode) { - templateModePtr++; - if (templateModePtr == templateModeStack.length) { - int[] newStack = new int[templateModeStack.length + 64]; - System.arraycopy(templateModeStack, 0, newStack, 0, templateModeStack.length); - templateModeStack = newStack; - } - templateModeStack[templateModePtr] = mode; - } - - @SuppressWarnings("unchecked") private void push(StackNode<T> node) throws SAXException { - currentPtr++; - if (currentPtr == stack.length) { - StackNode<T>[] newStack = new StackNode[stack.length + 64]; - System.arraycopy(stack, 0, newStack, 0, stack.length); - stack = newStack; - } - stack[currentPtr] = node; - elementPushed(node.ns, node.popName, node.node); - } - - @SuppressWarnings("unchecked") private void silentPush(StackNode<T> node) throws SAXException { - currentPtr++; - if (currentPtr == stack.length) { - StackNode<T>[] newStack = new StackNode[stack.length + 64]; - System.arraycopy(stack, 0, newStack, 0, stack.length); - stack = newStack; - } - stack[currentPtr] = node; - } - - @SuppressWarnings("unchecked") private void append(StackNode<T> node) { - listPtr++; - if (listPtr == listOfActiveFormattingElements.length) { - StackNode<T>[] newList = new StackNode[listOfActiveFormattingElements.length + 64]; - System.arraycopy(listOfActiveFormattingElements, 0, newList, 0, - listOfActiveFormattingElements.length); - listOfActiveFormattingElements = newList; - } - listOfActiveFormattingElements[listPtr] = node; - } - - @Inline private void insertMarker() { - append(null); - } - - private void clearTheListOfActiveFormattingElementsUpToTheLastMarker() { - while (listPtr > -1) { - if (listOfActiveFormattingElements[listPtr] == null) { - --listPtr; - return; - } - listOfActiveFormattingElements[listPtr].release(); - --listPtr; - } - } - - @Inline private boolean isCurrent(@Local String name) { - return stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" && - name == stack[currentPtr].name; - } - - private void removeFromStack(int pos) throws SAXException { - if (currentPtr == pos) { - pop(); - } else { - fatal(); - stack[pos].release(); - System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos); - assert debugOnlyClearLastStackSlot(); - currentPtr--; - } - } - - private void removeFromStack(StackNode<T> node) throws SAXException { - if (stack[currentPtr] == node) { - pop(); - } else { - int pos = currentPtr - 1; - while (pos >= 0 && stack[pos] != node) { - pos--; - } - if (pos == -1) { - // dead code? - return; - } - fatal(); - node.release(); - System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos); - currentPtr--; - } - } - - private void removeFromListOfActiveFormattingElements(int pos) { - assert listOfActiveFormattingElements[pos] != null; - listOfActiveFormattingElements[pos].release(); - if (pos == listPtr) { - assert debugOnlyClearLastListSlot(); - listPtr--; - return; - } - assert pos < listPtr; - System.arraycopy(listOfActiveFormattingElements, pos + 1, - listOfActiveFormattingElements, pos, listPtr - pos); - assert debugOnlyClearLastListSlot(); - listPtr--; - } - - /** - * Adoption agency algorithm. - * - * @param name subject as described in the specified algorithm. - * @return Returns true if the algorithm has completed and there is nothing remaining to - * be done. Returns false if the algorithm needs to "act as described in the 'any other - * end tag' entry" as described in the specified algorithm. - * @throws SAXException - */ - private boolean adoptionAgencyEndTag(@Local String name) throws SAXException { - // This check intends to ensure that for properly nested tags, closing tags will match - // against the stack instead of the listOfActiveFormattingElements. - if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" && - stack[currentPtr].name == name && - findInListOfActiveFormattingElements(stack[currentPtr]) == -1) { - // If the current element matches the name but isn't on the list of active - // formatting elements, then it is possible that the list was mangled by the Noah's Ark - // clause. In this case, we want to match the end tag against the stack instead of - // proceeding with the AAA algorithm that may match against the list of - // active formatting elements (and possibly mangle the tree in unexpected ways). - pop(); - return true; - } - - // If you crash around here, perhaps some stack node variable claimed to - // be a weak ref isn't. - for (int i = 0; i < 8; ++i) { - int formattingEltListPos = listPtr; - while (formattingEltListPos > -1) { - StackNode<T> listNode = listOfActiveFormattingElements[formattingEltListPos]; // weak ref - if (listNode == null) { - formattingEltListPos = -1; - break; - } else if (listNode.name == name) { - break; - } - formattingEltListPos--; - } - if (formattingEltListPos == -1) { - return false; - } - // this *looks* like a weak ref to the list of formatting elements - StackNode<T> formattingElt = listOfActiveFormattingElements[formattingEltListPos]; - int formattingEltStackPos = currentPtr; - boolean inScope = true; - while (formattingEltStackPos > -1) { - StackNode<T> node = stack[formattingEltStackPos]; // weak ref - if (node == formattingElt) { - break; - } else if (node.isScoping()) { - inScope = false; - } - formattingEltStackPos--; - } - if (formattingEltStackPos == -1) { - errNoElementToCloseButEndTagSeen(name); - removeFromListOfActiveFormattingElements(formattingEltListPos); - return true; - } - if (!inScope) { - errNoElementToCloseButEndTagSeen(name); - return true; - } - // stackPos now points to the formatting element and it is in scope - if (formattingEltStackPos != currentPtr) { - errEndTagViolatesNestingRules(name); - } - int furthestBlockPos = formattingEltStackPos + 1; - while (furthestBlockPos <= currentPtr) { - StackNode<T> node = stack[furthestBlockPos]; // weak ref - assert furthestBlockPos > 0: "How is formattingEltStackPos + 1 not > 0?"; - if (node.isSpecial()) { - break; - } - furthestBlockPos++; - } - if (furthestBlockPos > currentPtr) { - // no furthest block - while (currentPtr >= formattingEltStackPos) { - pop(); - } - removeFromListOfActiveFormattingElements(formattingEltListPos); - return true; - } - StackNode<T> commonAncestor = stack[formattingEltStackPos - 1]; // weak ref - StackNode<T> furthestBlock = stack[furthestBlockPos]; // weak ref - // detachFromParent(furthestBlock.node); XXX AAA CHANGE - int bookmark = formattingEltListPos; - int nodePos = furthestBlockPos; - StackNode<T> lastNode = furthestBlock; // weak ref - int j = 0; - for (;;) { - ++j; - nodePos--; - if (nodePos == formattingEltStackPos) { - break; - } - StackNode<T> node = stack[nodePos]; // weak ref - int nodeListPos = findInListOfActiveFormattingElements(node); - - if (j > 3 && nodeListPos != -1) { - removeFromListOfActiveFormattingElements(nodeListPos); - - // Adjust the indices into the list to account - // for the removal of nodeListPos. - if (nodeListPos <= formattingEltListPos) { - formattingEltListPos--; - } - if (nodeListPos <= bookmark) { - bookmark--; - } - - // Update position to reflect removal from list. - nodeListPos = -1; - } - - if (nodeListPos == -1) { - assert formattingEltStackPos < nodePos; - assert bookmark < nodePos; - assert furthestBlockPos > nodePos; - removeFromStack(nodePos); // node is now a bad pointer in C++ - furthestBlockPos--; - continue; - } - // now node is both on stack and in the list - if (nodePos == furthestBlockPos) { - bookmark = nodeListPos + 1; - } - // if (hasChildren(node.node)) { XXX AAA CHANGE - assert node == listOfActiveFormattingElements[nodeListPos]; - assert node == stack[nodePos]; - T clone = createElement("http://www.w3.org/1999/xhtml", - node.name, node.attributes.cloneAttributes(null), commonAncestor.node); - StackNode<T> newNode = new StackNode<T>(node.getFlags(), node.ns, - node.name, clone, node.popName, node.attributes - // [NOCPP[ - , node.getLocator() - // ]NOCPP] - ); // creation ownership goes to stack - node.dropAttributes(); // adopt ownership to newNode - stack[nodePos] = newNode; - newNode.retain(); // retain for list - listOfActiveFormattingElements[nodeListPos] = newNode; - node.release(); // release from stack - node.release(); // release from list - node = newNode; - // } XXX AAA CHANGE - detachFromParent(lastNode.node); - appendElement(lastNode.node, node.node); - lastNode = node; - } - if (commonAncestor.isFosterParenting()) { - fatal(); - detachFromParent(lastNode.node); - insertIntoFosterParent(lastNode.node); - } else { - detachFromParent(lastNode.node); - appendElement(lastNode.node, commonAncestor.node); - } - T clone = createElement("http://www.w3.org/1999/xhtml", - formattingElt.name, - formattingElt.attributes.cloneAttributes(null), furthestBlock.node); - StackNode<T> formattingClone = new StackNode<T>( - formattingElt.getFlags(), formattingElt.ns, - formattingElt.name, clone, formattingElt.popName, - formattingElt.attributes - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); // Ownership transfers to stack below - formattingElt.dropAttributes(); // transfer ownership to - // formattingClone - appendChildrenToNewParent(furthestBlock.node, clone); - appendElement(clone, furthestBlock.node); - removeFromListOfActiveFormattingElements(formattingEltListPos); - insertIntoListOfActiveFormattingElements(formattingClone, bookmark); - assert formattingEltStackPos < furthestBlockPos; - removeFromStack(formattingEltStackPos); - // furthestBlockPos is now off by one and points to the slot after - // it - insertIntoStack(formattingClone, furthestBlockPos); - } - return true; - } - - private void insertIntoStack(StackNode<T> node, int position) - throws SAXException { - assert currentPtr + 1 < stack.length; - assert position <= currentPtr + 1; - if (position == currentPtr + 1) { - push(node); - } else { - System.arraycopy(stack, position, stack, position + 1, - (currentPtr - position) + 1); - currentPtr++; - stack[position] = node; - } - } - - private void insertIntoListOfActiveFormattingElements( - StackNode<T> formattingClone, int bookmark) { - formattingClone.retain(); - assert listPtr + 1 < listOfActiveFormattingElements.length; - if (bookmark <= listPtr) { - System.arraycopy(listOfActiveFormattingElements, bookmark, - listOfActiveFormattingElements, bookmark + 1, - (listPtr - bookmark) + 1); - } - listPtr++; - listOfActiveFormattingElements[bookmark] = formattingClone; - } - - private int findInListOfActiveFormattingElements(StackNode<T> node) { - for (int i = listPtr; i >= 0; i--) { - if (node == listOfActiveFormattingElements[i]) { - return i; - } - } - return -1; - } - - private int findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker( - @Local String name) { - for (int i = listPtr; i >= 0; i--) { - StackNode<T> node = listOfActiveFormattingElements[i]; - if (node == null) { - return -1; - } else if (node.name == name) { - return i; - } - } - return -1; - } - - - private void maybeForgetEarlierDuplicateFormattingElement( - @Local String name, HtmlAttributes attributes) throws SAXException { - int candidate = -1; - int count = 0; - for (int i = listPtr; i >= 0; i--) { - StackNode<T> node = listOfActiveFormattingElements[i]; - if (node == null) { - break; - } - if (node.name == name && node.attributes.equalsAnother(attributes)) { - candidate = i; - ++count; - } - } - if (count >= 3) { - removeFromListOfActiveFormattingElements(candidate); - } - } - - private int findLastOrRoot(@Local String name) { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) { - return i; - } - } - return 0; - } - - private int findLastOrRoot(int group) { - for (int i = currentPtr; i > 0; i--) { - if (stack[i].getGroup() == group) { - return i; - } - } - return 0; - } - - /** - * Attempt to add attribute to the body element. - * @param attributes the attributes - * @return <code>true</code> iff the attributes were added - * @throws SAXException - */ - private boolean addAttributesToBody(HtmlAttributes attributes) - throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - if (currentPtr >= 1) { - StackNode<T> body = stack[1]; - if (body.getGroup() == TreeBuilder.BODY) { - addAttributesToElement(body.node, attributes); - return true; - } - } - return false; - } - - private void addAttributesToHtml(HtmlAttributes attributes) - throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - addAttributesToElement(stack[0].node, attributes); - } - - private void pushHeadPointerOntoStack() throws SAXException { - assert headPointer != null; - assert mode == AFTER_HEAD; - fatal(); - silentPush(new StackNode<T>(ElementName.HEAD, headPointer - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - )); - } - - /** - * @throws SAXException - * - */ - private void reconstructTheActiveFormattingElements() throws SAXException { - if (listPtr == -1) { - return; - } - StackNode<T> mostRecent = listOfActiveFormattingElements[listPtr]; - if (mostRecent == null || isInStack(mostRecent)) { - return; - } - int entryPos = listPtr; - for (;;) { - entryPos--; - if (entryPos == -1) { - break; - } - if (listOfActiveFormattingElements[entryPos] == null) { - break; - } - if (isInStack(listOfActiveFormattingElements[entryPos])) { - break; - } - } - while (entryPos < listPtr) { - entryPos++; - StackNode<T> entry = listOfActiveFormattingElements[entryPos]; - StackNode<T> currentNode = stack[currentPtr]; - - T clone; - if (currentNode.isFosterParenting()) { - clone = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", entry.name, - entry.attributes.cloneAttributes(null)); - } else { - clone = createElement("http://www.w3.org/1999/xhtml", entry.name, - entry.attributes.cloneAttributes(null), currentNode.node); - appendElement(clone, currentNode.node); - } - - StackNode<T> entryClone = new StackNode<T>(entry.getFlags(), - entry.ns, entry.name, clone, entry.popName, - entry.attributes - // [NOCPP[ - , entry.getLocator() - // ]NOCPP] - ); - - entry.dropAttributes(); // transfer ownership to entryClone - - push(entryClone); - // stack takes ownership of the local variable - listOfActiveFormattingElements[entryPos] = entryClone; - // overwriting the old entry on the list, so release & retain - entry.release(); - entryClone.retain(); - } - } - - private void insertIntoFosterParent(T child) throws SAXException { - int tablePos = findLastOrRoot(TreeBuilder.TABLE); - int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE); - - if (templatePos >= tablePos) { - appendElement(child, stack[templatePos].node); - return; - } - - StackNode<T> node = stack[tablePos]; - insertFosterParentedChild(child, node.node, stack[tablePos - 1].node); - } - - private T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, - HtmlAttributes attributes) throws SAXException { - return createAndInsertFosterParentedElement(ns, name, attributes, null); - } - - private T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, - HtmlAttributes attributes, T form) throws SAXException { - int tablePos = findLastOrRoot(TreeBuilder.TABLE); - int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE); - - if (templatePos >= tablePos) { - T child = createElement(ns, name, attributes, form, stack[templatePos].node); - appendElement(child, stack[templatePos].node); - return child; - } - - StackNode<T> node = stack[tablePos]; - return createAndInsertFosterParentedElement(ns, name, attributes, form, node.node, stack[tablePos - 1].node); - } - - private boolean isInStack(StackNode<T> node) { - for (int i = currentPtr; i >= 0; i--) { - if (stack[i] == node) { - return true; - } - } - return false; - } - - private void popTemplateMode() { - templateModePtr--; - } - - private void pop() throws SAXException { - StackNode<T> node = stack[currentPtr]; - assert debugOnlyClearLastStackSlot(); - currentPtr--; - elementPopped(node.ns, node.popName, node.node); - node.release(); - } - - private void silentPop() throws SAXException { - StackNode<T> node = stack[currentPtr]; - assert debugOnlyClearLastStackSlot(); - currentPtr--; - node.release(); - } - - private void popOnEof() throws SAXException { - StackNode<T> node = stack[currentPtr]; - assert debugOnlyClearLastStackSlot(); - currentPtr--; - markMalformedIfScript(node.node); - elementPopped(node.ns, node.popName, node.node); - node.release(); - } - - // [NOCPP[ - private void checkAttributes(HtmlAttributes attributes, @NsUri String ns) - throws SAXException { - if (errorHandler != null) { - int len = attributes.getXmlnsLength(); - for (int i = 0; i < len; i++) { - AttributeName name = attributes.getXmlnsAttributeName(i); - if (name == AttributeName.XMLNS) { - if (html4) { - err("Attribute \u201Cxmlns\u201D not allowed here. (HTML4-only error.)"); - } else { - String xmlns = attributes.getXmlnsValue(i); - if (!ns.equals(xmlns)) { - err("Bad value \u201C" - + xmlns - + "\u201D for the attribute \u201Cxmlns\u201D (only \u201C" - + ns + "\u201D permitted here)."); - switch (namePolicy) { - case ALTER_INFOSET: - // fall through - case ALLOW: - warn("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0."); - break; - case FATAL: - fatal("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0."); - break; - } - } - } - } else if (ns != "http://www.w3.org/1999/xhtml" - && name == AttributeName.XMLNS_XLINK) { - String xmlns = attributes.getXmlnsValue(i); - if (!"http://www.w3.org/1999/xlink".equals(xmlns)) { - err("Bad value \u201C" - + xmlns - + "\u201D for the attribute \u201Cxmlns:link\u201D (only \u201Chttp://www.w3.org/1999/xlink\u201D permitted here)."); - switch (namePolicy) { - case ALTER_INFOSET: - // fall through - case ALLOW: - warn("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics."); - break; - case FATAL: - fatal("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics."); - break; - } - } - } else { - err("Attribute \u201C" + attributes.getXmlnsLocalName(i) - + "\u201D not allowed here."); - switch (namePolicy) { - case ALTER_INFOSET: - // fall through - case ALLOW: - warn("Attribute with the local name \u201C" - + attributes.getXmlnsLocalName(i) - + "\u201D is not serializable as XML 1.0."); - break; - case FATAL: - fatal("Attribute with the local name \u201C" - + attributes.getXmlnsLocalName(i) - + "\u201D is not serializable as XML 1.0."); - break; - } - } - } - } - attributes.processNonNcNames(this, namePolicy); - } - - private String checkPopName(@Local String name) throws SAXException { - if (NCName.isNCName(name)) { - return name; - } else { - switch (namePolicy) { - case ALLOW: - warn("Element name \u201C" + name - + "\u201D cannot be represented as XML 1.0."); - return name; - case ALTER_INFOSET: - warn("Element name \u201C" + name - + "\u201D cannot be represented as XML 1.0."); - return NCName.escapeName(name); - case FATAL: - fatal("Element name \u201C" + name - + "\u201D cannot be represented as XML 1.0."); - } - } - return null; // keep compiler happy - } - - // ]NOCPP] - - private void appendHtmlElementToDocumentAndPush(HtmlAttributes attributes) - throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - T elt = createHtmlElementSetAsRoot(attributes); - StackNode<T> node = new StackNode<T>(ElementName.HTML, - elt - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - private void appendHtmlElementToDocumentAndPush() throws SAXException { - appendHtmlElementToDocumentAndPush(tokenizer.emptyAttributes()); - } - - private void appendToCurrentNodeAndPushHeadElement(HtmlAttributes attributes) - throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - T currentNode = stack[currentPtr].node; - T elt = createElement("http://www.w3.org/1999/xhtml", "head", attributes, currentNode); - appendElement(elt, currentNode); - headPointer = elt; - StackNode<T> node = new StackNode<T>(ElementName.HEAD, - elt - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - private void appendToCurrentNodeAndPushBodyElement(HtmlAttributes attributes) - throws SAXException { - appendToCurrentNodeAndPushElement(ElementName.BODY, - attributes); - } - - private void appendToCurrentNodeAndPushBodyElement() throws SAXException { - appendToCurrentNodeAndPushBodyElement(tokenizer.emptyAttributes()); - } - - private void appendToCurrentNodeAndPushFormElementMayFoster( - HtmlAttributes attributes) throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", "form", attributes); - } else { - elt = createElement("http://www.w3.org/1999/xhtml", "form", attributes, current.node); - appendElement(elt, current.node); - } - - if (!isTemplateContents()) { - formPointer = elt; - } - - StackNode<T> node = new StackNode<T>(ElementName.FORM, - elt - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - private void appendToCurrentNodeAndPushFormattingElementMayFoster( - ElementName elementName, HtmlAttributes attributes) - throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - // This method can't be called for custom elements - HtmlAttributes clone = attributes.cloneAttributes(null); - // Attributes must not be read after calling createElement, because - // createElement may delete attributes in C++. - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.name, attributes); - } else { - elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, attributes, current.node); - appendElement(elt, current.node); - } - StackNode<T> node = new StackNode<T>(elementName, elt, clone - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - append(node); - node.retain(); // append doesn't retain itself - } - - private void appendToCurrentNodeAndPushElement(ElementName elementName, - HtmlAttributes attributes) - throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - // This method can't be called for custom elements - T currentNode = stack[currentPtr].node; - T elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, attributes, currentNode); - appendElement(elt, currentNode); - if (ElementName.TEMPLATE == elementName) { - elt = getDocumentFragmentForTemplate(elt); - } - StackNode<T> node = new StackNode<T>(elementName, elt - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName, - HtmlAttributes attributes) - throws SAXException { - @Local String popName = elementName.name; - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - if (elementName.isCustom()) { - popName = checkPopName(popName); - } - // ]NOCPP] - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes); - } else { - elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, current.node); - appendElement(elt, current.node); - } - StackNode<T> node = new StackNode<T>(elementName, elt, popName - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - private void appendToCurrentNodeAndPushElementMayFosterMathML( - ElementName elementName, HtmlAttributes attributes) - throws SAXException { - @Local String popName = elementName.name; - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML"); - if (elementName.isCustom()) { - popName = checkPopName(popName); - } - // ]NOCPP] - boolean markAsHtmlIntegrationPoint = false; - if (ElementName.ANNOTATION_XML == elementName - && annotationXmlEncodingPermitsHtml(attributes)) { - markAsHtmlIntegrationPoint = true; - } - // Attributes must not be read after calling createElement(), since - // createElement may delete the object in C++. - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName, attributes); - } else { - elt = createElement("http://www.w3.org/1998/Math/MathML", popName, attributes, current.node); - appendElement(elt, current.node); - } - StackNode<T> node = new StackNode<T>(elementName, elt, popName, - markAsHtmlIntegrationPoint - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - // [NOCPP[ - T getDocumentFragmentForTemplate(T template) { - return template; - } - - T getFormPointerForContext(T context) { - return null; - } - // ]NOCPP] - - private boolean annotationXmlEncodingPermitsHtml(HtmlAttributes attributes) { - String encoding = attributes.getValue(AttributeName.ENCODING); - if (encoding == null) { - return false; - } - return Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "application/xhtml+xml", encoding) - || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( - "text/html", encoding); - } - - private void appendToCurrentNodeAndPushElementMayFosterSVG( - ElementName elementName, HtmlAttributes attributes) - throws SAXException { - @Local String popName = elementName.camelCaseName; - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/2000/svg"); - if (elementName.isCustom()) { - popName = checkPopName(popName); - } - // ]NOCPP] - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes); - } else { - elt = createElement("http://www.w3.org/2000/svg", popName, attributes, current.node); - appendElement(elt, current.node); - } - StackNode<T> node = new StackNode<T>(elementName, popName, elt - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName, - HtmlAttributes attributes, T form) - throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - // Can't be called for custom elements - T elt; - T formOwner = form == null || fragment || isTemplateContents() ? null : form; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.name, - attributes, formOwner); - } else { - elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, - attributes, formOwner, current.node); - appendElement(elt, current.node); - } - StackNode<T> node = new StackNode<T>(elementName, elt - // [NOCPP[ - , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) - // ]NOCPP] - ); - push(node); - } - - private void appendVoidElementToCurrentMayFoster( - @Local String name, HtmlAttributes attributes, T form) throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - // Can't be called for custom elements - T elt; - T formOwner = form == null || fragment || isTemplateContents() ? null : form; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", name, - attributes, formOwner); - } else { - elt = createElement("http://www.w3.org/1999/xhtml", name, - attributes, formOwner, current.node); - appendElement(elt, current.node); - } - elementPushed("http://www.w3.org/1999/xhtml", name, elt); - elementPopped("http://www.w3.org/1999/xhtml", name, elt); - } - - private void appendVoidElementToCurrentMayFoster( - ElementName elementName, HtmlAttributes attributes) - throws SAXException { - @Local String popName = elementName.name; - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - if (elementName.isCustom()) { - popName = checkPopName(popName); - } - // ]NOCPP] - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes); - } else { - elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, current.node); - appendElement(elt, current.node); - } - elementPushed("http://www.w3.org/1999/xhtml", popName, elt); - elementPopped("http://www.w3.org/1999/xhtml", popName, elt); - } - - private void appendVoidElementToCurrentMayFosterSVG( - ElementName elementName, HtmlAttributes attributes) - throws SAXException { - @Local String popName = elementName.camelCaseName; - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/2000/svg"); - if (elementName.isCustom()) { - popName = checkPopName(popName); - } - // ]NOCPP] - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes); - } else { - elt = createElement("http://www.w3.org/2000/svg", popName, attributes, current.node); - appendElement(elt, current.node); - } - elementPushed("http://www.w3.org/2000/svg", popName, elt); - elementPopped("http://www.w3.org/2000/svg", popName, elt); - } - - private void appendVoidElementToCurrentMayFosterMathML( - ElementName elementName, HtmlAttributes attributes) - throws SAXException { - @Local String popName = elementName.name; - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML"); - if (elementName.isCustom()) { - popName = checkPopName(popName); - } - // ]NOCPP] - T elt; - StackNode<T> current = stack[currentPtr]; - if (current.isFosterParenting()) { - fatal(); - elt = createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName, attributes); - } else { - elt = createElement("http://www.w3.org/1998/Math/MathML", popName, attributes, current.node); - appendElement(elt, current.node); - } - elementPushed("http://www.w3.org/1998/Math/MathML", popName, elt); - elementPopped("http://www.w3.org/1998/Math/MathML", popName, elt); - } - - private void appendVoidElementToCurrent( - @Local String name, HtmlAttributes attributes, T form) throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - // Can't be called for custom elements - T currentNode = stack[currentPtr].node; - T elt = createElement("http://www.w3.org/1999/xhtml", name, attributes, - form == null || fragment || isTemplateContents() ? null : form, currentNode); - appendElement(elt, currentNode); - elementPushed("http://www.w3.org/1999/xhtml", name, elt); - elementPopped("http://www.w3.org/1999/xhtml", name, elt); - } - - private void appendVoidFormToCurrent(HtmlAttributes attributes) throws SAXException { - // [NOCPP[ - checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); - // ]NOCPP] - T currentNode = stack[currentPtr].node; - T elt = createElement("http://www.w3.org/1999/xhtml", "form", - attributes, currentNode); - formPointer = elt; - // ownership transferred to form pointer - appendElement(elt, currentNode); - elementPushed("http://www.w3.org/1999/xhtml", "form", elt); - elementPopped("http://www.w3.org/1999/xhtml", "form", elt); - } - - // [NOCPP[ - - private final void accumulateCharactersForced(@Const @NoLength char[] buf, - int start, int length) throws SAXException { - System.arraycopy(buf, start, charBuffer, charBufferLen, length); - charBufferLen += length; - } - - @Override public void ensureBufferSpace(int inputLength) - throws SAXException { - // TODO: Unify Tokenizer.strBuf and TreeBuilder.charBuffer so that - // this method becomes unnecessary. - int worstCase = charBufferLen + inputLength; - if (charBuffer == null) { - // Add an arbitrary small value to avoid immediate reallocation - // once there are a few characters in the buffer. - charBuffer = new char[worstCase + 128]; - } else if (worstCase > charBuffer.length) { - // HotSpot reportedly allocates memory with 8-byte accuracy, so - // there's no point in trying to do math here to avoid slop. - // Maybe we should add some small constant to worstCase here - // but not doing that without profiling. In C++ with jemalloc, - // the corresponding method should do math to round up here - // to avoid slop. - char[] newBuf = new char[worstCase]; - System.arraycopy(charBuffer, 0, newBuf, 0, charBufferLen); - charBuffer = newBuf; - } - } - - // ]NOCPP] - - protected void accumulateCharacters(@Const @NoLength char[] buf, int start, - int length) throws SAXException { - appendCharacters(stack[currentPtr].node, buf, start, length); - } - - // ------------------------------- // - - protected final void requestSuspension() { - tokenizer.requestSuspension(); - } - - protected abstract T createElement(@NsUri String ns, @Local String name, - HtmlAttributes attributes, T intendedParent) throws SAXException; - - protected T createElement(@NsUri String ns, @Local String name, - HtmlAttributes attributes, T form, T intendedParent) throws SAXException { - return createElement("http://www.w3.org/1999/xhtml", name, attributes, intendedParent); - } - - protected abstract T createHtmlElementSetAsRoot(HtmlAttributes attributes) - throws SAXException; - - protected abstract void detachFromParent(T element) throws SAXException; - - protected abstract boolean hasChildren(T element) throws SAXException; - - protected abstract void appendElement(T child, T newParent) - throws SAXException; - - protected abstract void appendChildrenToNewParent(T oldParent, T newParent) - throws SAXException; - - protected abstract void insertFosterParentedChild(T child, T table, - T stackParent) throws SAXException; - - // We don't generate CPP code for this method because it is not used in generated CPP - // code. Instead, the form owner version of this method is called with a null form owner. - // [NOCPP[ - - protected abstract T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, - HtmlAttributes attributes, T table, T stackParent) throws SAXException; - - // ]NOCPP] - - protected T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, - HtmlAttributes attributes, T form, T table, T stackParent) throws SAXException { - return createAndInsertFosterParentedElement(ns, name, attributes, table, stackParent); - }; - - protected abstract void insertFosterParentedCharacters( - @NoLength char[] buf, int start, int length, T table, T stackParent) - throws SAXException; - - protected abstract void appendCharacters(T parent, @NoLength char[] buf, - int start, int length) throws SAXException; - - protected abstract void appendIsindexPrompt(T parent) throws SAXException; - - protected abstract void appendComment(T parent, @NoLength char[] buf, - int start, int length) throws SAXException; - - protected abstract void appendCommentToDocument(@NoLength char[] buf, - int start, int length) throws SAXException; - - protected abstract void addAttributesToElement(T element, - HtmlAttributes attributes) throws SAXException; - - protected void markMalformedIfScript(T elt) throws SAXException { - - } - - protected void start(boolean fragmentMode) throws SAXException { - - } - - protected void end() throws SAXException { - - } - - protected void appendDoctypeToDocument(@Local String name, - String publicIdentifier, String systemIdentifier) - throws SAXException { - - } - - protected void elementPushed(@NsUri String ns, @Local String name, T node) - throws SAXException { - - } - - protected void elementPopped(@NsUri String ns, @Local String name, T node) - throws SAXException { - - } - - // [NOCPP[ - - protected void documentMode(DocumentMode m, String publicIdentifier, - String systemIdentifier, boolean html4SpecificAdditionalErrorChecks) - throws SAXException { - - } - - /** - * @see nu.validator.htmlparser.common.TokenHandler#wantsComments() - */ - public boolean wantsComments() { - return wantingComments; - } - - public void setIgnoringComments(boolean ignoreComments) { - wantingComments = !ignoreComments; - } - - /** - * Sets the errorHandler. - * - * @param errorHandler - * the errorHandler to set - */ - public final void setErrorHandler(ErrorHandler errorHandler) { - this.errorHandler = errorHandler; - } - - /** - * Returns the errorHandler. - * - * @return the errorHandler - */ - public ErrorHandler getErrorHandler() { - return errorHandler; - } - - /** - * The argument MUST be an interned string or <code>null</code>. - * - * @param context - */ - public final void setFragmentContext(@Local String context) { - this.contextName = context; - this.contextNamespace = "http://www.w3.org/1999/xhtml"; - this.contextNode = null; - this.fragment = (contextName != null); - this.quirks = false; - } - - // ]NOCPP] - - /** - * @see nu.validator.htmlparser.common.TokenHandler#cdataSectionAllowed() - */ - @Inline public boolean cdataSectionAllowed() throws SAXException { - return isInForeign(); - } - - private boolean isInForeign() { - return currentPtr >= 0 - && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml"; - } - - private boolean isInForeignButNotHtmlOrMathTextIntegrationPoint() { - if (currentPtr < 0) { - return false; - } - return !isSpecialParentInForeign(stack[currentPtr]); - } - - /** - * The argument MUST be an interned string or <code>null</code>. - * - * @param context - */ - public final void setFragmentContext(@Local String context, - @NsUri String ns, T node, boolean quirks) { - // [NOCPP[ - if (!((context == null && ns == null) - || "http://www.w3.org/1999/xhtml" == ns - || "http://www.w3.org/2000/svg" == ns || "http://www.w3.org/1998/Math/MathML" == ns)) { - throw new IllegalArgumentException( - "The namespace must be the HTML, SVG or MathML namespace (or null when the local name is null). Got: " - + ns); - } - // ]NOCPP] - this.contextName = context; - this.contextNamespace = ns; - this.contextNode = node; - this.fragment = (contextName != null); - this.quirks = quirks; - } - - protected final T currentNode() { - return stack[currentPtr].node; - } - - /** - * Returns the scriptingEnabled. - * - * @return the scriptingEnabled - */ - public boolean isScriptingEnabled() { - return scriptingEnabled; - } - - /** - * Sets the scriptingEnabled. - * - * @param scriptingEnabled - * the scriptingEnabled to set - */ - public void setScriptingEnabled(boolean scriptingEnabled) { - this.scriptingEnabled = scriptingEnabled; - } - - public void setIsSrcdocDocument(boolean isSrcdocDocument) { - this.isSrcdocDocument = isSrcdocDocument; - } - - // [NOCPP[ - - /** - * Sets the doctypeExpectation. - * - * @param doctypeExpectation - * the doctypeExpectation to set - */ - public void setDoctypeExpectation(DoctypeExpectation doctypeExpectation) { - this.doctypeExpectation = doctypeExpectation; - } - - public void setNamePolicy(XmlViolationPolicy namePolicy) { - this.namePolicy = namePolicy; - } - - /** - * Sets the documentModeHandler. - * - * @param documentModeHandler - * the documentModeHandler to set - */ - public void setDocumentModeHandler(DocumentModeHandler documentModeHandler) { - this.documentModeHandler = documentModeHandler; - } - - /** - * Sets the reportingDoctype. - * - * @param reportingDoctype - * the reportingDoctype to set - */ - public void setReportingDoctype(boolean reportingDoctype) { - this.reportingDoctype = reportingDoctype; - } - - // ]NOCPP] - - /** - * Flushes the pending characters. Public for document.write use cases only. - * @throws SAXException - */ - public final void flushCharacters() throws SAXException { - if (charBufferLen > 0) { - if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) - && charBufferContainsNonWhitespace()) { - errNonSpaceInTable(); - reconstructTheActiveFormattingElements(); - if (!stack[currentPtr].isFosterParenting()) { - // reconstructing gave us a new current node - appendCharacters(currentNode(), charBuffer, 0, - charBufferLen); - charBufferLen = 0; - return; - } - - int tablePos = findLastOrRoot(TreeBuilder.TABLE); - int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE); - - if (templatePos >= tablePos) { - appendCharacters(stack[templatePos].node, charBuffer, 0, charBufferLen); - charBufferLen = 0; - return; - } - - StackNode<T> tableElt = stack[tablePos]; - insertFosterParentedCharacters(charBuffer, 0, charBufferLen, - tableElt.node, stack[tablePos - 1].node); - charBufferLen = 0; - return; - } - appendCharacters(currentNode(), charBuffer, 0, charBufferLen); - charBufferLen = 0; - } - } - - private boolean charBufferContainsNonWhitespace() { - for (int i = 0; i < charBufferLen; i++) { - switch (charBuffer[i]) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\u000C': - continue; - default: - return true; - } - } - return false; - } - - /** - * Creates a comparable snapshot of the tree builder state. Snapshot - * creation is only supported immediately after a script end tag has been - * processed. In C++ the caller is responsible for calling - * <code>delete</code> on the returned object. - * - * @return a snapshot. - * @throws SAXException - */ - @SuppressWarnings("unchecked") public TreeBuilderState<T> newSnapshot() - throws SAXException { - StackNode<T>[] listCopy = new StackNode[listPtr + 1]; - for (int i = 0; i < listCopy.length; i++) { - StackNode<T> node = listOfActiveFormattingElements[i]; - if (node != null) { - StackNode<T> newNode = new StackNode<T>(node.getFlags(), node.ns, - node.name, node.node, node.popName, - node.attributes.cloneAttributes(null) - // [NOCPP[ - , node.getLocator() - // ]NOCPP] - ); - listCopy[i] = newNode; - } else { - listCopy[i] = null; - } - } - StackNode<T>[] stackCopy = new StackNode[currentPtr + 1]; - for (int i = 0; i < stackCopy.length; i++) { - StackNode<T> node = stack[i]; - int listIndex = findInListOfActiveFormattingElements(node); - if (listIndex == -1) { - StackNode<T> newNode = new StackNode<T>(node.getFlags(), node.ns, - node.name, node.node, node.popName, - null - // [NOCPP[ - , node.getLocator() - // ]NOCPP] - ); - stackCopy[i] = newNode; - } else { - stackCopy[i] = listCopy[listIndex]; - stackCopy[i].retain(); - } - } - int[] templateModeStackCopy = new int[templateModePtr + 1]; - System.arraycopy(templateModeStack, 0, templateModeStackCopy, 0, - templateModeStackCopy.length); - return new StateSnapshot<T>(stackCopy, listCopy, templateModeStackCopy, formPointer, - headPointer, deepTreeSurrogateParent, mode, originalMode, framesetOk, - needToDropLF, quirks); - } - - public boolean snapshotMatches(TreeBuilderState<T> snapshot) { - StackNode<T>[] stackCopy = snapshot.getStack(); - int stackLen = snapshot.getStackLength(); - StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements(); - int listLen = snapshot.getListOfActiveFormattingElementsLength(); - int[] templateModeStackCopy = snapshot.getTemplateModeStack(); - int templateModeStackLen = snapshot.getTemplateModeStackLength(); - - if (stackLen != currentPtr + 1 - || listLen != listPtr + 1 - || templateModeStackLen != templateModePtr + 1 - || formPointer != snapshot.getFormPointer() - || headPointer != snapshot.getHeadPointer() - || deepTreeSurrogateParent != snapshot.getDeepTreeSurrogateParent() - || mode != snapshot.getMode() - || originalMode != snapshot.getOriginalMode() - || framesetOk != snapshot.isFramesetOk() - || needToDropLF != snapshot.isNeedToDropLF() - || quirks != snapshot.isQuirks()) { // maybe just assert quirks - return false; - } - for (int i = listLen - 1; i >= 0; i--) { - if (listCopy[i] == null - && listOfActiveFormattingElements[i] == null) { - continue; - } else if (listCopy[i] == null - || listOfActiveFormattingElements[i] == null) { - return false; - } - if (listCopy[i].node != listOfActiveFormattingElements[i].node) { - return false; // it's possible that this condition is overly - // strict - } - } - for (int i = stackLen - 1; i >= 0; i--) { - if (stackCopy[i].node != stack[i].node) { - return false; - } - } - for (int i = templateModeStackLen - 1; i >=0; i--) { - if (templateModeStackCopy[i] != templateModeStack[i]) { - return false; - } - } - return true; - } - - @SuppressWarnings("unchecked") public void loadState( - TreeBuilderState<T> snapshot, Interner interner) - throws SAXException { - StackNode<T>[] stackCopy = snapshot.getStack(); - int stackLen = snapshot.getStackLength(); - StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements(); - int listLen = snapshot.getListOfActiveFormattingElementsLength(); - int[] templateModeStackCopy = snapshot.getTemplateModeStack(); - int templateModeStackLen = snapshot.getTemplateModeStackLength(); - - for (int i = 0; i <= listPtr; i++) { - if (listOfActiveFormattingElements[i] != null) { - listOfActiveFormattingElements[i].release(); - } - } - if (listOfActiveFormattingElements.length < listLen) { - listOfActiveFormattingElements = new StackNode[listLen]; - } - listPtr = listLen - 1; - - for (int i = 0; i <= currentPtr; i++) { - stack[i].release(); - } - if (stack.length < stackLen) { - stack = new StackNode[stackLen]; - } - currentPtr = stackLen - 1; - - if (templateModeStack.length < templateModeStackLen) { - templateModeStack = new int[templateModeStackLen]; - } - templateModePtr = templateModeStackLen - 1; - - for (int i = 0; i < listLen; i++) { - StackNode<T> node = listCopy[i]; - if (node != null) { - StackNode<T> newNode = new StackNode<T>(node.getFlags(), node.ns, - Portability.newLocalFromLocal(node.name, interner), node.node, - Portability.newLocalFromLocal(node.popName, interner), - node.attributes.cloneAttributes(null) - // [NOCPP[ - , node.getLocator() - // ]NOCPP] - ); - listOfActiveFormattingElements[i] = newNode; - } else { - listOfActiveFormattingElements[i] = null; - } - } - for (int i = 0; i < stackLen; i++) { - StackNode<T> node = stackCopy[i]; - int listIndex = findInArray(node, listCopy); - if (listIndex == -1) { - StackNode<T> newNode = new StackNode<T>(node.getFlags(), node.ns, - Portability.newLocalFromLocal(node.name, interner), node.node, - Portability.newLocalFromLocal(node.popName, interner), - null - // [NOCPP[ - , node.getLocator() - // ]NOCPP] - ); - stack[i] = newNode; - } else { - stack[i] = listOfActiveFormattingElements[listIndex]; - stack[i].retain(); - } - } - System.arraycopy(templateModeStackCopy, 0, templateModeStack, 0, templateModeStackLen); - formPointer = snapshot.getFormPointer(); - headPointer = snapshot.getHeadPointer(); - deepTreeSurrogateParent = snapshot.getDeepTreeSurrogateParent(); - mode = snapshot.getMode(); - originalMode = snapshot.getOriginalMode(); - framesetOk = snapshot.isFramesetOk(); - needToDropLF = snapshot.isNeedToDropLF(); - quirks = snapshot.isQuirks(); - } - - private int findInArray(StackNode<T> node, StackNode<T>[] arr) { - for (int i = listPtr; i >= 0; i--) { - if (node == arr[i]) { - return i; - } - } - return -1; - } - - /** - * @see nu.validator.htmlparser.impl.TreeBuilderState#getFormPointer() - */ - public T getFormPointer() { - return formPointer; - } - - /** - * Returns the headPointer. - * - * @return the headPointer - */ - public T getHeadPointer() { - return headPointer; - } - - /** - * Returns the deepTreeSurrogateParent. - * - * @return the deepTreeSurrogateParent - */ - public T getDeepTreeSurrogateParent() { - return deepTreeSurrogateParent; - } - - /** - * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElements() - */ - public StackNode<T>[] getListOfActiveFormattingElements() { - return listOfActiveFormattingElements; - } - - /** - * @see nu.validator.htmlparser.impl.TreeBuilderState#getStack() - */ - public StackNode<T>[] getStack() { - return stack; - } - - /** - * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStack() - */ - public int[] getTemplateModeStack() { - return templateModeStack; - } - - /** - * Returns the mode. - * - * @return the mode - */ - public int getMode() { - return mode; - } - - /** - * Returns the originalMode. - * - * @return the originalMode - */ - public int getOriginalMode() { - return originalMode; - } - - /** - * Returns the framesetOk. - * - * @return the framesetOk - */ - public boolean isFramesetOk() { - return framesetOk; - } - - /** - * Returns the needToDropLF. - * - * @return the needToDropLF - */ - public boolean isNeedToDropLF() { - return needToDropLF; - } - - /** - * Returns the quirks. - * - * @return the quirks - */ - public boolean isQuirks() { - return quirks; - } - - /** - * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElementsLength() - */ - public int getListOfActiveFormattingElementsLength() { - return listPtr + 1; - } - - /** - * @see nu.validator.htmlparser.impl.TreeBuilderState#getStackLength() - */ - public int getStackLength() { - return currentPtr + 1; - } - - /** - * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStackLength() - */ - public int getTemplateModeStackLength() { - return templateModePtr + 1; - } - - /** - * Reports a stray start tag. - * @param name the name of the stray tag - * - * @throws SAXException - */ - private void errStrayStartTag(@Local String name) throws SAXException { - err("Stray start tag \u201C" + name + "\u201D."); - } - - /** - * Reports a stray end tag. - * @param name the name of the stray tag - * - * @throws SAXException - */ - private void errStrayEndTag(@Local String name) throws SAXException { - err("Stray end tag \u201C" + name + "\u201D."); - } - - /** - * Reports a state when elements expected to be closed were not. - * - * @param eltPos the position of the start tag on the stack of the element - * being closed. - * @param name the name of the end tag - * - * @throws SAXException - */ - private void errUnclosedElements(int eltPos, @Local String name) throws SAXException { - errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements."); - errListUnclosedStartTags(eltPos); - } - - /** - * Reports a state when elements expected to be closed ahead of an implied - * end tag but were not. - * - * @param eltPos the position of the start tag on the stack of the element - * being closed. - * @param name the name of the end tag - * - * @throws SAXException - */ - private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException { - errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements."); - errListUnclosedStartTags(eltPos); - } - - /** - * Reports a state when elements expected to be closed ahead of an implied - * table cell close. - * - * @param eltPos the position of the start tag on the stack of the element - * being closed. - * @throws SAXException - */ - private void errUnclosedElementsCell(int eltPos) throws SAXException { - errNoCheck("A table cell was implicitly closed, but there were open elements."); - errListUnclosedStartTags(eltPos); - } - - private void errStrayDoctype() throws SAXException { - err("Stray doctype."); - } - - private void errAlmostStandardsDoctype() throws SAXException { - if (!isSrcdocDocument) { - err("Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D."); - } - } - - private void errQuirkyDoctype() throws SAXException { - if (!isSrcdocDocument) { - err("Quirky doctype. Expected \u201C<!DOCTYPE html>\u201D."); - } - } - - private void errNonSpaceInTrailer() throws SAXException { - err("Non-space character in page trailer."); - } - - private void errNonSpaceAfterFrameset() throws SAXException { - err("Non-space after \u201Cframeset\u201D."); - } - - private void errNonSpaceInFrameset() throws SAXException { - err("Non-space in \u201Cframeset\u201D."); - } - - private void errNonSpaceAfterBody() throws SAXException { - err("Non-space character after body."); - } - - private void errNonSpaceInColgroupInFragment() throws SAXException { - err("Non-space in \u201Ccolgroup\u201D when parsing fragment."); - } - - private void errNonSpaceInNoscriptInHead() throws SAXException { - err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D."); - } - - private void errFooBetweenHeadAndBody(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("\u201C" + name + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D."); - } - - private void errStartTagWithoutDoctype() throws SAXException { - if (!isSrcdocDocument) { - err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); - } - } - - private void errNoSelectInTableScope() throws SAXException { - err("No \u201Cselect\u201D in table scope."); - } - - private void errStartSelectWhereEndSelectExpected() throws SAXException { - err("\u201Cselect\u201D start tag where end tag expected."); - } - - private void errStartTagWithSelectOpen(@Local String name) - throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("\u201C" + name - + "\u201D start tag with \u201Cselect\u201D open."); - } - - private void errBadStartTagInHead(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("Bad start tag in \u201C" + name - + "\u201D in \u201Chead\u201D."); - } - - private void errImage() throws SAXException { - err("Saw a start tag \u201Cimage\u201D."); - } - - private void errIsindex() throws SAXException { - err("\u201Cisindex\u201D seen."); - } - - private void errFooSeenWhenFooOpen(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("An \u201C" + name + "\u201D start tag seen but an element of the same type was already open."); - } - - private void errHeadingWhenHeadingOpen() throws SAXException { - err("Heading cannot be a child of another heading."); - } - - private void errFramesetStart() throws SAXException { - err("\u201Cframeset\u201D start tag seen."); - } - - private void errNoCellToClose() throws SAXException { - err("No cell to close."); - } - - private void errStartTagInTable(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("Start tag \u201C" + name - + "\u201D seen in \u201Ctable\u201D."); - } - - private void errFormWhenFormOpen() throws SAXException { - err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag."); - } - - private void errTableSeenWhileTableOpen() throws SAXException { - err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open."); - } - - private void errStartTagInTableBody(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("\u201C" + name + "\u201D start tag in table body."); - } - - private void errEndTagSeenWithoutDoctype() throws SAXException { - if (!isSrcdocDocument) { - err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); - } - } - - private void errEndTagAfterBody() throws SAXException { - err("Saw an end tag after \u201Cbody\u201D had been closed."); - } - - private void errEndTagSeenWithSelectOpen(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("\u201C" + name - + "\u201D end tag with \u201Cselect\u201D open."); - } - - private void errGarbageInColgroup() throws SAXException { - err("Garbage in \u201Ccolgroup\u201D fragment."); - } - - private void errEndTagBr() throws SAXException { - err("End tag \u201Cbr\u201D."); - } - - private void errNoElementToCloseButEndTagSeen(@Local String name) - throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("No \u201C" + name + "\u201D element in scope but a \u201C" - + name + "\u201D end tag seen."); - } - - private void errHtmlStartTagInForeignContext(@Local String name) - throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("HTML start tag \u201C" + name - + "\u201D in a foreign namespace context."); - } - - private void errTableClosedWhileCaptionOpen() throws SAXException { - err("\u201Ctable\u201D closed but \u201Ccaption\u201D was still open."); - } - - private void errNoTableRowToClose() throws SAXException { - err("No table row to close."); - } - - private void errNonSpaceInTable() throws SAXException { - err("Misplaced non-space characters insided a table."); - } - - private void errUnclosedChildrenInRuby() throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("Unclosed children in \u201Cruby\u201D."); - } - - private void errStartTagSeenWithoutRuby(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("Start tag \u201C" - + name - + "\u201D seen without a \u201Cruby\u201D element being open."); - } - - private void errSelfClosing() throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag."); - } - - private void errNoCheckUnclosedElementsOnStack() throws SAXException { - errNoCheck("Unclosed elements on stack."); - } - - private void errEndTagDidNotMatchCurrentOpenElement(@Local String name, - @Local String currOpenName) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("End tag \u201C" - + name - + "\u201D did not match the name of the current open element (\u201C" - + currOpenName + "\u201D)."); - } - - private void errEndTagViolatesNestingRules(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules."); - } - - private void errEofWithUnclosedElements() throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("End of file seen and there were open elements."); - // just report all remaining unclosed elements - errListUnclosedStartTags(0); - } - - /** - * Reports arriving at/near end of document with unclosed elements remaining. - * - * @param message - * the message - * @throws SAXException - */ - private void errEndWithUnclosedElements(@Local String name) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck("End tag for \u201C" - + name - + "\u201D seen, but there were unclosed elements."); - // just report all remaining unclosed elements - errListUnclosedStartTags(0); - } -} |