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