| 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 |