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
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 struct SkDOMAttr {
46 const char* fName;
47 const char* fValue;
48 };
49
50 struct SkDOMNode {
51 const char* fName;
52 SkDOMNode* fFirstChild;
53 SkDOMNode* fNextSibling;
54 SkDOMAttr* fAttrs;
55 uint16_t fAttrCount;
56 uint8_t fType;
57 uint8_t fPad;
58
attrsSkDOMNode59 const SkDOMAttr* attrs() const {
60 return fAttrs;
61 }
62
attrsSkDOMNode63 SkDOMAttr* attrs() {
64 return fAttrs;
65 }
66 };
67
68 /////////////////////////////////////////////////////////////////////////
69
70 #define kMinChunkSize 4096
71
SkDOM()72 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
73
~SkDOM()74 SkDOM::~SkDOM() {}
75
getRootNode() const76 const SkDOM::Node* SkDOM::getRootNode() const {
77 return fRoot;
78 }
79
getFirstChild(const Node * node,const char name[]) const80 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
81 SkASSERT(node);
82 const Node* child = node->fFirstChild;
83
84 if (name) {
85 for (; child != nullptr; child = child->fNextSibling) {
86 if (!strcmp(name, child->fName)) {
87 break;
88 }
89 }
90 }
91 return child;
92 }
93
getNextSibling(const Node * node,const char name[]) const94 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
95 SkASSERT(node);
96 const Node* sibling = node->fNextSibling;
97 if (name) {
98 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
99 if (!strcmp(name, sibling->fName)) {
100 break;
101 }
102 }
103 }
104 return sibling;
105 }
106
getType(const Node * node) const107 SkDOM::Type SkDOM::getType(const Node* node) const {
108 SkASSERT(node);
109 return (Type)node->fType;
110 }
111
getName(const Node * node) const112 const char* SkDOM::getName(const Node* node) const {
113 SkASSERT(node);
114 return node->fName;
115 }
116
findAttr(const Node * node,const char name[]) const117 const char* SkDOM::findAttr(const Node* node, const char name[]) const {
118 SkASSERT(node);
119 const Attr* attr = node->attrs();
120 const Attr* stop = attr + node->fAttrCount;
121
122 while (attr < stop) {
123 if (!strcmp(attr->fName, name)) {
124 return attr->fValue;
125 }
126 attr += 1;
127 }
128 return nullptr;
129 }
130
131 /////////////////////////////////////////////////////////////////////////////////////
132
getFirstAttr(const Node * node) const133 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
134 return node->fAttrCount ? node->attrs() : nullptr;
135 }
136
getNextAttr(const Node * node,const Attr * attr) const137 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
138 SkASSERT(node);
139 if (attr == nullptr) {
140 return nullptr;
141 }
142 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
143 }
144
getAttrName(const Node * node,const Attr * attr) const145 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
146 SkASSERT(node);
147 SkASSERT(attr);
148 return attr->fName;
149 }
150
getAttrValue(const Node * node,const Attr * attr) const151 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
152 SkASSERT(node);
153 SkASSERT(attr);
154 return attr->fValue;
155 }
156
157 /////////////////////////////////////////////////////////////////////////////////////
158
AttrIter(const SkDOM &,const SkDOM::Node * node)159 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
160 SkASSERT(node);
161 fAttr = node->attrs();
162 fStop = fAttr + node->fAttrCount;
163 }
164
next(const char ** value)165 const char* SkDOM::AttrIter::next(const char** value) {
166 const char* name = nullptr;
167
168 if (fAttr < fStop) {
169 name = fAttr->fName;
170 if (value)
171 *value = fAttr->fValue;
172 fAttr += 1;
173 }
174 return name;
175 }
176
177 //////////////////////////////////////////////////////////////////////////////
178
179 #include "include/private/SkTDArray.h"
180 #include "src/xml/SkXMLParser.h"
181
dupstr(SkArenaAlloc * chunk,const char src[],size_t srcLen)182 static char* dupstr(SkArenaAlloc* chunk, const char src[], size_t srcLen) {
183 SkASSERT(chunk && src);
184 char* dst = chunk->makeArrayDefault<char>(srcLen + 1);
185 memcpy(dst, src, srcLen);
186 dst[srcLen] = '\0';
187 return dst;
188 }
189
190 class SkDOMParser : public SkXMLParser {
191 public:
SkDOMParser(SkArenaAllocWithReset * chunk)192 SkDOMParser(SkArenaAllocWithReset* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
193 fAlloc->reset();
194 fRoot = nullptr;
195 fLevel = 0;
196 fNeedToFlush = true;
197 }
getRoot() const198 SkDOM::Node* getRoot() const { return fRoot; }
199 SkXMLParserError fParserError;
200
201 protected:
flushAttributes()202 void flushAttributes() {
203 SkASSERT(fLevel > 0);
204
205 int attrCount = fAttrs.count();
206
207 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
208 SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
209
210 node->fName = fElemName;
211 node->fFirstChild = nullptr;
212 node->fAttrCount = SkToU16(attrCount);
213 node->fAttrs = attrs;
214 node->fType = fElemType;
215
216 if (fRoot == nullptr) {
217 node->fNextSibling = nullptr;
218 fRoot = node;
219 } else { // this adds siblings in reverse order. gets corrected in onEndElement()
220 SkDOM::Node* parent = fParentStack.top();
221 SkASSERT(fRoot && parent);
222 node->fNextSibling = parent->fFirstChild;
223 parent->fFirstChild = node;
224 }
225 *fParentStack.push() = node;
226
227 sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
228 fAttrs.reset();
229
230 }
231
onStartElement(const char elem[])232 bool onStartElement(const char elem[]) override {
233 this->startCommon(elem, strlen(elem), SkDOM::kElement_Type);
234 return false;
235 }
236
onAddAttribute(const char name[],const char value[])237 bool onAddAttribute(const char name[], const char value[]) override {
238 SkDOM::Attr* attr = fAttrs.append();
239 attr->fName = dupstr(fAlloc, name, strlen(name));
240 attr->fValue = dupstr(fAlloc, value, strlen(value));
241 return false;
242 }
243
onEndElement(const char elem[])244 bool onEndElement(const char elem[]) override {
245 --fLevel;
246 if (fNeedToFlush)
247 this->flushAttributes();
248 fNeedToFlush = false;
249
250 SkDOM::Node* parent;
251
252 fParentStack.pop(&parent);
253
254 SkDOM::Node* child = parent->fFirstChild;
255 SkDOM::Node* prev = nullptr;
256 while (child) {
257 SkDOM::Node* next = child->fNextSibling;
258 child->fNextSibling = prev;
259 prev = child;
260 child = next;
261 }
262 parent->fFirstChild = prev;
263 return false;
264 }
265
onText(const char text[],int len)266 bool onText(const char text[], int len) override {
267 this->startCommon(text, len, SkDOM::kText_Type);
268 this->SkDOMParser::onEndElement(fElemName);
269
270 return false;
271 }
272
273 private:
startCommon(const char elem[],size_t elemSize,SkDOM::Type type)274 void startCommon(const char elem[], size_t elemSize, SkDOM::Type type) {
275 if (fLevel > 0 && fNeedToFlush) {
276 this->flushAttributes();
277 }
278 fNeedToFlush = true;
279 fElemName = dupstr(fAlloc, elem, elemSize);
280 fElemType = type;
281 ++fLevel;
282 }
283
284 SkTDArray<SkDOM::Node*> fParentStack;
285 SkArenaAllocWithReset* fAlloc;
286 SkDOM::Node* fRoot;
287 bool fNeedToFlush;
288
289 // state needed for flushAttributes()
290 SkTDArray<SkDOM::Attr> fAttrs;
291 char* fElemName;
292 SkDOM::Type fElemType;
293 int fLevel;
294 };
295
build(SkStream & docStream)296 const SkDOM::Node* SkDOM::build(SkStream& docStream) {
297 SkDOMParser parser(&fAlloc);
298 if (!parser.parse(docStream))
299 {
300 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
301 fRoot = nullptr;
302 fAlloc.reset();
303 return nullptr;
304 }
305 fRoot = parser.getRoot();
306 return fRoot;
307 }
308
309 ///////////////////////////////////////////////////////////////////////////
310
walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)311 static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
312 const char* elem = dom.getName(node);
313 if (dom.getType(node) == SkDOM::kText_Type) {
314 SkASSERT(dom.countChildren(node) == 0);
315 parser->text(elem, SkToInt(strlen(elem)));
316 return;
317 }
318
319 parser->startElement(elem);
320
321 SkDOM::AttrIter iter(dom, node);
322 const char* name;
323 const char* value;
324 while ((name = iter.next(&value)) != nullptr)
325 parser->addAttribute(name, value);
326
327 node = dom.getFirstChild(node, nullptr);
328 while (node)
329 {
330 walk_dom(dom, node, parser);
331 node = dom.getNextSibling(node, nullptr);
332 }
333
334 parser->endElement(elem);
335 }
336
copy(const SkDOM & dom,const SkDOM::Node * node)337 const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
338 SkDOMParser parser(&fAlloc);
339
340 walk_dom(dom, node, &parser);
341
342 fRoot = parser.getRoot();
343 return fRoot;
344 }
345
beginParsing()346 SkXMLParser* SkDOM::beginParsing() {
347 SkASSERT(!fParser);
348 fParser = std::make_unique<SkDOMParser>(&fAlloc);
349
350 return fParser.get();
351 }
352
finishParsing()353 const SkDOM::Node* SkDOM::finishParsing() {
354 SkASSERT(fParser);
355 fRoot = fParser->getRoot();
356 fParser.reset();
357
358 return fRoot;
359 }
360
361 //////////////////////////////////////////////////////////////////////////
362
countChildren(const Node * node,const char elem[]) const363 int SkDOM::countChildren(const Node* node, const char elem[]) const {
364 int count = 0;
365
366 node = this->getFirstChild(node, elem);
367 while (node) {
368 count += 1;
369 node = this->getNextSibling(node, elem);
370 }
371 return count;
372 }
373
374 //////////////////////////////////////////////////////////////////////////
375
376 #include "include/utils/SkParse.h"
377
findS32(const Node * node,const char name[],int32_t * value) const378 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
379 const char* vstr = this->findAttr(node, name);
380 return vstr && SkParse::FindS32(vstr, value);
381 }
382
findScalars(const Node * node,const char name[],SkScalar value[],int count) const383 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
384 const char* vstr = this->findAttr(node, name);
385 return vstr && SkParse::FindScalars(vstr, value, count);
386 }
387
findHex(const Node * node,const char name[],uint32_t * value) const388 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
389 const char* vstr = this->findAttr(node, name);
390 return vstr && SkParse::FindHex(vstr, value);
391 }
392
findBool(const Node * node,const char name[],bool * value) const393 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
394 const char* vstr = this->findAttr(node, name);
395 return vstr && SkParse::FindBool(vstr, value);
396 }
397
findList(const Node * node,const char name[],const char list[]) const398 int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
399 const char* vstr = this->findAttr(node, name);
400 return vstr ? SkParse::FindList(vstr, list) : -1;
401 }
402
hasAttr(const Node * node,const char name[],const char value[]) const403 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
404 const char* vstr = this->findAttr(node, name);
405 return vstr && !strcmp(vstr, value);
406 }
407
hasS32(const Node * node,const char name[],int32_t target) const408 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
409 const char* vstr = this->findAttr(node, name);
410 int32_t value;
411 return vstr && SkParse::FindS32(vstr, &value) && value == target;
412 }
413
hasScalar(const Node * node,const char name[],SkScalar target) const414 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
415 const char* vstr = this->findAttr(node, name);
416 SkScalar value;
417 return vstr && SkParse::FindScalar(vstr, &value) && value == target;
418 }
419
hasHex(const Node * node,const char name[],uint32_t target) const420 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
421 const char* vstr = this->findAttr(node, name);
422 uint32_t value;
423 return vstr && SkParse::FindHex(vstr, &value) && value == target;
424 }
425
hasBool(const Node * node,const char name[],bool target) const426 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
427 const char* vstr = this->findAttr(node, name);
428 bool value;
429 return vstr && SkParse::FindBool(vstr, &value) && value == target;
430 }
431