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 17bool 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#define kMinChunkSize 4096 46 47SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {} 48 49SkDOM::~SkDOM() {} 50 51const SkDOM::Node* SkDOM::getRootNode() const { 52 return fRoot; 53} 54 55const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const { 56 SkASSERT(node); 57 const Node* child = node->fFirstChild; 58 59 if (name) { 60 for (; child != nullptr; child = child->fNextSibling) { 61 if (!strcmp(name, child->fName)) { 62 break; 63 } 64 } 65 } 66 return child; 67} 68 69const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const { 70 SkASSERT(node); 71 const Node* sibling = node->fNextSibling; 72 if (name) { 73 for (; sibling != nullptr; sibling = sibling->fNextSibling) { 74 if (!strcmp(name, sibling->fName)) { 75 break; 76 } 77 } 78 } 79 return sibling; 80} 81 82SkDOM::Type SkDOM::getType(const Node* node) const { 83 SkASSERT(node); 84 return (Type)node->fType; 85} 86 87const char* SkDOM::getName(const Node* node) const { 88 SkASSERT(node); 89 return node->fName; 90} 91 92const char* SkDOM::findAttr(const Node* node, const char name[]) const { 93 SkASSERT(node); 94 const Attr* attr = node->attrs(); 95 const Attr* stop = attr + node->fAttrCount; 96 97 while (attr < stop) { 98 if (!strcmp(attr->fName, name)) { 99 return attr->fValue; 100 } 101 attr += 1; 102 } 103 return nullptr; 104} 105 106///////////////////////////////////////////////////////////////////////////////////// 107 108const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const { 109 return node->fAttrCount ? node->attrs() : nullptr; 110} 111 112const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const { 113 SkASSERT(node); 114 if (attr == nullptr) { 115 return nullptr; 116 } 117 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr; 118} 119 120const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const { 121 SkASSERT(node); 122 SkASSERT(attr); 123 return attr->fName; 124} 125 126const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const { 127 SkASSERT(node); 128 SkASSERT(attr); 129 return attr->fValue; 130} 131 132///////////////////////////////////////////////////////////////////////////////////// 133 134SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) { 135 SkASSERT(node); 136 fAttr = node->attrs(); 137 fStop = fAttr + node->fAttrCount; 138} 139 140const char* SkDOM::AttrIter::next(const char** value) { 141 const char* name = nullptr; 142 143 if (fAttr < fStop) { 144 name = fAttr->fName; 145 if (value) 146 *value = fAttr->fValue; 147 fAttr += 1; 148 } 149 return name; 150} 151 152////////////////////////////////////////////////////////////////////////////// 153 154#include "src/xml/SkDOMParser.h" 155 156const SkDOM::Node* SkDOM::build(SkStream& docStream) { 157 SkDOMParser parser(&fAlloc); 158 if (!parser.parse(docStream)) 159 { 160 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());) 161 fRoot = nullptr; 162 fAlloc.reset(); 163 return nullptr; 164 } 165 fRoot = parser.getRoot(); 166 return fRoot; 167} 168 169/////////////////////////////////////////////////////////////////////////// 170 171void SkDOM::walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) { 172 const char* elem = dom.getName(node); 173 if (dom.getType(node) == SkDOM::kText_Type) { 174 SkASSERT(dom.countChildren(node) == 0); 175 parser->text(elem, SkToInt(strlen(elem))); 176 return; 177 } 178 179 parser->startElement(elem); 180 181 SkDOM::AttrIter iter(dom, node); 182 const char* name; 183 const char* value; 184 while ((name = iter.next(&value)) != nullptr) 185 parser->addAttribute(name, value); 186 187 node = dom.getFirstChild(node, nullptr); 188 while (node) 189 { 190 walk_dom(dom, node, parser); 191 node = dom.getNextSibling(node, nullptr); 192 } 193 194 parser->endElement(elem); 195} 196 197const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) { 198 SkDOMParser parser(&fAlloc); 199 200 walk_dom(dom, node, &parser); 201 202 fRoot = parser.getRoot(); 203 return fRoot; 204} 205 206SkXMLParser* SkDOM::beginParsing() { 207 SkASSERT(!fParser); 208 fParser = std::make_unique<SkDOMParser>(&fAlloc); 209 210 return fParser.get(); 211} 212 213const SkDOM::Node* SkDOM::finishParsing() { 214 SkASSERT(fParser); 215 fRoot = fParser->getRoot(); 216 fParser.reset(); 217 218 return fRoot; 219} 220 221////////////////////////////////////////////////////////////////////////// 222 223int SkDOM::countChildren(const Node* node, const char elem[]) const { 224 int count = 0; 225 226 node = this->getFirstChild(node, elem); 227 while (node) { 228 count += 1; 229 node = this->getNextSibling(node, elem); 230 } 231 return count; 232} 233 234////////////////////////////////////////////////////////////////////////// 235 236#include "include/utils/SkParse.h" 237 238bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const { 239 const char* vstr = this->findAttr(node, name); 240 return vstr && SkParse::FindS32(vstr, value); 241} 242 243bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const { 244 const char* vstr = this->findAttr(node, name); 245 return vstr && SkParse::FindScalars(vstr, value, count); 246} 247 248bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const { 249 const char* vstr = this->findAttr(node, name); 250 return vstr && SkParse::FindHex(vstr, value); 251} 252 253bool SkDOM::findBool(const Node* node, const char name[], bool* value) const { 254 const char* vstr = this->findAttr(node, name); 255 return vstr && SkParse::FindBool(vstr, value); 256} 257 258int SkDOM::findList(const Node* node, const char name[], const char list[]) const { 259 const char* vstr = this->findAttr(node, name); 260 return vstr ? SkParse::FindList(vstr, list) : -1; 261} 262 263bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const { 264 const char* vstr = this->findAttr(node, name); 265 return vstr && !strcmp(vstr, value); 266} 267 268bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const { 269 const char* vstr = this->findAttr(node, name); 270 int32_t value; 271 return vstr && SkParse::FindS32(vstr, &value) && value == target; 272} 273 274bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const { 275 const char* vstr = this->findAttr(node, name); 276 SkScalar value; 277 return vstr && SkParse::FindScalar(vstr, &value) && value == target; 278} 279 280bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const { 281 const char* vstr = this->findAttr(node, name); 282 uint32_t value; 283 return vstr && SkParse::FindHex(vstr, &value) && value == target; 284} 285 286bool SkDOM::hasBool(const Node* node, const char name[], bool target) const { 287 const char* vstr = this->findAttr(node, name); 288 bool value; 289 return vstr && SkParse::FindBool(vstr, &value) && value == target; 290} 291