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