• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkDOM.h"
11 
12 /////////////////////////////////////////////////////////////////////////
13 
14 #include "SkXMLParser.h"
15 
parse(const SkDOM & dom,const SkDOMNode * node)16 bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node)
17 {
18     const char* elemName = dom.getName(node);
19 
20     if (this->startElement(elemName))
21         return false;
22 
23     SkDOM::AttrIter iter(dom, node);
24     const char*     name, *value;
25 
26     while ((name = iter.next(&value)) != NULL)
27         if (this->addAttribute(name, value))
28             return false;
29 
30     if ((node = dom.getFirstChild(node)) != NULL)
31         do {
32             if (!this->parse(dom, node))
33                 return false;
34         } while ((node = dom.getNextSibling(node)) != NULL);
35 
36     return !this->endElement(elemName);
37 }
38 
39 /////////////////////////////////////////////////////////////////////////
40 
41 struct SkDOMAttr {
42     const char* fName;
43     const char* fValue;
44 };
45 
46 struct SkDOMNode {
47     const char* fName;
48     SkDOMNode*  fFirstChild;
49     SkDOMNode*  fNextSibling;
50     uint16_t    fAttrCount;
51     uint8_t     fType;
52     uint8_t     fPad;
53 
attrsSkDOMNode54     const SkDOMAttr* attrs() const
55     {
56         return (const SkDOMAttr*)(this + 1);
57     }
attrsSkDOMNode58     SkDOMAttr* attrs()
59     {
60         return (SkDOMAttr*)(this + 1);
61     }
62 };
63 
64 /////////////////////////////////////////////////////////////////////////
65 
66 #define kMinChunkSize   512
67 
SkDOM()68 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(NULL)
69 {
70 }
71 
~SkDOM()72 SkDOM::~SkDOM()
73 {
74 }
75 
getRootNode() const76 const SkDOM::Node* SkDOM::getRootNode() const
77 {
78     return fRoot;
79 }
80 
getFirstChild(const Node * node,const char name[]) const81 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const
82 {
83     SkASSERT(node);
84     const Node* child = node->fFirstChild;
85 
86     if (name)
87     {
88         for (; child != NULL; child = child->fNextSibling)
89             if (!strcmp(name, child->fName))
90                 break;
91     }
92     return child;
93 }
94 
getNextSibling(const Node * node,const char name[]) const95 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const
96 {
97     SkASSERT(node);
98     const Node* sibling = node->fNextSibling;
99     if (name)
100     {
101         for (; sibling != NULL; sibling = sibling->fNextSibling)
102             if (!strcmp(name, sibling->fName))
103                 break;
104     }
105     return sibling;
106 }
107 
getType(const Node * node) const108 SkDOM::Type SkDOM::getType(const Node* node) const
109 {
110     SkASSERT(node);
111     return (Type)node->fType;
112 }
113 
getName(const Node * node) const114 const char* SkDOM::getName(const Node* node) const
115 {
116     SkASSERT(node);
117     return node->fName;
118 }
119 
findAttr(const Node * node,const char name[]) const120 const char* SkDOM::findAttr(const Node* node, const char name[]) const
121 {
122     SkASSERT(node);
123     const Attr* attr = node->attrs();
124     const Attr* stop = attr + node->fAttrCount;
125 
126     while (attr < stop)
127     {
128         if (!strcmp(attr->fName, name))
129             return attr->fValue;
130         attr += 1;
131     }
132     return NULL;
133 }
134 
135 /////////////////////////////////////////////////////////////////////////////////////
136 
getFirstAttr(const Node * node) const137 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const
138 {
139     return node->fAttrCount ? node->attrs() : NULL;
140 }
141 
getNextAttr(const Node * node,const Attr * attr) const142 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const
143 {
144     SkASSERT(node);
145     if (attr == NULL)
146         return NULL;
147     return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : NULL;
148 }
149 
getAttrName(const Node * node,const Attr * attr) const150 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const
151 {
152     SkASSERT(node);
153     SkASSERT(attr);
154     return attr->fName;
155 }
156 
getAttrValue(const Node * node,const Attr * attr) const157 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const
158 {
159     SkASSERT(node);
160     SkASSERT(attr);
161     return attr->fValue;
162 }
163 
164 /////////////////////////////////////////////////////////////////////////////////////
165 
AttrIter(const SkDOM &,const SkDOM::Node * node)166 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node)
167 {
168     SkASSERT(node);
169     fAttr = node->attrs();
170     fStop = fAttr + node->fAttrCount;
171 }
172 
next(const char ** value)173 const char* SkDOM::AttrIter::next(const char** value)
174 {
175     const char* name = NULL;
176 
177     if (fAttr < fStop)
178     {
179         name = fAttr->fName;
180         if (value)
181             *value = fAttr->fValue;
182         fAttr += 1;
183     }
184     return name;
185 }
186 
187 //////////////////////////////////////////////////////////////////////////////
188 
189 #include "SkXMLParser.h"
190 #include "SkTDArray.h"
191 
dupstr(SkChunkAlloc * chunk,const char src[])192 static char* dupstr(SkChunkAlloc* chunk, const char src[])
193 {
194     SkASSERT(chunk && src);
195     size_t  len = strlen(src);
196     char*   dst = (char*)chunk->alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType);
197     memcpy(dst, src, len + 1);
198     return dst;
199 }
200 
201 class SkDOMParser : public SkXMLParser {
202     bool fNeedToFlush;
203 public:
SkDOMParser(SkChunkAlloc * chunk)204     SkDOMParser(SkChunkAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk)
205     {
206         fRoot = NULL;
207         fLevel = 0;
208         fNeedToFlush = true;
209     }
getRoot() const210     SkDOM::Node* getRoot() const { return fRoot; }
211     SkXMLParserError fParserError;
212 protected:
flushAttributes()213     void flushAttributes()
214     {
215         int attrCount = fAttrs.count();
216 
217         SkDOM::Node* node = (SkDOM::Node*)fAlloc->alloc(sizeof(SkDOM::Node) + attrCount * sizeof(SkDOM::Attr),
218                                                         SkChunkAlloc::kThrow_AllocFailType);
219 
220         node->fName = fElemName;
221         node->fFirstChild = NULL;
222         node->fAttrCount = SkToU16(attrCount);
223         node->fType = SkDOM::kElement_Type;
224 
225         if (fRoot == NULL)
226         {
227             node->fNextSibling = NULL;
228             fRoot = node;
229         }
230         else    // this adds siblings in reverse order. gets corrected in onEndElement()
231         {
232             SkDOM::Node* parent = fParentStack.top();
233             SkASSERT(fRoot && parent);
234             node->fNextSibling = parent->fFirstChild;
235             parent->fFirstChild = node;
236         }
237         *fParentStack.push() = node;
238 
239         memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
240         fAttrs.reset();
241 
242     }
onStartElement(const char elem[])243     virtual bool onStartElement(const char elem[])
244     {
245         if (fLevel > 0 && fNeedToFlush)
246             this->flushAttributes();
247         fNeedToFlush = true;
248         fElemName = dupstr(fAlloc, elem);
249         ++fLevel;
250         return false;
251     }
onAddAttribute(const char name[],const char value[])252     virtual bool onAddAttribute(const char name[], const char value[])
253     {
254         SkDOM::Attr* attr = fAttrs.append();
255         attr->fName = dupstr(fAlloc, name);
256         attr->fValue = dupstr(fAlloc, value);
257         return false;
258     }
onEndElement(const char elem[])259     virtual bool onEndElement(const char elem[])
260     {
261         --fLevel;
262         if (fNeedToFlush)
263             this->flushAttributes();
264         fNeedToFlush = false;
265 
266         SkDOM::Node* parent;
267 
268         fParentStack.pop(&parent);
269 
270         SkDOM::Node* child = parent->fFirstChild;
271         SkDOM::Node* prev = NULL;
272         while (child)
273         {
274             SkDOM::Node* next = child->fNextSibling;
275             child->fNextSibling = prev;
276             prev = child;
277             child = next;
278         }
279         parent->fFirstChild = prev;
280         return false;
281     }
282 private:
283     SkTDArray<SkDOM::Node*> fParentStack;
284     SkChunkAlloc*   fAlloc;
285     SkDOM::Node*    fRoot;
286 
287     // state needed for flushAttributes()
288     SkTDArray<SkDOM::Attr>  fAttrs;
289     char*                   fElemName;
290     int                     fLevel;
291 };
292 
build(const char doc[],size_t len)293 const SkDOM::Node* SkDOM::build(const char doc[], size_t len)
294 {
295     fAlloc.reset();
296     SkDOMParser parser(&fAlloc);
297     if (!parser.parse(doc, len))
298     {
299         SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
300         fRoot = NULL;
301         fAlloc.reset();
302         return NULL;
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 {
312     const char* elem = dom.getName(node);
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)) != NULL)
320         parser->addAttribute(name, value);
321 
322     node = dom.getFirstChild(node, NULL);
323     while (node)
324     {
325         walk_dom(dom, node, parser);
326         node = dom.getNextSibling(node, NULL);
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 {
334     fAlloc.reset();
335     SkDOMParser parser(&fAlloc);
336 
337     walk_dom(dom, node, &parser);
338 
339     fRoot = parser.getRoot();
340     return fRoot;
341 }
342 
343 //////////////////////////////////////////////////////////////////////////
344 
countChildren(const Node * node,const char elem[]) const345 int SkDOM::countChildren(const Node* node, const char elem[]) const
346 {
347     int count = 0;
348 
349     node = this->getFirstChild(node, elem);
350     while (node)
351     {
352         count += 1;
353         node = this->getNextSibling(node, elem);
354     }
355     return count;
356 }
357 
358 //////////////////////////////////////////////////////////////////////////
359 
360 #include "SkParse.h"
361 
findS32(const Node * node,const char name[],int32_t * value) const362 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const
363 {
364     const char* vstr = this->findAttr(node, name);
365     return vstr && SkParse::FindS32(vstr, value);
366 }
367 
findScalars(const Node * node,const char name[],SkScalar value[],int count) const368 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const
369 {
370     const char* vstr = this->findAttr(node, name);
371     return vstr && SkParse::FindScalars(vstr, value, count);
372 }
373 
findHex(const Node * node,const char name[],uint32_t * value) const374 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const
375 {
376     const char* vstr = this->findAttr(node, name);
377     return vstr && SkParse::FindHex(vstr, value);
378 }
379 
findBool(const Node * node,const char name[],bool * value) const380 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const
381 {
382     const char* vstr = this->findAttr(node, name);
383     return vstr && SkParse::FindBool(vstr, value);
384 }
385 
findList(const Node * node,const char name[],const char list[]) const386 int SkDOM::findList(const Node* node, const char name[], const char list[]) const
387 {
388     const char* vstr = this->findAttr(node, name);
389     return vstr ? SkParse::FindList(vstr, list) : -1;
390 }
391 
hasAttr(const Node * node,const char name[],const char value[]) const392 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const
393 {
394     const char* vstr = this->findAttr(node, name);
395     return vstr && !strcmp(vstr, value);
396 }
397 
hasS32(const Node * node,const char name[],int32_t target) const398 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const
399 {
400     const char* vstr = this->findAttr(node, name);
401     int32_t     value;
402     return vstr && SkParse::FindS32(vstr, &value) && value == target;
403 }
404 
hasScalar(const Node * node,const char name[],SkScalar target) const405 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const
406 {
407     const char* vstr = this->findAttr(node, name);
408     SkScalar    value;
409     return vstr && SkParse::FindScalar(vstr, &value) && value == target;
410 }
411 
hasHex(const Node * node,const char name[],uint32_t target) const412 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const
413 {
414     const char* vstr = this->findAttr(node, name);
415     uint32_t    value;
416     return vstr && SkParse::FindHex(vstr, &value) && value == target;
417 }
418 
hasBool(const Node * node,const char name[],bool target) const419 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const
420 {
421     const char* vstr = this->findAttr(node, name);
422     bool        value;
423     return vstr && SkParse::FindBool(vstr, &value) && value == target;
424 }
425 
426 //////////////////////////////////////////////////////////////////////////
427 
428 #ifdef SK_DEBUG
429 
tab(int level)430 static void tab(int level)
431 {
432     while (--level >= 0)
433         SkDebugf("\t");
434 }
435 
dump(const Node * node,int level) const436 void SkDOM::dump(const Node* node, int level) const
437 {
438     if (node == NULL)
439         node = this->getRootNode();
440     if (node)
441     {
442         tab(level);
443         SkDebugf("<%s", this->getName(node));
444 
445         const Attr* attr = node->attrs();
446         const Attr* stop = attr + node->fAttrCount;
447         for (; attr < stop; attr++)
448             SkDebugf(" %s=\"%s\"", attr->fName, attr->fValue);
449 
450         const Node* child = this->getFirstChild(node);
451         if (child)
452         {
453             SkDebugf(">\n");
454             while (child)
455             {
456                 this->dump(child, level+1);
457                 child = this->getNextSibling(child);
458             }
459             tab(level);
460             SkDebugf("</%s>\n", node->fName);
461         }
462         else
463             SkDebugf("/>\n");
464     }
465 }
466 
UnitTest()467 void SkDOM::UnitTest()
468 {
469 #ifdef SK_SUPPORT_UNITTEST
470     static const char gDoc[] =
471         "<root a='1' b='2'>"
472             "<elem1 c='3' />"
473             "<elem2 d='4' />"
474             "<elem3 e='5'>"
475                 "<subelem1/>"
476                 "<subelem2 f='6' g='7'/>"
477             "</elem3>"
478             "<elem4 h='8'/>"
479         "</root>"
480         ;
481 
482     SkDOM   dom;
483 
484     SkASSERT(dom.getRootNode() == NULL);
485 
486     const Node* root = dom.build(gDoc, sizeof(gDoc) - 1);
487     SkASSERT(root && dom.getRootNode() == root);
488 
489     const char* v = dom.findAttr(root, "a");
490     SkASSERT(v && !strcmp(v, "1"));
491     v = dom.findAttr(root, "b");
492     SkASSERT(v && !strcmp(v, "2"));
493     v = dom.findAttr(root, "c");
494     SkASSERT(v == NULL);
495 
496     SkASSERT(dom.getFirstChild(root, "elem1"));
497     SkASSERT(!dom.getFirstChild(root, "subelem1"));
498 
499     dom.dump();
500 #endif
501 }
502 
503 #endif
504 
505