Bug 1355479 - Remove isindex on the Java side and allow the C++ side to reduce malloc in attribute handling.

Tag UXP Issue #1344
This commit is contained in:
Gaming4JC 2020-01-18 14:01:12 -05:00 • committed by Roy Tam
commit 67a2c5cb06
10 changed files with 180 additions and 336 deletions

View file

@ -33,7 +33,6 @@ import nu.validator.htmlparser.annotation.NsUri;
import nu.validator.htmlparser.annotation.Prefix; import nu.validator.htmlparser.annotation.Prefix;
import nu.validator.htmlparser.annotation.QName; import nu.validator.htmlparser.annotation.QName;
import nu.validator.htmlparser.annotation.Unsigned; import nu.validator.htmlparser.annotation.Unsigned;
import nu.validator.htmlparser.annotation.Virtual;
import nu.validator.htmlparser.common.Interner; import nu.validator.htmlparser.common.Interner;
public final class AttributeName public final class AttributeName
@ -275,35 +274,19 @@ public final class AttributeName
*/ */
static AttributeName nameByBuffer(@NoLength char[] buf, int offset, static AttributeName nameByBuffer(@NoLength char[] buf, int offset,
int length int length
// [NOCPP[
, boolean checkNcName
// ]NOCPP]
, Interner interner) { , Interner interner) {
// XXX deal with offset // XXX deal with offset
@Unsigned int hash = AttributeName.bufToHash(buf, length); @Unsigned int hash = AttributeName.bufToHash(buf, length);
int index = Arrays.binarySearch(AttributeName.ATTRIBUTE_HASHES, hash); int index = Arrays.binarySearch(AttributeName.ATTRIBUTE_HASHES, hash);
if (index < 0) { if (index < 0) {
return AttributeName.createAttributeName( return null;
Portability.newLocalNameFromBuffer(buf, offset, length,
interner)
// [NOCPP[
, checkNcName
// ]NOCPP]
);
} else {
AttributeName attributeName = AttributeName.ATTRIBUTE_NAMES[index];
@Local String name = attributeName.getLocal(AttributeName.HTML);
if (!Portability.localEqualsBuffer(name, buf, offset, length)) {
return AttributeName.createAttributeName(
Portability.newLocalNameFromBuffer(buf, offset, length,
interner)
// [NOCPP[
, checkNcName
// ]NOCPP]
);
}
return attributeName;
} }
AttributeName attributeName = AttributeName.ATTRIBUTE_NAMES[index];
@Local String name = attributeName.getLocal(AttributeName.HTML);
if (!Portability.localEqualsBuffer(name, buf, offset, length)) {
return null;
}
return attributeName;
} }
/** /**
@ -385,6 +368,8 @@ public final class AttributeName
*/ */
private final @Prefix @NoLength String[] prefix; private final @Prefix @NoLength String[] prefix;
// CPPONLY: private final boolean custom;
// [NOCPP[ // [NOCPP[
private final int flags; private final int flags;
@ -410,7 +395,7 @@ public final class AttributeName
* @param xmlns * @param xmlns
* whether this is an xmlns attribute * whether this is an xmlns attribute
*/ */
protected AttributeName(@NsUri @NoLength String[] uri, private AttributeName(@NsUri @NoLength String[] uri,
@Local @NoLength String[] local, @Prefix @NoLength String[] prefix @Local @NoLength String[] local, @Prefix @NoLength String[] prefix
// [NOCPP[ // [NOCPP[
, int flags , int flags
@ -423,8 +408,27 @@ public final class AttributeName
this.qName = COMPUTE_QNAME(local, prefix); this.qName = COMPUTE_QNAME(local, prefix);
this.flags = flags; this.flags = flags;
// ]NOCPP] // ]NOCPP]
// CPPONLY: this.custom = false;
} }
// CPPONLY: public AttributeName() {
// CPPONLY: this.uri = AttributeName.ALL_NO_NS;
// CPPONLY: this.local = AttributeName.SAME_LOCAL(null);
// CPPONLY: this.prefix = ALL_NO_PREFIX;
// CPPONLY: this.custom = true;
// CPPONLY: }
// CPPONLY:
// CPPONLY: public boolean isInterned() {
// CPPONLY: return !custom;
// CPPONLY: }
// CPPONLY:
// CPPONLY: public void setNameForNonInterned(@Local String name) {
// CPPONLY: assert custom;
// CPPONLY: local[0] = name;
// CPPONLY: local[1] = name;
// CPPONLY: local[2] = name;
// CPPONLY: }
/** /**
* Creates an <code>AttributeName</code> for a local name. * Creates an <code>AttributeName</code> for a local name.
* *
@ -434,7 +438,7 @@ public final class AttributeName
* whether to check ncnameness * whether to check ncnameness
* @return an <code>AttributeName</code> * @return an <code>AttributeName</code>
*/ */
private static AttributeName createAttributeName(@Local String name static AttributeName createAttributeName(@Local String name
// [NOCPP[ // [NOCPP[
, boolean checkNcName , boolean checkNcName
// ]NOCPP] // ]NOCPP]
@ -451,33 +455,13 @@ public final class AttributeName
AttributeName.SAME_LOCAL(name), ALL_NO_PREFIX, flags); AttributeName.SAME_LOCAL(name), ALL_NO_PREFIX, flags);
} }
/**
* Deletes runtime-allocated instances in C++.
*/
@Virtual void release() {
// No-op in Java.
// Implement as |delete this;| in subclass.
}
/** /**
* The C++ destructor. * The C++ destructor.
*/ */
@SuppressWarnings("unused") @Virtual private void destructor() { @SuppressWarnings("unused") private void destructor() {
Portability.deleteArray(local); Portability.deleteArray(local);
} }
/**
* Clones the attribute using an interner. Returns <code>this</code> in Java
* and for non-dynamic instances in C++.
*
* @param interner
* an interner
* @return a clone
*/
@Virtual public AttributeName cloneAttributeName(Interner interner) {
return this;
}
// [NOCPP[ // [NOCPP[
/** /**
* Creator for use when the XML violation policy requires an attribute name * Creator for use when the XML violation policy requires an attribute name

View file

@ -22,10 +22,10 @@
package nu.validator.htmlparser.impl; package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.NoLength;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import nu.validator.htmlparser.annotation.NoLength;
/** /**
* A common superclass for tree builders that coalesce their text nodes. * A common superclass for tree builders that coalesce their text nodes.
* *
@ -48,13 +48,6 @@ public abstract class CoalescingTreeBuilder<T> extends TreeBuilder<T> {
appendCharacters(parent, new String(buf, start, length)); appendCharacters(parent, new String(buf, start, length));
} }
/**
* @see nu.validator.htmlparser.impl.TreeBuilder#appendIsindexPrompt(java.lang.Object)
*/
@Override protected void appendIsindexPrompt(T parent) throws SAXException {
appendCharacters(parent, "This is a searchable index. Enter search keywords: ");
}
protected abstract void appendCharacters(T parent, String text) throws SAXException; protected abstract void appendCharacters(T parent, String text) throws SAXException;
/** /**

View file

@ -192,6 +192,11 @@ public final class ElementName
assert this.flags == (TreeBuilder.OTHER | NOT_INTERNED); assert this.flags == (TreeBuilder.OTHER | NOT_INTERNED);
} }
// CPPONLY: public static final ElementName ISINDEX = new ElementName("isindex", "isindex", TreeBuilder.ISINDEX | SPECIAL);
// [NOCPP[
public static final ElementName ISINDEX = new ElementName("isindex", "isindex", TreeBuilder.OTHER);
// ]NOCPP]
// START CODE ONLY USED FOR GENERATING CODE uncomment and run to regenerate // START CODE ONLY USED FOR GENERATING CODE uncomment and run to regenerate
// /** // /**
@ -421,6 +426,9 @@ public final class ElementName
// } // }
// for (int i = 0; i < ELEMENT_NAMES.length; i++) { // for (int i = 0; i < ELEMENT_NAMES.length; i++) {
// ElementName el = ELEMENT_NAMES[i]; // ElementName el = ELEMENT_NAMES[i];
// if ("isindex".equals(el.name)) {
// continue;
// }
// System.out.println("public static final ElementName " // System.out.println("public static final ElementName "
// + el.constName() + " = new ElementName" + el.toString() // + el.constName() + " = new ElementName" + el.toString()
// + ";"); // + ";");
@ -439,6 +447,7 @@ public final class ElementName
// System.out.println("};"); // System.out.println("};");
// } // }
// START GENERATED CODE // START GENERATED CODE
public static final ElementName AND = new ElementName("and", "and", TreeBuilder.OTHER); public static final ElementName AND = new ElementName("and", "and", TreeBuilder.OTHER);
public static final ElementName ARG = new ElementName("arg", "arg", TreeBuilder.OTHER); public static final ElementName ARG = new ElementName("arg", "arg", TreeBuilder.OTHER);
@ -828,7 +837,6 @@ public final class ElementName
public static final ElementName APPROX = new ElementName("approx", "approx", TreeBuilder.OTHER); public static final ElementName APPROX = new ElementName("approx", "approx", TreeBuilder.OTHER);
public static final ElementName FECOLORMATRIX = new ElementName("fecolormatrix", "feColorMatrix", TreeBuilder.OTHER); public static final ElementName FECOLORMATRIX = new ElementName("fecolormatrix", "feColorMatrix", TreeBuilder.OTHER);
public static final ElementName FECONVOLVEMATRIX = new ElementName("feconvolvematrix", "feConvolveMatrix", TreeBuilder.OTHER); public static final ElementName FECONVOLVEMATRIX = new ElementName("feconvolvematrix", "feConvolveMatrix", TreeBuilder.OTHER);
public static final ElementName ISINDEX = new ElementName("isindex", "isindex", TreeBuilder.ISINDEX | SPECIAL);
public static final ElementName MATRIX = new ElementName("matrix", "matrix", TreeBuilder.OTHER); public static final ElementName MATRIX = new ElementName("matrix", "matrix", TreeBuilder.OTHER);
public static final ElementName APPLY = new ElementName("apply", "apply", TreeBuilder.OTHER); public static final ElementName APPLY = new ElementName("apply", "apply", TreeBuilder.OTHER);
public static final ElementName BODY = new ElementName("body", "body", TreeBuilder.BODY | SPECIAL | OPTIONAL_END_TAG); public static final ElementName BODY = new ElementName("body", "body", TreeBuilder.BODY | SPECIAL | OPTIONAL_END_TAG);

View file

@ -25,7 +25,9 @@
package nu.validator.htmlparser.impl; package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.Auto; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import nu.validator.htmlparser.annotation.IdType; import nu.validator.htmlparser.annotation.IdType;
import nu.validator.htmlparser.annotation.Local; import nu.validator.htmlparser.annotation.Local;
import nu.validator.htmlparser.annotation.NsUri; import nu.validator.htmlparser.annotation.NsUri;
@ -34,9 +36,6 @@ import nu.validator.htmlparser.annotation.QName;
import nu.validator.htmlparser.common.Interner; import nu.validator.htmlparser.common.Interner;
import nu.validator.htmlparser.common.XmlViolationPolicy; 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. * Be careful with this class. QName is the name in from HTML tokenization.
* Otherwise, please refer to the interface doc. * Otherwise, please refer to the interface doc.
@ -46,14 +45,10 @@ import org.xml.sax.SAXException;
*/ */
public final class HtmlAttributes implements Attributes { public final class HtmlAttributes implements Attributes {
// [NOCPP[
private static final AttributeName[] EMPTY_ATTRIBUTENAMES = new AttributeName[0]; private static final AttributeName[] EMPTY_ATTRIBUTENAMES = new AttributeName[0];
private static final String[] EMPTY_STRINGS = new String[0]; private static final String[] EMPTY_STRINGS = new String[0];
// ]NOCPP]
public static final HtmlAttributes EMPTY_ATTRIBUTES = new HtmlAttributes( public static final HtmlAttributes EMPTY_ATTRIBUTES = new HtmlAttributes(
AttributeName.HTML); AttributeName.HTML);
@ -61,13 +56,9 @@ public final class HtmlAttributes implements Attributes {
private int length; private int length;
private @Auto AttributeName[] names; private AttributeName[] names;
private @Auto String[] values; // XXX perhaps make this @NoLength? private String[] values;
// CPPONLY: private @Auto int[] lines; // XXX perhaps make this @NoLength?
// [NOCPP[
private String idValue; private String idValue;
@ -77,21 +68,15 @@ public final class HtmlAttributes implements Attributes {
private String[] xmlnsValues; private String[] xmlnsValues;
// ]NOCPP]
public HtmlAttributes(int mode) { public HtmlAttributes(int mode) {
this.mode = mode; this.mode = mode;
this.length = 0; this.length = 0;
/* /*
* The length of 5 covers covers 98.3% of elements * The length of 5 covers covers 98.3% of elements
* according to Hixie, but lets round to the next power of two for * according to Hixie.
* jemalloc.
*/ */
this.names = new AttributeName[8]; this.names = new AttributeName[5];
this.values = new String[8]; this.values = new String[5];
// CPPONLY: this.lines = new int[8];
// [NOCPP[
this.idValue = null; this.idValue = null;
@ -101,25 +86,6 @@ public final class HtmlAttributes implements Attributes {
this.xmlnsValues = HtmlAttributes.EMPTY_STRINGS; 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);
} }
/** /**
@ -161,7 +127,6 @@ public final class HtmlAttributes implements Attributes {
* @return the local name at index * @return the local name at index
*/ */
public @Local String getLocalNameNoBoundsCheck(int index) { public @Local String getLocalNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getLocal(mode); return names[index].getLocal(mode);
} }
@ -171,7 +136,6 @@ public final class HtmlAttributes implements Attributes {
* @return the namespace URI at index * @return the namespace URI at index
*/ */
public @NsUri String getURINoBoundsCheck(int index) { public @NsUri String getURINoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getUri(mode); return names[index].getUri(mode);
} }
@ -181,7 +145,6 @@ public final class HtmlAttributes implements Attributes {
* @return the namespace prefix at index * @return the namespace prefix at index
*/ */
public @Prefix String getPrefixNoBoundsCheck(int index) { public @Prefix String getPrefixNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getPrefix(mode); return names[index].getPrefix(mode);
} }
@ -191,7 +154,6 @@ public final class HtmlAttributes implements Attributes {
* @return the attribute value at index * @return the attribute value at index
*/ */
public String getValueNoBoundsCheck(int index) { public String getValueNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return values[index]; return values[index];
} }
@ -201,21 +163,9 @@ public final class HtmlAttributes implements Attributes {
* @return the attribute name at index * @return the attribute name at index
*/ */
public AttributeName getAttributeNameNoBoundsCheck(int index) { public AttributeName getAttributeNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index]; 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. * Variant of <code>getQName(int index)</code> without bounds check.
@ -404,15 +354,9 @@ public final class HtmlAttributes implements Attributes {
} }
} }
// ]NOCPP]
void addAttribute(AttributeName name, String value void addAttribute(AttributeName name, String value
// [NOCPP[
, XmlViolationPolicy xmlnsPolicy , XmlViolationPolicy xmlnsPolicy
// ]NOCPP]
// CPPONLY: , int line
) throws SAXException { ) throws SAXException {
// [NOCPP[
if (name == AttributeName.ID) { if (name == AttributeName.ID) {
idValue = value; idValue = value;
} }
@ -441,8 +385,6 @@ public final class HtmlAttributes implements Attributes {
} }
} }
// ]NOCPP]
if (names.length == length) { if (names.length == length) {
int newLen = length << 1; // The first growth covers virtually int newLen = length << 1; // The first growth covers virtually
// 100% of elements according to // 100% of elements according to
@ -453,53 +395,25 @@ public final class HtmlAttributes implements Attributes {
String[] newValues = new String[newLen]; String[] newValues = new String[newLen];
System.arraycopy(values, 0, newValues, 0, values.length); System.arraycopy(values, 0, newValues, 0, values.length);
values = newValues; values = newValues;
// CPPONLY: int[] newLines = new int[newLen];
// CPPONLY: System.arraycopy(lines, 0, newLines, 0, lines.length);
// CPPONLY: lines = newLines;
} }
names[length] = name; names[length] = name;
values[length] = value; values[length] = value;
// CPPONLY: lines[length] = line;
length++; length++;
} }
void clear(int m) { void clear(int m) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
names[i].release();
names[i] = null; names[i] = null;
Portability.releaseString(values[i]);
values[i] = null; values[i] = null;
} }
length = 0; length = 0;
mode = m; mode = m;
// [NOCPP[
idValue = null; idValue = null;
for (int i = 0; i < xmlnsLength; i++) { for (int i = 0; i < xmlnsLength; i++) {
xmlnsNames[i] = null; xmlnsNames[i] = null;
xmlnsValues[i] = null; xmlnsValues[i] = null;
} }
xmlnsLength = 0; 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) { boolean contains(AttributeName name) {
@ -508,13 +422,11 @@ public final class HtmlAttributes implements Attributes {
return true; return true;
} }
} }
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) { for (int i = 0; i < xmlnsLength; i++) {
if (name.equalsAnother(xmlnsNames[i])) { if (name.equalsAnother(xmlnsNames[i])) {
return true; return true;
} }
} }
// ]NOCPP]
return false; return false;
} }
@ -529,27 +441,20 @@ public final class HtmlAttributes implements Attributes {
public HtmlAttributes cloneAttributes(Interner interner) public HtmlAttributes cloneAttributes(Interner interner)
throws SAXException { throws SAXException {
assert (length == 0 assert (length == 0
// [NOCPP[
&& xmlnsLength == 0 && xmlnsLength == 0
// ]NOCPP]
) )
|| mode == 0 || mode == 3; || mode == 0 || mode == 3;
HtmlAttributes clone = new HtmlAttributes(0); HtmlAttributes clone = new HtmlAttributes(0);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
clone.addAttribute(names[i].cloneAttributeName(interner), clone.addAttribute(names[i],
Portability.newStringFromString(values[i]) values[i]
// [NOCPP[
, XmlViolationPolicy.ALLOW , XmlViolationPolicy.ALLOW
// ]NOCPP]
// CPPONLY: , lines[i]
); );
} }
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) { for (int i = 0; i < xmlnsLength; i++) {
clone.addAttribute(xmlnsNames[i], xmlnsValues[i], clone.addAttribute(xmlnsNames[i], xmlnsValues[i],
XmlViolationPolicy.ALLOW); XmlViolationPolicy.ALLOW);
} }
// ]NOCPP]
return clone; // XXX!!! return clone; // XXX!!!
} }
@ -568,9 +473,10 @@ public final class HtmlAttributes implements Attributes {
for (int j = 0; j < otherLength; j++) { for (int j = 0; j < otherLength; j++) {
if (ownLocal == other.names[j].getLocal(AttributeName.HTML)) { if (ownLocal == other.names[j].getLocal(AttributeName.HTML)) {
found = true; found = true;
if (!Portability.stringEqualsString(values[i], other.values[j])) { if (!values[i].equals(other.values[j])) {
return false; return false;
} }
break;
} }
} }
if (!found) { if (!found) {
@ -579,9 +485,7 @@ public final class HtmlAttributes implements Attributes {
} }
return true; return true;
} }
// [NOCPP[
void processNonNcNames(TreeBuilder<?> treeBuilder, XmlViolationPolicy namePolicy) throws SAXException { void processNonNcNames(TreeBuilder<?> treeBuilder, XmlViolationPolicy namePolicy) throws SAXException {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
AttributeName attName = names[i]; AttributeName attName = names[i];
@ -613,8 +517,4 @@ public final class HtmlAttributes implements Attributes {
} }
} }
} }
// ]NOCPP]
} }

