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 "include/core/SkStream.h"
11 #include "include/private/SkTo.h"
12 #include "src/xml/SkXMLParser.h"
13 #include "src/xml/SkXMLWriter.h"
14 
parse(const SkDOM & dom,const SkDOMNode * node)15 bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
16     const char* elemName = dom.getName(node);
17 
18     if (this->startElement(elemName)) {
19         return false;
20     }
21 
22     SkDOM::AttrIter iter(dom, node);
23     const char*     name, *value;
24 
25     while ((name = iter.next(&value)) != nullptr) {
26         if (this->addAttribute(name, value)) {
27             return false;
28         }
29     }
30 
31     if ((node = dom.getFirstChild(node)) != nullptr) {
32         do {
33             if (!this->parse(dom, node)) {
34                 return false;
35             }
36         } while ((node = dom.getNextSibling(node)) != nullptr);
37     }
38     return !this->endElement(elemName);
39 }
40 
41 /////////////////////////////////////////////////////////////////////////
42 
43 struct SkDOMAttr {
44     const char* fName;
45     const char* fValue;
46 };
47 
48 struct SkDOMNode {
49     const char* fName;
50     SkDOMNode*  fFirstChild;
51     SkDOMNode*  fNextSibling;
52     SkDOMAttr*  fAttrs;
53     uint16_t    fAttrCount;
54     uint8_t     fType;
55     uint8_t     fPad;
56 
attrsSkDOMNode57     const SkDOMAttr* attrs() const {
58         return fAttrs;
59     }
60 
attrsSkDOMNode61     SkDOMAttr* attrs() {
62         return fAttrs;
63     }
64 };
65 
66 /////////////////////////////////////////////////////////////////////////
67 
68 #define kMinChunkSize   4096
69 
SkDOM()70 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
71 
~SkDOM()72 SkDOM::~SkDOM() {}
73 
getRootNode() const74 const SkDOM::Node* SkDOM::getRootNode() const {
75     return fRoot;
76 }
77 
getFirstChild(const Node * node,const char name[]) const78 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
79     SkASSERT(node);
80     const Node* child = node->fFirstChild;
81 
82     if (name) {
83         for (; child != nullptr; child = child->fNextSibling) {
84             if (!strcmp(name, child->fName)) {
85                 break;
86             }
87         }
88     }
89     return child;
90 }
91 
getNextSibling(const Node * node,const char name[]) const92 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
93     SkASSERT(node);
94     const Node* sibling = node->fNextSibling;
95     if (name) {
96         for (; sibling != nullptr; sibling = sibling->fNextSibling) {
97             if (!strcmp(name, sibling->fName)) {
98                 break;
99             }
100         }
101     }
102     return sibling;
103 }
104 
getType(const Node * node) const105 SkDOM::Type SkDOM::getType(const Node* node) const {
106     SkASSERT(node);
107     return (Type)node->fType;
108 }
109 
getName(const Node * node) const110 const char* SkDOM::getName(const Node* node) const {
111     SkASSERT(node);
112     return node->fName;
113 }
114 
findAttr(const Node * node,const char name[]) const115 const char* SkDOM::findAttr(const Node* node, const char name[]) const {
116     SkASSERT(node);
117     const Attr* attr = node->attrs();
118     const Attr* stop = attr + node->fAttrCount;
119 
120     while (attr < stop) {
121         if (!strcmp(attr->fName, name)) {
122             return attr->fValue;
123         }
124         attr += 1;
125     }
126     return nullptr;
127 }
128 
129 /////////////////////////////////////////////////////////////////////////////////////
130 
getFirstAttr(const Node * node) const131 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
132     return node->fAttrCount ? node->attrs() : nullptr;
133 }
134 
getNextAttr(const Node * node,const Attr * attr) const135 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
136     SkASSERT(node);
137     if (attr == nullptr) {
138         return nullptr;
139     }
140     return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
141 }
142 
getAttrName(const Node * node,const Attr * attr) const143 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
144     SkASSERT(node);
145     SkASSERT(attr);
146     return attr->fName;
147 }
148 
getAttrValue(const Node * node,const Attr * attr) const149 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
150     SkASSERT(node);
151     SkASSERT(attr);
152     return attr->fValue;
153 }
154 
155 /////////////////////////////////////////////////////////////////////////////////////
156 
AttrIter(const SkDOM &,const SkDOM::Node * node)157 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
158     SkASSERT(node);
159     fAttr = node->attrs();
160     fStop = fAttr + node->fAttrCount;
161 }
162 
next(const char ** value)163 const char* SkDOM::AttrIter::next(const char** value) {
164     const char* name = nullptr;
165 
166     if (fAttr < fStop) {
167         name = fAttr->fName;
168         if (value)
169             *value = fAttr->fValue;
170         fAttr += 1;
171     }
172     return name;
173 }
174 
175 //////////////////////////////////////////////////////////////////////////////
176 
177 #include "include/private/SkTDArray.h"
178 #include "src/xml/SkXMLParser.h"
179 
dupstr(SkArenaAlloc * chunk,const char src[])180 static char* dupstr(SkArenaAlloc* chunk, const char src[]) {
181     SkASSERT(chunk && src);
182     size_t  len = strlen(src);
183     char*   dst = chunk->makeArrayDefault<char>(len + 1);
184     memcpy(dst, src, len + 1);
185     return dst;
186 }
187 
188 class SkDOMParser : public SkXMLParser {
189 public:
SkDOMParser(SkArenaAlloc * chunk)190     SkDOMParser(SkArenaAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
191         fAlloc->reset();
192         fRoot = nullptr;
193         fLevel = 0;
194         fNeedToFlush = true;
195     }
getRoot() const196     SkDOM::Node* getRoot() const { return fRoot; }
197     SkXMLParserError fParserError;
198 
199 protected:
flushAttributes()200     void flushAttributes() {
201         SkASSERT(fLevel > 0);
202 
203         int attrCount = fAttrs.count();
204 
205         SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
206         SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
207 
208         node->fName = fElemName;
209         node->fFirstChild = nullptr;
210         node->fAttrCount = SkToU16(attrCount);
211         node->fAttrs = attrs;
212         node->fType = fElemType;
213 
214         if (fRoot == nullptr) {
215             node->fNextSibling = nullptr;
216             fRoot = node;
217         } else { // this adds siblings in reverse order. gets corrected in onEndElement()
218             SkDOM::Node* parent = fParentStack.top();
219             SkASSERT(fRoot && parent);
220             node->fNextSibling = parent->fFirstChild;
221             parent->fFirstChild = node;
222         }
223         *fParentStack.push() = node;
224 
225         sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
226         fAttrs.reset();
227 
228     }
229 
onStartElement(const char elem[])230     bool onStartElement(const char elem[]) override {
231         this->startCommon(elem, SkDOM::kElement_Type);
232         return false;
233     }
234 
onAddAttribute(const char name[],const char value[])235     bool onAddAttribute(const char name[], const char value[]) override {
236         SkDOM::Attr* attr = fAttrs.append();
237         attr->fName = dupstr(fAlloc, name);
238         attr->fValue = dupstr(fAlloc, value);
239         return false;
240     }
241 
onEndElement(const char elem[])242     bool onEndElement(const char elem[]) override {
243         --fLevel;
244         if (fNeedToFlush)
245             this->flushAttributes();
246         fNeedToFlush = false;
247 
248         SkDOM::Node* parent;
249 
250         fParentStack.pop(&parent);
251 
252         SkDOM::Node* child = parent->fFirstChild;
253         SkDOM::Node* prev = nullptr;
254         while (child) {
255             SkDOM::Node* next = child->fNextSibling;
256             child->fNextSibling = prev;
257             prev = child;
258             child = next;
259         }
260         parent->fFirstChild = prev;
261         return false;
262     }
263 
onText(const char text[],int len)264     bool onText(const char text[], int len) override {
265         SkString str(text, len);
266         this->startCommon(str.c_str(), SkDOM::kText_Type);
267         this->SkDOMParser::onEndElement(str.c_str());
268 
269         return false;
270     }
271 
272 private:
startCommon(const char elem[],SkDOM::Type type)273     void startCommon(const char elem[], SkDOM::Type type) {
274         if (fLevel > 0 && fNeedToFlush) {
275             this->flushAttributes();
276         }
277         fNeedToFlush = true;
278         fElemName = dupstr(fAlloc, elem);
279         fElemType = type;
280         ++fLevel;
281     }
282 
283     SkTDArray<SkDOM::Node*> fParentStack;
284     SkArenaAlloc*           fAlloc;
285     SkDOM::Node*            fRoot;
286     bool                    fNeedToFlush;
287 
288     // state needed for flushAttributes()
289     SkTDArray<SkDOM::Attr>  fAttrs;
290     char*                   fElemName;
291     SkDOM::Type             fElemType;
292     int                     fLevel;
293 };
294 
build(SkStream & docStream)295 const SkDOM::Node* SkDOM::build(SkStream& docStream) {
296     SkDOMParser parser(&fAlloc);
297     if (!parser.parse(docStream))
298     {
299         SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
300         fRoot = nullptr;
301         fAlloc.reset();
302         return nullptr;
303     }
304     fRoot = parser.getRoot();
305     return fRoot;
306 }
307 
308 ///////////////////////////////////////////////////////////////////////////
309 
walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)310 static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
311     const char* elem = dom.getName(node);
312     if (dom.getType(node) == SkDOM::kText_Type) {
313         SkASSERT(dom.countChildren(node) == 0);
314         parser->text(elem, SkToInt(strlen(elem)));
315         return;
316     }
317 
318     parser->startElement(elem);
319 
320     SkDOM::AttrIter iter(dom, node);
321     const char*     name;
322     const char*     value;
323     while ((name = iter.next(&value)) != nullptr)
324         parser->addAttribute(name, value);
325 
326     node = dom.getFirstChild(node, nullptr);
327     while (node)
328     {
329         walk_dom(dom, node, parser);
330         node = dom.getNextSibling(node, nullptr);
331     }
332 
333     parser->endElement(elem);
334 }
335 
copy(const SkDOM & dom,const SkDOM::Node * node)336 const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
337     SkDOMParser parser(&fAlloc);
338 
339     walk_dom(dom, node, &parser);
340 
341     fRoot = parser.getRoot();
342     return fRoot;
343 }
344 
beginParsing()345 SkXMLParser* SkDOM::beginParsing() {
346     SkASSERT(!fParser);
347     fParser.reset(new SkDOMParser(&fAlloc));
348 
349     return fParser.get();
350 }
351 
finishParsing()352 const SkDOM::Node* SkDOM::finishParsing() {
353     SkASSERT(fParser);
354     fRoot = fParser->getRoot();
355     fParser.reset();
356 
357     return fRoot;
358 }
359 
360 //////////////////////////////////////////////////////////////////////////
361 
countChildren(const Node * node,const char elem[]) const362 int SkDOM::countChildren(const Node* node, const char elem[]) const {
363     int count = 0;
364 
365     node = this->getFirstChild(node, elem);
366     while (node) {
367         count += 1;
368         node = this->getNextSibling(node, elem);
369     }
370     return count;
371 }
372 
373 //////////////////////////////////////////////////////////////////////////
374 
375 #include "include/utils/SkParse.h"
376 
findS32(const Node * node,const char name[],int32_t * value) const377 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
378     const char* vstr = this->findAttr(node, name);
379     return vstr && SkParse::FindS32(vstr, value);
380 }
381 
findScalars(const Node * node,const char name[],SkScalar value[],int count) const382 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
383     const char* vstr = this->findAttr(node, name);
384     return vstr && SkParse::FindScalars(vstr, value, count);
385 }
386 
findHex(const Node * node,const char name[],uint32_t * value) const387 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
388     const char* vstr = this->findAttr(node, name);
389     return vstr && SkParse::FindHex(vstr, value);
390 }
391 
findBool(const Node * node,const char name[],bool * value) const392 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
393     const char* vstr = this->findAttr(node, name);
394     return vstr && SkParse::FindBool(vstr, value);
395 }
396 
findList(const Node * node,const char name[],const char list[]) const397 int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
398     const char* vstr = this->findAttr(node, name);
399     return vstr ? SkParse::FindList(vstr, list) : -1;
400 }
401 
hasAttr(const Node * node,const char name[],const char value[]) const402 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
403     const char* vstr = this->findAttr(node, name);
404     return vstr && !strcmp(vstr, value);
405 }
406 
hasS32(const Node * node,const char name[],int32_t target) const407 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
408     const char* vstr = this->findAttr(node, name);
409     int32_t     value;
410     return vstr && SkParse::FindS32(vstr, &value) && value == target;
411 }
412 
hasScalar(const Node * node,const char name[],SkScalar target) const413 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
414     const char* vstr = this->findAttr(node, name);
415     SkScalar    value;
416     return vstr && SkParse::FindScalar(vstr, &value) && value == target;
417 }
418 
hasHex(const Node * node,const char name[],uint32_t target) const419 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
420     const char* vstr = this->findAttr(node, name);
421     uint32_t    value;
422     return vstr && SkParse::FindHex(vstr, &value) && value == target;
423 }
424 
hasBool(const Node * node,const char name[],bool target) const425 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
426     const char* vstr = this->findAttr(node, name);
427     bool        value;
428     return vstr && SkParse::FindBool(vstr, &value) && value == target;
429 }
430