1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDOM.h" 107a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkStream.h" 11c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed#include "SkXMLParser.h" 127a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkXMLWriter.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 14c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) { 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* elemName = dom.getName(node); 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (this->startElement(elemName)) { 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 19c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 20d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::AttrIter iter(dom, node); 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* name, *value; 23d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 24c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed while ((name = iter.next(&value)) != nullptr) { 25c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (this->addAttribute(name, value)) { 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 27c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 28c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 30c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if ((node = dom.getFirstChild(node)) != nullptr) { 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 32c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (!this->parse(dom, node)) { 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 34c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 3596fcdcc219d2a0d3579719b84b28bede76efba64halcanary } while ((node = dom.getNextSibling(node)) != nullptr); 36c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return !this->endElement(elemName); 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////// 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct SkDOMAttr { 438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* fName; 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* fValue; 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct SkDOMNode { 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* fName; 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOMNode* fFirstChild; 508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOMNode* fNextSibling; 5170c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby SkDOMAttr* fAttrs; 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint16_t fAttrCount; 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t fType; 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t fPad; 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 56c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed const SkDOMAttr* attrs() const { 5770c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby return fAttrs; 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 59c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed 60c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed SkDOMAttr* attrs() { 6170c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby return fAttrs; 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////// 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 67f67c45994dedc96eb979e331ab156649847071a4Mike Reed#define kMinChunkSize 4096 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 69c3063e54cb1274359f36d9720d4c1b3acf37c203Mike ReedSkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {} 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 71c3063e54cb1274359f36d9720d4c1b3acf37c203Mike ReedSkDOM::~SkDOM() {} 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 73c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst SkDOM::Node* SkDOM::getRootNode() const { 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return fRoot; 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 77c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const { 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Node* child = node->fFirstChild; 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 81c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (name) { 82c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed for (; child != nullptr; child = child->fNextSibling) { 83c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (!strcmp(name, child->fName)) { 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 85c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 86c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return child; 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 91c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const { 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Node* sibling = node->fNextSibling; 94c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (name) { 95c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed for (; sibling != nullptr; sibling = sibling->fNextSibling) { 96c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (!strcmp(name, sibling->fName)) { 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 98c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 99c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return sibling; 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 104c3063e54cb1274359f36d9720d4c1b3acf37c203Mike ReedSkDOM::Type SkDOM::getType(const Node* node) const { 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (Type)node->fType; 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 109c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst char* SkDOM::getName(const Node* node) const { 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return node->fName; 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 114c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst char* SkDOM::findAttr(const Node* node, const char name[]) const { 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Attr* attr = node->attrs(); 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Attr* stop = attr + node->fAttrCount; 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 119c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed while (attr < stop) { 120c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (!strcmp(attr->fName, name)) { 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return attr->fValue; 122c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com attr += 1; 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12596fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////////// 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 130c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const { 13196fcdcc219d2a0d3579719b84b28bede76efba64halcanary return node->fAttrCount ? node->attrs() : nullptr; 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 134c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const { 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 136c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (attr == nullptr) { 13796fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 138c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 13996fcdcc219d2a0d3579719b84b28bede76efba64halcanary return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr; 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 142c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst char* SkDOM::getAttrName(const Node* node, const Attr* attr) const { 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(attr); 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return attr->fName; 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 148c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const { 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(attr); 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return attr->fValue; 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////////// 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 156c3063e54cb1274359f36d9720d4c1b3acf37c203Mike ReedSkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) { 1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(node); 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fAttr = node->attrs(); 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fStop = fAttr + node->fAttrCount; 1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 162c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst char* SkDOM::AttrIter::next(const char** value) { 16396fcdcc219d2a0d3579719b84b28bede76efba64halcanary const char* name = nullptr; 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 165c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (fAttr < fStop) { 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com name = fAttr->fName; 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (value) 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *value = fAttr->fValue; 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fAttr += 1; 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return name; 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////// 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkXMLParser.h" 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTDArray.h" 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17970c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derbystatic char* dupstr(SkArenaAlloc* chunk, const char src[]) { 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(chunk && src); 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size_t len = strlen(src); 18270c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby char* dst = chunk->makeArrayDefault<char>(len + 1); 1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(dst, src, len + 1); 1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return dst; 1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkDOMParser : public SkXMLParser { 1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic: 18970c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby SkDOMParser(SkArenaAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) { 1907a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita fAlloc->reset(); 19196fcdcc219d2a0d3579719b84b28bede76efba64halcanary fRoot = nullptr; 1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLevel = 0; 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedToFlush = true; 1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::Node* getRoot() const { return fRoot; } 1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkXMLParserError fParserError; 1977a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected: 199c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed void flushAttributes() { 2007a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita SkASSERT(fLevel > 0); 2017a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int attrCount = fAttrs.count(); 2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 20470c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount); 20570c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby SkDOM::Node* node = fAlloc->make<SkDOM::Node>(); 2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com node->fName = fElemName; 20896fcdcc219d2a0d3579719b84b28bede76efba64halcanary node->fFirstChild = nullptr; 2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com node->fAttrCount = SkToU16(attrCount); 21070c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby node->fAttrs = attrs; 2117a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita node->fType = fElemType; 2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 213c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (fRoot == nullptr) { 21496fcdcc219d2a0d3579719b84b28bede76efba64halcanary node->fNextSibling = nullptr; 2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRoot = node; 216c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } else { // this adds siblings in reverse order. gets corrected in onEndElement() 2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::Node* parent = fParentStack.top(); 2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fRoot && parent); 2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com node->fNextSibling = parent->fFirstChild; 2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com parent->fFirstChild = node; 2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *fParentStack.push() = node; 2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 224067e90e72fdeba83eff7aeb917b2b25f74759282mtklein sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr)); 2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fAttrs.reset(); 2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2287a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2297a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita bool onStartElement(const char elem[]) override { 2307a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita this->startCommon(elem, SkDOM::kElement_Type); 2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2337a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2347a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita bool onAddAttribute(const char name[], const char value[]) override { 2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::Attr* attr = fAttrs.append(); 2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com attr->fName = dupstr(fAlloc, name); 2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com attr->fValue = dupstr(fAlloc, value); 2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2407a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2417a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita bool onEndElement(const char elem[]) override { 2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com --fLevel; 2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fNeedToFlush) 2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->flushAttributes(); 2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedToFlush = false; 2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::Node* parent; 2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fParentStack.pop(&parent); 2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::Node* child = parent->fFirstChild; 25296fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkDOM::Node* prev = nullptr; 253c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed while (child) { 2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::Node* next = child->fNextSibling; 2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com child->fNextSibling = prev; 2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com prev = child; 2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com child = next; 2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com parent->fFirstChild = prev; 2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2627a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2637a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita bool onText(const char text[], int len) override { 2647a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita SkString str(text, len); 2657a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita this->startCommon(str.c_str(), SkDOM::kText_Type); 2667a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita this->SkDOMParser::onEndElement(str.c_str()); 2677a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2687a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita return false; 2697a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita } 2707a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate: 2727a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita void startCommon(const char elem[], SkDOM::Type type) { 273c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed if (fLevel > 0 && fNeedToFlush) { 2747a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita this->flushAttributes(); 275c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed } 2767a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita fNeedToFlush = true; 2777a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita fElemName = dupstr(fAlloc, elem); 2787a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita fElemType = type; 2797a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita ++fLevel; 2807a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita } 2817a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTDArray<SkDOM::Node*> fParentStack; 28370c60638be6eba5f5b54e0056bc0fd716f086eb0Herb Derby SkArenaAlloc* fAlloc; 2847a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita SkDOM::Node* fRoot; 2857a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita bool fNeedToFlush; 2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // state needed for flushAttributes() 2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTDArray<SkDOM::Attr> fAttrs; 2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com char* fElemName; 2907a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita SkDOM::Type fElemType; 2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int fLevel; 2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2947445e86bac478dea91da32473e5a01baff637c23fmalitaconst SkDOM::Node* SkDOM::build(SkStream& docStream) { 2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOMParser parser(&fAlloc); 2967445e86bac478dea91da32473e5a01baff637c23fmalita if (!parser.parse(docStream)) 2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());) 29996fcdcc219d2a0d3579719b84b28bede76efba64halcanary fRoot = nullptr; 3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fAlloc.reset(); 30196fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRoot = parser.getRoot(); 3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return fRoot; 3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////// 3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 309c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedstatic void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) { 3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* elem = dom.getName(node); 3117a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita if (dom.getType(node) == SkDOM::kText_Type) { 3127a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita SkASSERT(dom.countChildren(node) == 0); 3137a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita parser->text(elem, SkToInt(strlen(elem))); 3147a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita return; 3157a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita } 3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com parser->startElement(elem); 318d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOM::AttrIter iter(dom, node); 3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* name; 3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* value; 32296fcdcc219d2a0d3579719b84b28bede76efba64halcanary while ((name = iter.next(&value)) != nullptr) 3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com parser->addAttribute(name, value); 3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 32596fcdcc219d2a0d3579719b84b28bede76efba64halcanary node = dom.getFirstChild(node, nullptr); 3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while (node) 3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com walk_dom(dom, node, parser); 32996fcdcc219d2a0d3579719b84b28bede76efba64halcanary node = dom.getNextSibling(node, nullptr); 3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com parser->endElement(elem); 3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 335c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedconst SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) { 3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDOMParser parser(&fAlloc); 3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com walk_dom(dom, node, &parser); 3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRoot = parser.getRoot(); 3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return fRoot; 3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3447a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitaSkXMLParser* SkDOM::beginParsing() { 3457a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita SkASSERT(!fParser); 346385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary fParser.reset(new SkDOMParser(&fAlloc)); 3477a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 3487a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita return fParser.get(); 3497a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita} 3507a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 3517a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitaconst SkDOM::Node* SkDOM::finishParsing() { 3527a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita SkASSERT(fParser); 3537a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita fRoot = fParser->getRoot(); 354852f15da7ceb53cfb49b9f728baa6dbc53b27694mtklein fParser.reset(); 3557a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 3567a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita return fRoot; 3577a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita} 3587a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita 3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////// 3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 361c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedint SkDOM::countChildren(const Node* node, const char elem[]) const { 3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count = 0; 3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com node = this->getFirstChild(node, elem); 365c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reed while (node) { 3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count += 1; 3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com node = this->getNextSibling(node, elem); 3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return count; 3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////// 3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkParse.h" 3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 376c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const { 3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindS32(vstr, value); 3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 381c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const { 3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindScalars(vstr, value, count); 3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 386c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const { 3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindHex(vstr, value); 3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 391c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::findBool(const Node* node, const char name[], bool* value) const { 3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindBool(vstr, value); 3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 396c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedint SkDOM::findList(const Node* node, const char name[], const char list[]) const { 3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr ? SkParse::FindList(vstr, list) : -1; 3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 401c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const { 4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && !strcmp(vstr, value); 4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 406c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const { 4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int32_t value; 4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindS32(vstr, &value) && value == target; 4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 412c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const { 4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar value; 4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindScalar(vstr, &value) && value == target; 4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 418c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const { 4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t value; 4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindHex(vstr, &value) && value == target; 4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 424c3063e54cb1274359f36d9720d4c1b3acf37c203Mike Reedbool SkDOM::hasBool(const Node* node, const char name[], bool target) const { 4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* vstr = this->findAttr(node, name); 4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool value; 4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return vstr && SkParse::FindBool(vstr, &value) && value == target; 4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 429