View file

@ -434,6 +434,8 @@ public class Tokenizer implements Locator {
*/ */
protected AttributeName attributeName = null; protected AttributeName attributeName = null;
// CPPONLY: private AttributeName nonInternedAttributeName = null;
// [NOCPP[ // [NOCPP[
/** /**
@ -530,6 +532,7 @@ public class Tokenizer implements Locator {
this.tagName = null; this.tagName = null;
this.nonInternedTagName = new ElementName(); this.nonInternedTagName = new ElementName();
this.attributeName = null; this.attributeName = null;
// CPPONLY: this.nonInternedAttributeName = new AttributeName();
this.doctypeName = null; this.doctypeName = null;
this.publicIdentifier = null; this.publicIdentifier = null;
this.systemIdentifier = null; this.systemIdentifier = null;
@ -560,6 +563,7 @@ public class Tokenizer implements Locator {
this.tagName = null; this.tagName = null;
this.nonInternedTagName = new ElementName(); this.nonInternedTagName = new ElementName();
this.attributeName = null; this.attributeName = null;
// CPPONLY: this.nonInternedAttributeName = new AttributeName();
this.doctypeName = null; this.doctypeName = null;
this.publicIdentifier = null; this.publicIdentifier = null;
this.systemIdentifier = null; this.systemIdentifier = null;
@ -1174,11 +1178,17 @@ public class Tokenizer implements Locator {
} }
private void attributeNameComplete() throws SAXException { private void attributeNameComplete() throws SAXException {
attributeName = AttributeName.nameByBuffer(strBuf, 0, strBufLen attributeName = AttributeName.nameByBuffer(strBuf, 0, strBufLen, interner);
// [NOCPP[ if (attributeName == null) {
, namePolicy != XmlViolationPolicy.ALLOW // [NOCPP[
// ]NOCPP] attributeName = AttributeName.createAttributeName(
, interner); Portability.newLocalNameFromBuffer(strBuf, 0, strBufLen,
interner),
namePolicy != XmlViolationPolicy.ALLOW);
// ]NOCPP]
// CPPONLY: nonInternedAttributeName.setNameForNonInterned(Portability.newLocalNameFromBuffer(strBuf, 0, strBufLen, interner));
// CPPONLY: attributeName = nonInternedAttributeName;
}
clearStrBufAfterUse(); clearStrBufAfterUse();
if (attributes == null) { if (attributes == null) {
@ -1195,7 +1205,6 @@ public class Tokenizer implements Locator {
*/ */
if (attributes.contains(attributeName)) { if (attributes.contains(attributeName)) {
errDuplicateAttribute(); errDuplicateAttribute();
attributeName.release();
attributeName = null; attributeName = null;
} }
} }
@ -1244,8 +1253,7 @@ public class Tokenizer implements Locator {
// [NOCPP[ // [NOCPP[
} }
// ]NOCPP] // ]NOCPP]
attributeName = null; // attributeName has been adopted by the attributeName = null;
// |attributes| object
} else { } else {
clearStrBufAfterUse(); clearStrBufAfterUse();
} }
@ -1276,8 +1284,7 @@ public class Tokenizer implements Locator {
// ]NOCPP] // ]NOCPP]
// CPPONLY: , attributeLine // CPPONLY: , attributeLine
); );
attributeName = null; // attributeName has been adopted by the attributeName = null;
// |attributes| object
} else { } else {
// We have a duplicate attribute. Explicitly discard its value. // We have a duplicate attribute. Explicitly discard its value.
clearStrBufAfterUse(); clearStrBufAfterUse();
@ -6667,10 +6674,8 @@ public class Tokenizer implements Locator {
} }
tagName = null; tagName = null;
nonInternedTagName.setNameForNonInterned(null); nonInternedTagName.setNameForNonInterned(null);
if (attributeName != null) { attributeName = null;
attributeName.release(); // CPPONLY: nonInternedAttributeName.setNameForNonInterned(null);
attributeName = null;
}
tokenHandler.endTokenization(); tokenHandler.endTokenization();
if (attributes != null) { if (attributes != null) {
// [NOCPP[ // [NOCPP[
@ -6747,13 +6752,8 @@ public class Tokenizer implements Locator {
endTag = false; endTag = false;
shouldSuspend = false; shouldSuspend = false;
initDoctypeFields(); initDoctypeFields();
if (tagName != null) { tagName = null;
tagName = null; attributeName = null;
}
if (attributeName != null) {
attributeName.release();
attributeName = null;
}
if (newAttributesEachTime) { if (newAttributesEachTime) {
if (attributes != null) { if (attributes != null) {
Portability.delete(attributes); Portability.delete(attributes);
@ -6818,22 +6818,27 @@ public class Tokenizer implements Locator {
} else if (other.tagName.isInterned()) { } else if (other.tagName.isInterned()) {
tagName = other.tagName; tagName = other.tagName;
} else { } else {
// In the C++ case, We might be loading state from another // In the C++ case, the atoms in the other tokenizer are from a
// tokenizer that has atoms from a different tokenizer-scoped // different tokenizer-scoped atom table. Therefore, we have to
// atom table. Therefore, we have to obtain the correspoding // obtain the correspoding atom from our own atom table.
// atom from our own atom table.
nonInternedTagName.setNameForNonInterned(Portability.newLocalFromLocal(other.tagName.getName(), interner)); nonInternedTagName.setNameForNonInterned(Portability.newLocalFromLocal(other.tagName.getName(), interner));
tagName = nonInternedTagName; tagName = nonInternedTagName;
} }
if (attributeName != null) { // [NOCPP[
attributeName.release(); attributeName = other.attributeName;
} // ]NOCPP]
if (other.attributeName == null) { // CPPONLY: if (other.attributeName == null) {
attributeName = null; // CPPONLY: attributeName = null;
} else { // CPPONLY: } else if (other.attributeName.isInterned()) {
attributeName = other.attributeName.cloneAttributeName(interner); // CPPONLY: attributeName = other.attributeName;
} // CPPONLY: } else {
// CPPONLY: // In the C++ case, the atoms in the other tokenizer are from a
// CPPONLY: // different tokenizer-scoped atom table. Therefore, we have to
// CPPONLY: // obtain the correspoding atom from our own atom table.
// CPPONLY: nonInternedAttributeName.setNameForNonInterned(Portability.newLocalFromLocal(other.attributeName.getLocal(AttributeName.HTML), interner));
// CPPONLY: attributeName = nonInternedAttributeName;
// CPPONLY: }
Portability.delete(attributes); Portability.delete(attributes);
if (other.attributes == null) { if (other.attributes == null) {
@ -7075,6 +7080,7 @@ public class Tokenizer implements Locator {
void destructor() { void destructor() {
Portability.delete(nonInternedTagName); Portability.delete(nonInternedTagName);
// CPPONLY: Portability.delete(nonInternedAttributeName);
nonInternedTagName = null; nonInternedTagName = null;
// The translator will write refcount tracing stuff here // The translator will write refcount tracing stuff here
Portability.delete(attributes); Portability.delete(attributes);

View file

@ -2326,85 +2326,74 @@ public abstract class TreeBuilder<T> implements TokenHandler,
selfClosing = false; selfClosing = false;
attributes = null; // CPP attributes = null; // CPP
break starttagloop; break starttagloop;
case ISINDEX: // CPPONLY:case ISINDEX:
errIsindex(); // CPPONLY: errIsindex();
if (formPointer != null && !isTemplateContents()) { // CPPONLY: if (formPointer != null && !isTemplateContents()) {
break starttagloop; // CPPONLY: break starttagloop;
} // CPPONLY: }
implicitlyCloseP(); // CPPONLY: implicitlyCloseP();
HtmlAttributes formAttrs = new HtmlAttributes(0); // CPPONLY: HtmlAttributes formAttrs = new HtmlAttributes(0);
int actionIndex = attributes.getIndex(AttributeName.ACTION); // CPPONLY: int actionIndex = attributes.getIndex(AttributeName.ACTION);
if (actionIndex > -1) { // CPPONLY: if (actionIndex > -1) {
formAttrs.addAttribute( // CPPONLY: formAttrs.addAttribute(
AttributeName.ACTION, // CPPONLY: AttributeName.ACTION,
attributes.getValueNoBoundsCheck(actionIndex) // CPPONLY: attributes.getValueNoBoundsCheck(actionIndex),
// [NOCPP[ // CPPONLY: attributes.getLineNoBoundsCheck(actionIndex)
, XmlViolationPolicy.ALLOW // CPPONLY: );
// ]NOCPP] // CPPONLY: }
// CPPONLY: , attributes.getLineNoBoundsCheck(actionIndex) // CPPONLY: appendToCurrentNodeAndPushFormElementMayFoster(formAttrs);
); // CPPONLY: appendVoidElementToCurrentMayFoster(
} // CPPONLY: ElementName.HR,
appendToCurrentNodeAndPushFormElementMayFoster(formAttrs); // CPPONLY: HtmlAttributes.EMPTY_ATTRIBUTES);
appendVoidElementToCurrentMayFoster( // CPPONLY: appendToCurrentNodeAndPushElementMayFoster(
ElementName.HR, // CPPONLY: ElementName.LABEL,
HtmlAttributes.EMPTY_ATTRIBUTES); // CPPONLY: HtmlAttributes.EMPTY_ATTRIBUTES);
appendToCurrentNodeAndPushElementMayFoster( // CPPONLY: int promptIndex = attributes.getIndex(AttributeName.PROMPT);
ElementName.LABEL, // CPPONLY: if (promptIndex > -1) {
HtmlAttributes.EMPTY_ATTRIBUTES); // CPPONLY: @Auto char[] prompt = Portability.newCharArrayFromString(attributes.getValueNoBoundsCheck(promptIndex));
int promptIndex = attributes.getIndex(AttributeName.PROMPT); // CPPONLY: appendCharacters(stack[currentPtr].node,
if (promptIndex > -1) { // CPPONLY: prompt, 0, prompt.length);
@Auto char[] prompt = Portability.newCharArrayFromString(attributes.getValueNoBoundsCheck(promptIndex)); // CPPONLY: } else {
appendCharacters(stack[currentPtr].node, // CPPONLY: appendIsindexPrompt(stack[currentPtr].node);
prompt, 0, prompt.length); // CPPONLY: }
} else { // CPPONLY: HtmlAttributes inputAttributes = new HtmlAttributes(
appendIsindexPrompt(stack[currentPtr].node); // CPPONLY: 0);
} // CPPONLY: inputAttributes.addAttribute(
HtmlAttributes inputAttributes = new HtmlAttributes( // CPPONLY: AttributeName.NAME,
0); // CPPONLY: Portability.newStringFromLiteral("isindex"),
inputAttributes.addAttribute( // CPPONLY: tokenizer.getLineNumber()
AttributeName.NAME, // CPPONLY: );
Portability.newStringFromLiteral("isindex") // CPPONLY: for (int i = 0; i < attributes.getLength(); i++) {
// [NOCPP[ // CPPONLY: @Local String attributeQName = attributes.getLocalNameNoBoundsCheck(i);
, XmlViolationPolicy.ALLOW // CPPONLY: if ("name" == attributeQName
// ]NOCPP] // CPPONLY: || "prompt" == attributeQName) {
// CPPONLY: , tokenizer.getLineNumber() // CPPONLY: attributes.releaseValue(i);
); // CPPONLY: } else if ("action" != attributeQName) {
for (int i = 0; i < attributes.getLength(); i++) { // CPPONLY: inputAttributes.AddAttributeWithLocal(
AttributeName attributeQName = attributes.getAttributeNameNoBoundsCheck(i); // CPPONLY: attributeQName,
if (AttributeName.NAME == attributeQName // CPPONLY: attributes.getValueNoBoundsCheck(i),
|| AttributeName.PROMPT == attributeQName) { // CPPONLY: attributes.getLineNoBoundsCheck(i)
attributes.releaseValue(i); // CPPONLY: );
} else if (AttributeName.ACTION != attributeQName) { // CPPONLY: }
inputAttributes.addAttribute( // CPPONLY: }
attributeQName, // CPPONLY: attributes.clearWithoutReleasingContents();
attributes.getValueNoBoundsCheck(i) // CPPONLY: appendVoidElementToCurrentMayFoster(
// [NOCPP[ // CPPONLY: "input",
, XmlViolationPolicy.ALLOW // CPPONLY: inputAttributes, formPointer);
// ]NOCPP] // CPPONLY: pop(); // label
// CPPONLY: , attributes.getLineNoBoundsCheck(i) // CPPONLY: appendVoidElementToCurrentMayFoster(
); // CPPONLY: ElementName.HR,
} // CPPONLY: HtmlAttributes.EMPTY_ATTRIBUTES);
} // CPPONLY: pop(); // form
attributes.clearWithoutReleasingContents(); // CPPONLY:
appendVoidElementToCurrentMayFoster( // CPPONLY: if (!isTemplateContents()) {
"input", // CPPONLY: formPointer = null;
inputAttributes, formPointer); // CPPONLY: }
pop(); // label // CPPONLY:
appendVoidElementToCurrentMayFoster( // CPPONLY: selfClosing = false;
ElementName.HR, // CPPONLY: // Don't delete attributes, they are deleted
HtmlAttributes.EMPTY_ATTRIBUTES); // CPPONLY: // later
pop(); // form // CPPONLY: break starttagloop;
if (!isTemplateContents()) {
formPointer = null;
}
selfClosing = false;
// Portability.delete(formAttrs);
// Portability.delete(inputAttributes);
// Don't delete attributes, they are deleted
// later
break starttagloop;
case TEXTAREA: case TEXTAREA:
appendToCurrentNodeAndPushElementMayFoster( appendToCurrentNodeAndPushElementMayFoster(
elementName, elementName,
@ -3837,7 +3826,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
case INPUT: case INPUT:
case KEYGEN: // XXX?? case KEYGEN: // XXX??
case HR: case HR:
case ISINDEX: // CPPONLY: case ISINDEX:
case IFRAME: case IFRAME:
case NOEMBED: // XXX??? case NOEMBED: // XXX???
case NOFRAMES: // XXX?? case NOFRAMES: // XXX??
@ -5681,7 +5670,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
protected abstract void appendCharacters(T parent, @NoLength char[] buf, protected abstract void appendCharacters(T parent, @NoLength char[] buf,
int start, int length) throws SAXException; int start, int length) throws SAXException;
protected abstract void appendIsindexPrompt(T parent) throws SAXException; // CPPONLY: protected abstract void appendIsindexPrompt(T parent) throws SAXException;
protected abstract void appendComment(T parent, @NoLength char[] buf, protected abstract void appendComment(T parent, @NoLength char[] buf,
int start, int length) throws SAXException; int start, int length) throws SAXException;
@ -6377,9 +6366,9 @@ public abstract class TreeBuilder<T> implements TokenHandler,
err("Saw a start tag \u201Cimage\u201D."); err("Saw a start tag \u201Cimage\u201D.");
} }
private void errIsindex() throws SAXException { // CPPONLY: private void errIsindex() throws SAXException {
err("\u201Cisindex\u201D seen."); // CPPONLY: err("\u201Cisindex\u201D seen.");
} // CPPONLY: }
private void errFooSeenWhenFooOpen(@Local String name) throws SAXException { private void errFooSeenWhenFooOpen(@Local String name) throws SAXException {
if (errorHandler == null) { if (errorHandler == null) {

View file

@ -23,26 +23,24 @@
package nu.validator.htmlparser.sax; package nu.validator.htmlparser.sax;
import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.TreeBuilder;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException; import org.xml.sax.SAXParseException;
import org.xml.sax.ext.LexicalHandler; import org.xml.sax.ext.LexicalHandler;
class SAXStreamer extends TreeBuilder<Attributes>{ import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.TreeBuilder;
private static final char[] ISINDEX_PROMPT = "This is a searchable index. Enter search keywords: ".toCharArray(); class SAXStreamer extends TreeBuilder<Attributes>{
private ContentHandler contentHandler = null; private ContentHandler contentHandler = null;
private LexicalHandler lexicalHandler = null; private LexicalHandler lexicalHandler = null;
SAXStreamer() { SAXStreamer() {
super(); super();
} }
@Override @Override
protected void addAttributesToElement(Attributes element, HtmlAttributes attributes) throws SAXException { protected void addAttributesToElement(Attributes element, HtmlAttributes attributes) throws SAXException {
Attributes existingAttrs = element; Attributes existingAttrs = element;
@ -59,14 +57,6 @@ class SAXStreamer extends TreeBuilder<Attributes>{
contentHandler.characters(buf, start, length); contentHandler.characters(buf, start, length);
} }
/**
* @see nu.validator.htmlparser.impl.TreeBuilder#appendIsindexPrompt(java.lang.Object)
*/
@Override protected void appendIsindexPrompt(Attributes parent)
throws SAXException {
contentHandler.characters(ISINDEX_PROMPT, 0, ISINDEX_PROMPT.length);
}
@Override @Override
protected void appendChildrenToNewParent(Attributes oldParent, Attributes newParent) throws SAXException { protected void appendChildrenToNewParent(Attributes oldParent, Attributes newParent) throws SAXException {
fatal(); fatal();

View file

@ -23,6 +23,8 @@
package nu.validator.htmlparser.sax; package nu.validator.htmlparser.sax;
import org.xml.sax.SAXException;
import nu.validator.htmlparser.impl.HtmlAttributes; import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.TreeBuilder; import nu.validator.htmlparser.impl.TreeBuilder;
import nu.validator.saxtree.Characters; import nu.validator.saxtree.Characters;
@ -34,12 +36,8 @@ import nu.validator.saxtree.Element;
import nu.validator.saxtree.Node; import nu.validator.saxtree.Node;
import nu.validator.saxtree.ParentNode; import nu.validator.saxtree.ParentNode;
import org.xml.sax.SAXException;
class SAXTreeBuilder extends TreeBuilder<Element> { class SAXTreeBuilder extends TreeBuilder<Element> {
private static final char[] ISINDEX_PROMPT = "This is a searchable index. Enter search keywords: ".toCharArray();
private Document document; private Document document;
private Node cachedTable = null; private Node cachedTable = null;
@ -65,14 +63,6 @@ class SAXTreeBuilder extends TreeBuilder<Element> {
parent.appendChild(new Characters(tokenizer, buf, start, length)); parent.appendChild(new Characters(tokenizer, buf, start, length));
} }
/**
* @see nu.validator.htmlparser.impl.TreeBuilder#appendIsindexPrompt(java.lang.Object)
*/
@Override protected void appendIsindexPrompt(Element parent)
throws SAXException {
parent.appendChild(new Characters(tokenizer, ISINDEX_PROMPT, 0, ISINDEX_PROMPT.length));
}
@Override @Override
protected boolean hasChildren(Element element) { protected boolean hasChildren(Element element) {
return element.getFirstChild() != null; return element.getFirstChild() != null;

View file

@ -448,13 +448,6 @@ public class CppVisitor extends AnnotationHelperVisitor<LocalSymbolTable> {
printer.print("#include \""); printer.print("#include \"");
printer.print(className); printer.print(className);
printer.printLn(".h\""); printer.printLn(".h\"");
if ("AttributeName".equals(javaClassName)) {
printer.print("#include \"");
printer.print(cppTypes.classPrefix());
printer.print("Releasable");
printer.print(javaClassName);
printer.printLn(".h\"");
}
printer.printLn(); printer.printLn();
} }
@ -1386,18 +1379,12 @@ public class CppVisitor extends AnnotationHelperVisitor<LocalSymbolTable> {
suppressPointer = true; suppressPointer = true;
printTypeArgs(n.getTypeArgs(), arg); printTypeArgs(n.getTypeArgs(), arg);
if ("createAttributeName".equals(currentMethod)) { n.getType().accept(this, arg);
printer.print(cppTypes.classPrefix());
printer.print("Releasable");
printer.print(n.getType().getName());
} else {
n.getType().accept(this, arg);
}
suppressPointer = false; suppressPointer = false;
if ("AttributeName".equals(n.getType().getName())) { if ("AttributeName".equals(n.getType().getName())) {
List<Expression> args = n.getArgs(); List<Expression> args = n.getArgs();
while (args.size() > 3) { while (args != null && args.size() > 3) {
args.remove(3); args.remove(3);
} }
} }

View file

@ -37,19 +37,18 @@
package nu.validator.htmlparser.cpptranslate; package nu.validator.htmlparser.cpptranslate;
import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;
public class Main { public class Main {
static final String[] H_LIST = { static final String[] H_LIST = {
@ -58,7 +57,6 @@ public class Main {
"MetaScanner", "MetaScanner",
"AttributeName", "AttributeName",
"ElementName", "ElementName",
"HtmlAttributes",
"StackNode", "StackNode",
"UTF16Buffer", "UTF16Buffer",
"StateSnapshot", "StateSnapshot",
@ -71,7 +69,6 @@ public class Main {
"MetaScanner", "MetaScanner",
"AttributeName", "AttributeName",
"ElementName", "ElementName",
"HtmlAttributes",
"StackNode", "StackNode",
"UTF16Buffer", "UTF16Buffer",
"StateSnapshot", "StateSnapshot",