Browse Source

Remove obsolete javasrc snapshot

pull/24/head
Matt A. Tobin 3 years ago committed by Roy Tam
parent
commit
e490bc29d0
  1. 2473
      parser/html/javasrc/AttributeName.java
  2. 1609
      parser/html/javasrc/ElementName.java
  3. 618
      parser/html/javasrc/HtmlAttributes.java
  4. 854
      parser/html/javasrc/MetaScanner.java
  5. 150
      parser/html/javasrc/Portability.java
  6. 6
      parser/html/javasrc/README.txt
  7. 295
      parser/html/javasrc/StackNode.java
  8. 204
      parser/html/javasrc/StateSnapshot.java
  9. 7089
      parser/html/javasrc/Tokenizer.java
  10. 6552
      parser/html/javasrc/TreeBuilder.java
  11. 151
      parser/html/javasrc/UTF16Buffer.java

2473
parser/html/javasrc/AttributeName.java

File diff suppressed because it is too large Load Diff

1609
parser/html/javasrc/ElementName.java

File diff suppressed because it is too large Load Diff

618
parser/html/javasrc/HtmlAttributes.java

@ -1,618 +0,0 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2011 Mozilla Foundation
*
* 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.
*/
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.Auto;
import nu.validator.htmlparser.annotation.IdType;
import nu.validator.htmlparser.annotation.Local;
import nu.validator.htmlparser.annotation.NsUri;
import nu.validator.htmlparser.annotation.Prefix;
import nu.validator.htmlparser.annotation.QName;
import nu.validator.htmlparser.common.Interner;
import nu.validator.htmlparser.common.XmlViolationPolicy;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* Be careful with this class. QName is the name in from HTML tokenization.
* Otherwise, please refer to the interface doc.
*
* @version $Id: AttributesImpl.java 206 2008-03-20 14:09:29Z hsivonen $
* @author hsivonen
*/
public final class HtmlAttributes implements Attributes {
// [NOCPP[
private static final AttributeName[] EMPTY_ATTRIBUTENAMES = new AttributeName[0];
private static final String[] EMPTY_STRINGS = new String[0];
// ]NOCPP]
public static final HtmlAttributes EMPTY_ATTRIBUTES = new HtmlAttributes(
AttributeName.HTML);
private int mode;
private int length;
private @Auto AttributeName[] names;
private @Auto String[] values; // XXX perhaps make this @NoLength?
// CPPONLY: private @Auto int[] lines; // XXX perhaps make this @NoLength?
// [NOCPP[
private String idValue;
private int xmlnsLength;
private AttributeName[] xmlnsNames;
private String[] xmlnsValues;
// ]NOCPP]
public HtmlAttributes(int mode) {
this.mode = mode;
this.length = 0;
/*
* The length of 5 covers covers 98.3% of elements
* according to Hixie, but lets round to the next power of two for
* jemalloc.
*/
this.names = new AttributeName[8];
this.values = new String[8];
// CPPONLY: this.lines = new int[8];
// [NOCPP[
this.idValue = null;
this.xmlnsLength = 0;
this.xmlnsNames = HtmlAttributes.EMPTY_ATTRIBUTENAMES;
this.xmlnsValues = HtmlAttributes.EMPTY_STRINGS;
// ]NOCPP]
}
/*
public HtmlAttributes(HtmlAttributes other) {
this.mode = other.mode;
this.length = other.length;
this.names = new AttributeName[other.length];
this.values = new String[other.length];
// [NOCPP[
this.idValue = other.idValue;
this.xmlnsLength = other.xmlnsLength;
this.xmlnsNames = new AttributeName[other.xmlnsLength];
this.xmlnsValues = new String[other.xmlnsLength];
// ]NOCPP]
}
*/
void destructor() {
clear(0);
}
/**
* Only use with a static argument
*
* @param name
* @return
*/
public int getIndex(AttributeName name) {
for (int i = 0; i < length; i++) {
if (names[i] == name) {
return i;
}
}
return -1;
}
/**
* Only use with static argument.
*
* @see org.xml.sax.Attributes#getValue(java.lang.String)
*/
public String getValue(AttributeName name) {
int index = getIndex(name);
if (index == -1) {
return null;
} else {
return getValueNoBoundsCheck(index);
}
}
public int getLength() {
return length;
}
/**
* Variant of <code>getLocalName(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the local name at index
*/
public @Local String getLocalNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getLocal(mode);
}
/**
* Variant of <code>getURI(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the namespace URI at index
*/
public @NsUri String getURINoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getUri(mode);
}
/**
* Variant of <code>getPrefix(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the namespace prefix at index
*/
public @Prefix String getPrefixNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getPrefix(mode);
}
/**
* Variant of <code>getValue(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the attribute value at index
*/
public String getValueNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return values[index];
}
/**
* Variant of <code>getAttributeName(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the attribute name at index
*/
public AttributeName getAttributeNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index];
}
// CPPONLY: /**
// CPPONLY: * Obtains a line number without bounds check.
// CPPONLY: * @param index a valid attribute index
// CPPONLY: * @return the line number at index or -1 if unknown
// CPPONLY: */
// CPPONLY: public int getLineNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
// CPPONLY: return lines[index];
// CPPONLY: }
// [NOCPP[
/**
* Variant of <code>getQName(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the QName at index
*/
public @QName String getQNameNoBoundsCheck(int index) {
return names[index].getQName(mode);
}
/**
* Variant of <code>getType(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the attribute type at index
*/
public @IdType String getTypeNoBoundsCheck(int index) {
return (names[index] == AttributeName.ID) ? "ID" : "CDATA";
}
public int getIndex(String qName) {
for (int i = 0; i < length; i++) {
if (names[i].getQName(mode).equals(qName)) {
return i;
}
}
return -1;
}
public int getIndex(String uri, String localName) {
for (int i = 0; i < length; i++) {
if (names[i].getLocal(mode).equals(localName)
&& names[i].getUri(mode).equals(uri)) {
return i;
}
}
return -1;
}
public @IdType String getType(String qName) {
int index = getIndex(qName);
if (index == -1) {
return null;
} else {
return getType(index);
}
}
public @IdType String getType(String uri, String localName) {
int index = getIndex(uri, localName);
if (index == -1) {
return null;
} else {
return getType(index);
}
}
public String getValue(String qName) {
int index = getIndex(qName);
if (index == -1) {
return null;
} else {
return getValue(index);
}
}
public String getValue(String uri, String localName) {
int index = getIndex(uri, localName);
if (index == -1) {
return null;
} else {
return getValue(index);
}
}
public @Local String getLocalName(int index) {
if (index < length && index >= 0) {
return names[index].getLocal(mode);
} else {
return null;
}
}
public @QName String getQName(int index) {
if (index < length && index >= 0) {
return names[index].getQName(mode);
} else {
return null;
}
}
public @IdType String getType(int index) {
if (index < length && index >= 0) {
return (names[index] == AttributeName.ID) ? "ID" : "CDATA";
} else {
return null;
}
}
public AttributeName getAttributeName(int index) {
if (index < length && index >= 0) {
return names[index];
} else {
return null;
}
}
public @NsUri String getURI(int index) {
if (index < length && index >= 0) {
return names[index].getUri(mode);
} else {
return null;
}
}
public @Prefix String getPrefix(int index) {
if (index < length && index >= 0) {
return names[index].getPrefix(mode);
} else {
return null;
}
}
public String getValue(int index) {
if (index < length && index >= 0) {
return values[index];
} else {
return null;
}
}
public String getId() {
return idValue;
}
public int getXmlnsLength() {
return xmlnsLength;
}
public @Local String getXmlnsLocalName(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsNames[index].getLocal(mode);
} else {
return null;
}
}
public @NsUri String getXmlnsURI(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsNames[index].getUri(mode);
} else {
return null;
}
}
public String getXmlnsValue(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsValues[index];
} else {
return null;
}
}
public int getXmlnsIndex(AttributeName name) {
for (int i = 0; i < xmlnsLength; i++) {
if (xmlnsNames[i] == name) {
return i;
}
}
return -1;
}
public String getXmlnsValue(AttributeName name) {
int index = getXmlnsIndex(name);
if (index == -1) {
return null;
} else {
return getXmlnsValue(index);
}
}
public AttributeName getXmlnsAttributeName(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsNames[index];
} else {
return null;
}
}
// ]NOCPP]
void addAttribute(AttributeName name, String value
// [NOCPP[
, XmlViolationPolicy xmlnsPolicy
// ]NOCPP]
// CPPONLY: , int line
) throws SAXException {
// [NOCPP[
if (name == AttributeName.ID) {
idValue = value;
}
if (name.isXmlns()) {
if (xmlnsNames.length == xmlnsLength) {
int newLen = xmlnsLength == 0 ? 2 : xmlnsLength << 1;
AttributeName[] newNames = new AttributeName[newLen];
System.arraycopy(xmlnsNames, 0, newNames, 0, xmlnsNames.length);
xmlnsNames = newNames;
String[] newValues = new String[newLen];
System.arraycopy(xmlnsValues, 0, newValues, 0, xmlnsValues.length);
xmlnsValues = newValues;
}
xmlnsNames[xmlnsLength] = name;
xmlnsValues[xmlnsLength] = value;
xmlnsLength++;
switch (xmlnsPolicy) {
case FATAL:
// this is ugly
throw new SAXException("Saw an xmlns attribute.");
case ALTER_INFOSET:
return;
case ALLOW:
// fall through
}
}
// ]NOCPP]
if (names.length == length) {
int newLen = length << 1; // The first growth covers virtually
// 100% of elements according to
// Hixie
AttributeName[] newNames = new AttributeName[newLen];
System.arraycopy(names, 0, newNames, 0, names.length);
names = newNames;
String[] newValues = new String[newLen];
System.arraycopy(values, 0, newValues, 0, values.length);
values = newValues;
// CPPONLY: int[] newLines = new int[newLen];
// CPPONLY: System.arraycopy(lines, 0, newLines, 0, lines.length);
// CPPONLY: lines = newLines;
}
names[length] = name;
values[length] = value;
// CPPONLY: lines[length] = line;
length++;
}
void clear(int m) {
for (int i = 0; i < length; i++) {
names[i].release();
names[i] = null;
Portability.releaseString(values[i]);
values[i] = null;
}
length = 0;
mode = m;
// [NOCPP[
idValue = null;
for (int i = 0; i < xmlnsLength; i++) {
xmlnsNames[i] = null;
xmlnsValues[i] = null;
}
xmlnsLength = 0;
// ]NOCPP]
}
/**
* This is used in C++ to release special <code>isindex</code>
* attribute values whose ownership is not transferred.
*/
void releaseValue(int i) {
Portability.releaseString(values[i]);
}
/**
* This is only used for <code>AttributeName</code> ownership transfer
* in the isindex case to avoid freeing custom names twice in C++.
*/
void clearWithoutReleasingContents() {
for (int i = 0; i < length; i++) {
names[i] = null;
values[i] = null;
}
length = 0;
}
boolean contains(AttributeName name) {
for (int i = 0; i < length; i++) {
if (name.equalsAnother(names[i])) {
return true;
}
}
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) {
if (name.equalsAnother(xmlnsNames[i])) {
return true;
}
}
// ]NOCPP]
return false;
}
public void adjustForMath() {
mode = AttributeName.MATHML;
}
public void adjustForSvg() {
mode = AttributeName.SVG;
}
public HtmlAttributes cloneAttributes(Interner interner)
throws SAXException {
assert (length == 0
// [NOCPP[
&& xmlnsLength == 0
// ]NOCPP]
)
|| mode == 0 || mode == 3;
HtmlAttributes clone = new HtmlAttributes(0);
for (int i = 0; i < length; i++) {
clone.addAttribute(names[i].cloneAttributeName(interner),
Portability.newStringFromString(values[i])
// [NOCPP[
, XmlViolationPolicy.ALLOW
// ]NOCPP]
// CPPONLY: , lines[i]
);
}
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) {
clone.addAttribute(xmlnsNames[i], xmlnsValues[i],
XmlViolationPolicy.ALLOW);
}
// ]NOCPP]
return clone; // XXX!!!
}
public boolean equalsAnother(HtmlAttributes other) {
assert mode == 0 || mode == 3 : "Trying to compare attributes in foreign content.";
int otherLength = other.getLength();
if (length != otherLength) {
return false;
}
for (int i = 0; i < length; i++) {
// Work around the limitations of C++
boolean found = false;
// The comparing just the local names is OK, since these attribute
// holders are both supposed to belong to HTML formatting elements
@Local String ownLocal = names[i].getLocal(AttributeName.HTML);
for (int j = 0; j < otherLength; j++) {
if (ownLocal == other.names[j].getLocal(AttributeName.HTML)) {
found = true;
if (!Portability.stringEqualsString(values[i], other.values[j])) {
return false;
}
}
}
if (!found) {
return false;
}
}
return true;
}
// [NOCPP[
void processNonNcNames(TreeBuilder<?> treeBuilder, XmlViolationPolicy namePolicy) throws SAXException {
for (int i = 0; i < length; i++) {
AttributeName attName = names[i];
if (!attName.isNcName(mode)) {
String name = attName.getLocal(mode);
switch (namePolicy) {
case ALTER_INFOSET:
names[i] = AttributeName.create(NCName.escapeName(name));
// fall through
case ALLOW:
if (attName != AttributeName.XML_LANG) {
treeBuilder.warn("Attribute \u201C" + name + "\u201D is not serializable as XML 1.0.");
}
break;
case FATAL:
treeBuilder.fatal("Attribute \u201C" + name + "\u201D is not serializable as XML 1.0.");
break;
}
}
}
}
public void merge(HtmlAttributes attributes) throws SAXException {
int len = attributes.getLength();
for (int i = 0; i < len; i++) {
AttributeName name = attributes.getAttributeNameNoBoundsCheck(i);
if (!contains(name)) {
addAttribute(name, attributes.getValueNoBoundsCheck(i), XmlViolationPolicy.ALLOW);
}
}
}
// ]NOCPP]
}

