Home | History | Annotate | Download | only in xml
      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