?? xml_tokenizer.cpp
字號:
/**
* This file is part of the DOM implementation for KDE.
*
* Copyright (C) 2000 Peter Kelly (pmk@post.com)
* Copyright (C) 2005 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#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 "html/html_tableimpl.h"
#include "misc/htmltags.h"
#include "misc/htmlattrs.h"
#include "misc/loader.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include <kdebug.h>
#include <klocale.h>
#if !NOKIA_CHANGES
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#endif
#include <qptrstack.h>
using DOM::DocumentImpl;
using DOM::DocumentPtr;
using DOM::DOMString;
using DOM::ElementImpl;
using DOM::HTMLScriptElementImpl;
using DOM::HTMLTableSectionElementImpl;
using DOM::Node;
using DOM::NodeImpl;
using DOM::ProcessingInstructionImpl;
using DOM::TextImpl;
namespace khtml {
const int maxErrors = 25;
// FIXME: Move to the newer libxml API that handles namespaces and dump XMLNamespace, XMLAttributes, and XMLNamespaceStack.
struct XMLNamespace {
QString m_prefix;
QString m_uri;
XMLNamespace* m_parent;
int m_ref;
XMLNamespace() :m_parent(0), m_ref(0) {}
XMLNamespace(const QString& p, const QString& u, XMLNamespace* parent)
:m_prefix(p),
m_uri(u),
m_parent(parent),
m_ref(0)
{
if (m_parent) m_parent->ref();
}
QString uriForPrefix(const QString& prefix) {
if (prefix == m_prefix)
return m_uri;
if (m_parent)
return m_parent->uriForPrefix(prefix);
return "";
}
void ref() { m_ref++; }
void deref() { if (--m_ref == 0) { if (m_parent) m_parent->deref(); delete this; } }
};
class XMLAttributes
OOM_MODIFIED
{
public:
XMLAttributes() : _ref(0), _length(0), _names(0), _values(0), _uris(0) { }
XMLAttributes(const char **expatStyleAttributes);
~XMLAttributes();
XMLAttributes(const XMLAttributes &);
XMLAttributes &operator=(const XMLAttributes &);
int length() const { return _length; }
QString qName(int index) const { return _names[index]; }
QString localName(int index) const;
QString uri(int index) const { if (!_uris) return QString::null; return _uris[index]; }
QString value(int index) const { return _values[index]; }
QString value(const QString &) const;
void split(XMLNamespace* ns);
private:
mutable int *_ref;
int _length;
QString *_names;
QString *_values;
QString *_uris;
};
class XMLNamespaceStack
OOM_MODIFIED
{
public:
~XMLNamespaceStack();
XMLNamespace *pushNamespaces(XMLAttributes& attributes);
void popNamespaces();
private:
QPtrStack<XMLNamespace> m_namespaceStack;
};
class XMLTokenizer : public Tokenizer, public CachedObjectClient
{
public:
XMLTokenizer(DocumentPtr *, KHTMLView * = 0);
~XMLTokenizer();
enum ErrorType { warning, nonFatal, fatal };
// from Tokenizer
virtual void write(const TokenizerString &str, bool);
virtual void finish();
virtual void setOnHold(bool onHold);
virtual bool isWaitingForScripts() const;
#ifdef KHTML_XSLT
void setTransformSource(DocumentImpl* doc);
#endif
// from CachedObjectClient
virtual void notifyFinished(CachedObject *finishedObj);
#if !NOKIA_CHANGES
// callbacks from parser SAX
void error(ErrorType, const char *message, va_list args);
void startElement(const xmlChar *name, const xmlChar **libxmlAttributes);
void endElement();
void characters(const xmlChar *s, int len);
void processingInstruction(const xmlChar *target, const xmlChar *data);
void cdataBlock(const xmlChar *s, int len);
void comment(const xmlChar *s);
#endif
private:
void end();
int lineNumber() const;
int columnNumber() const;
void stopParsing();
void insertErrorMessageBlock();
void executeScripts();
void addScripts(NodeImpl *n);
XMLNamespace *pushNamespaces(XMLAttributes& attributes) { return m_namespaceStack.pushNamespaces(attributes); }
void popNamespaces() { m_namespaceStack.popNamespaces(); }
bool enterText();
void exitText();
DocumentPtr *m_doc;
KHTMLView *m_view;
QString m_xmlCode;
#if !NOKIA_CHANGES
xmlParserCtxtPtr m_context;
#endif
DOM::NodeImpl *m_currentNode;
XMLNamespaceStack m_namespaceStack;
bool m_sawError;
bool m_parserStopped;
bool m_sawXSLTransform;
int m_errorCount;
int m_lastErrorLine;
int m_lastErrorColumn;
DOMString m_errorMessages;
QPtrList<HTMLScriptElementImpl> m_scripts;
QPtrListIterator<HTMLScriptElementImpl> *m_scriptsIt;
CachedScript *m_cachedScript;
};
// --------------------------------
#if !NOKIA_CHANGES
static int globalDescriptor = 0;
static int matchFunc(const char* uri)
{
return 1; // Match everything.
}
static void* openFunc(const char * uri) {
return &globalDescriptor;
}
static int readFunc(void* context, char* buffer, int len)
{
// Always just do 0-byte reads
return 0;
}
static int writeFunc(void* context, const char* buffer, int len)
{
// Always just do 0-byte writes
return 0;
}
static xmlParserCtxtPtr createQStringParser(xmlSAXHandlerPtr handlers, void *userData, const char* uri = NULL)
{
static bool didInit = false;
if (!didInit) {
xmlInitParser();
xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, NULL);
xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, NULL);
didInit = true;
}
xmlParserCtxtPtr parser = xmlCreatePushParserCtxt(handlers, userData, NULL, 0, uri);
const QChar BOM(0xFEFF);
const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char *>(&BOM);
xmlSwitchEncoding(parser, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
return parser;
}
static void parseQString(xmlParserCtxtPtr parser, const QString &string)
{
xmlParseChunk(parser,
reinterpret_cast<const char *>(string.unicode()),
string.length() * sizeof(QChar), 1);
}
#endif
// --------------------------------
XMLTokenizer::XMLTokenizer(DocumentPtr *_doc, KHTMLView *_view)
: m_doc(_doc), m_view(_view),
#if !NOKIA_CHANGES
m_context(NULL),
#endif
m_currentNode(m_doc->document()),
m_sawError(false), m_parserStopped(false), m_errorCount(0),
m_lastErrorLine(0), m_scriptsIt(0), m_cachedScript(0)
{
if (m_doc)
m_doc->ref();
//FIXME: XMLTokenizer should use this in a fashion similiar to how
//HTMLTokenizer uses loadStopped, in the future.
loadStopped = false;
}
XMLTokenizer::~XMLTokenizer()
{
if (m_doc)
m_doc->deref();
delete m_scriptsIt;
if (m_cachedScript)
m_cachedScript->deref(this);
}
void XMLTokenizer::write(const TokenizerString &s, bool /*appendData*/ )
{
m_xmlCode += s.toString();
}
void XMLTokenizer::setOnHold(bool onHold)
{
// Will we need to implement this when we do incremental XML parsing?
}
#if !NOKIA_CHANGES
void XMLTokenizer::startElement(const xmlChar *name, const xmlChar **libxmlAttributes)
{
if (m_parserStopped)
return;
XMLAttributes atts(reinterpret_cast<const char **>(libxmlAttributes));
XMLNamespace *ns = pushNamespaces(atts);
atts.split(ns);
QString qName = QString::fromUtf8(reinterpret_cast<const char *>(name));
QString uri;
QString prefix;
int colonPos = qName.find(':');
if (colonPos != -1) {
prefix = qName.left(colonPos);
}
uri = ns->uriForPrefix(prefix);
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
int exceptioncode = 0;
ElementImpl *newElement = m_doc->document()->createElementNS(uri, qName, exceptioncode);
if (!newElement)
return;
int i;
for (i = 0; i < atts.length(); i++) {
// FIXME: qualified name not supported for attributes! The prefix has been lost.
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 /* allocate */);
newElement->setAttribute(id, val.implementation(), exceptioncode);
if (exceptioncode) // exception setting attributes
return;
}
// FIXME: This hack ensures implicit table bodies get constructed in XHTML and XML files.
// We want to consolidate this with the HTML parser and HTML DOM code at some point.
// For now, it's too risky to rip that code up.
if (m_currentNode->id() == ID_TABLE &&
newElement->id() == ID_TR &&
m_currentNode->isHTMLElement() && newElement->isHTMLElement()) {
NodeImpl* implicitTBody =
new HTMLTableSectionElementImpl( m_doc, ID_TBODY, true /* implicit */ );
m_currentNode->addChild(implicitTBody);
if (m_view && !implicitTBody->attached())
implicitTBody->attach();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -