1 /* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "src/xml/SkDOM.h" 9 10 #include <memory> 11 12 #include "include/core/SkStream.h" 13 #include "include/private/SkTo.h" 14 #include "src/xml/SkXMLParser.h" 15 #include "src/xml/SkXMLWriter.h" 16 parse(const SkDOM & dom,const SkDOMNode * node)17 bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) { 18 const char* elemName = dom.getName(node); 19 20 if (this->startElement(elemName)) { 21 return false; 22 } 23 24 SkDOM::AttrIter iter(dom, node); 25 const char* name, *value; 26 27 while ((name = iter.next(&value)) != nullptr) { 28 if (this->addAttribute(name, value)) { 29 return false; 30 } 31 } 32 33 if ((node = dom.getFirstChild(node)) != nullptr) { 34 do { 35 if (!this->parse(dom, node)) { 36 return false; 37 } 38 } while ((node = dom.getNextSibling(node)) != nullptr); 39 } 40 return !this->endElement(elemName); 41 } 42 43 ///////////////////////////////////////////////////////////////////////// 44 45 struct SkDOMAttr { 46 const char* fName; 47 const char* fValue; 48 }; 49 50 struct SkDOMNode { 51 const char* fName; 52 SkDOMNode* fFirstChild; 53 SkDOMNode* fNextSibling; 54 SkDOMAttr* fAttrs; 55 uint16_t fAttrCount; 56 uint8_t fType; 57 uint8_t fPad; 58 attrsSkDOMNode59 const SkDOMAttr* attrs() const { 60 return fAttrs; 61 } 62 attrsSkDOMNode63 SkDOMAttr* attrs() { 64 return fAttrs; 65 } 66 }; 67 68 ///////////////////////////////////////////////////////////////////////// 69 70 #define kMinChunkSize 4096 71 SkDOM()72 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {} 73 ~SkDOM()74 SkDOM::~SkDOM() {} 75 getRootNode() const76 const SkDOM::Node* SkDOM::getRootNode() const { 77 return fRoot; 78 } 79 getFirstChild(const Node * node,const char name[]) const80 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const { 81 SkASSERT(node); 82 const Node* child = node->fFirstChild; 83 84 if (name) { 85 for (; child != nullptr; child = child->fNextSibling) { 86 if (!strcmp(name, child->fName)) { 87 break; 88 } 89 } 90 } 91 return child; 92 } 93 getNextSibling(const Node * node,const char name[]) const94 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const { 95 SkASSERT(node); 96 const Node* sibling = node->fNextSibling; 97 if (name) { 98 for (; sibling != nullptr; sibling = sibling->fNextSibling) { 99 if (!strcmp(name, sibling->fName)) { 100 break; 101 } 102 } 103 } 104 return sibling; 105 } 106 getType(const Node * node) const107 SkDOM::Type SkDOM::getType(const Node* node) const { 108 SkASSERT(node); 109 return (Type)node->fType; 110 } 111 getName(const Node * node) const112 const char* SkDOM::getName(const Node* node) const { 113 SkASSERT(node); 114 return node->fName; 115 } 116 findAttr(const Node * node,const char name[]) const117 const char* SkDOM::findAttr(const Node* node, const char name[]) const { 118 SkASSERT(node); 119 const Attr* attr = node->attrs(); 120 const Attr* stop = attr + node->fAttrCount; 121 122 while (attr < stop) { 123 if (!strcmp(attr->fName, name)) { 124 return attr->fValue; 125 } 126 attr += 1; 127 } 128 return nullptr; 129 } 130 131 ///////////////////////////////////////////////////////////////////////////////////// 132 getFirstAttr(const Node * node) const133 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const { 134 return node->fAttrCount ? node->attrs() : nullptr; 135 } 136 getNextAttr(const Node * node,const Attr * attr) const137 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const { 138 SkASSERT(node); 139 if (attr == nullptr) { 140 return nullptr; 141 } 142 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr; 143 } 144 getAttrName(const Node * node,const Attr * attr) const145 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const { 146 SkASSERT(node); 147 SkASSERT(attr); 148 return attr->fName; 149 } 150 getAttrValue(const Node * node,const Attr * attr) const151 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const { 152 SkASSERT(node); 153 SkASSERT(attr); 154 return attr->fValue; 155 } 156 157 ///////////////////////////////////////////////////////////////////////////////////// 158 AttrIter(const SkDOM &,const SkDOM::Node * node)159 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) { 160 SkASSERT(node); 161 fAttr = node->attrs(); 162 fStop = fAttr + node->fAttrCount; 163 } 164 next(const char ** value)165 const char* SkDOM::AttrIter::next(const char** value) { 166 const char* name = nullptr; 167 168 if (fAttr < fStop) { 169 name = fAttr->fName; 170 if (value) 171 *value = fAttr->fValue; 172 fAttr += 1; 173 } 174 return name; 175 } 176 177 ////////////////////////////////////////////////////////////////////////////// 178 179 #include "include/private/SkTDArray.h" 180 #include "src/xml/SkXMLParser.h" 181 dupstr(SkArenaAlloc * chunk,const char src[],size_t srcLen)182 static char* dupstr(SkArenaAlloc* chunk, const char src[], size_t srcLen) { 183 SkASSERT(chunk && src); 184 char* dst = chunk->makeArrayDefault<char>(srcLen + 1); 185 memcpy(dst, src, srcLen); 186 dst[srcLen] = '\0'; 187 return dst; 188 } 189 190 class SkDOMParser : public SkXMLParser { 191 public: SkDOMParser(SkArenaAllocWithReset * chunk)192 SkDOMParser(SkArenaAllocWithReset* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) { 193 fAlloc->reset(); 194 fRoot = nullptr; 195 fLevel = 0; 196 fNeedToFlush = true; 197 } getRoot() const198 SkDOM::Node* getRoot() const { return fRoot; } 199 SkXMLParserError fParserError; 200 201 protected: flushAttributes()202 void flushAttributes() { 203 SkASSERT(fLevel > 0); 204 205 int attrCount = fAttrs.count(); 206 207 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount); 208 SkDOM::Node* node = fAlloc->make<SkDOM::Node>(); 209 210 node->fName = fElemName; 211 node->fFirstChild = nullptr; 212 node->fAttrCount = SkToU16(attrCount); 213 node->fAttrs = attrs; 214 node->fType = fElemType; 215 216 if (fRoot == nullptr) { 217 node->fNextSibling = nullptr; 218 fRoot = node; 219 } else { // this adds siblings in reverse order. gets corrected in onEndElement() 220 SkDOM::Node* parent = fParentStack.top(); 221 SkASSERT(fRoot && parent); 222 node->fNextSibling = parent->fFirstChild; 223 parent->fFirstChild = node; 224 } 225 *fParentStack.push() = node; 226 227 sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr)); 228 fAttrs.reset(); 229 230 } 231 onStartElement(const char elem[])232 bool onStartElement(const char elem[]) override { 233 this->startCommon(elem, strlen(elem), SkDOM::kElement_Type); 234 return false; 235 } 236 onAddAttribute(const char name[],const char value[])237 bool onAddAttribute(const char name[], const char value[]) override { 238 SkDOM::Attr* attr = fAttrs.append(); 239 attr->fName = dupstr(fAlloc, name, strlen(name)); 240 attr->fValue = dupstr(fAlloc, value, strlen(value)); 241 return false; 242 } 243 onEndElement(const char elem[])244 bool onEndElement(const char elem[]) override { 245 --fLevel; 246 if (fNeedToFlush) 247 this->flushAttributes(); 248 fNeedToFlush = false; 249 250 SkDOM::Node* parent; 251 252 fParentStack.pop(&parent); 253 254 SkDOM::Node* child = parent->fFirstChild; 255 SkDOM::Node* prev = nullptr; 256 while (child) { 257 SkDOM::Node* next = child->fNextSibling; 258 child->fNextSibling = prev; 259 prev = child; 260 child = next; 261 } 262 parent->fFirstChild = prev; 263 return false; 264 } 265 onText(const char text[],int len)266 bool onText(const char text[], int len) override { 267 this->startCommon(text, len, SkDOM::kText_Type); 268 this->SkDOMParser::onEndElement(fElemName); 269 270 return false; 271 } 272 273 private: startCommon(const char elem[],size_t elemSize,SkDOM::Type type)274 void startCommon(const char elem[], size_t elemSize, SkDOM::Type type) { 275 if (fLevel > 0 && fNeedToFlush) { 276 this->flushAttributes(); 277 } 278 fNeedToFlush = true; 279 fElemName = dupstr(fAlloc, elem, elemSize); 280 fElemType = type; 281 ++fLevel; 282 } 283 284 SkTDArray<SkDOM::Node*> fParentStack; 285 SkArenaAllocWithReset* fAlloc; 286 SkDOM::Node* fRoot; 287 bool fNeedToFlush; 288 289 // state needed for flushAttributes() 290 SkTDArray<SkDOM::Attr> fAttrs; 291 char* fElemName; 292 SkDOM::Type fElemType; 293 int fLevel; 294 }; 295 build(SkStream & docStream)296 const SkDOM::Node* SkDOM::build(SkStream& docStream) { 297 SkDOMParser parser(&fAlloc); 298 if (!parser.parse(docStream)) 299 { 300 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());) 301 fRoot = nullptr; 302 fAlloc.reset(); 303 return nullptr; 304 } 305 fRoot = parser.getRoot(); 306 return fRoot; 307 } 308 309 /////////////////////////////////////////////////////////////////////////// 310 walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)311 static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) { 312 const char* elem = dom.getName(node); 313 if (dom.getType(node) == SkDOM::kText_Type) { 314 SkASSERT(dom.countChildren(node) == 0); 315 parser->text(elem, SkToInt(strlen(elem))); 316 return; 317 } 318 319 parser->startElement(elem); 320 321 SkDOM::AttrIter iter(dom, node); 322 const char* name; 323 const char* value; 324 while ((name = iter.next(&value)) != nullptr) 325 parser->addAttribute(name, value); 326 327 node = dom.getFirstChild(node, nullptr); 328 while (node) 329 { 330 walk_dom(dom, node, parser); 331 node = dom.getNextSibling(node, nullptr); 332 } 333 334 parser->endElement(elem); 335 } 336 copy(const SkDOM & dom,const SkDOM::Node * node)337 const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) { 338 SkDOMParser parser(&fAlloc); 339 340 walk_dom(dom, node, &parser); 341 342 fRoot = parser.getRoot(); 343 return fRoot; 344 } 345 beginParsing()346 SkXMLParser* SkDOM::beginParsing() { 347 SkASSERT(!fParser); 348 fParser = std::make_unique<SkDOMParser>(&fAlloc); 349 350 return fParser.get(); 351 } 352 finishParsing()353 const SkDOM::Node* SkDOM::finishParsing() { 354 SkASSERT(fParser); 355 fRoot = fParser->getRoot(); 356 fParser.reset(); 357 358 return fRoot; 359 } 360 361 ////////////////////////////////////////////////////////////////////////// 362 countChildren(const Node * node,const char elem[]) const363 int SkDOM::countChildren(const Node* node, const char elem[]) const { 364 int count = 0; 365 366 node = this->getFirstChild(node, elem); 367 while (node) { 368 count += 1; 369 node = this->getNextSibling(node, elem); 370 } 371 return count; 372 } 373 374 ////////////////////////////////////////////////////////////////////////// 375 376 #include "include/utils/SkParse.h" 377 findS32(const Node * node,const char name[],int32_t * value) const378 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const { 379 const char* vstr = this->findAttr(node, name); 380 return vstr && SkParse::FindS32(vstr, value); 381 } 382 findScalars(const Node * node,const char name[],SkScalar value[],int count) const383 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const { 384 const char* vstr = this->findAttr(node, name); 385 return vstr && SkParse::FindScalars(vstr, value, count); 386 } 387 findHex(const Node * node,const char name[],uint32_t * value) const388 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const { 389 const char* vstr = this->findAttr(node, name); 390 return vstr && SkParse::FindHex(vstr, value); 391 } 392 findBool(const Node * node,const char name[],bool * value) const393 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const { 394 const char* vstr = this->findAttr(node, name); 395 return vstr && SkParse::FindBool(vstr, value); 396 } 397 findList(const Node * node,const char name[],const char list[]) const398 int SkDOM::findList(const Node* node, const char name[], const char list[]) const { 399 const char* vstr = this->findAttr(node, name); 400 return vstr ? SkParse::FindList(vstr, list) : -1; 401 } 402 hasAttr(const Node * node,const char name[],const char value[]) const403 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const { 404 const char* vstr = this->findAttr(node, name); 405 return vstr && !strcmp(vstr, value); 406 } 407 hasS32(const Node * node,const char name[],int32_t target) const408 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const { 409 const char* vstr = this->findAttr(node, name); 410 int32_t value; 411 return vstr && SkParse::FindS32(vstr, &value) && value == target; 412 } 413 hasScalar(const Node * node,const char name[],SkScalar target) const414 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const { 415 const char* vstr = this->findAttr(node, name); 416 SkScalar value; 417 return vstr && SkParse::FindScalar(vstr, &value) && value == target; 418 } 419 hasHex(const Node * node,const char name[],uint32_t target) const420 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const { 421 const char* vstr = this->findAttr(node, name); 422 uint32_t value; 423 return vstr && SkParse::FindHex(vstr, &value) && value == target; 424 } 425 hasBool(const Node * node,const char name[],bool target) const426 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const { 427 const char* vstr = this->findAttr(node, name); 428 bool value; 429 return vstr && SkParse::FindBool(vstr, &value) && value == target; 430 } 431