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