📄 xmltokenizerlibxml2.cpp
字号:
void setLoaderForLibXMLCallbacks(DocLoader* docLoader){ globalDocLoader = docLoader;}static bool didInit = false;static xmlParserCtxtPtr createStringParser(xmlSAXHandlerPtr handlers, void* userData){ if (!didInit) { xmlInitParser(); xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc); xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc); libxmlLoaderThread = currentThread(); didInit = true; } xmlParserCtxtPtr parser = xmlCreatePushParserCtxt(handlers, 0, 0, 0, 0); parser->_private = userData; parser->replaceEntities = true; const UChar 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;}// Chunk should be encoded in UTF-8static xmlParserCtxtPtr createMemoryParser(xmlSAXHandlerPtr handlers, void* userData, const char* chunk){ if (!didInit) { xmlInitParser(); xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc); xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc); libxmlLoaderThread = currentThread(); didInit = true; } xmlParserCtxtPtr parser = xmlCreateMemoryParserCtxt(chunk, xmlStrlen((const xmlChar*)chunk)); if (!parser) return 0; // Copy the sax handler memcpy(parser->sax, handlers, sizeof(xmlSAXHandler)); // Set parser options. // XML_PARSE_NODICT: default dictionary option. // XML_PARSE_NOENT: force entities substitutions. xmlCtxtUseOptions(parser, XML_PARSE_NODICT | XML_PARSE_NOENT); // Internal initialization parser->sax2 = 1; parser->instate = XML_PARSER_CONTENT; // We are parsing a CONTENT parser->depth = 0; parser->str_xml = xmlDictLookup(parser->dict, BAD_CAST "xml", 3); parser->str_xmlns = xmlDictLookup(parser->dict, BAD_CAST "xmlns", 5); parser->str_xml_ns = xmlDictLookup(parser->dict, XML_XML_NAMESPACE, 36); parser->_private = userData; return parser;}// --------------------------------XMLTokenizer::XMLTokenizer(Document* _doc, FrameView* _view) : m_doc(_doc) , m_view(_view) , m_context(0) , m_pendingCallbacks(new PendingCallbacks) , m_currentNode(_doc) , m_currentNodeIsReferenced(false) , m_sawError(false) , m_sawXSLTransform(false) , m_sawFirstElement(false) , m_isXHTMLDocument(false) , m_parserPaused(false) , m_requestingScript(false) , m_finishCalled(false) , m_errorCount(0) , m_lastErrorLine(0) , m_lastErrorColumn(0) , m_pendingScript(0) , m_scriptStartLine(0) , m_parsingFragment(false){}XMLTokenizer::XMLTokenizer(DocumentFragment* fragment, Element* parentElement) : m_doc(fragment->document()) , m_view(0) , m_context(0) , m_pendingCallbacks(new PendingCallbacks) , m_currentNode(fragment) , m_currentNodeIsReferenced(fragment) , m_sawError(false) , m_sawXSLTransform(false) , m_sawFirstElement(false) , m_isXHTMLDocument(false) , m_parserPaused(false) , m_requestingScript(false) , m_finishCalled(false) , m_errorCount(0) , m_lastErrorLine(0) , m_lastErrorColumn(0) , m_pendingScript(0) , m_scriptStartLine(0) , m_parsingFragment(true){ if (fragment) fragment->ref(); if (m_doc) m_doc->ref(); // Add namespaces based on the parent node Vector<Element*> elemStack; while (parentElement) { elemStack.append(parentElement); Node* n = parentElement->parentNode(); if (!n || !n->isElementNode()) break; parentElement = static_cast<Element*>(n); } if (elemStack.isEmpty()) return; for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) { if (NamedAttrMap* attrs = element->attributes()) { for (unsigned i = 0; i < attrs->length(); i++) { Attribute* attr = attrs->attributeItem(i); if (attr->localName() == "xmlns") m_defaultNamespaceURI = attr->value(); else if (attr->prefix() == "xmlns") m_prefixToNamespaceMap.set(attr->localName(), attr->value()); } } } // If the parent element is not in document tree, there may be no xmlns attribute; just default to the parent's namespace. if (m_defaultNamespaceURI.isNull() && !parentElement->inDocument()) m_defaultNamespaceURI = parentElement->namespaceURI();}XMLTokenizer::~XMLTokenizer(){ setCurrentNode(0); if (m_parsingFragment && m_doc) m_doc->deref(); if (m_pendingScript) m_pendingScript->removeClient(this); if (m_context) xmlFreeParserCtxt(m_context);}void XMLTokenizer::doWrite(const String& parseString){ if (!m_context) initializeParserContext(); // libXML throws an error if you try to switch the encoding for an empty string. if (parseString.length()) { // Hack around libxml2's lack of encoding overide support by manually // resetting the encoding to UTF-16 before every chunk. Otherwise libxml // will detect <?xml version="1.0" encoding="<encoding name>"?> blocks // and switch encodings, causing the parse to fail. const UChar BOM = 0xFEFF; const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM); xmlSwitchEncoding(m_context, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE); xmlParseChunk(m_context, reinterpret_cast<const char*>(parseString.characters()), sizeof(UChar) * parseString.length(), 0); } if (m_doc->decoder() && m_doc->decoder()->sawError()) { // If the decoder saw an error, report it as fatal (stops parsing) handleError(fatal, "Encoding error", lineNumber(), columnNumber()); } return;}static inline String toString(const xmlChar* str, unsigned len){ return UTF8Encoding().decode(reinterpret_cast<const char*>(str), len);}static inline String toString(const xmlChar* str){ if (!str) return String(); return UTF8Encoding().decode(reinterpret_cast<const char*>(str), strlen(reinterpret_cast<const char*>(str)));}struct _xmlSAX2Namespace { const xmlChar* prefix; const xmlChar* uri;};typedef struct _xmlSAX2Namespace xmlSAX2Namespace;static inline void handleElementNamespaces(Element* newElement, const xmlChar** libxmlNamespaces, int nb_namespaces, ExceptionCode& ec){ xmlSAX2Namespace* namespaces = reinterpret_cast<xmlSAX2Namespace*>(libxmlNamespaces); for(int i = 0; i < nb_namespaces; i++) { String namespaceQName = "xmlns"; String namespaceURI = toString(namespaces[i].uri); if (namespaces[i].prefix) namespaceQName = "xmlns:" + toString(namespaces[i].prefix); newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec); if (ec) // exception setting attributes return; }}struct _xmlSAX2Attributes { const xmlChar* localname; const xmlChar* prefix; const xmlChar* uri; const xmlChar* value; const xmlChar* end;};typedef struct _xmlSAX2Attributes xmlSAX2Attributes;static inline void handleElementAttributes(Element* newElement, const xmlChar** libxmlAttributes, int nb_attributes, ExceptionCode& ec){ xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes); for(int i = 0; i < nb_attributes; i++) { String attrLocalName = toString(attributes[i].localname); int valueLength = (int) (attributes[i].end - attributes[i].value); String attrValue = toString(attributes[i].value, valueLength); String attrPrefix = toString(attributes[i].prefix); String attrURI = attrPrefix.isEmpty() ? String() : toString(attributes[i].uri); String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName; newElement->setAttributeNS(attrURI, attrQName, attrValue, ec); if (ec) // exception setting attributes return; }}void XMLTokenizer::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces, const xmlChar** libxmlNamespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes){ if (m_parserStopped) return; if (m_parserPaused) { m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces, nb_attributes, nb_defaulted, libxmlAttributes); return; } bool isFirstElement = !m_sawFirstElement; m_sawFirstElement = true; exitText(); String localName = toString(xmlLocalName); String uri = toString(xmlURI); String prefix = toString(xmlPrefix); if (m_parsingFragment && uri.isNull()) { if (!prefix.isNull()) uri = m_prefixToNamespaceMap.get(prefix); else uri = m_defaultNamespaceURI; } QualifiedName qName(prefix, localName, uri); RefPtr<Element> newElement = m_doc->createElement(qName, true); if (!newElement) { stopParsing(); return; } ExceptionCode ec = 0; handleElementNamespaces(newElement.get(), libxmlNamespaces, nb_namespaces, ec); if (ec) { stopParsing(); return; } ScriptController* jsProxy = m_doc->frame() ? m_doc->frame()->script() : 0; if (jsProxy && m_doc->frame()->script()->isEnabled()) jsProxy->setEventHandlerLineno(lineNumber()); handleElementAttributes(newElement.get(), libxmlAttributes, nb_attributes, ec); if (ec) { stopParsing(); return; } if (jsProxy) jsProxy->setEventHandlerLineno(0); newElement->beginParsingChildren(); ScriptElement* scriptElement = toScriptElement(newElement.get()); if (scriptElement) m_scriptStartLine = lineNumber(); if (!m_currentNode->addChild(newElement.get())) { stopParsing(); return; } setCurrentNode(newElement.get()); if (m_view && !newElement->attached()) newElement->attach(); if (isFirstElement && m_doc->frame()) m_doc->frame()->loader()->dispatchDocumentElementAvailable();}void XMLTokenizer::endElementNs(){ if (m_parserStopped) return; if (m_parserPaused) { m_pendingCallbacks->appendEndElementNSCallback(); return; } exitText(); Node* n = m_currentNode; RefPtr<Node> parent = n->parentNode(); n->finishParsingChildren(); if (!n->isElementNode() || !m_view) { setCurrentNode(parent.get()); return; } Element* element = static_cast<Element*>(n); ScriptElement* scriptElement = toScriptElement(element); if (!scriptElement) { setCurrentNode(parent.get()); return; } // don't load external scripts for standalone documents (for now) ASSERT(!m_pendingScript); m_requestingScript = true; String scriptHref = scriptElement->sourceAttributeValue(); if (!scriptHref.isEmpty()) { // we have a src attribute String scriptCharset = scriptElement->scriptCharset(); if ((m_pendingScript = m_doc->docLoader()->requestScript(scriptHref, scriptCharset))) { m_scriptElement = element; m_pendingScript->addClient(this); // m_pendingScript will be 0 if script was already loaded and ref() executed it if (m_pendingScript) pauseParsing(); } else m_scriptElement = 0; } else m_view->frame()->loader()->executeScript(ScriptSourceCode(scriptElement->scriptContent(), m_doc->url(), m_scriptStartLine)); m_requestingScript = false; setCurrentNode(parent.get());}void XMLTokenizer::characters(const xmlChar* s, int len){ if (m_parserStopped) return; if (m_parserPaused) { m_pendingCallbacks->appendCharactersCallback(s, len); return; } if (m_currentNode->isTextNode() || enterText()) m_bufferedText.append(s, len);}void XMLTokenizer::error(ErrorType type, const char* message, va_list args){ if (m_parserStopped) return;#if PLATFORM(WIN_OS) char m[1024]; vsnprintf(m, sizeof(m) - 1, message, args);#else char* m; vasprintf(&m, message, args);#endif if (m_parserPaused) m_pendingCallbacks->appendErrorCallback(type, m, lineNumber(), columnNumber()); else handleError(type, m, lineNumber(), columnNumber());#if !PLATFORM(WIN_OS) free(m);#endif}void XMLTokenizer::processingInstruction(const xmlChar* target, const xmlChar* data){ if (m_parserStopped) return; if (m_parserPaused) { m_pendingCallbacks->appendProcessingInstructionCallback(target, data); return; } exitText(); // ### handle exceptions int exception = 0; RefPtr<ProcessingInstruction> pi = m_doc->createProcessingInstruction( toString(target), toString(data), exception); if (exception) return; pi->setCreatedByParser(true); if (!m_currentNode->addChild(pi.get())) return; if (m_view && !pi->attached()) pi->attach(); pi->finishParsingChildren();#if ENABLE(XSLT) m_sawXSLTransform = !m_sawFirstElement && pi->isXSL(); if (m_sawXSLTransform && !m_doc->transformSourceDocument()) stopParsing();#endif}void XMLTokenizer::cdataBlock(const xmlChar* s, int len){ if (m_parserStopped) return; if (m_parserPaused) { m_pendingCallbacks->appendCDATABlockCallback(s, len); return; } exitText(); RefPtr<Node> newNode = new CDATASection(m_doc, toString(s, len)); if (!m_currentNode->addChild(newNode.get())) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -