#include "xml_tokenizer.h"
#include "xml/dom_docimpl.h"
#include "xml/dom_textimpl.h"
#include "xml/dom_xmlimpl.h"
#include "html/html_headimpl.h"
#include "rendering/render_object.h"
#include "misc/htmltags.h"
#include "misc/htmlattrs.h"
#include "misc/loader.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include <qvariant.h>
#include <kdebug.h>
#include <klocale.h>
using namespace DOM;
using namespace khtml;
XMLHandler::XMLHandler(DocumentPtr *_doc, KHTMLView *_view)
: errorLine(0)
{
m_doc = _doc;
if ( m_doc ) m_doc->ref();
m_view = _view;
m_currentNode = _doc->document();
}
XMLHandler::~XMLHandler()
{
if ( m_doc ) m_doc->deref();
}
QString XMLHandler::errorProtocol()
{
return errorProt;
}
bool XMLHandler::startDocument()
{
errorProt = "";
state = StateInit;
return true;
}
bool XMLHandler::startElement( const QString& namespaceURI, const QString& , const QString& qName, const QXmlAttributes& atts )
{
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
int exceptioncode = 0;
ElementImpl *newElement = m_doc->document()->createElementNS(namespaceURI,qName,exceptioncode);
if (!newElement)
return false;
int i;
for (i = 0; i < atts.length(); i++) {
DOMString uri(atts.uri(i));
DOMString ln(atts.localName(i));
DOMString val(atts.value(i));
NodeImpl::Id id = m_doc->document()->attrId(uri.implementation(),
ln.implementation(),
false );
newElement->setAttribute(id, val.implementation(), exceptioncode);
if (exceptioncode) return false;
}
if (m_currentNode->id() == ID_TABLE &&
newElement->id() == ID_TR &&
m_currentNode->isHTMLElement() && newElement->isHTMLElement()) {
NodeImpl* implicitTBody =
new HTMLTableSectionElementImpl( m_doc, ID_TBODY, true );
m_currentNode->addChild(implicitTBody);
if (m_view && !implicitTBody->attached())
implicitTBody->attach();
m_currentNode = implicitTBody;
}
if (m_currentNode->addChild(newElement)) {
if (m_view && !newElement->attached())
newElement->attach();
m_currentNode = newElement;
return true;
}
else {
delete newElement;
return false;
}
}
bool XMLHandler::endElement( const QString& , const QString& , const QString& )
{
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
if (m_currentNode->parentNode() != 0) {
m_currentNode->closeRenderer();
do {
m_currentNode = m_currentNode->parentNode();
} while (m_currentNode && m_currentNode->implicitNode());
}
return true;
}
bool XMLHandler::startCDATA()
{
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
NodeImpl *newNode = m_doc->document()->createCDATASection("");
if (m_currentNode->addChild(newNode)) {
if (m_view && !newNode->attached())
newNode->attach();
m_currentNode = newNode;
return true;
}
else {
delete newNode;
return false;
}
}
bool XMLHandler::endCDATA()
{
if (m_currentNode->parentNode() != 0)
m_currentNode = m_currentNode->parentNode();
return true;
}
bool XMLHandler::characters( const QString& ch )
{
if (m_currentNode->nodeType() == Node::TEXT_NODE ||
m_currentNode->nodeType() == Node::CDATA_SECTION_NODE ||
enterText()) {
int exceptioncode = 0;
static_cast<TextImpl*>(m_currentNode)->appendData(ch,exceptioncode);
if (exceptioncode)
return false;
return true;
}
else
return false;
}
bool XMLHandler::comment(const QString & ch)
{
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
m_currentNode->addChild(m_doc->document()->createComment(ch));
return true;
}
bool XMLHandler::processingInstruction(const QString &target, const QString &data)
{
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
ProcessingInstructionImpl *pi = m_doc->document()->createProcessingInstruction(target,data);
m_currentNode->addChild(pi);
if (m_doc->document()->part()) {
pi->checkStyleSheet();
}
return true;
}
QString XMLHandler::errorString()
{
#if APPLE_CHANGES
return "error";
#else
return i18n("the document is not in the correct file format");
#endif
}
bool XMLHandler::fatalError( const QXmlParseException& exception )
{
#if APPLE_CHANGES
errorProt += QString("fatal parsing error: %1 in line %2, column %3")
#else
errorProt += i18n( "fatal parsing error: %1 in line %2, column %3" )
#endif
.arg( exception.message() )
.arg( exception.lineNumber() )
.arg( exception.columnNumber() );
errorLine = exception.lineNumber();
errorCol = exception.columnNumber();
return false;
}
bool XMLHandler::enterText()
{
NodeImpl *newNode = m_doc->document()->createTextNode("");
if (m_currentNode->addChild(newNode)) {
m_currentNode = newNode;
return true;
}
else {
delete newNode;
return false;
}
}
void XMLHandler::exitText()
{
if (m_view && m_currentNode && !m_currentNode->attached())
m_currentNode->attach();
NodeImpl* par = m_currentNode->parentNode();
if (par != 0)
m_currentNode = par;
}
bool XMLHandler::attributeDecl(const QString &, const QString &, const QString &,
const QString &, const QString &)
{
return true;
}
bool XMLHandler::externalEntityDecl(const QString &, const QString &, const QString &)
{
return true;
}
bool XMLHandler::internalEntityDecl(const QString &name, const QString &value)
{
EntityImpl *e = new EntityImpl(m_doc,name);
e->addChild(m_doc->document()->createTextNode(value));
return true;
}
bool XMLHandler::notationDecl(const QString &name, const QString &publicId, const QString &systemId)
{
return true;
}
bool XMLHandler::unparsedEntityDecl(const QString &, const QString &,
const QString &, const QString &)
{
return true;
}
XMLTokenizer::XMLTokenizer(DOM::DocumentPtr *_doc, KHTMLView *_view)
{
m_doc = _doc;
if ( m_doc ) m_doc->ref();
m_view = _view;
m_xmlCode = "";
m_scriptsIt = 0;
m_cachedScript = 0;
}
XMLTokenizer::~XMLTokenizer()
{
if ( m_doc ) m_doc->deref();
if (m_scriptsIt)
delete m_scriptsIt;
if (m_cachedScript)
m_cachedScript->deref(this);
}
void XMLTokenizer::begin()
{
}
void XMLTokenizer::write( const QString &str, bool )
{
m_xmlCode += str;
}
void XMLTokenizer::end()
{
emit finishedParsing();
}
void XMLTokenizer::finish()
{
XMLHandler handler(m_doc,m_view);
QXmlInputSource source;
source.setData(m_xmlCode);
QXmlSimpleReader reader;
reader.setContentHandler( &handler );
reader.setLexicalHandler( &handler );
reader.setErrorHandler( &handler );
reader.setDeclHandler( &handler );
reader.setDTDHandler( &handler );
bool ok = reader.parse( source );
if (!ok) {
int exceptioncode = 0;
while (m_doc->document()->hasChildNodes())
static_cast<NodeImpl*>(m_doc->document())->removeChild(m_doc->document()->firstChild(),exceptioncode);
QString line;
QString errorLocPtr;
if (handler.errorLine) {
QTextIStream stream(&m_xmlCode);
for (unsigned long lineno = 0; lineno < handler.errorLine-1; lineno++)
stream.readLine();
line = stream.readLine();
for (unsigned long colno = 0; colno < handler.errorCol-1; colno++)
errorLocPtr += " ";
errorLocPtr += "^";
}
DocumentImpl *doc = m_doc->document();
NodeImpl *html = doc->createElementNS(XHTML_NAMESPACE,"html",exceptioncode);
NodeImpl *body = doc->createElementNS(XHTML_NAMESPACE,"body",exceptioncode);
NodeImpl *h1 = doc->createElementNS(XHTML_NAMESPACE,"h1",exceptioncode);
#if APPLE_CHANGES
NodeImpl *headingText = doc->createTextNode("XML parsing error");
#else
NodeImpl *headingText = doc->createTextNode(i18n("XML parsing error"));
#endif
NodeImpl *errorText = doc->createTextNode(handler.errorProtocol());
NodeImpl *hr = 0;
NodeImpl *pre = 0;
NodeImpl *lineText = 0;
NodeImpl *errorLocText = 0;
if (!line.isNull()) {
hr = doc->createElementNS(XHTML_NAMESPACE,"hr",exceptioncode);
pre = doc->createElementNS(XHTML_NAMESPACE,"pre",exceptioncode);
lineText = doc->createTextNode(line+"\n");
errorLocText = doc->createTextNode(errorLocPtr);
}
doc->appendChild(html,exceptioncode);
html->appendChild(body,exceptioncode);
body->appendChild(h1,exceptioncode);
h1->appendChild(headingText,exceptioncode);
body->appendChild(errorText,exceptioncode);
if (hr)
body->appendChild(hr,exceptioncode);
if (pre) {
body->appendChild(pre,exceptioncode);
pre->appendChild(lineText,exceptioncode);
pre->appendChild(errorLocText,exceptioncode);
}
h1->closeRenderer();
if (pre)
pre->closeRenderer();
body->closeRenderer();
m_doc->document()->recalcStyle( NodeImpl::Inherit );
m_doc->document()->updateRendering();
end();
}
else {
addScripts(m_doc->document());
m_scriptsIt = new QPtrListIterator<HTMLScriptElementImpl>(m_scripts);
executeScripts();
}
}
void XMLTokenizer::addScripts(NodeImpl *n)
{
if (n->id() == ID_SCRIPT) {
m_scripts.append(static_cast<HTMLScriptElementImpl*>(n));
}
NodeImpl *child;
for (child = n->firstChild(); child; child = child->nextSibling())
addScripts(child);
}
void XMLTokenizer::executeScripts()
{
while (m_scriptsIt->current()) {
DOMString scriptSrc = m_scriptsIt->current()->getAttribute(ATTR_SRC);
QString charset = m_scriptsIt->current()->getAttribute(ATTR_CHARSET).string();
if (scriptSrc != "" && m_doc->document()->part()) {
m_cachedScript = m_doc->document()->docLoader()->requestScript(scriptSrc, charset);
++(*m_scriptsIt);
m_cachedScript->ref(this); return;
}
else {
QString scriptCode = "";
NodeImpl *child;
for (child = m_scriptsIt->current()->firstChild(); child; child = child->nextSibling()) {
if (child->nodeType() == Node::TEXT_NODE || child->nodeType() == Node::CDATA_SECTION_NODE) {
scriptCode += static_cast<TextImpl*>(child)->data().string();
}
}
if (m_view) {
m_view->part()->executeScript(scriptCode);
}
++(*m_scriptsIt);
}
}
m_doc->document()->updateStyleSelector();
end();
}
void XMLTokenizer::notifyFinished(CachedObject *finishedObj)
{
if (finishedObj == m_cachedScript) {
DOMString scriptSource = m_cachedScript->script();
m_cachedScript->deref(this);
m_cachedScript = 0;
m_view->part()->executeScript(scriptSource.string());
executeScripts();
}
}
bool XMLTokenizer::isWaitingForScripts()
{
return m_cachedScript != 0;
}
#include "xml_tokenizer.moc"