• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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