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