/*
* Copyright (c) 2008 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.perftest;
import nu.validator.htmlparser.common.TokenHandler;
import nu.validator.htmlparser.impl.ElementName;
import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.Tokenizer;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
public class TokensToSax implements TokenHandler {
private static final int PHASE_START = 0;
private static final int PHASE_CONTENT = 1;
private static final int PHASE_TRAILING = 2;
private final ContentHandler contentHandler;
private final LexicalHandler lexicalHandler;
private String[] stack;
private int stackLen;
private int phase;
/**
* @param contentHandler
* @param lexicalHandler
*/
public TokensToSax(ContentHandler contentHandler,
LexicalHandler lexicalHandler) {
if (contentHandler == null) {
throw new IllegalArgumentException("ContentHandler must not be null.");
}
this.contentHandler = contentHandler;
this.lexicalHandler = lexicalHandler;
}
/**
* @param contentHandler
* @param lexicalHandler
*/
public TokensToSax(ContentHandler contentHandler) {
if (contentHandler == null) {
throw new IllegalArgumentException("ContentHandler must not be null.");
}
this.contentHandler = contentHandler;
this.lexicalHandler = null;
}
/**
* @see org.xml.sax.ContentHandler#characters(char[], int, int)
*/
public void characters(char[] buf, int start, int length)
throws SAXException {
if (phase == PHASE_CONTENT) {
contentHandler.characters(buf, start, length);
}
}
public void comment(char[] buf, int start, int length) throws SAXException {
lexicalHandler.comment(buf, start, length);
}
public void doctype(String name, String publicIdentifier,
String systemIdentifier, boolean forceQuirks) throws SAXException {
if (phase == PHASE_START && lexicalHandler != null) {
lexicalHandler.startDTD(name, publicIdentifier, systemIdentifier);
lexicalHandler.endDTD();
}
}
public void endTag(ElementName eltName) throws SAXException {
if (phase != PHASE_CONTENT) {
return;
}
String name = eltName.name;
if (stack[--stackLen] == name) {
contentHandler.endElement("http://www.w3.org/1999/xhtml", name, null);
} else {
// OK, the end tag didn't match, let's see if there's an open tag on the stack
for (int i = stackLen; i >= 0; i--) {
if (stack[i] == name) {
// found a match
for (int j = stackLen; j >= i; j--) {
contentHandler.endElement("http://www.w3.org/1999/xhtml", stack[j], null);
}
stackLen = i;
return;
}
}
}
if (stackLen == 0) {
phase = PHASE_TRAILING;
}
}
public void endTokenization() throws SAXException {
contentHandler.endDocument();
stack = null;
}
public void eof() throws SAXException {
}
public boolean inForeign() throws SAXException {
return true;
}
public void startTag(ElementName eltName, HtmlAttributes attributes,
boolean selfClosing) throws SAXException {
switch (phase) {
case PHASE_START:
phase = PHASE_CONTENT;
case PHASE_CONTENT:
String name = eltName.name;
contentHandler.startElement("http://www.w3.org/1999/xhtml",
name, null, attributes);
if (selfClosing) {
contentHandler.endElement("http://www.w3.org/1999/xhtml",
name, null);
} else {
push(name);
}
}
}
private void push(String name) {
if (stackLen == stack.length) {
String[] newBuf = new String[stackLen + (stackLen >> 1)];
System.arraycopy(stack, 0, newBuf, 0, stackLen);
stack = newBuf;
}
stack[stackLen++] = name;
}
public void startTokenization(Tokenizer self) throws SAXException {
stack = new String[16];
phase = PHASE_START;
stackLen = 0;
contentHandler.setDocumentLocator(self);
contentHandler.startDocument();
}
public boolean wantsComments() throws SAXException {
return lexicalHandler != null;
}
}