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