• 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/base/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/base/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.size();
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.back();
221             SkASSERT(fRoot && parent);
222             node->fNextSibling = parent->fFirstChild;
223             parent->fFirstChild = node;
224         }
225         *fParentStack.append() = node;
226 
227         sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
228         fAttrs.reset();
229     }
230 
onStartElement(const char elem[])231     bool onStartElement(const char elem[]) override {
232         this->startCommon(elem, strlen(elem), SkDOM::kElement_Type);
233         return false;
234     }
235 
onAddAttribute(const char name[],const char value[])236     bool onAddAttribute(const char name[], const char value[]) override {
237         SkDOM::Attr* attr = fAttrs.append();
238         attr->fName = dupstr(fAlloc, name, strlen(name));
239         attr->fValue = dupstr(fAlloc, value, strlen(value));
240         return false;
241     }
242 
onEndElement(const char elem[])243     bool onEndElement(const char elem[]) override {
244         if (fNeedToFlush)
245             this->flushAttributes();
246         fNeedToFlush = false;
247         --fLevel;
248 
249         SkDOM::Node* parent = fParentStack.back();
250         fParentStack.pop_back();
251 
252         SkDOM::Node* child = parent->fFirstChild;
253         SkDOM::Node* prev = nullptr;
254         while (child) {
255             SkDOM::Node* next = child->fNextSibling;
256             child->fNextSibling = prev;
257             prev = child;
258             child = next;
259         }
260         parent->fFirstChild = prev;
261         return false;
262     }
263 
onText(const char text[],int len)264     bool onText(const char text[], int len) override {
265         this->startCommon(text, len, SkDOM::kText_Type);
266         this->SkDOMParser::onEndElement(fElemName);
267 
268         return false;
269     }
270 
271 private:
startCommon(const char elem[],size_t elemSize,SkDOM::Type type)272     void startCommon(const char elem[], size_t elemSize, SkDOM::Type type) {
273         if (fLevel > 0 && fNeedToFlush) {
274             this->flushAttributes();
275         }
276         fNeedToFlush = true;
277         fElemName = dupstr(fAlloc, elem, elemSize);
278         fElemType = type;
279         ++fLevel;
280     }
281 
282     SkTDArray<SkDOM::Node*> fParentStack;
283     SkArenaAllocWithReset*  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 
build(SkStream & docStream)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 
walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)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 
copy(const SkDOM & dom,const SkDOM::Node * node)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 
beginParsing()344 SkXMLParser* SkDOM::beginParsing() {
345     SkASSERT(!fParser);
346     fParser = std::make_unique<SkDOMParser>(&fAlloc);
347 
348     return fParser.get();
349 }
350 
finishParsing()351 const SkDOM::Node* SkDOM::finishParsing() {
352     SkASSERT(fParser);
353     fRoot = fParser->getRoot();
354     fParser.reset();
355 
356     return fRoot;
357 }
358 
359 //////////////////////////////////////////////////////////////////////////
360 
countChildren(const Node * node,const char elem[]) const361 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 "include/utils/SkParse.h"
375 
findS32(const Node * node,const char name[],int32_t * value) const376 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 
findScalars(const Node * node,const char name[],SkScalar value[],int count) const381 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 
findHex(const Node * node,const char name[],uint32_t * value) const386 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 
findBool(const Node * node,const char name[],bool * value) const391 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 
findList(const Node * node,const char name[],const char list[]) const396 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 
hasAttr(const Node * node,const char name[],const char value[]) const401 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 
hasS32(const Node * node,const char name[],int32_t target) const406 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 
hasScalar(const Node * node,const char name[],SkScalar target) const412 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 
hasHex(const Node * node,const char name[],uint32_t target) const418 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 
hasBool(const Node * node,const char name[],bool target) const424 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