1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/xml/SkDOM.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,503 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkDOM.h" 1.14 + 1.15 +///////////////////////////////////////////////////////////////////////// 1.16 + 1.17 +#include "SkXMLParser.h" 1.18 + 1.19 +bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) 1.20 +{ 1.21 + const char* elemName = dom.getName(node); 1.22 + 1.23 + if (this->startElement(elemName)) 1.24 + return false; 1.25 + 1.26 + SkDOM::AttrIter iter(dom, node); 1.27 + const char* name, *value; 1.28 + 1.29 + while ((name = iter.next(&value)) != NULL) 1.30 + if (this->addAttribute(name, value)) 1.31 + return false; 1.32 + 1.33 + if ((node = dom.getFirstChild(node)) != NULL) 1.34 + do { 1.35 + if (!this->parse(dom, node)) 1.36 + return false; 1.37 + } while ((node = dom.getNextSibling(node)) != NULL); 1.38 + 1.39 + return !this->endElement(elemName); 1.40 +} 1.41 + 1.42 +///////////////////////////////////////////////////////////////////////// 1.43 + 1.44 +struct SkDOMAttr { 1.45 + const char* fName; 1.46 + const char* fValue; 1.47 +}; 1.48 + 1.49 +struct SkDOMNode { 1.50 + const char* fName; 1.51 + SkDOMNode* fFirstChild; 1.52 + SkDOMNode* fNextSibling; 1.53 + uint16_t fAttrCount; 1.54 + uint8_t fType; 1.55 + uint8_t fPad; 1.56 + 1.57 + const SkDOMAttr* attrs() const 1.58 + { 1.59 + return (const SkDOMAttr*)(this + 1); 1.60 + } 1.61 + SkDOMAttr* attrs() 1.62 + { 1.63 + return (SkDOMAttr*)(this + 1); 1.64 + } 1.65 +}; 1.66 + 1.67 +///////////////////////////////////////////////////////////////////////// 1.68 + 1.69 +#define kMinChunkSize 512 1.70 + 1.71 +SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(NULL) 1.72 +{ 1.73 +} 1.74 + 1.75 +SkDOM::~SkDOM() 1.76 +{ 1.77 +} 1.78 + 1.79 +const SkDOM::Node* SkDOM::getRootNode() const 1.80 +{ 1.81 + return fRoot; 1.82 +} 1.83 + 1.84 +const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const 1.85 +{ 1.86 + SkASSERT(node); 1.87 + const Node* child = node->fFirstChild; 1.88 + 1.89 + if (name) 1.90 + { 1.91 + for (; child != NULL; child = child->fNextSibling) 1.92 + if (!strcmp(name, child->fName)) 1.93 + break; 1.94 + } 1.95 + return child; 1.96 +} 1.97 + 1.98 +const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const 1.99 +{ 1.100 + SkASSERT(node); 1.101 + const Node* sibling = node->fNextSibling; 1.102 + if (name) 1.103 + { 1.104 + for (; sibling != NULL; sibling = sibling->fNextSibling) 1.105 + if (!strcmp(name, sibling->fName)) 1.106 + break; 1.107 + } 1.108 + return sibling; 1.109 +} 1.110 + 1.111 +SkDOM::Type SkDOM::getType(const Node* node) const 1.112 +{ 1.113 + SkASSERT(node); 1.114 + return (Type)node->fType; 1.115 +} 1.116 + 1.117 +const char* SkDOM::getName(const Node* node) const 1.118 +{ 1.119 + SkASSERT(node); 1.120 + return node->fName; 1.121 +} 1.122 + 1.123 +const char* SkDOM::findAttr(const Node* node, const char name[]) const 1.124 +{ 1.125 + SkASSERT(node); 1.126 + const Attr* attr = node->attrs(); 1.127 + const Attr* stop = attr + node->fAttrCount; 1.128 + 1.129 + while (attr < stop) 1.130 + { 1.131 + if (!strcmp(attr->fName, name)) 1.132 + return attr->fValue; 1.133 + attr += 1; 1.134 + } 1.135 + return NULL; 1.136 +} 1.137 + 1.138 +///////////////////////////////////////////////////////////////////////////////////// 1.139 + 1.140 +const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const 1.141 +{ 1.142 + return node->fAttrCount ? node->attrs() : NULL; 1.143 +} 1.144 + 1.145 +const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const 1.146 +{ 1.147 + SkASSERT(node); 1.148 + if (attr == NULL) 1.149 + return NULL; 1.150 + return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : NULL; 1.151 +} 1.152 + 1.153 +const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const 1.154 +{ 1.155 + SkASSERT(node); 1.156 + SkASSERT(attr); 1.157 + return attr->fName; 1.158 +} 1.159 + 1.160 +const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const 1.161 +{ 1.162 + SkASSERT(node); 1.163 + SkASSERT(attr); 1.164 + return attr->fValue; 1.165 +} 1.166 + 1.167 +///////////////////////////////////////////////////////////////////////////////////// 1.168 + 1.169 +SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) 1.170 +{ 1.171 + SkASSERT(node); 1.172 + fAttr = node->attrs(); 1.173 + fStop = fAttr + node->fAttrCount; 1.174 +} 1.175 + 1.176 +const char* SkDOM::AttrIter::next(const char** value) 1.177 +{ 1.178 + const char* name = NULL; 1.179 + 1.180 + if (fAttr < fStop) 1.181 + { 1.182 + name = fAttr->fName; 1.183 + if (value) 1.184 + *value = fAttr->fValue; 1.185 + fAttr += 1; 1.186 + } 1.187 + return name; 1.188 +} 1.189 + 1.190 +////////////////////////////////////////////////////////////////////////////// 1.191 + 1.192 +#include "SkXMLParser.h" 1.193 +#include "SkTDArray.h" 1.194 + 1.195 +static char* dupstr(SkChunkAlloc* chunk, const char src[]) 1.196 +{ 1.197 + SkASSERT(chunk && src); 1.198 + size_t len = strlen(src); 1.199 + char* dst = (char*)chunk->alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType); 1.200 + memcpy(dst, src, len + 1); 1.201 + return dst; 1.202 +} 1.203 + 1.204 +class SkDOMParser : public SkXMLParser { 1.205 + bool fNeedToFlush; 1.206 +public: 1.207 + SkDOMParser(SkChunkAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) 1.208 + { 1.209 + fRoot = NULL; 1.210 + fLevel = 0; 1.211 + fNeedToFlush = true; 1.212 + } 1.213 + SkDOM::Node* getRoot() const { return fRoot; } 1.214 + SkXMLParserError fParserError; 1.215 +protected: 1.216 + void flushAttributes() 1.217 + { 1.218 + int attrCount = fAttrs.count(); 1.219 + 1.220 + SkDOM::Node* node = (SkDOM::Node*)fAlloc->alloc(sizeof(SkDOM::Node) + attrCount * sizeof(SkDOM::Attr), 1.221 + SkChunkAlloc::kThrow_AllocFailType); 1.222 + 1.223 + node->fName = fElemName; 1.224 + node->fFirstChild = NULL; 1.225 + node->fAttrCount = SkToU16(attrCount); 1.226 + node->fType = SkDOM::kElement_Type; 1.227 + 1.228 + if (fRoot == NULL) 1.229 + { 1.230 + node->fNextSibling = NULL; 1.231 + fRoot = node; 1.232 + } 1.233 + else // this adds siblings in reverse order. gets corrected in onEndElement() 1.234 + { 1.235 + SkDOM::Node* parent = fParentStack.top(); 1.236 + SkASSERT(fRoot && parent); 1.237 + node->fNextSibling = parent->fFirstChild; 1.238 + parent->fFirstChild = node; 1.239 + } 1.240 + *fParentStack.push() = node; 1.241 + 1.242 + memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr)); 1.243 + fAttrs.reset(); 1.244 + 1.245 + } 1.246 + virtual bool onStartElement(const char elem[]) 1.247 + { 1.248 + if (fLevel > 0 && fNeedToFlush) 1.249 + this->flushAttributes(); 1.250 + fNeedToFlush = true; 1.251 + fElemName = dupstr(fAlloc, elem); 1.252 + ++fLevel; 1.253 + return false; 1.254 + } 1.255 + virtual bool onAddAttribute(const char name[], const char value[]) 1.256 + { 1.257 + SkDOM::Attr* attr = fAttrs.append(); 1.258 + attr->fName = dupstr(fAlloc, name); 1.259 + attr->fValue = dupstr(fAlloc, value); 1.260 + return false; 1.261 + } 1.262 + virtual bool onEndElement(const char elem[]) 1.263 + { 1.264 + --fLevel; 1.265 + if (fNeedToFlush) 1.266 + this->flushAttributes(); 1.267 + fNeedToFlush = false; 1.268 + 1.269 + SkDOM::Node* parent; 1.270 + 1.271 + fParentStack.pop(&parent); 1.272 + 1.273 + SkDOM::Node* child = parent->fFirstChild; 1.274 + SkDOM::Node* prev = NULL; 1.275 + while (child) 1.276 + { 1.277 + SkDOM::Node* next = child->fNextSibling; 1.278 + child->fNextSibling = prev; 1.279 + prev = child; 1.280 + child = next; 1.281 + } 1.282 + parent->fFirstChild = prev; 1.283 + return false; 1.284 + } 1.285 +private: 1.286 + SkTDArray<SkDOM::Node*> fParentStack; 1.287 + SkChunkAlloc* fAlloc; 1.288 + SkDOM::Node* fRoot; 1.289 + 1.290 + // state needed for flushAttributes() 1.291 + SkTDArray<SkDOM::Attr> fAttrs; 1.292 + char* fElemName; 1.293 + int fLevel; 1.294 +}; 1.295 + 1.296 +const SkDOM::Node* SkDOM::build(const char doc[], size_t len) 1.297 +{ 1.298 + fAlloc.reset(); 1.299 + SkDOMParser parser(&fAlloc); 1.300 + if (!parser.parse(doc, len)) 1.301 + { 1.302 + SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());) 1.303 + fRoot = NULL; 1.304 + fAlloc.reset(); 1.305 + return NULL; 1.306 + } 1.307 + fRoot = parser.getRoot(); 1.308 + return fRoot; 1.309 +} 1.310 + 1.311 +/////////////////////////////////////////////////////////////////////////// 1.312 + 1.313 +static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) 1.314 +{ 1.315 + const char* elem = dom.getName(node); 1.316 + 1.317 + parser->startElement(elem); 1.318 + 1.319 + SkDOM::AttrIter iter(dom, node); 1.320 + const char* name; 1.321 + const char* value; 1.322 + while ((name = iter.next(&value)) != NULL) 1.323 + parser->addAttribute(name, value); 1.324 + 1.325 + node = dom.getFirstChild(node, NULL); 1.326 + while (node) 1.327 + { 1.328 + walk_dom(dom, node, parser); 1.329 + node = dom.getNextSibling(node, NULL); 1.330 + } 1.331 + 1.332 + parser->endElement(elem); 1.333 +} 1.334 + 1.335 +const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) 1.336 +{ 1.337 + fAlloc.reset(); 1.338 + SkDOMParser parser(&fAlloc); 1.339 + 1.340 + walk_dom(dom, node, &parser); 1.341 + 1.342 + fRoot = parser.getRoot(); 1.343 + return fRoot; 1.344 +} 1.345 + 1.346 +////////////////////////////////////////////////////////////////////////// 1.347 + 1.348 +int SkDOM::countChildren(const Node* node, const char elem[]) const 1.349 +{ 1.350 + int count = 0; 1.351 + 1.352 + node = this->getFirstChild(node, elem); 1.353 + while (node) 1.354 + { 1.355 + count += 1; 1.356 + node = this->getNextSibling(node, elem); 1.357 + } 1.358 + return count; 1.359 +} 1.360 + 1.361 +////////////////////////////////////////////////////////////////////////// 1.362 + 1.363 +#include "SkParse.h" 1.364 + 1.365 +bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const 1.366 +{ 1.367 + const char* vstr = this->findAttr(node, name); 1.368 + return vstr && SkParse::FindS32(vstr, value); 1.369 +} 1.370 + 1.371 +bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const 1.372 +{ 1.373 + const char* vstr = this->findAttr(node, name); 1.374 + return vstr && SkParse::FindScalars(vstr, value, count); 1.375 +} 1.376 + 1.377 +bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const 1.378 +{ 1.379 + const char* vstr = this->findAttr(node, name); 1.380 + return vstr && SkParse::FindHex(vstr, value); 1.381 +} 1.382 + 1.383 +bool SkDOM::findBool(const Node* node, const char name[], bool* value) const 1.384 +{ 1.385 + const char* vstr = this->findAttr(node, name); 1.386 + return vstr && SkParse::FindBool(vstr, value); 1.387 +} 1.388 + 1.389 +int SkDOM::findList(const Node* node, const char name[], const char list[]) const 1.390 +{ 1.391 + const char* vstr = this->findAttr(node, name); 1.392 + return vstr ? SkParse::FindList(vstr, list) : -1; 1.393 +} 1.394 + 1.395 +bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const 1.396 +{ 1.397 + const char* vstr = this->findAttr(node, name); 1.398 + return vstr && !strcmp(vstr, value); 1.399 +} 1.400 + 1.401 +bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const 1.402 +{ 1.403 + const char* vstr = this->findAttr(node, name); 1.404 + int32_t value; 1.405 + return vstr && SkParse::FindS32(vstr, &value) && value == target; 1.406 +} 1.407 + 1.408 +bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const 1.409 +{ 1.410 + const char* vstr = this->findAttr(node, name); 1.411 + SkScalar value; 1.412 + return vstr && SkParse::FindScalar(vstr, &value) && value == target; 1.413 +} 1.414 + 1.415 +bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const 1.416 +{ 1.417 + const char* vstr = this->findAttr(node, name); 1.418 + uint32_t value; 1.419 + return vstr && SkParse::FindHex(vstr, &value) && value == target; 1.420 +} 1.421 + 1.422 +bool SkDOM::hasBool(const Node* node, const char name[], bool target) const 1.423 +{ 1.424 + const char* vstr = this->findAttr(node, name); 1.425 + bool value; 1.426 + return vstr && SkParse::FindBool(vstr, &value) && value == target; 1.427 +} 1.428 + 1.429 +////////////////////////////////////////////////////////////////////////// 1.430 + 1.431 +#ifdef SK_DEBUG 1.432 + 1.433 +static void tab(int level) 1.434 +{ 1.435 + while (--level >= 0) 1.436 + SkDebugf("\t"); 1.437 +} 1.438 + 1.439 +void SkDOM::dump(const Node* node, int level) const 1.440 +{ 1.441 + if (node == NULL) 1.442 + node = this->getRootNode(); 1.443 + if (node) 1.444 + { 1.445 + tab(level); 1.446 + SkDebugf("<%s", this->getName(node)); 1.447 + 1.448 + const Attr* attr = node->attrs(); 1.449 + const Attr* stop = attr + node->fAttrCount; 1.450 + for (; attr < stop; attr++) 1.451 + SkDebugf(" %s=\"%s\"", attr->fName, attr->fValue); 1.452 + 1.453 + const Node* child = this->getFirstChild(node); 1.454 + if (child) 1.455 + { 1.456 + SkDebugf(">\n"); 1.457 + while (child) 1.458 + { 1.459 + this->dump(child, level+1); 1.460 + child = this->getNextSibling(child); 1.461 + } 1.462 + tab(level); 1.463 + SkDebugf("</%s>\n", node->fName); 1.464 + } 1.465 + else 1.466 + SkDebugf("/>\n"); 1.467 + } 1.468 +} 1.469 + 1.470 +void SkDOM::UnitTest() 1.471 +{ 1.472 +#ifdef SK_SUPPORT_UNITTEST 1.473 + static const char gDoc[] = 1.474 + "<root a='1' b='2'>" 1.475 + "<elem1 c='3' />" 1.476 + "<elem2 d='4' />" 1.477 + "<elem3 e='5'>" 1.478 + "<subelem1/>" 1.479 + "<subelem2 f='6' g='7'/>" 1.480 + "</elem3>" 1.481 + "<elem4 h='8'/>" 1.482 + "</root>" 1.483 + ; 1.484 + 1.485 + SkDOM dom; 1.486 + 1.487 + SkASSERT(dom.getRootNode() == NULL); 1.488 + 1.489 + const Node* root = dom.build(gDoc, sizeof(gDoc) - 1); 1.490 + SkASSERT(root && dom.getRootNode() == root); 1.491 + 1.492 + const char* v = dom.findAttr(root, "a"); 1.493 + SkASSERT(v && !strcmp(v, "1")); 1.494 + v = dom.findAttr(root, "b"); 1.495 + SkASSERT(v && !strcmp(v, "2")); 1.496 + v = dom.findAttr(root, "c"); 1.497 + SkASSERT(v == NULL); 1.498 + 1.499 + SkASSERT(dom.getFirstChild(root, "elem1")); 1.500 + SkASSERT(!dom.getFirstChild(root, "subelem1")); 1.501 + 1.502 + dom.dump(); 1.503 +#endif 1.504 +} 1.505 + 1.506 +#endif