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 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 54 const SkDOMAttr* attrs() const 55 { 56 return (const SkDOMAttr*)(this + 1); 57 } 58 SkDOMAttr* attrs() 59 { 60 return (SkDOMAttr*)(this + 1); 61 } 62 }; 63 64 ///////////////////////////////////////////////////////////////////////// 65 66 #define kMinChunkSize 512 67 68 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(NULL) 69 { 70 } 71 72 SkDOM::~SkDOM() 73 { 74 } 75 76 const SkDOM::Node* SkDOM::getRootNode() const 77 { 78 return fRoot; 79 } 80 81 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 95 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 108 SkDOM::Type SkDOM::getType(const Node* node) const 109 { 110 SkASSERT(node); 111 return (Type)node->fType; 112 } 113 114 const char* SkDOM::getName(const Node* node) const 115 { 116 SkASSERT(node); 117 return node->fName; 118 } 119 120 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 137 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const 138 { 139 return node->fAttrCount ? node->attrs() : NULL; 140 } 141 142 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 150 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const 151 { 152 SkASSERT(node); 153 SkASSERT(attr); 154 return attr->fName; 155 } 156 157 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 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 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 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: 204 SkDOMParser(SkChunkAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) 205 { 206 fRoot = NULL; 207 fLevel = 0; 208 fNeedToFlush = true; 209 } 210 SkDOM::Node* getRoot() const { return fRoot; } 211 SkXMLParserError fParserError; 212 protected: 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 } 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 } 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 } 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 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 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 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 345 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 362 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 368 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 374 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 380 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 386 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 392 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 398 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 405 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 412 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 419 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 430 static void tab(int level) 431 { 432 while (--level >= 0) 433 SkDebugf("\t"); 434 } 435 436 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 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