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/base/SkTo.h"
14 #include "src/xml/SkXMLParser.h"
15 #include "src/xml/SkXMLWriter.h"
16
parse(const SkDOM & dom,const SkDOMNode * node)17 bool 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
46 /////////////////////////////////////////////////////////////////////////
47
48 #define kMinChunkSize 4096
49
SkDOM()50 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
51
~SkDOM()52 SkDOM::~SkDOM() {}
53
getRootNode() const54 const SkDOM::Node* SkDOM::getRootNode() const {
55 return fRoot;
56 }
57
getFirstChild(const Node * node,const char name[]) const58 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
59 SkASSERT(node);
60 const Node* child = node->fFirstChild;
61
62 if (name) {
63 for (; child != nullptr; child = child->fNextSibling) {
64 if (!strcmp(name, child->fName)) {
65 break;
66 }
67 }
68 }
69 return child;
70 }
71
getNextSibling(const Node * node,const char name[]) const72 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
73 SkASSERT(node);
74 const Node* sibling = node->fNextSibling;
75 if (name) {
76 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
77 if (!strcmp(name, sibling->fName)) {
78 break;
79 }
80 }
81 }
82 return sibling;
83 }
84
getType(const Node * node) const85 SkDOM::Type SkDOM::getType(const Node* node) const {
86 SkASSERT(node);
87 return (Type)node->fType;
88 }
89
getName(const Node * node) const90 const char* SkDOM::getName(const Node* node) const {
91 SkASSERT(node);
92 return node->fName;
93 }
94
findAttr(const Node * node,const char name[]) const95 const char* SkDOM::findAttr(const Node* node, const char name[]) const {
96 SkASSERT(node);
97 const Attr* attr = node->attrs();
98 const Attr* stop = attr + node->fAttrCount;
99
100 while (attr < stop) {
101 if (!strcmp(attr->fName, name)) {
102 return attr->fValue;
103 }
104 attr += 1;
105 }
106 return nullptr;
107 }
108
109 /////////////////////////////////////////////////////////////////////////////////////
110
getFirstAttr(const Node * node) const111 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
112 return node->fAttrCount ? node->attrs() : nullptr;
113 }
114
getNextAttr(const Node * node,const Attr * attr) const115 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
116 SkASSERT(node);
117 if (attr == nullptr) {
118 return nullptr;
119 }
120 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
121 }
122
getAttrName(const Node * node,const Attr * attr) const123 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
124 SkASSERT(node);
125 SkASSERT(attr);
126 return attr->fName;
127 }
128
getAttrValue(const Node * node,const Attr * attr) const129 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
130 SkASSERT(node);
131 SkASSERT(attr);
132 return attr->fValue;
133 }
134
135 /////////////////////////////////////////////////////////////////////////////////////
136
AttrIter(const SkDOM &,const SkDOM::Node * node)137 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
138 SkASSERT(node);
139 fAttr = node->attrs();
140 fStop = fAttr + node->fAttrCount;
141 }
142
next(const char ** value)143 const char* SkDOM::AttrIter::next(const char** value) {
144 const char* name = nullptr;
145
146 if (fAttr < fStop) {
147 name = fAttr->fName;
148 if (value)
149 *value = fAttr->fValue;
150 fAttr += 1;
151 }
152 return name;
153 }
154
155 //////////////////////////////////////////////////////////////////////////////
156 #include "src/xml/SkDOMParser.h"
157
build(SkStream & docStream)158 const SkDOM::Node* SkDOM::build(SkStream& docStream) {
159 SkDOMParser parser(&fAlloc);
160 if (!parser.parse(docStream))
161 {
162 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
163 fRoot = nullptr;
164 fAlloc.reset();
165 return nullptr;
166 }
167 fRoot = parser.getRoot();
168 return fRoot;
169 }
170
171 ///////////////////////////////////////////////////////////////////////////
172
walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)173 void SkDOM::walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
174 const char* elem = dom.getName(node);
175 if (dom.getType(node) == SkDOM::kText_Type) {
176 SkASSERT(dom.countChildren(node) == 0);
177 parser->text(elem, SkToInt(strlen(elem)));
178 return;
179 }
180
181 parser->startElement(elem);
182
183 SkDOM::AttrIter iter(dom, node);
184 const char* name;
185 const char* value;
186 while ((name = iter.next(&value)) != nullptr)
187 parser->addAttribute(name, value);
188
189 node = dom.getFirstChild(node, nullptr);
190 while (node)
191 {
192 walk_dom(dom, node, parser);
193 node = dom.getNextSibling(node, nullptr);
194 }
195
196 parser->endElement(elem);
197 }
198
copy(const SkDOM & dom,const SkDOM::Node * node)199 const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
200 SkDOMParser parser(&fAlloc);
201
202 walk_dom(dom, node, &parser);
203
204 fRoot = parser.getRoot();
205 return fRoot;
206 }
207
beginParsing()208 SkXMLParser* SkDOM::beginParsing() {
209 SkASSERT(!fParser);
210 fParser = std::make_unique<SkDOMParser>(&fAlloc);
211
212 return fParser.get();
213 }
214
finishParsing()215 const SkDOM::Node* SkDOM::finishParsing() {
216 SkASSERT(fParser);
217 fRoot = fParser->getRoot();
218 fParser.reset();
219
220 return fRoot;
221 }
222
223 //////////////////////////////////////////////////////////////////////////
224
countChildren(const Node * node,const char elem[]) const225 int SkDOM::countChildren(const Node* node, const char elem[]) const {
226 int count = 0;
227
228 node = this->getFirstChild(node, elem);
229 while (node) {
230 count += 1;
231 node = this->getNextSibling(node, elem);
232 }
233 return count;
234 }
235
236 //////////////////////////////////////////////////////////////////////////
237
238 #include "include/utils/SkParse.h"
239
findS32(const Node * node,const char name[],int32_t * value) const240 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
241 const char* vstr = this->findAttr(node, name);
242 return vstr && SkParse::FindS32(vstr, value);
243 }
244
findScalars(const Node * node,const char name[],SkScalar value[],int count) const245 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
246 const char* vstr = this->findAttr(node, name);
247 return vstr && SkParse::FindScalars(vstr, value, count);
248 }
249
findHex(const Node * node,const char name[],uint32_t * value) const250 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
251 const char* vstr = this->findAttr(node, name);
252 return vstr && SkParse::FindHex(vstr, value);
253 }
254
findBool(const Node * node,const char name[],bool * value) const255 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
256 const char* vstr = this->findAttr(node, name);
257 return vstr && SkParse::FindBool(vstr, value);
258 }
259
findList(const Node * node,const char name[],const char list[]) const260 int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
261 const char* vstr = this->findAttr(node, name);
262 return vstr ? SkParse::FindList(vstr, list) : -1;
263 }
264
hasAttr(const Node * node,const char name[],const char value[]) const265 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
266 const char* vstr = this->findAttr(node, name);
267 return vstr && !strcmp(vstr, value);
268 }
269
hasS32(const Node * node,const char name[],int32_t target) const270 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
271 const char* vstr = this->findAttr(node, name);
272 int32_t value;
273 return vstr && SkParse::FindS32(vstr, &value) && value == target;
274 }
275
hasScalar(const Node * node,const char name[],SkScalar target) const276 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
277 const char* vstr = this->findAttr(node, name);
278 SkScalar value;
279 return vstr && SkParse::FindScalar(vstr, &value) && value == target;
280 }
281
hasHex(const Node * node,const char name[],uint32_t target) const282 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
283 const char* vstr = this->findAttr(node, name);
284 uint32_t value;
285 return vstr && SkParse::FindHex(vstr, &value) && value == target;
286 }
287
hasBool(const Node * node,const char name[],bool target) const288 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
289 const char* vstr = this->findAttr(node, name);
290 bool value;
291 return vstr && SkParse::FindBool(vstr, &value) && value == target;
292 }
293