OLD | NEW |
| (Empty) |
1 /* libs/graphics/xml/SkDOM.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkDOM.h" | |
19 | |
20 ///////////////////////////////////////////////////////////////////////// | |
21 | |
22 #include "SkXMLParser.h" | |
23 | |
24 bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) | |
25 { | |
26 const char* elemName = dom.getName(node); | |
27 | |
28 if (this->startElement(elemName)) | |
29 return false; | |
30 | |
31 SkDOM::AttrIter iter(dom, node); | |
32 const char* name, *value; | |
33 | |
34 while ((name = iter.next(&value)) != NULL) | |
35 if (this->addAttribute(name, value)) | |
36 return false; | |
37 | |
38 if ((node = dom.getFirstChild(node)) != NULL) | |
39 do { | |
40 if (!this->parse(dom, node)) | |
41 return false; | |
42 } while ((node = dom.getNextSibling(node)) != NULL); | |
43 | |
44 return !this->endElement(elemName); | |
45 } | |
46 | |
47 ///////////////////////////////////////////////////////////////////////// | |
48 | |
49 struct SkDOMAttr { | |
50 const char* fName; | |
51 const char* fValue; | |
52 }; | |
53 | |
54 struct SkDOMNode { | |
55 const char* fName; | |
56 SkDOMNode* fFirstChild; | |
57 SkDOMNode* fNextSibling; | |
58 uint16_t fAttrCount; | |
59 uint8_t fType; | |
60 uint8_t fPad; | |
61 | |
62 const SkDOMAttr* attrs() const | |
63 { | |
64 return (const SkDOMAttr*)(this + 1); | |
65 } | |
66 SkDOMAttr* attrs() | |
67 { | |
68 return (SkDOMAttr*)(this + 1); | |
69 } | |
70 }; | |
71 | |
72 ///////////////////////////////////////////////////////////////////////// | |
73 | |
74 #define kMinChunkSize 512 | |
75 | |
76 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(NULL) | |
77 { | |
78 } | |
79 | |
80 SkDOM::~SkDOM() | |
81 { | |
82 } | |
83 | |
84 const SkDOM::Node* SkDOM::getRootNode() const | |
85 { | |
86 return fRoot; | |
87 } | |
88 | |
89 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) con
st | |
90 { | |
91 SkASSERT(node); | |
92 const Node* child = node->fFirstChild; | |
93 | |
94 if (name) | |
95 { | |
96 for (; child != NULL; child = child->fNextSibling) | |
97 if (!strcmp(name, child->fName)) | |
98 break; | |
99 } | |
100 return child; | |
101 } | |
102 | |
103 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) co
nst | |
104 { | |
105 SkASSERT(node); | |
106 const Node* sibling = node->fNextSibling; | |
107 if (name) | |
108 { | |
109 for (; sibling != NULL; sibling = sibling->fNextSibling) | |
110 if (!strcmp(name, sibling->fName)) | |
111 break; | |
112 } | |
113 return sibling; | |
114 } | |
115 | |
116 SkDOM::Type SkDOM::getType(const Node* node) const | |
117 { | |
118 SkASSERT(node); | |
119 return (Type)node->fType; | |
120 } | |
121 | |
122 const char* SkDOM::getName(const Node* node) const | |
123 { | |
124 SkASSERT(node); | |
125 return node->fName; | |
126 } | |
127 | |
128 const char* SkDOM::findAttr(const Node* node, const char name[]) const | |
129 { | |
130 SkASSERT(node); | |
131 const Attr* attr = node->attrs(); | |
132 const Attr* stop = attr + node->fAttrCount; | |
133 | |
134 while (attr < stop) | |
135 { | |
136 if (!strcmp(attr->fName, name)) | |
137 return attr->fValue; | |
138 attr += 1; | |
139 } | |
140 return NULL; | |
141 } | |
142 | |
143 ////////////////////////////////////////////////////////////////////////////////
///// | |
144 | |
145 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const | |
146 { | |
147 return node->fAttrCount ? node->attrs() : NULL; | |
148 } | |
149 | |
150 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const | |
151 { | |
152 SkASSERT(node); | |
153 if (attr == NULL) | |
154 return NULL; | |
155 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : NULL; | |
156 } | |
157 | |
158 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const | |
159 { | |
160 SkASSERT(node); | |
161 SkASSERT(attr); | |
162 return attr->fName; | |
163 } | |
164 | |
165 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const | |
166 { | |
167 SkASSERT(node); | |
168 SkASSERT(attr); | |
169 return attr->fValue; | |
170 } | |
171 | |
172 ////////////////////////////////////////////////////////////////////////////////
///// | |
173 | |
174 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) | |
175 { | |
176 SkASSERT(node); | |
177 fAttr = node->attrs(); | |
178 fStop = fAttr + node->fAttrCount; | |
179 } | |
180 | |
181 const char* SkDOM::AttrIter::next(const char** value) | |
182 { | |
183 const char* name = NULL; | |
184 | |
185 if (fAttr < fStop) | |
186 { | |
187 name = fAttr->fName; | |
188 if (value) | |
189 *value = fAttr->fValue; | |
190 fAttr += 1; | |
191 } | |
192 return name; | |
193 } | |
194 | |
195 ////////////////////////////////////////////////////////////////////////////// | |
196 | |
197 #include "SkXMLParser.h" | |
198 #include "SkTDArray.h" | |
199 | |
200 static char* dupstr(SkChunkAlloc* chunk, const char src[]) | |
201 { | |
202 SkASSERT(chunk && src); | |
203 size_t len = strlen(src); | |
204 char* dst = (char*)chunk->alloc(len + 1, SkChunkAlloc::kThrow_AllocFailTyp
e); | |
205 memcpy(dst, src, len + 1); | |
206 return dst; | |
207 } | |
208 | |
209 class SkDOMParser : public SkXMLParser { | |
210 bool fNeedToFlush; | |
211 public: | |
212 SkDOMParser(SkChunkAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) | |
213 { | |
214 fRoot = NULL; | |
215 fLevel = 0; | |
216 fNeedToFlush = true; | |
217 } | |
218 SkDOM::Node* getRoot() const { return fRoot; } | |
219 SkXMLParserError fParserError; | |
220 protected: | |
221 void flushAttributes() | |
222 { | |
223 int attrCount = fAttrs.count(); | |
224 | |
225 SkDOM::Node* node = (SkDOM::Node*)fAlloc->alloc(sizeof(SkDOM::Node) + at
trCount * sizeof(SkDOM::Attr), | |
226 SkChunkAlloc::kThrow_All
ocFailType); | |
227 | |
228 node->fName = fElemName; | |
229 node->fFirstChild = NULL; | |
230 node->fAttrCount = SkToU16(attrCount); | |
231 node->fType = SkDOM::kElement_Type; | |
232 | |
233 if (fRoot == NULL) | |
234 { | |
235 node->fNextSibling = NULL; | |
236 fRoot = node; | |
237 } | |
238 else // this adds siblings in reverse order. gets corrected in onEndE
lement() | |
239 { | |
240 SkDOM::Node* parent = fParentStack.top(); | |
241 SkASSERT(fRoot && parent); | |
242 node->fNextSibling = parent->fFirstChild; | |
243 parent->fFirstChild = node; | |
244 } | |
245 *fParentStack.push() = node; | |
246 | |
247 memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr)); | |
248 fAttrs.reset(); | |
249 | |
250 } | |
251 virtual bool onStartElement(const char elem[]) | |
252 { | |
253 if (fLevel > 0 && fNeedToFlush) | |
254 this->flushAttributes(); | |
255 fNeedToFlush = true; | |
256 fElemName = dupstr(fAlloc, elem); | |
257 ++fLevel; | |
258 return false; | |
259 } | |
260 virtual bool onAddAttribute(const char name[], const char value[]) | |
261 { | |
262 SkDOM::Attr* attr = fAttrs.append(); | |
263 attr->fName = dupstr(fAlloc, name); | |
264 attr->fValue = dupstr(fAlloc, value); | |
265 return false; | |
266 } | |
267 virtual bool onEndElement(const char elem[]) | |
268 { | |
269 --fLevel; | |
270 if (fNeedToFlush) | |
271 this->flushAttributes(); | |
272 fNeedToFlush = false; | |
273 | |
274 SkDOM::Node* parent; | |
275 | |
276 fParentStack.pop(&parent); | |
277 | |
278 SkDOM::Node* child = parent->fFirstChild; | |
279 SkDOM::Node* prev = NULL; | |
280 while (child) | |
281 { | |
282 SkDOM::Node* next = child->fNextSibling; | |
283 child->fNextSibling = prev; | |
284 prev = child; | |
285 child = next; | |
286 } | |
287 parent->fFirstChild = prev; | |
288 return false; | |
289 } | |
290 private: | |
291 SkTDArray<SkDOM::Node*> fParentStack; | |
292 SkChunkAlloc* fAlloc; | |
293 SkDOM::Node* fRoot; | |
294 | |
295 // state needed for flushAttributes() | |
296 SkTDArray<SkDOM::Attr> fAttrs; | |
297 char* fElemName; | |
298 int fLevel; | |
299 }; | |
300 | |
301 const SkDOM::Node* SkDOM::build(const char doc[], size_t len) | |
302 { | |
303 fAlloc.reset(); | |
304 SkDOMParser parser(&fAlloc); | |
305 if (!parser.parse(doc, len)) | |
306 { | |
307 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.g
etLineNumber());) | |
308 fRoot = NULL; | |
309 fAlloc.reset(); | |
310 return NULL; | |
311 } | |
312 fRoot = parser.getRoot(); | |
313 return fRoot; | |
314 } | |
315 | |
316 /////////////////////////////////////////////////////////////////////////// | |
317 | |
318 static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* par
ser) | |
319 { | |
320 const char* elem = dom.getName(node); | |
321 | |
322 parser->startElement(elem); | |
323 | |
324 SkDOM::AttrIter iter(dom, node); | |
325 const char* name; | |
326 const char* value; | |
327 while ((name = iter.next(&value)) != NULL) | |
328 parser->addAttribute(name, value); | |
329 | |
330 node = dom.getFirstChild(node, NULL); | |
331 while (node) | |
332 { | |
333 walk_dom(dom, node, parser); | |
334 node = dom.getNextSibling(node, NULL); | |
335 } | |
336 | |
337 parser->endElement(elem); | |
338 } | |
339 | |
340 const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) | |
341 { | |
342 fAlloc.reset(); | |
343 SkDOMParser parser(&fAlloc); | |
344 | |
345 walk_dom(dom, node, &parser); | |
346 | |
347 fRoot = parser.getRoot(); | |
348 return fRoot; | |
349 } | |
350 | |
351 ////////////////////////////////////////////////////////////////////////// | |
352 | |
353 int SkDOM::countChildren(const Node* node, const char elem[]) const | |
354 { | |
355 int count = 0; | |
356 | |
357 node = this->getFirstChild(node, elem); | |
358 while (node) | |
359 { | |
360 count += 1; | |
361 node = this->getNextSibling(node, elem); | |
362 } | |
363 return count; | |
364 } | |
365 | |
366 ////////////////////////////////////////////////////////////////////////// | |
367 | |
368 #include "SkParse.h" | |
369 | |
370 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const | |
371 { | |
372 const char* vstr = this->findAttr(node, name); | |
373 return vstr && SkParse::FindS32(vstr, value); | |
374 } | |
375 | |
376 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], i
nt count) const | |
377 { | |
378 const char* vstr = this->findAttr(node, name); | |
379 return vstr && SkParse::FindScalars(vstr, value, count); | |
380 } | |
381 | |
382 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const | |
383 { | |
384 const char* vstr = this->findAttr(node, name); | |
385 return vstr && SkParse::FindHex(vstr, value); | |
386 } | |
387 | |
388 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const | |
389 { | |
390 const char* vstr = this->findAttr(node, name); | |
391 return vstr && SkParse::FindBool(vstr, value); | |
392 } | |
393 | |
394 int SkDOM::findList(const Node* node, const char name[], const char list[]) cons
t | |
395 { | |
396 const char* vstr = this->findAttr(node, name); | |
397 return vstr ? SkParse::FindList(vstr, list) : -1; | |
398 } | |
399 | |
400 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) con
st | |
401 { | |
402 const char* vstr = this->findAttr(node, name); | |
403 return vstr && !strcmp(vstr, value); | |
404 } | |
405 | |
406 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const | |
407 { | |
408 const char* vstr = this->findAttr(node, name); | |
409 int32_t value; | |
410 return vstr && SkParse::FindS32(vstr, &value) && value == target; | |
411 } | |
412 | |
413 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) cons
t | |
414 { | |
415 const char* vstr = this->findAttr(node, name); | |
416 SkScalar value; | |
417 return vstr && SkParse::FindScalar(vstr, &value) && value == target; | |
418 } | |
419 | |
420 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const | |
421 { | |
422 const char* vstr = this->findAttr(node, name); | |
423 uint32_t value; | |
424 return vstr && SkParse::FindHex(vstr, &value) && value == target; | |
425 } | |
426 | |
427 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const | |
428 { | |
429 const char* vstr = this->findAttr(node, name); | |
430 bool value; | |
431 return vstr && SkParse::FindBool(vstr, &value) && value == target; | |
432 } | |
433 | |
434 ////////////////////////////////////////////////////////////////////////// | |
435 | |
436 #ifdef SK_DEBUG | |
437 | |
438 static void tab(int level) | |
439 { | |
440 while (--level >= 0) | |
441 SkDebugf("\t"); | |
442 } | |
443 | |
444 void SkDOM::dump(const Node* node, int level) const | |
445 { | |
446 if (node == NULL) | |
447 node = this->getRootNode(); | |
448 if (node) | |
449 { | |
450 tab(level); | |
451 SkDebugf("<%s", this->getName(node)); | |
452 | |
453 const Attr* attr = node->attrs(); | |
454 const Attr* stop = attr + node->fAttrCount; | |
455 for (; attr < stop; attr++) | |
456 SkDebugf(" %s=\"%s\"", attr->fName, attr->fValue); | |
457 | |
458 const Node* child = this->getFirstChild(node); | |
459 if (child) | |
460 { | |
461 SkDebugf(">\n"); | |
462 while (child) | |
463 { | |
464 this->dump(child, level+1); | |
465 child = this->getNextSibling(child); | |
466 } | |
467 tab(level); | |
468 SkDebugf("</%s>\n", node->fName); | |
469 } | |
470 else | |
471 SkDebugf("/>\n"); | |
472 } | |
473 } | |
474 | |
475 void SkDOM::UnitTest() | |
476 { | |
477 #ifdef SK_SUPPORT_UNITTEST | |
478 static const char gDoc[] = | |
479 "<root a='1' b='2'>" | |
480 "<elem1 c='3' />" | |
481 "<elem2 d='4' />" | |
482 "<elem3 e='5'>" | |
483 "<subelem1/>" | |
484 "<subelem2 f='6' g='7'/>" | |
485 "</elem3>" | |
486 "<elem4 h='8'/>" | |
487 "</root>" | |
488 ; | |
489 | |
490 SkDOM dom; | |
491 | |
492 SkASSERT(dom.getRootNode() == NULL); | |
493 | |
494 const Node* root = dom.build(gDoc, sizeof(gDoc) - 1); | |
495 SkASSERT(root && dom.getRootNode() == root); | |
496 | |
497 const char* v = dom.findAttr(root, "a"); | |
498 SkASSERT(v && !strcmp(v, "1")); | |
499 v = dom.findAttr(root, "b"); | |
500 SkASSERT(v && !strcmp(v, "2")); | |
501 v = dom.findAttr(root, "c"); | |
502 SkASSERT(v == NULL); | |
503 | |
504 SkASSERT(dom.getFirstChild(root, "elem1")); | |
505 SkASSERT(!dom.getFirstChild(root, "subelem1")); | |
506 | |
507 dom.dump(); | |
508 #endif | |
509 } | |
510 | |
511 #endif | |
512 | |
OLD | NEW |