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