1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/xml/SkDOM.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include <memory>
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
14cb93a386Sopenharmony_ci#include "src/xml/SkXMLParser.h"
15cb93a386Sopenharmony_ci#include "src/xml/SkXMLWriter.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_cibool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
18cb93a386Sopenharmony_ci    const char* elemName = dom.getName(node);
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci    if (this->startElement(elemName)) {
21cb93a386Sopenharmony_ci        return false;
22cb93a386Sopenharmony_ci    }
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci    SkDOM::AttrIter iter(dom, node);
25cb93a386Sopenharmony_ci    const char*     name, *value;
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ci    while ((name = iter.next(&value)) != nullptr) {
28cb93a386Sopenharmony_ci        if (this->addAttribute(name, value)) {
29cb93a386Sopenharmony_ci            return false;
30cb93a386Sopenharmony_ci        }
31cb93a386Sopenharmony_ci    }
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ci    if ((node = dom.getFirstChild(node)) != nullptr) {
34cb93a386Sopenharmony_ci        do {
35cb93a386Sopenharmony_ci            if (!this->parse(dom, node)) {
36cb93a386Sopenharmony_ci                return false;
37cb93a386Sopenharmony_ci            }
38cb93a386Sopenharmony_ci        } while ((node = dom.getNextSibling(node)) != nullptr);
39cb93a386Sopenharmony_ci    }
40cb93a386Sopenharmony_ci    return !this->endElement(elemName);
41cb93a386Sopenharmony_ci}
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci#define kMinChunkSize   4096
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ciSkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ciSkDOM::~SkDOM() {}
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ciconst SkDOM::Node* SkDOM::getRootNode() const {
52cb93a386Sopenharmony_ci    return fRoot;
53cb93a386Sopenharmony_ci}
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ciconst SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
56cb93a386Sopenharmony_ci    SkASSERT(node);
57cb93a386Sopenharmony_ci    const Node* child = node->fFirstChild;
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci    if (name) {
60cb93a386Sopenharmony_ci        for (; child != nullptr; child = child->fNextSibling) {
61cb93a386Sopenharmony_ci            if (!strcmp(name, child->fName)) {
62cb93a386Sopenharmony_ci                break;
63cb93a386Sopenharmony_ci            }
64cb93a386Sopenharmony_ci        }
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci    return child;
67cb93a386Sopenharmony_ci}
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ciconst SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
70cb93a386Sopenharmony_ci    SkASSERT(node);
71cb93a386Sopenharmony_ci    const Node* sibling = node->fNextSibling;
72cb93a386Sopenharmony_ci    if (name) {
73cb93a386Sopenharmony_ci        for (; sibling != nullptr; sibling = sibling->fNextSibling) {
74cb93a386Sopenharmony_ci            if (!strcmp(name, sibling->fName)) {
75cb93a386Sopenharmony_ci                break;
76cb93a386Sopenharmony_ci            }
77cb93a386Sopenharmony_ci        }
78cb93a386Sopenharmony_ci    }
79cb93a386Sopenharmony_ci    return sibling;
80cb93a386Sopenharmony_ci}
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ciSkDOM::Type SkDOM::getType(const Node* node) const {
83cb93a386Sopenharmony_ci    SkASSERT(node);
84cb93a386Sopenharmony_ci    return (Type)node->fType;
85cb93a386Sopenharmony_ci}
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ciconst char* SkDOM::getName(const Node* node) const {
88cb93a386Sopenharmony_ci    SkASSERT(node);
89cb93a386Sopenharmony_ci    return node->fName;
90cb93a386Sopenharmony_ci}
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ciconst char* SkDOM::findAttr(const Node* node, const char name[]) const {
93cb93a386Sopenharmony_ci    SkASSERT(node);
94cb93a386Sopenharmony_ci    const Attr* attr = node->attrs();
95cb93a386Sopenharmony_ci    const Attr* stop = attr + node->fAttrCount;
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci    while (attr < stop) {
98cb93a386Sopenharmony_ci        if (!strcmp(attr->fName, name)) {
99cb93a386Sopenharmony_ci            return attr->fValue;
100cb93a386Sopenharmony_ci        }
101cb93a386Sopenharmony_ci        attr += 1;
102cb93a386Sopenharmony_ci    }
103cb93a386Sopenharmony_ci    return nullptr;
104cb93a386Sopenharmony_ci}
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ciconst SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
109cb93a386Sopenharmony_ci    return node->fAttrCount ? node->attrs() : nullptr;
110cb93a386Sopenharmony_ci}
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ciconst SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
113cb93a386Sopenharmony_ci    SkASSERT(node);
114cb93a386Sopenharmony_ci    if (attr == nullptr) {
115cb93a386Sopenharmony_ci        return nullptr;
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci    return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
118cb93a386Sopenharmony_ci}
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ciconst char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
121cb93a386Sopenharmony_ci    SkASSERT(node);
122cb93a386Sopenharmony_ci    SkASSERT(attr);
123cb93a386Sopenharmony_ci    return attr->fName;
124cb93a386Sopenharmony_ci}
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ciconst char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
127cb93a386Sopenharmony_ci    SkASSERT(node);
128cb93a386Sopenharmony_ci    SkASSERT(attr);
129cb93a386Sopenharmony_ci    return attr->fValue;
130cb93a386Sopenharmony_ci}
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ciSkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
135cb93a386Sopenharmony_ci    SkASSERT(node);
136cb93a386Sopenharmony_ci    fAttr = node->attrs();
137cb93a386Sopenharmony_ci    fStop = fAttr + node->fAttrCount;
138cb93a386Sopenharmony_ci}
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ciconst char* SkDOM::AttrIter::next(const char** value) {
141cb93a386Sopenharmony_ci    const char* name = nullptr;
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci    if (fAttr < fStop) {
144cb93a386Sopenharmony_ci        name = fAttr->fName;
145cb93a386Sopenharmony_ci        if (value)
146cb93a386Sopenharmony_ci            *value = fAttr->fValue;
147cb93a386Sopenharmony_ci        fAttr += 1;
148cb93a386Sopenharmony_ci    }
149cb93a386Sopenharmony_ci    return name;
150cb93a386Sopenharmony_ci}
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci#include "src/xml/SkDOMParser.h"
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ciconst SkDOM::Node* SkDOM::build(SkStream& docStream) {
157cb93a386Sopenharmony_ci    SkDOMParser parser(&fAlloc);
158cb93a386Sopenharmony_ci    if (!parser.parse(docStream))
159cb93a386Sopenharmony_ci    {
160cb93a386Sopenharmony_ci        SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
161cb93a386Sopenharmony_ci        fRoot = nullptr;
162cb93a386Sopenharmony_ci        fAlloc.reset();
163cb93a386Sopenharmony_ci        return nullptr;
164cb93a386Sopenharmony_ci    }
165cb93a386Sopenharmony_ci    fRoot = parser.getRoot();
166cb93a386Sopenharmony_ci    return fRoot;
167cb93a386Sopenharmony_ci}
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_civoid SkDOM::walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
172cb93a386Sopenharmony_ci    const char* elem = dom.getName(node);
173cb93a386Sopenharmony_ci    if (dom.getType(node) == SkDOM::kText_Type) {
174cb93a386Sopenharmony_ci        SkASSERT(dom.countChildren(node) == 0);
175cb93a386Sopenharmony_ci        parser->text(elem, SkToInt(strlen(elem)));
176cb93a386Sopenharmony_ci        return;
177cb93a386Sopenharmony_ci    }
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci    parser->startElement(elem);
180cb93a386Sopenharmony_ci
181cb93a386Sopenharmony_ci    SkDOM::AttrIter iter(dom, node);
182cb93a386Sopenharmony_ci    const char*     name;
183cb93a386Sopenharmony_ci    const char*     value;
184cb93a386Sopenharmony_ci    while ((name = iter.next(&value)) != nullptr)
185cb93a386Sopenharmony_ci        parser->addAttribute(name, value);
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ci    node = dom.getFirstChild(node, nullptr);
188cb93a386Sopenharmony_ci    while (node)
189cb93a386Sopenharmony_ci    {
190cb93a386Sopenharmony_ci        walk_dom(dom, node, parser);
191cb93a386Sopenharmony_ci        node = dom.getNextSibling(node, nullptr);
192cb93a386Sopenharmony_ci    }
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ci    parser->endElement(elem);
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ciconst SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
198cb93a386Sopenharmony_ci    SkDOMParser parser(&fAlloc);
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ci    walk_dom(dom, node, &parser);
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci    fRoot = parser.getRoot();
203cb93a386Sopenharmony_ci    return fRoot;
204cb93a386Sopenharmony_ci}
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_ciSkXMLParser* SkDOM::beginParsing() {
207cb93a386Sopenharmony_ci    SkASSERT(!fParser);
208cb93a386Sopenharmony_ci    fParser = std::make_unique<SkDOMParser>(&fAlloc);
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ci    return fParser.get();
211cb93a386Sopenharmony_ci}
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ciconst SkDOM::Node* SkDOM::finishParsing() {
214cb93a386Sopenharmony_ci    SkASSERT(fParser);
215cb93a386Sopenharmony_ci    fRoot = fParser->getRoot();
216cb93a386Sopenharmony_ci    fParser.reset();
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    return fRoot;
219cb93a386Sopenharmony_ci}
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_ciint SkDOM::countChildren(const Node* node, const char elem[]) const {
224cb93a386Sopenharmony_ci    int count = 0;
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci    node = this->getFirstChild(node, elem);
227cb93a386Sopenharmony_ci    while (node) {
228cb93a386Sopenharmony_ci        count += 1;
229cb93a386Sopenharmony_ci        node = this->getNextSibling(node, elem);
230cb93a386Sopenharmony_ci    }
231cb93a386Sopenharmony_ci    return count;
232cb93a386Sopenharmony_ci}
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci#include "include/utils/SkParse.h"
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_cibool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
239cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
240cb93a386Sopenharmony_ci    return vstr && SkParse::FindS32(vstr, value);
241cb93a386Sopenharmony_ci}
242cb93a386Sopenharmony_ci
243cb93a386Sopenharmony_cibool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
244cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
245cb93a386Sopenharmony_ci    return vstr && SkParse::FindScalars(vstr, value, count);
246cb93a386Sopenharmony_ci}
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_cibool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
249cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
250cb93a386Sopenharmony_ci    return vstr && SkParse::FindHex(vstr, value);
251cb93a386Sopenharmony_ci}
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_cibool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
254cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
255cb93a386Sopenharmony_ci    return vstr && SkParse::FindBool(vstr, value);
256cb93a386Sopenharmony_ci}
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_ciint SkDOM::findList(const Node* node, const char name[], const char list[]) const {
259cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
260cb93a386Sopenharmony_ci    return vstr ? SkParse::FindList(vstr, list) : -1;
261cb93a386Sopenharmony_ci}
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_cibool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
264cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
265cb93a386Sopenharmony_ci    return vstr && !strcmp(vstr, value);
266cb93a386Sopenharmony_ci}
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_cibool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
269cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
270cb93a386Sopenharmony_ci    int32_t     value;
271cb93a386Sopenharmony_ci    return vstr && SkParse::FindS32(vstr, &value) && value == target;
272cb93a386Sopenharmony_ci}
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_cibool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
275cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
276cb93a386Sopenharmony_ci    SkScalar    value;
277cb93a386Sopenharmony_ci    return vstr && SkParse::FindScalar(vstr, &value) && value == target;
278cb93a386Sopenharmony_ci}
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_cibool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
281cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
282cb93a386Sopenharmony_ci    uint32_t    value;
283cb93a386Sopenharmony_ci    return vstr && SkParse::FindHex(vstr, &value) && value == target;
284cb93a386Sopenharmony_ci}
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_cibool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
287cb93a386Sopenharmony_ci    const char* vstr = this->findAttr(node, name);
288cb93a386Sopenharmony_ci    bool        value;
289cb93a386Sopenharmony_ci    return vstr && SkParse::FindBool(vstr, &value) && value == target;
290cb93a386Sopenharmony_ci}
291