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[]) const 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[]) const 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_AllocFailType); 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) + attrCount * sizeof(SkDOM::Attr), 226 SkChunkAlloc::kThrow_AllocFailType); 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 onEndElement() 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.getLineNumber());) 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* parser) 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[], int 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[]) const 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[]) const 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) const 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 513