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