📄 xmltokenizerlibxml2.cpp
字号:
/* * Copyright (C) 2000 Peter Kelly (pmk@post.com) * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008 Holger Hans Peter Freyther * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#include "config.h"#include "XMLTokenizer.h"#include "CDATASection.h"#include "CString.h"#include "CachedScript.h"#include "Comment.h"#include "DocLoader.h"#include "Document.h"#include "DocumentFragment.h"#include "DocumentType.h"#include "Frame.h"#include "FrameLoader.h"#include "FrameView.h"#include "HTMLLinkElement.h"#include "HTMLStyleElement.h"#include "HTMLTokenizer.h" // for decodeNamedEntity#include "ProcessingInstruction.h"#include "ResourceError.h"#include "ResourceHandle.h"#include "ResourceRequest.h"#include "ResourceResponse.h"#include "ScriptController.h"#include "ScriptElement.h"#include "ScriptSourceCode.h"#include "ScriptValue.h"#include "TextResourceDecoder.h"#include <libxml/parser.h>#include <libxml/parserInternals.h>#include <wtf/Platform.h>#include <wtf/StringExtras.h>#include <wtf/Threading.h>#include <wtf/UnusedParam.h>#include <wtf/Vector.h>#if ENABLE(XSLT)#include <libxslt/xslt.h>#endifusing namespace std;namespace WebCore {class PendingCallbacks : Noncopyable {public: ~PendingCallbacks() { deleteAllValues(m_callbacks); } void appendStartElementNSCallback(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces, const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** attributes) { PendingStartElementNSCallback* callback = new PendingStartElementNSCallback; callback->xmlLocalName = xmlStrdup(xmlLocalName); callback->xmlPrefix = xmlStrdup(xmlPrefix); callback->xmlURI = xmlStrdup(xmlURI); callback->nb_namespaces = nb_namespaces; callback->namespaces = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_namespaces * 2)); for (int i = 0; i < nb_namespaces * 2 ; i++) callback->namespaces[i] = xmlStrdup(namespaces[i]); callback->nb_attributes = nb_attributes; callback->nb_defaulted = nb_defaulted; callback->attributes = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_attributes * 5)); for (int i = 0; i < nb_attributes; i++) { // Each attribute has 5 elements in the array: // name, prefix, uri, value and an end pointer. for (int j = 0; j < 3; j++) callback->attributes[i * 5 + j] = xmlStrdup(attributes[i * 5 + j]); int len = attributes[i * 5 + 4] - attributes[i * 5 + 3]; callback->attributes[i * 5 + 3] = xmlStrndup(attributes[i * 5 + 3], len); callback->attributes[i * 5 + 4] = callback->attributes[i * 5 + 3] + len; } m_callbacks.append(callback); } void appendEndElementNSCallback() { PendingEndElementNSCallback* callback = new PendingEndElementNSCallback; m_callbacks.append(callback); } void appendCharactersCallback(const xmlChar* s, int len) { PendingCharactersCallback* callback = new PendingCharactersCallback; callback->s = xmlStrndup(s, len); callback->len = len; m_callbacks.append(callback); } void appendProcessingInstructionCallback(const xmlChar* target, const xmlChar* data) { PendingProcessingInstructionCallback* callback = new PendingProcessingInstructionCallback; callback->target = xmlStrdup(target); callback->data = xmlStrdup(data); m_callbacks.append(callback); } void appendCDATABlockCallback(const xmlChar* s, int len) { PendingCDATABlockCallback* callback = new PendingCDATABlockCallback; callback->s = xmlStrndup(s, len); callback->len = len; m_callbacks.append(callback); } void appendCommentCallback(const xmlChar* s) { PendingCommentCallback* callback = new PendingCommentCallback; callback->s = xmlStrdup(s); m_callbacks.append(callback); } void appendInternalSubsetCallback(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID) { PendingInternalSubsetCallback* callback = new PendingInternalSubsetCallback; callback->name = xmlStrdup(name); callback->externalID = xmlStrdup(externalID); callback->systemID = xmlStrdup(systemID); m_callbacks.append(callback); } void appendErrorCallback(XMLTokenizer::ErrorType type, const char* message, int lineNumber, int columnNumber) { PendingErrorCallback* callback = new PendingErrorCallback; callback->message = strdup(message); callback->type = type; callback->lineNumber = lineNumber; callback->columnNumber = columnNumber; m_callbacks.append(callback); } void callAndRemoveFirstCallback(XMLTokenizer* tokenizer) { OwnPtr<PendingCallback> callback(m_callbacks.first()); m_callbacks.removeFirst(); callback->call(tokenizer); } bool isEmpty() const { return m_callbacks.isEmpty(); } private: struct PendingCallback { virtual ~PendingCallback() { } virtual void call(XMLTokenizer* tokenizer) = 0; }; struct PendingStartElementNSCallback : public PendingCallback { virtual ~PendingStartElementNSCallback() { xmlFree(xmlLocalName); xmlFree(xmlPrefix); xmlFree(xmlURI); for (int i = 0; i < nb_namespaces * 2; i++) xmlFree(namespaces[i]); xmlFree(namespaces); for (int i = 0; i < nb_attributes; i++) for (int j = 0; j < 4; j++) xmlFree(attributes[i * 5 + j]); xmlFree(attributes); } virtual void call(XMLTokenizer* tokenizer) { tokenizer->startElementNs(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, const_cast<const xmlChar**>(namespaces), nb_attributes, nb_defaulted, const_cast<const xmlChar**>(attributes)); } xmlChar* xmlLocalName; xmlChar* xmlPrefix; xmlChar* xmlURI; int nb_namespaces; xmlChar** namespaces; int nb_attributes; int nb_defaulted; xmlChar** attributes; }; struct PendingEndElementNSCallback : public PendingCallback { virtual void call(XMLTokenizer* tokenizer) { tokenizer->endElementNs(); } }; struct PendingCharactersCallback : public PendingCallback { virtual ~PendingCharactersCallback() { xmlFree(s); } virtual void call(XMLTokenizer* tokenizer) { tokenizer->characters(s, len); } xmlChar* s; int len; }; struct PendingProcessingInstructionCallback : public PendingCallback { virtual ~PendingProcessingInstructionCallback() { xmlFree(target); xmlFree(data); } virtual void call(XMLTokenizer* tokenizer) { tokenizer->processingInstruction(target, data); } xmlChar* target; xmlChar* data; }; struct PendingCDATABlockCallback : public PendingCallback { virtual ~PendingCDATABlockCallback() { xmlFree(s); } virtual void call(XMLTokenizer* tokenizer) { tokenizer->cdataBlock(s, len); } xmlChar* s; int len; }; struct PendingCommentCallback : public PendingCallback { virtual ~PendingCommentCallback() { xmlFree(s); } virtual void call(XMLTokenizer* tokenizer) { tokenizer->comment(s); } xmlChar* s; }; struct PendingInternalSubsetCallback : public PendingCallback { virtual ~PendingInternalSubsetCallback() { xmlFree(name); xmlFree(externalID); xmlFree(systemID); } virtual void call(XMLTokenizer* tokenizer) { tokenizer->internalSubset(name, externalID, systemID); } xmlChar* name; xmlChar* externalID; xmlChar* systemID; }; struct PendingErrorCallback: public PendingCallback { virtual ~PendingErrorCallback() { free (message); } virtual void call(XMLTokenizer* tokenizer) { tokenizer->handleError(type, message, lineNumber, columnNumber); } XMLTokenizer::ErrorType type; char* message; int lineNumber; int columnNumber; }; Deque<PendingCallback*> m_callbacks;};// --------------------------------static int globalDescriptor = 0;static DocLoader* globalDocLoader = 0;static ThreadIdentifier libxmlLoaderThread = 0;static int matchFunc(const char*){ // Only match loads initiated due to uses of libxml2 from within XMLTokenizer to avoid // interfering with client applications that also use libxml2. http://bugs.webkit.org/show_bug.cgi?id=17353 return globalDocLoader && currentThread() == libxmlLoaderThread;}class OffsetBuffer {public: OffsetBuffer(const Vector<char>& b) : m_buffer(b), m_currentOffset(0) { } int readOutBytes(char* outputBuffer, unsigned askedToRead) { unsigned bytesLeft = m_buffer.size() - m_currentOffset; unsigned lenToCopy = min(askedToRead, bytesLeft); if (lenToCopy) { memcpy(outputBuffer, m_buffer.data() + m_currentOffset, lenToCopy); m_currentOffset += lenToCopy; } return lenToCopy; }private: Vector<char> m_buffer; unsigned m_currentOffset;};static bool shouldAllowExternalLoad(const KURL& url){ String urlString = url.string(); // On non-Windows platforms libxml asks for this URL, the // "XML_XML_DEFAULT_CATALOG", on initialization. if (urlString == "file:///etc/xml/catalog") return false; // On Windows, libxml computes a URL relative to where its DLL resides. if (urlString.startsWith("file:///", false) && urlString.endsWith("/etc/catalog", false)) return false; // The most common DTD. There isn't much point in hammering www.w3c.org // by requesting this URL for every XHTML document. if (urlString.startsWith("http://www.w3.org/TR/xhtml", false)) return false; // Similarly, there isn't much point in requesting the SVG DTD. if (urlString.startsWith("http://www.w3.org/Graphics/SVG", false)) return false; // The libxml doesn't give us a lot of context for deciding whether to // allow this request. In the worst case, this load could be for an // external entity and the resulting document could simply read the // retrieved content. If we had more context, we could potentially allow // the parser to load a DTD. As things stand, we take the conservative // route and allow same-origin requests only. if (!globalDocLoader->doc()->securityOrigin()->canRequest(url)) { globalDocLoader->printAccessDeniedMessage(url); return false; } return true;}static void* openFunc(const char* uri){ ASSERT(globalDocLoader); ASSERT(currentThread() == libxmlLoaderThread); KURL url(KURL(), uri); if (!shouldAllowExternalLoad(url)) return &globalDescriptor; ResourceError error; ResourceResponse response; Vector<char> data; DocLoader* docLoader = globalDocLoader; globalDocLoader = 0; // FIXME: We should restore the original global error handler as well. if (docLoader->frame()) docLoader->frame()->loader()->loadResourceSynchronously(url, error, response, data); globalDocLoader = docLoader; // We have to check the URL again after the load to catch redirects. // See <https://bugs.webkit.org/show_bug.cgi?id=21963>. if (!shouldAllowExternalLoad(response.url())) return &globalDescriptor; return new OffsetBuffer(data);}static int readFunc(void* context, char* buffer, int len){ // Do 0-byte reads in case of a null descriptor if (context == &globalDescriptor) return 0; OffsetBuffer* data = static_cast<OffsetBuffer*>(context); return data->readOutBytes(buffer, len);}static int writeFunc(void*, const char*, int){ // Always just do 0-byte writes return 0;}static int closeFunc(void* context){ if (context != &globalDescriptor) { OffsetBuffer* data = static_cast<OffsetBuffer*>(context); delete data; } return 0;}#if ENABLE(XSLT)static void errorFunc(void*, const char*, ...){ // FIXME: It would be nice to display error messages somewhere.}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -