Source code
Revision control
Copy as Markdown
Other Tools
/*
* Copyright (c) 2005-2007 Henri Sivonen
* Copyright (c) 2007-2017 Mozilla Foundation
* Portions of comments Copyright 2004-2010 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.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit Tokenizer.java instead and regenerate.
*/
#define nsHtml5Tokenizer_cpp__
#include "nsHtml5AttributeName.h"
#include "nsHtml5ElementName.h"
#include "nsHtml5TreeBuilder.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5Tokenizer.h"
#include "nsHtml5TokenizerLoopPolicies.h"
char16_t nsHtml5Tokenizer::LT_GT[] = {'<', '>'};
char16_t nsHtml5Tokenizer::LT_SOLIDUS[] = {'<', '/'};
char16_t nsHtml5Tokenizer::RSQB_RSQB[] = {']', ']'};
char16_t nsHtml5Tokenizer::REPLACEMENT_CHARACTER[] = {0xfffd};
char16_t nsHtml5Tokenizer::LF[] = {'\n'};
char16_t nsHtml5Tokenizer::CDATA_LSQB[] = {'C', 'D', 'A', 'T', 'A', '['};
char16_t nsHtml5Tokenizer::OCTYPE[] = {'o', 'c', 't', 'y', 'p', 'e'};
char16_t nsHtml5Tokenizer::UBLIC[] = {'u', 'b', 'l', 'i', 'c'};
char16_t nsHtml5Tokenizer::YSTEM[] = {'y', 's', 't', 'e', 'm'};
static char16_t const TITLE_ARR_DATA[] = {'t', 'i', 't', 'l', 'e'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::TITLE_ARR = {
TITLE_ARR_DATA, std::size(TITLE_ARR_DATA)};
static char16_t const SCRIPT_ARR_DATA[] = {'s', 'c', 'r', 'i', 'p', 't'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::SCRIPT_ARR = {
SCRIPT_ARR_DATA, std::size(SCRIPT_ARR_DATA)};
static char16_t const STYLE_ARR_DATA[] = {'s', 't', 'y', 'l', 'e'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::STYLE_ARR = {
STYLE_ARR_DATA, std::size(STYLE_ARR_DATA)};
static char16_t const PLAINTEXT_ARR_DATA[] = {'p', 'l', 'a', 'i', 'n',
't', 'e', 'x', 't'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::PLAINTEXT_ARR = {
PLAINTEXT_ARR_DATA, std::size(PLAINTEXT_ARR_DATA)};
static char16_t const XMP_ARR_DATA[] = {'x', 'm', 'p'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::XMP_ARR = {
XMP_ARR_DATA, std::size(XMP_ARR_DATA)};
static char16_t const TEXTAREA_ARR_DATA[] = {'t', 'e', 'x', 't',
'a', 'r', 'e', 'a'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::TEXTAREA_ARR = {
TEXTAREA_ARR_DATA, std::size(TEXTAREA_ARR_DATA)};
static char16_t const IFRAME_ARR_DATA[] = {'i', 'f', 'r', 'a', 'm', 'e'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::IFRAME_ARR = {
IFRAME_ARR_DATA, std::size(IFRAME_ARR_DATA)};
static char16_t const NOEMBED_ARR_DATA[] = {'n', 'o', 'e', 'm', 'b', 'e', 'd'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::NOEMBED_ARR = {
NOEMBED_ARR_DATA, std::size(NOEMBED_ARR_DATA)};
static char16_t const NOSCRIPT_ARR_DATA[] = {'n', 'o', 's', 'c',
'r', 'i', 'p', 't'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::NOSCRIPT_ARR = {
NOSCRIPT_ARR_DATA, std::size(NOSCRIPT_ARR_DATA)};
static char16_t const NOFRAMES_ARR_DATA[] = {'n', 'o', 'f', 'r',
'a', 'm', 'e', 's'};
staticJArray<char16_t, int32_t> nsHtml5Tokenizer::NOFRAMES_ARR = {
NOFRAMES_ARR_DATA, std::size(NOFRAMES_ARR_DATA)};
nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler,
bool viewingXmlSource)
: tokenHandler(tokenHandler),
encodingDeclarationHandler(nullptr),
lastCR(false),
stateSave(0),
returnStateSave(0),
index(0),
forceQuirks(false),
additional('\0'),
entCol(0),
firstCharKey(0),
lo(0),
hi(0),
candidate(0),
charRefBufMark(0),
value(0),
seenDigits(false),
suspendAfterCurrentNonTextToken(false),
cstart(0),
strBufLen(0),
charRefBuf(jArray<char16_t, int32_t>::newJArray(32)),
charRefBufLen(0),
bmpChar(jArray<char16_t, int32_t>::newJArray(1)),
astralChar(jArray<char16_t, int32_t>::newJArray(2)),
endTagExpectation(nullptr),
endTagExpectationAsArray(nullptr),
endTag(false),
containsHyphen(false),
tagName(nullptr),
nonInternedTagName(new nsHtml5ElementName()),
attributeName(nullptr),
nonInternedAttributeName(new nsHtml5AttributeName()),
doctypeName(nullptr),
publicIdentifier(nullptr),
systemIdentifier(nullptr),
attributes(tokenHandler->HasBuilder() ? new nsHtml5HtmlAttributes(0)
: nullptr),
newAttributesEachTime(!tokenHandler->HasBuilder()),
shouldSuspend(false),
keepBuffer(false),
confident(false),
line(0),
attributeLine(0),
interner(nullptr),
viewingXmlSource(viewingXmlSource) {
MOZ_COUNT_CTOR(nsHtml5Tokenizer);
}
void nsHtml5Tokenizer::setInterner(nsHtml5AtomTable* interner) {
this->interner = interner;
}
void nsHtml5Tokenizer::initLocation(nsHtml5String newPublicId,
nsHtml5String newSystemId) {
this->systemId = newSystemId;
this->publicId = newPublicId;
}
bool nsHtml5Tokenizer::isViewingXmlSource() { return viewingXmlSource; }
void nsHtml5Tokenizer::setKeepBuffer(bool keepBuffer) {
this->keepBuffer = keepBuffer;
}
bool nsHtml5Tokenizer::dropBufferIfLongerThan(int32_t length) {
if (strBuf.length > length) {
strBuf = nullptr;
return true;
}
return false;
}
void nsHtml5Tokenizer::setState(int32_t specialTokenizerState) {
this->stateSave = specialTokenizerState;
this->endTagExpectation = nullptr;
this->endTagExpectationAsArray = nullptr;
}
void nsHtml5Tokenizer::setStateAndEndTagExpectation(
int32_t specialTokenizerState, nsHtml5ElementName* endTagExpectation) {
this->stateSave = specialTokenizerState;
this->endTagExpectation = endTagExpectation;
endTagExpectationToArray();
}
void nsHtml5Tokenizer::endTagExpectationToArray() {
switch (endTagExpectation->getGroup()) {
case nsHtml5TreeBuilder::TITLE: {
endTagExpectationAsArray = TITLE_ARR;
return;
}
case nsHtml5TreeBuilder::SCRIPT: {
endTagExpectationAsArray = SCRIPT_ARR;
return;
}
case nsHtml5TreeBuilder::STYLE: {
endTagExpectationAsArray = STYLE_ARR;
return;
}
case nsHtml5TreeBuilder::PLAINTEXT: {
endTagExpectationAsArray = PLAINTEXT_ARR;
return;
}
case nsHtml5TreeBuilder::XMP: {
endTagExpectationAsArray = XMP_ARR;
return;
}
case nsHtml5TreeBuilder::TEXTAREA: {
endTagExpectationAsArray = TEXTAREA_ARR;
return;
}
case nsHtml5TreeBuilder::IFRAME: {
endTagExpectationAsArray = IFRAME_ARR;
return;
}
case nsHtml5TreeBuilder::NOEMBED: {
endTagExpectationAsArray = NOEMBED_ARR;
return;
}
case nsHtml5TreeBuilder::NOSCRIPT: {
endTagExpectationAsArray = NOSCRIPT_ARR;
return;
}
case nsHtml5TreeBuilder::NOFRAMES: {
endTagExpectationAsArray = NOFRAMES_ARR;
return;
}
default: {
MOZ_ASSERT(false, "Bad end tag expectation.");
return;
}
}
}
void nsHtml5Tokenizer::setLineNumber(int32_t line) {
this->attributeLine = line;
this->line = line;
}
nsHtml5HtmlAttributes* nsHtml5Tokenizer::emptyAttributes() {
return nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES;
}
void nsHtml5Tokenizer::emitOrAppendCharRefBuf(int32_t returnState) {
if ((returnState & DATA_AND_RCDATA_MASK)) {
appendCharRefBufToStrBuf();
} else {
if (charRefBufLen > 0) {
tokenHandler->characters(charRefBuf, 0, charRefBufLen);
charRefBufLen = 0;
}
}
}
nsHtml5String nsHtml5Tokenizer::strBufToString() {
nsHtml5String str = nsHtml5Portability::newStringFromBuffer(
strBuf, 0, strBufLen, tokenHandler,
!newAttributesEachTime &&
attributeName == nsHtml5AttributeName::ATTR_CLASS);
clearStrBufAfterUse();
return str;
}
void nsHtml5Tokenizer::strBufToDoctypeName() {
doctypeName =
nsHtml5Portability::newLocalNameFromBuffer(strBuf, strBufLen, interner);
clearStrBufAfterUse();
}
void nsHtml5Tokenizer::emitStrBuf() {
if (strBufLen > 0) {
tokenHandler->characters(strBuf, 0, strBufLen);
clearStrBufAfterUse();
}
}
void nsHtml5Tokenizer::appendStrBuf(char16_t* buffer, int32_t offset,
int32_t length) {
int32_t newLen = nsHtml5Portability::checkedAdd(strBufLen, length);
MOZ_ASSERT(newLen <= strBuf.length, "Previous buffer length insufficient.");
if (MOZ_UNLIKELY(strBuf.length < newLen)) {
if (MOZ_UNLIKELY(!EnsureBufferSpace(length))) {
MOZ_CRASH("Unable to recover from buffer reallocation failure");
}
}
nsHtml5ArrayCopy::arraycopy(buffer, offset, strBuf, strBufLen, length);
strBufLen = newLen;
}
void nsHtml5Tokenizer::emitComment(int32_t provisionalHyphens, int32_t pos) {
RememberGt(pos);
tokenHandler->comment(strBuf, 0, strBufLen - provisionalHyphens);
clearStrBufAfterUse();
cstart = pos + 1;
suspendIfRequestedAfterCurrentNonTextToken();
}
void nsHtml5Tokenizer::flushChars(char16_t* buf, int32_t pos) {
if (pos > cstart) {
tokenHandler->characters(buf, cstart, pos - cstart);
}
cstart = INT32_MAX;
}
void nsHtml5Tokenizer::strBufToElementNameString() {
if (containsHyphen) {
nsAtom* annotationName = nsHtml5ElementName::ELT_ANNOTATION_XML->getName();
if (nsHtml5Portability::localEqualsBuffer(annotationName, strBuf,
strBufLen)) {
tagName = nsHtml5ElementName::ELT_ANNOTATION_XML;
} else {
nonInternedTagName->setNameForNonInterned(
nsHtml5Portability::newLocalNameFromBuffer(strBuf, strBufLen,
interner),
true);
tagName = nonInternedTagName;
}
} else {
tagName = nsHtml5ElementName::elementNameByBuffer(strBuf, strBufLen);
if (!tagName) {
nonInternedTagName->setNameForNonInterned(
nsHtml5Portability::newLocalNameFromBuffer(strBuf, strBufLen,
interner),
false);
tagName = nonInternedTagName;
}
}
containsHyphen = false;
clearStrBufAfterUse();
}
int32_t nsHtml5Tokenizer::emitCurrentTagToken(bool selfClosing, int32_t pos) {
RememberGt(pos);
cstart = pos + 1;
maybeErrSlashInEndTag(selfClosing);
stateSave = nsHtml5Tokenizer::DATA;
nsHtml5HtmlAttributes* attrs =
(!attributes ? nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES : attributes);
if (endTag) {
maybeErrAttributesOnEndTag(attrs);
if (!viewingXmlSource) {
tokenHandler->endTag(tagName);
}
if (newAttributesEachTime) {
delete attributes;
attributes = nullptr;
}
} else {
if (viewingXmlSource) {
MOZ_ASSERT(newAttributesEachTime);
delete attributes;
attributes = nullptr;
} else {
tokenHandler->startTag(tagName, attrs, selfClosing);
}
}
tagName = nullptr;
if (newAttributesEachTime) {
attributes = nullptr;
} else {
attributes->clear(0);
}
suspendIfRequestedAfterCurrentNonTextToken();
return stateSave;
}
void nsHtml5Tokenizer::attributeNameComplete() {
attributeName =
nsHtml5AttributeName::nameByBuffer(strBuf, strBufLen, interner);
if (!attributeName) {
nonInternedAttributeName->setNameForNonInterned(
nsHtml5Portability::newLocalNameFromBuffer(strBuf, strBufLen,
interner));
attributeName = nonInternedAttributeName;
}
clearStrBufAfterUse();
if (!attributes) {
attributes = new nsHtml5HtmlAttributes(0);
}
if (attributes->contains(attributeName)) {
errDuplicateAttribute();
attributeName = nullptr;
}
}
void nsHtml5Tokenizer::addAttributeWithoutValue() {
if (attributeName) {
attributes->addAttribute(
attributeName, nsHtml5Portability::newEmptyString(), attributeLine);
attributeName = nullptr;
} else {
clearStrBufAfterUse();
}
}
void nsHtml5Tokenizer::addAttributeWithValue() {
if (attributeName) {
nsHtml5String val = strBufToString();
if (mViewSource) {
mViewSource->MaybeLinkifyAttributeValue(attributeName, val);
}
attributes->addAttribute(attributeName, val, attributeLine);
attributeName = nullptr;
} else {
clearStrBufAfterUse();
}
}
void nsHtml5Tokenizer::start() {
initializeWithoutStarting();
tokenHandler->startTokenization(this);
if (mViewSource) {
line = 1;
col = -1;
nextCharOnNewLine = false;
} else if (tokenHandler->WantsLineAndColumn()) {
line = 0;
col = 1;
nextCharOnNewLine = true;
} else {
line = -1;
col = -1;
nextCharOnNewLine = false;
}
}
bool nsHtml5Tokenizer::tokenizeBuffer(nsHtml5UTF16Buffer* buffer) {
int32_t state = stateSave;
int32_t returnState = returnStateSave;
char16_t c = '\0';
shouldSuspend = false;
lastCR = false;
int32_t start = buffer->getStart();
int32_t end = buffer->getEnd();
int32_t pos = start - 1;
switch (state) {
case DATA:
case RCDATA:
case SCRIPT_DATA:
case PLAINTEXT:
case RAWTEXT:
case CDATA_SECTION:
case SCRIPT_DATA_ESCAPED:
case SCRIPT_DATA_ESCAPE_START:
case SCRIPT_DATA_ESCAPE_START_DASH:
case SCRIPT_DATA_ESCAPED_DASH:
case SCRIPT_DATA_ESCAPED_DASH_DASH:
case SCRIPT_DATA_DOUBLE_ESCAPE_START:
case SCRIPT_DATA_DOUBLE_ESCAPED:
case SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN:
case SCRIPT_DATA_DOUBLE_ESCAPED_DASH:
case SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH:
case SCRIPT_DATA_DOUBLE_ESCAPE_END: {
cstart = start;
break;
}
default: {
cstart = INT32_MAX;
break;
}
}
if (mViewSource) {
mViewSource->SetBuffer(buffer);
pos = stateLoop<nsHtml5ViewSourcePolicy>(state, c, pos, buffer->getBuffer(),
false, returnState,
buffer->getEnd());
mViewSource->DropBuffer((pos == buffer->getEnd()) ? pos : pos + 1);
} else if (tokenHandler->WantsLineAndColumn()) {
pos = stateLoop<nsHtml5LineColPolicy>(state, c, pos, buffer->getBuffer(),
false, returnState, buffer->getEnd());
} else {
pos = stateLoop<nsHtml5FastestPolicy>(state, c, pos, buffer->getBuffer(),
false, returnState, buffer->getEnd());
}
if (pos == end) {
buffer->setStart(pos);
} else {
buffer->setStart(pos + 1);
}
return lastCR;
}
template <class P>
int32_t nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos,
char16_t* buf, bool reconsume,
int32_t returnState, int32_t endPos) {
bool reportedConsecutiveHyphens = false;
stateloop:
for (;;) {
switch (state) {
case DATA: {
for (;;) {
if (reconsume) {
reconsume = false;
} else {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
}
switch (c) {
case '&': {
flushChars(buf, pos);
MOZ_ASSERT(!charRefBufLen,
"charRefBufLen not reset after previous use!");
appendCharRefBuf(c);
setAdditionalAndRememberAmpersandLocation('\0');
returnState = state;
state =
P::transition(mViewSource.get(),
nsHtml5Tokenizer::CONSUME_CHARACTER_REFERENCE,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '<': {
flushChars(buf, pos);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::TAG_OPEN, reconsume, pos);
NS_HTML5_BREAK(dataloop);
}
case '\0': {
maybeEmitReplacementCharacter(buf, pos);
continue;
}
case '\r': {
emitCarriageReturn<P>(buf, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
default: {
continue;
}
}
}
dataloop_end:;
[[fallthrough]];
}
case TAG_OPEN: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
if (c >= 'A' && c <= 'Z') {
endTag = false;
clearStrBufBeforeUse();
appendStrBuf((char16_t)(c + 0x20));
containsHyphen = false;
state = P::transition(mViewSource.get(), nsHtml5Tokenizer::TAG_NAME,
reconsume, pos);
NS_HTML5_BREAK(tagopenloop);
} else if (c >= 'a' && c <= 'z') {
endTag = false;
clearStrBufBeforeUse();
appendStrBuf(c);
containsHyphen = false;
state = P::transition(mViewSource.get(), nsHtml5Tokenizer::TAG_NAME,
reconsume, pos);
NS_HTML5_BREAK(tagopenloop);
}
switch (c) {
case '!': {
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::MARKUP_DECLARATION_OPEN,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '/': {
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::CLOSE_TAG_OPEN, reconsume,
pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\?': {
if (viewingXmlSource) {
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::PROCESSING_INSTRUCTION,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
if (P::reportErrors) {
errProcessingInstruction();
}
clearStrBufBeforeUse();
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BOGUS_COMMENT, reconsume,
pos);
NS_HTML5_CONTINUE(stateloop);
}
case '>': {
if (P::reportErrors) {
errLtGt();
}
tokenHandler->characters(nsHtml5Tokenizer::LT_GT, 0, 2);
cstart = pos + 1;
state = P::transition(mViewSource.get(), nsHtml5Tokenizer::DATA,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
default: {
if (P::reportErrors) {
errBadCharAfterLt(c);
}
tokenHandler->characters(nsHtml5Tokenizer::LT_GT, 0, 1);
cstart = pos;
reconsume = true;
state = P::transition(mViewSource.get(), nsHtml5Tokenizer::DATA,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
tagopenloop_end:;
[[fallthrough]];
}
case TAG_NAME: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '\r': {
P::silentCarriageReturn(this);
strBufToElementNameString();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
case ' ':
case '\t':
case '\f': {
strBufToElementNameString();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_BREAK(tagnameloop);
}
case '/': {
strBufToElementNameString();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::SELF_CLOSING_START_TAG,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '>': {
strBufToElementNameString();
state = P::transition(mViewSource.get(),
emitCurrentTagToken(false, pos), reconsume,
pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
default: {
if (c >= 'A' && c <= 'Z') {
c += 0x20;
} else if (c == '-') {
containsHyphen = true;
}
appendStrBuf(c);
continue;
}
}
}
tagnameloop_end:;
[[fallthrough]];
}
case BEFORE_ATTRIBUTE_NAME: {
for (;;) {
if (reconsume) {
reconsume = false;
} else {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
}
switch (c) {
case '\r': {
P::silentCarriageReturn(this);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
case ' ':
case '\t':
case '\f': {
continue;
}
case '/': {
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::SELF_CLOSING_START_TAG,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '>': {
state = P::transition(mViewSource.get(),
emitCurrentTagToken(false, pos), reconsume,
pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
case '\"':
case '\'':
case '<':
case '=': {
if (P::reportErrors) {
errBadCharBeforeAttributeNameOrNull(c);
}
[[fallthrough]];
}
default: {
if (c >= 'A' && c <= 'Z') {
c += 0x20;
}
attributeLine = line;
clearStrBufBeforeUse();
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::ATTRIBUTE_NAME, reconsume,
pos);
NS_HTML5_BREAK(beforeattributenameloop);
}
}
}
beforeattributenameloop_end:;
[[fallthrough]];
}
case ATTRIBUTE_NAME: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '\r': {
P::silentCarriageReturn(this);
attributeNameComplete();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::AFTER_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
case ' ':
case '\t':
case '\f': {
attributeNameComplete();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::AFTER_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '/': {
attributeNameComplete();
addAttributeWithoutValue();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::SELF_CLOSING_START_TAG,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '=': {
attributeNameComplete();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_VALUE,
reconsume, pos);
NS_HTML5_BREAK(attributenameloop);
}
case '>': {
attributeNameComplete();
addAttributeWithoutValue();
state = P::transition(mViewSource.get(),
emitCurrentTagToken(false, pos), reconsume,
pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
case '\"':
case '\'':
case '<': {
if (P::reportErrors) {
errQuoteOrLtInAttributeNameOrNull(c);
}
[[fallthrough]];
}
default: {
if (c >= 'A' && c <= 'Z') {
c += 0x20;
}
appendStrBuf(c);
continue;
}
}
}
attributenameloop_end:;
[[fallthrough]];
}
case BEFORE_ATTRIBUTE_VALUE: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '\r': {
P::silentCarriageReturn(this);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
case ' ':
case '\t':
case '\f': {
continue;
}
case '\"': {
attributeLine = line;
clearStrBufBeforeUse();
state =
P::transition(mViewSource.get(),
nsHtml5Tokenizer::ATTRIBUTE_VALUE_DOUBLE_QUOTED,
reconsume, pos);
NS_HTML5_BREAK(beforeattributevalueloop);
}
case '&': {
attributeLine = line;
clearStrBufBeforeUse();
reconsume = true;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::ATTRIBUTE_VALUE_UNQUOTED,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\'': {
attributeLine = line;
clearStrBufBeforeUse();
state =
P::transition(mViewSource.get(),
nsHtml5Tokenizer::ATTRIBUTE_VALUE_SINGLE_QUOTED,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '>': {
if (P::reportErrors) {
errAttributeValueMissing();
}
addAttributeWithoutValue();
state = P::transition(mViewSource.get(),
emitCurrentTagToken(false, pos), reconsume,
pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
case '<':
case '=':
case '`': {
if (P::reportErrors) {
errLtOrEqualsOrGraveInUnquotedAttributeOrNull(c);
}
[[fallthrough]];
}
default: {
attributeLine = line;
clearStrBufBeforeUse();
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::ATTRIBUTE_VALUE_UNQUOTED,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
beforeattributevalueloop_end:;
[[fallthrough]];
}
case ATTRIBUTE_VALUE_DOUBLE_QUOTED: {
for (;;) {
if (reconsume) {
reconsume = false;
} else {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
}
switch (c) {
case '\"': {
addAttributeWithValue();
state =
P::transition(mViewSource.get(),
nsHtml5Tokenizer::AFTER_ATTRIBUTE_VALUE_QUOTED,
reconsume, pos);
NS_HTML5_BREAK(attributevaluedoublequotedloop);
}
case '&': {
MOZ_ASSERT(!charRefBufLen,
"charRefBufLen not reset after previous use!");
appendCharRefBuf(c);
setAdditionalAndRememberAmpersandLocation('\"');
returnState = state;
state =
P::transition(mViewSource.get(),
nsHtml5Tokenizer::CONSUME_CHARACTER_REFERENCE,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\r': {
appendStrBufCarriageReturn<P>();
NS_HTML5_BREAK(stateloop);
}
case '\n': {
appendStrBufLineFeed<P>();
continue;
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
default: {
appendStrBuf(c);
continue;
}
}
}
attributevaluedoublequotedloop_end:;
[[fallthrough]];
}
case AFTER_ATTRIBUTE_VALUE_QUOTED: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '\r': {
P::silentCarriageReturn(this);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
case ' ':
case '\t':
case '\f': {
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '/': {
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::SELF_CLOSING_START_TAG,
reconsume, pos);
NS_HTML5_BREAK(afterattributevaluequotedloop);
}
case '>': {
state = P::transition(mViewSource.get(),
emitCurrentTagToken(false, pos), reconsume,
pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
default: {
if (P::reportErrors) {
errNoSpaceBetweenAttributes();
}
reconsume = true;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
afterattributevaluequotedloop_end:;
[[fallthrough]];
}
case SELF_CLOSING_START_TAG: {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '>': {
state =
P::transition(mViewSource.get(), emitCurrentTagToken(true, pos),
reconsume, pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
default: {
if (P::reportErrors) {
errSlashNotFollowedByGt();
}
reconsume = true;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
case ATTRIBUTE_VALUE_UNQUOTED: {
for (;;) {
if (reconsume) {
reconsume = false;
} else {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
}
switch (c) {
case '\r': {
P::silentCarriageReturn(this);
addAttributeWithValue();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
case ' ':
case '\t':
case '\f': {
addAttributeWithValue();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '&': {
MOZ_ASSERT(!charRefBufLen,
"charRefBufLen not reset after previous use!");
appendCharRefBuf(c);
setAdditionalAndRememberAmpersandLocation('>');
returnState = state;
state =
P::transition(mViewSource.get(),
nsHtml5Tokenizer::CONSUME_CHARACTER_REFERENCE,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '>': {
addAttributeWithValue();
state = P::transition(mViewSource.get(),
emitCurrentTagToken(false, pos), reconsume,
pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
case '<':
case '\"':
case '\'':
case '=':
case '`': {
if (P::reportErrors) {
errUnquotedAttributeValOrNull(c);
}
[[fallthrough]];
}
default: {
appendStrBuf(c);
continue;
}
}
}
}
case AFTER_ATTRIBUTE_NAME: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '\r': {
P::silentCarriageReturn(this);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
P::silentLineFeed(this);
[[fallthrough]];
}
case ' ':
case '\t':
case '\f': {
continue;
}
case '/': {
addAttributeWithoutValue();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::SELF_CLOSING_START_TAG,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '=': {
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BEFORE_ATTRIBUTE_VALUE,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '>': {
addAttributeWithoutValue();
state = P::transition(mViewSource.get(),
emitCurrentTagToken(false, pos), reconsume,
pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
case '\"':
case '\'':
case '<': {
if (P::reportErrors) {
errQuoteOrLtInAttributeNameOrNull(c);
}
[[fallthrough]];
}
default: {
addAttributeWithoutValue();
if (c >= 'A' && c <= 'Z') {
c += 0x20;
}
clearStrBufBeforeUse();
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::ATTRIBUTE_NAME, reconsume,
pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
}
case MARKUP_DECLARATION_OPEN: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '-': {
clearStrBufBeforeUse();
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::MARKUP_DECLARATION_HYPHEN,
reconsume, pos);
NS_HTML5_BREAK(markupdeclarationopenloop);
}
case 'd':
case 'D': {
clearStrBufBeforeUse();
appendStrBuf(c);
index = 0;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::MARKUP_DECLARATION_OCTYPE,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '[': {
if (tokenHandler->cdataSectionAllowed()) {
clearStrBufBeforeUse();
appendStrBuf(c);
index = 0;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::CDATA_START, reconsume,
pos);
NS_HTML5_CONTINUE(stateloop);
}
[[fallthrough]];
}
default: {
if (P::reportErrors) {
errBogusComment();
}
clearStrBufBeforeUse();
reconsume = true;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BOGUS_COMMENT, reconsume,
pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
markupdeclarationopenloop_end:;
[[fallthrough]];
}
case MARKUP_DECLARATION_HYPHEN: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '-': {
clearStrBufAfterOneHyphen();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_START, reconsume,
pos);
NS_HTML5_BREAK(markupdeclarationhyphenloop);
}
default: {
if (P::reportErrors) {
errBogusComment();
}
reconsume = true;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::BOGUS_COMMENT, reconsume,
pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
markupdeclarationhyphenloop_end:;
[[fallthrough]];
}
case COMMENT_START: {
reportedConsecutiveHyphens = false;
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '-': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_START_DASH,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '>': {
if (P::reportErrors) {
errPrematureEndOfComment();
}
emitComment(0, pos);
state = P::transition(mViewSource.get(), nsHtml5Tokenizer::DATA,
reconsume, pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '<': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_LESSTHAN,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\r': {
appendStrBufCarriageReturn<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
appendStrBufLineFeed<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_BREAK(commentstartloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
default: {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_BREAK(commentstartloop);
}
}
}
commentstartloop_end:;
[[fallthrough]];
}
case COMMENT: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '-': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_END_DASH,
reconsume, pos);
NS_HTML5_BREAK(commentloop);
}
case '<': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_LESSTHAN,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\r': {
appendStrBufCarriageReturn<P>();
NS_HTML5_BREAK(stateloop);
}
case '\n': {
appendStrBufLineFeed<P>();
continue;
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
default: {
appendStrBuf(c);
continue;
}
}
}
commentloop_end:;
[[fallthrough]];
}
case COMMENT_END_DASH: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '-': {
appendStrBuf(c);
state =
P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_END, reconsume, pos);
NS_HTML5_BREAK(commentenddashloop);
}
case '<': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_LESSTHAN,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\r': {
appendStrBufCarriageReturn<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
appendStrBufLineFeed<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
default: {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
commentenddashloop_end:;
[[fallthrough]];
}
case COMMENT_END: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '>': {
emitComment(2, pos);
state = P::transition(mViewSource.get(), nsHtml5Tokenizer::DATA,
reconsume, pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '-': {
adjustDoubleHyphenAndAppendToStrBufAndErr(
c, reportedConsecutiveHyphens);
reportedConsecutiveHyphens = true;
continue;
}
case '<': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_LESSTHAN,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\r': {
adjustDoubleHyphenAndAppendToStrBufCarriageReturn<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
adjustDoubleHyphenAndAppendToStrBufLineFeed<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '!': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_END_BANG,
reconsume, pos);
NS_HTML5_BREAK(commentendloop);
}
case '\0': {
c = 0xfffd;
[[fallthrough]];
}
default: {
adjustDoubleHyphenAndAppendToStrBufAndErr(
c, reportedConsecutiveHyphens);
reportedConsecutiveHyphens = true;
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
}
}
commentendloop_end:;
[[fallthrough]];
}
case COMMENT_END_BANG: {
for (;;) {
if (++pos == endPos) {
NS_HTML5_BREAK(stateloop);
}
c = P::checkChar(this, buf, pos);
switch (c) {
case '>': {
emitComment(3, pos);
state = P::transition(mViewSource.get(), nsHtml5Tokenizer::DATA,
reconsume, pos);
if (shouldSuspend) {
NS_HTML5_BREAK(stateloop);
}
NS_HTML5_CONTINUE(stateloop);
}
case '-': {
appendStrBuf(c);
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT_END_DASH,
reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\r': {
appendStrBufCarriageReturn<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_BREAK(stateloop);
}
case '\n': {
appendStrBufLineFeed<P>();
state = P::transition(mViewSource.get(),
nsHtml5Tokenizer::COMMENT, reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
}
case '\0': {
c = 0xfffd;