854
parser/html/javasrc/MetaScanner.java

@ -1,854 +0,0 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2015 Mozilla Foundation
*
* 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.
*/
package nu.validator.htmlparser.impl;
import java.io.IOException;
import nu.validator.htmlparser.annotation.Auto;
import nu.validator.htmlparser.annotation.Inline;
import nu.validator.htmlparser.common.ByteReadable;
import org.xml.sax.SAXException;
public abstract class MetaScanner {
/**
* Constant for "charset".
*/
private static final char[] CHARSET = { 'h', 'a', 'r', 's', 'e', 't' };
/**
* Constant for "content".
*/
private static final char[] CONTENT = { 'o', 'n', 't', 'e', 'n', 't' };
/**
* Constant for "http-equiv".
*/
private static final char[] HTTP_EQUIV = { 't', 't', 'p', '-', 'e', 'q',
'u', 'i', 'v' };
/**
* Constant for "content-type".
*/
private static final char[] CONTENT_TYPE = { 'c', 'o', 'n', 't', 'e', 'n',
't', '-', 't', 'y', 'p', 'e' };
private static final int NO = 0;
private static final int M = 1;
private static final int E = 2;
private static final int T = 3;
private static final int A = 4;
private static final int DATA = 0;
private static final int TAG_OPEN = 1;
private static final int SCAN_UNTIL_GT = 2;
private static final int TAG_NAME = 3;
private static final int BEFORE_ATTRIBUTE_NAME = 4;
private static final int ATTRIBUTE_NAME = 5;
private static final int AFTER_ATTRIBUTE_NAME = 6;
private static final int BEFORE_ATTRIBUTE_VALUE = 7;
private static final int ATTRIBUTE_VALUE_DOUBLE_QUOTED = 8;
private static final int ATTRIBUTE_VALUE_SINGLE_QUOTED = 9;
private static final int ATTRIBUTE_VALUE_UNQUOTED = 10;
private static final int AFTER_ATTRIBUTE_VALUE_QUOTED = 11;
private static final int MARKUP_DECLARATION_OPEN = 13;
private static final int MARKUP_DECLARATION_HYPHEN = 14;
private static final int COMMENT_START = 15;
private static final int COMMENT_START_DASH = 16;
private static final int COMMENT = 17;
private static final int COMMENT_END_DASH = 18;
private static final int COMMENT_END = 19;
private static final int SELF_CLOSING_START_TAG = 20;
private static final int HTTP_EQUIV_NOT_SEEN = 0;
private static final int HTTP_EQUIV_CONTENT_TYPE = 1;
private static final int HTTP_EQUIV_OTHER = 2;
/**
* The data source.
*/
protected ByteReadable readable;
/**
* The state of the state machine that recognizes the tag name "meta".
*/
private int metaState = NO;
/**
* The current position in recognizing the attribute name "content".
*/
private int contentIndex = Integer.MAX_VALUE;
/**
* The current position in recognizing the attribute name "charset".
*/
private int charsetIndex = Integer.MAX_VALUE;
/**
* The current position in recognizing the attribute name "http-equive".
*/
private int httpEquivIndex = Integer.MAX_VALUE;
/**
* The current position in recognizing the attribute value "content-type".
*/
private int contentTypeIndex = Integer.MAX_VALUE;
/**
* The tokenizer state.
*/
protected int stateSave = DATA;
/**
* The currently filled length of strBuf.
*/
private int strBufLen;
/**
* Accumulation buffer for attribute values.
*/
private @Auto char[] strBuf;
private String content;
private String charset;
private int httpEquivState;
// CPPONLY: private TreeBuilder treeBuilder;
public MetaScanner(
// CPPONLY: TreeBuilder tb
) {
this.readable = null;
this.metaState = NO;
this.contentIndex = Integer.MAX_VALUE;
this.charsetIndex = Integer.MAX_VALUE;
this.httpEquivIndex = Integer.MAX_VALUE;
this.contentTypeIndex = Integer.MAX_VALUE;
this.stateSave = DATA;
this.strBufLen = 0;
this.strBuf = new char[36];
this.content = null;
this.charset = null;
this.httpEquivState = HTTP_EQUIV_NOT_SEEN;
// CPPONLY: this.treeBuilder = tb;
}
@SuppressWarnings("unused") private void destructor() {
Portability.releaseString(content);
Portability.releaseString(charset);
}
// [NOCPP[
/**
* Reads a byte from the data source.
*
* -1 means end.
* @return
* @throws IOException
*/
protected int read() throws IOException {
return readable.readByte();
}
// ]NOCPP]
// WARNING When editing this, makes sure the bytecode length shown by javap
// stays under 8000 bytes!
/**
* The runs the meta scanning algorithm.
*/
protected final void stateLoop(int state)
throws SAXException, IOException {
int c = -1;
boolean reconsume = false;
stateloop: for (;;) {
switch (state) {
case DATA:
dataloop: for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '<':
state = MetaScanner.TAG_OPEN;
break dataloop; // FALL THROUGH continue
// stateloop;
default:
continue;
}
}
// WARNING FALLTHRU CASE TRANSITION: DON'T REORDER
case TAG_OPEN:
tagopenloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case 'm':
case 'M':
metaState = M;
state = MetaScanner.TAG_NAME;
break tagopenloop;
// continue stateloop;
case '!':
state = MetaScanner.MARKUP_DECLARATION_OPEN;
continue stateloop;
case '?':
case '/':
state = MetaScanner.SCAN_UNTIL_GT;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
metaState = NO;
state = MetaScanner.TAG_NAME;
break tagopenloop;
// continue stateloop;
}
state = MetaScanner.DATA;
reconsume = true;
continue stateloop;
}
}
// FALL THROUGH DON'T REORDER
case TAG_NAME:
tagnameloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
break tagnameloop;
// continue stateloop;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
case 'e':
case 'E':
if (metaState == M) {
metaState = E;
} else {
metaState = NO;
}
continue;
case 't':
case 'T':
if (metaState == E) {
metaState = T;
} else {
metaState = NO;
}
continue;
case 'a':
case 'A':
if (metaState == T) {
metaState = A;
} else {
metaState = NO;
}
continue;
default:
metaState = NO;
continue;
}
}
// FALLTHRU DON'T REORDER
case BEFORE_ATTRIBUTE_NAME:
beforeattributenameloop: for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
/*
* Consume the next input character:
*/
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
continue;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = DATA;
continue stateloop;
case 'c':
case 'C':
contentIndex = 0;
charsetIndex = 0;
httpEquivIndex = Integer.MAX_VALUE;
contentTypeIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
break beforeattributenameloop;
case 'h':
case 'H':
contentIndex = Integer.MAX_VALUE;
charsetIndex = Integer.MAX_VALUE;
httpEquivIndex = 0;
contentTypeIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
break beforeattributenameloop;
default:
contentIndex = Integer.MAX_VALUE;
charsetIndex = Integer.MAX_VALUE;
httpEquivIndex = Integer.MAX_VALUE;
contentTypeIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
break beforeattributenameloop;
// continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case ATTRIBUTE_NAME:
attributenameloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
state = MetaScanner.AFTER_ATTRIBUTE_NAME;
continue stateloop;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '=':
strBufLen = 0;
contentTypeIndex = 0;
state = MetaScanner.BEFORE_ATTRIBUTE_VALUE;
break attributenameloop;
// continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
if (metaState == A) {
if (c >= 'A' && c <= 'Z') {
c += 0x20;
}
if (contentIndex < CONTENT.length && c == CONTENT[contentIndex]) {
++contentIndex;
} else {
contentIndex = Integer.MAX_VALUE;
}
if (charsetIndex < CHARSET.length && c == CHARSET[charsetIndex]) {
++charsetIndex;
} else {
charsetIndex = Integer.MAX_VALUE;
}
if (httpEquivIndex < HTTP_EQUIV.length && c == HTTP_EQUIV[httpEquivIndex]) {
++httpEquivIndex;
} else {
httpEquivIndex = Integer.MAX_VALUE;
}
}
continue;
}
}
// FALLTHRU DON'T REORDER
case BEFORE_ATTRIBUTE_VALUE:
beforeattributevalueloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
continue;
case '"':
state = MetaScanner.ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break beforeattributevalueloop;
// continue stateloop;
case '\'':
state = MetaScanner.ATTRIBUTE_VALUE_SINGLE_QUOTED;
continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
handleCharInAttributeValue(c);
state = MetaScanner.ATTRIBUTE_VALUE_UNQUOTED;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case ATTRIBUTE_VALUE_DOUBLE_QUOTED:
attributevaluedoublequotedloop: for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '"':
handleAttributeValue();
state = MetaScanner.AFTER_ATTRIBUTE_VALUE_QUOTED;
break attributevaluedoublequotedloop;
// continue stateloop;
default:
handleCharInAttributeValue(c);
continue;
}
}
// FALLTHRU DON'T REORDER
case AFTER_ATTRIBUTE_VALUE_QUOTED:
afterattributevaluequotedloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
continue stateloop;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
break afterattributevaluequotedloop;
// continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
reconsume = true;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case SELF_CLOSING_START_TAG:
c = read();
switch (c) {
case -1:
break stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
reconsume = true;
continue stateloop;
}
// XXX reorder point
case ATTRIBUTE_VALUE_UNQUOTED:
for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
handleAttributeValue();
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
continue stateloop;
case '>':
handleAttributeValue();
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
handleCharInAttributeValue(c);
continue;
}
}
// XXX reorder point
case AFTER_ATTRIBUTE_NAME:
for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
continue;
case '/':
handleAttributeValue();
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '=':
strBufLen = 0;
contentTypeIndex = 0;
state = MetaScanner.BEFORE_ATTRIBUTE_VALUE;
continue stateloop;
case '>':
handleAttributeValue();
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
case 'c':
case 'C':
contentIndex = 0;
charsetIndex = 0;
state = MetaScanner.ATTRIBUTE_NAME;
continue stateloop;
default:
contentIndex = Integer.MAX_VALUE;
charsetIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
continue stateloop;
}
}
// XXX reorder point
case MARKUP_DECLARATION_OPEN:
markupdeclarationopenloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.MARKUP_DECLARATION_HYPHEN;
break markupdeclarationopenloop;
// continue stateloop;
default:
state = MetaScanner.SCAN_UNTIL_GT;
reconsume = true;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case MARKUP_DECLARATION_HYPHEN:
markupdeclarationhyphenloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_START;
break markupdeclarationhyphenloop;
// continue stateloop;
default:
state = MetaScanner.SCAN_UNTIL_GT;
reconsume = true;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case COMMENT_START:
commentstartloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_START_DASH;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.COMMENT;
break commentstartloop;
// continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case COMMENT:
commentloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_END_DASH;
break commentloop;
// continue stateloop;
default:
continue;
}
}
// FALLTHRU DON'T REORDER
case COMMENT_END_DASH:
commentenddashloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_END;
break commentenddashloop;
// continue stateloop;
default:
state = MetaScanner.COMMENT;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case COMMENT_END:
for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
case '-':
continue;
default:
state = MetaScanner.COMMENT;
continue stateloop;
}
}
// XXX reorder point
case COMMENT_START_DASH:
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_END;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.COMMENT;
continue stateloop;
}
// XXX reorder point
case ATTRIBUTE_VALUE_SINGLE_QUOTED:
for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '\'':
handleAttributeValue();
state = MetaScanner.AFTER_ATTRIBUTE_VALUE_QUOTED;
continue stateloop;
default:
handleCharInAttributeValue(c);
continue;
}
}
// XXX reorder point
case SCAN_UNTIL_GT:
for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
continue;
}
}
}
}
stateSave = state;
}
private void handleCharInAttributeValue(int c) {
if (metaState == A) {
if (contentIndex == CONTENT.length || charsetIndex == CHARSET.length) {
addToBuffer(c);
} else if (httpEquivIndex == HTTP_EQUIV.length) {
if (contentTypeIndex < CONTENT_TYPE.length && toAsciiLowerCase(c) == CONTENT_TYPE[contentTypeIndex]) {
++contentTypeIndex;
} else {
contentTypeIndex = Integer.MAX_VALUE;
}
}
}
}
@Inline private int toAsciiLowerCase(int c) {
if (c >= 'A' && c <= 'Z') {
return c + 0x20;
}
return c;
}
/**
* Adds a character to the accumulation buffer.
* @param c the character to add
*/
private void addToBuffer(int c) {
if (strBufLen == strBuf.length) {
char[] newBuf = new char[strBuf.length + (strBuf.length << 1)];
System.arraycopy(strBuf, 0, newBuf, 0, strBuf.length);
strBuf = newBuf;
}
strBuf[strBufLen++] = (char)c;
}
/**
* Attempts to extract a charset name from the accumulation buffer.
* @return <code>true</code> if successful
* @throws SAXException
*/
private void handleAttributeValue() throws SAXException {
if (metaState != A) {
return;
}