xref: /aosp_15_r20/external/skia/src/xml/SkDOM.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2006 The Android Open Source Project
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/xml/SkDOM.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
11*c8dee2aaSAndroid Build Coastguard Worker 
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/xml/SkXMLParser.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/xml/SkXMLWriter.h"
16*c8dee2aaSAndroid Build Coastguard Worker 
parse(const SkDOM & dom,const SkDOMNode * node)17*c8dee2aaSAndroid Build Coastguard Worker bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
18*c8dee2aaSAndroid Build Coastguard Worker     const char* elemName = dom.getName(node);
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker     if (this->startElement(elemName)) {
21*c8dee2aaSAndroid Build Coastguard Worker         return false;
22*c8dee2aaSAndroid Build Coastguard Worker     }
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker     SkDOM::AttrIter iter(dom, node);
25*c8dee2aaSAndroid Build Coastguard Worker     const char*     name, *value;
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker     while ((name = iter.next(&value)) != nullptr) {
28*c8dee2aaSAndroid Build Coastguard Worker         if (this->addAttribute(name, value)) {
29*c8dee2aaSAndroid Build Coastguard Worker             return false;
30*c8dee2aaSAndroid Build Coastguard Worker         }
31*c8dee2aaSAndroid Build Coastguard Worker     }
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker     if ((node = dom.getFirstChild(node)) != nullptr) {
34*c8dee2aaSAndroid Build Coastguard Worker         do {
35*c8dee2aaSAndroid Build Coastguard Worker             if (!this->parse(dom, node)) {
36*c8dee2aaSAndroid Build Coastguard Worker                 return false;
37*c8dee2aaSAndroid Build Coastguard Worker             }
38*c8dee2aaSAndroid Build Coastguard Worker         } while ((node = dom.getNextSibling(node)) != nullptr);
39*c8dee2aaSAndroid Build Coastguard Worker     }
40*c8dee2aaSAndroid Build Coastguard Worker     return !this->endElement(elemName);
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker struct SkDOMAttr {
46*c8dee2aaSAndroid Build Coastguard Worker     const char* fName;
47*c8dee2aaSAndroid Build Coastguard Worker     const char* fValue;
48*c8dee2aaSAndroid Build Coastguard Worker };
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker struct SkDOMNode {
51*c8dee2aaSAndroid Build Coastguard Worker     const char* fName;
52*c8dee2aaSAndroid Build Coastguard Worker     SkDOMNode*  fFirstChild;
53*c8dee2aaSAndroid Build Coastguard Worker     SkDOMNode*  fNextSibling;
54*c8dee2aaSAndroid Build Coastguard Worker     SkDOMAttr*  fAttrs;
55*c8dee2aaSAndroid Build Coastguard Worker     uint16_t    fAttrCount;
56*c8dee2aaSAndroid Build Coastguard Worker     uint8_t     fType;
57*c8dee2aaSAndroid Build Coastguard Worker     uint8_t     fPad;
58*c8dee2aaSAndroid Build Coastguard Worker 
attrsSkDOMNode59*c8dee2aaSAndroid Build Coastguard Worker     const SkDOMAttr* attrs() const {
60*c8dee2aaSAndroid Build Coastguard Worker         return fAttrs;
61*c8dee2aaSAndroid Build Coastguard Worker     }
62*c8dee2aaSAndroid Build Coastguard Worker 
attrsSkDOMNode63*c8dee2aaSAndroid Build Coastguard Worker     SkDOMAttr* attrs() {
64*c8dee2aaSAndroid Build Coastguard Worker         return fAttrs;
65*c8dee2aaSAndroid Build Coastguard Worker     }
66*c8dee2aaSAndroid Build Coastguard Worker };
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker #define kMinChunkSize   4096
71*c8dee2aaSAndroid Build Coastguard Worker 
SkDOM()72*c8dee2aaSAndroid Build Coastguard Worker SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
73*c8dee2aaSAndroid Build Coastguard Worker 
~SkDOM()74*c8dee2aaSAndroid Build Coastguard Worker SkDOM::~SkDOM() {}
75*c8dee2aaSAndroid Build Coastguard Worker 
getRootNode() const76*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Node* SkDOM::getRootNode() const {
77*c8dee2aaSAndroid Build Coastguard Worker     return fRoot;
78*c8dee2aaSAndroid Build Coastguard Worker }
79*c8dee2aaSAndroid Build Coastguard Worker 
getFirstChild(const Node * node,const char name[]) const80*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
81*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
82*c8dee2aaSAndroid Build Coastguard Worker     const Node* child = node->fFirstChild;
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker     if (name) {
85*c8dee2aaSAndroid Build Coastguard Worker         for (; child != nullptr; child = child->fNextSibling) {
86*c8dee2aaSAndroid Build Coastguard Worker             if (!strcmp(name, child->fName)) {
87*c8dee2aaSAndroid Build Coastguard Worker                 break;
88*c8dee2aaSAndroid Build Coastguard Worker             }
89*c8dee2aaSAndroid Build Coastguard Worker         }
90*c8dee2aaSAndroid Build Coastguard Worker     }
91*c8dee2aaSAndroid Build Coastguard Worker     return child;
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker 
getNextSibling(const Node * node,const char name[]) const94*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
95*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
96*c8dee2aaSAndroid Build Coastguard Worker     const Node* sibling = node->fNextSibling;
97*c8dee2aaSAndroid Build Coastguard Worker     if (name) {
98*c8dee2aaSAndroid Build Coastguard Worker         for (; sibling != nullptr; sibling = sibling->fNextSibling) {
99*c8dee2aaSAndroid Build Coastguard Worker             if (!strcmp(name, sibling->fName)) {
100*c8dee2aaSAndroid Build Coastguard Worker                 break;
101*c8dee2aaSAndroid Build Coastguard Worker             }
102*c8dee2aaSAndroid Build Coastguard Worker         }
103*c8dee2aaSAndroid Build Coastguard Worker     }
104*c8dee2aaSAndroid Build Coastguard Worker     return sibling;
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker 
getType(const Node * node) const107*c8dee2aaSAndroid Build Coastguard Worker SkDOM::Type SkDOM::getType(const Node* node) const {
108*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
109*c8dee2aaSAndroid Build Coastguard Worker     return (Type)node->fType;
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker 
getName(const Node * node) const112*c8dee2aaSAndroid Build Coastguard Worker const char* SkDOM::getName(const Node* node) const {
113*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
114*c8dee2aaSAndroid Build Coastguard Worker     return node->fName;
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker 
findAttr(const Node * node,const char name[]) const117*c8dee2aaSAndroid Build Coastguard Worker const char* SkDOM::findAttr(const Node* node, const char name[]) const {
118*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
119*c8dee2aaSAndroid Build Coastguard Worker     const Attr* attr = node->attrs();
120*c8dee2aaSAndroid Build Coastguard Worker     const Attr* stop = attr + node->fAttrCount;
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker     while (attr < stop) {
123*c8dee2aaSAndroid Build Coastguard Worker         if (!strcmp(attr->fName, name)) {
124*c8dee2aaSAndroid Build Coastguard Worker             return attr->fValue;
125*c8dee2aaSAndroid Build Coastguard Worker         }
126*c8dee2aaSAndroid Build Coastguard Worker         attr += 1;
127*c8dee2aaSAndroid Build Coastguard Worker     }
128*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////////////
132*c8dee2aaSAndroid Build Coastguard Worker 
getFirstAttr(const Node * node) const133*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
134*c8dee2aaSAndroid Build Coastguard Worker     return node->fAttrCount ? node->attrs() : nullptr;
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker 
getNextAttr(const Node * node,const Attr * attr) const137*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
138*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
139*c8dee2aaSAndroid Build Coastguard Worker     if (attr == nullptr) {
140*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker     return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
143*c8dee2aaSAndroid Build Coastguard Worker }
144*c8dee2aaSAndroid Build Coastguard Worker 
getAttrName(const Node * node,const Attr * attr) const145*c8dee2aaSAndroid Build Coastguard Worker const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
146*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
147*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(attr);
148*c8dee2aaSAndroid Build Coastguard Worker     return attr->fName;
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker 
getAttrValue(const Node * node,const Attr * attr) const151*c8dee2aaSAndroid Build Coastguard Worker const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
152*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
153*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(attr);
154*c8dee2aaSAndroid Build Coastguard Worker     return attr->fValue;
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////////////
158*c8dee2aaSAndroid Build Coastguard Worker 
AttrIter(const SkDOM &,const SkDOM::Node * node)159*c8dee2aaSAndroid Build Coastguard Worker SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
160*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(node);
161*c8dee2aaSAndroid Build Coastguard Worker     fAttr = node->attrs();
162*c8dee2aaSAndroid Build Coastguard Worker     fStop = fAttr + node->fAttrCount;
163*c8dee2aaSAndroid Build Coastguard Worker }
164*c8dee2aaSAndroid Build Coastguard Worker 
next(const char ** value)165*c8dee2aaSAndroid Build Coastguard Worker const char* SkDOM::AttrIter::next(const char** value) {
166*c8dee2aaSAndroid Build Coastguard Worker     const char* name = nullptr;
167*c8dee2aaSAndroid Build Coastguard Worker 
168*c8dee2aaSAndroid Build Coastguard Worker     if (fAttr < fStop) {
169*c8dee2aaSAndroid Build Coastguard Worker         name = fAttr->fName;
170*c8dee2aaSAndroid Build Coastguard Worker         if (value)
171*c8dee2aaSAndroid Build Coastguard Worker             *value = fAttr->fValue;
172*c8dee2aaSAndroid Build Coastguard Worker         fAttr += 1;
173*c8dee2aaSAndroid Build Coastguard Worker     }
174*c8dee2aaSAndroid Build Coastguard Worker     return name;
175*c8dee2aaSAndroid Build Coastguard Worker }
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
180*c8dee2aaSAndroid Build Coastguard Worker #include "src/xml/SkXMLParser.h"
181*c8dee2aaSAndroid Build Coastguard Worker 
dupstr(SkArenaAlloc * chunk,const char src[],size_t srcLen)182*c8dee2aaSAndroid Build Coastguard Worker static char* dupstr(SkArenaAlloc* chunk, const char src[], size_t srcLen) {
183*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(chunk && src);
184*c8dee2aaSAndroid Build Coastguard Worker     char* dst = chunk->makeArrayDefault<char>(srcLen + 1);
185*c8dee2aaSAndroid Build Coastguard Worker     memcpy(dst, src, srcLen);
186*c8dee2aaSAndroid Build Coastguard Worker     dst[srcLen] = '\0';
187*c8dee2aaSAndroid Build Coastguard Worker     return dst;
188*c8dee2aaSAndroid Build Coastguard Worker }
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker class SkDOMParser : public SkXMLParser {
191*c8dee2aaSAndroid Build Coastguard Worker public:
SkDOMParser(SkArenaAllocWithReset * chunk)192*c8dee2aaSAndroid Build Coastguard Worker     SkDOMParser(SkArenaAllocWithReset* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
193*c8dee2aaSAndroid Build Coastguard Worker         fAlloc->reset();
194*c8dee2aaSAndroid Build Coastguard Worker         fRoot = nullptr;
195*c8dee2aaSAndroid Build Coastguard Worker         fLevel = 0;
196*c8dee2aaSAndroid Build Coastguard Worker         fNeedToFlush = true;
197*c8dee2aaSAndroid Build Coastguard Worker     }
getRoot() const198*c8dee2aaSAndroid Build Coastguard Worker     SkDOM::Node* getRoot() const { return fRoot; }
199*c8dee2aaSAndroid Build Coastguard Worker     SkXMLParserError fParserError;
200*c8dee2aaSAndroid Build Coastguard Worker 
201*c8dee2aaSAndroid Build Coastguard Worker protected:
flushAttributes()202*c8dee2aaSAndroid Build Coastguard Worker     void flushAttributes() {
203*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fLevel > 0);
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker         int attrCount = fAttrs.size();
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker         SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
208*c8dee2aaSAndroid Build Coastguard Worker         SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker         node->fName = fElemName;
211*c8dee2aaSAndroid Build Coastguard Worker         node->fFirstChild = nullptr;
212*c8dee2aaSAndroid Build Coastguard Worker         node->fAttrCount = SkToU16(attrCount);
213*c8dee2aaSAndroid Build Coastguard Worker         node->fAttrs = attrs;
214*c8dee2aaSAndroid Build Coastguard Worker         node->fType = fElemType;
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker         if (fRoot == nullptr) {
217*c8dee2aaSAndroid Build Coastguard Worker             node->fNextSibling = nullptr;
218*c8dee2aaSAndroid Build Coastguard Worker             fRoot = node;
219*c8dee2aaSAndroid Build Coastguard Worker         } else { // this adds siblings in reverse order. gets corrected in onEndElement()
220*c8dee2aaSAndroid Build Coastguard Worker             SkDOM::Node* parent = fParentStack.back();
221*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fRoot && parent);
222*c8dee2aaSAndroid Build Coastguard Worker             node->fNextSibling = parent->fFirstChild;
223*c8dee2aaSAndroid Build Coastguard Worker             parent->fFirstChild = node;
224*c8dee2aaSAndroid Build Coastguard Worker         }
225*c8dee2aaSAndroid Build Coastguard Worker         *fParentStack.append() = node;
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker         sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
228*c8dee2aaSAndroid Build Coastguard Worker         fAttrs.reset();
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
onStartElement(const char elem[])231*c8dee2aaSAndroid Build Coastguard Worker     bool onStartElement(const char elem[]) override {
232*c8dee2aaSAndroid Build Coastguard Worker         this->startCommon(elem, strlen(elem), SkDOM::kElement_Type);
233*c8dee2aaSAndroid Build Coastguard Worker         return false;
234*c8dee2aaSAndroid Build Coastguard Worker     }
235*c8dee2aaSAndroid Build Coastguard Worker 
onAddAttribute(const char name[],const char value[])236*c8dee2aaSAndroid Build Coastguard Worker     bool onAddAttribute(const char name[], const char value[]) override {
237*c8dee2aaSAndroid Build Coastguard Worker         SkDOM::Attr* attr = fAttrs.append();
238*c8dee2aaSAndroid Build Coastguard Worker         attr->fName = dupstr(fAlloc, name, strlen(name));
239*c8dee2aaSAndroid Build Coastguard Worker         attr->fValue = dupstr(fAlloc, value, strlen(value));
240*c8dee2aaSAndroid Build Coastguard Worker         return false;
241*c8dee2aaSAndroid Build Coastguard Worker     }
242*c8dee2aaSAndroid Build Coastguard Worker 
onEndElement(const char elem[])243*c8dee2aaSAndroid Build Coastguard Worker     bool onEndElement(const char elem[]) override {
244*c8dee2aaSAndroid Build Coastguard Worker         if (fNeedToFlush)
245*c8dee2aaSAndroid Build Coastguard Worker             this->flushAttributes();
246*c8dee2aaSAndroid Build Coastguard Worker         fNeedToFlush = false;
247*c8dee2aaSAndroid Build Coastguard Worker         --fLevel;
248*c8dee2aaSAndroid Build Coastguard Worker 
249*c8dee2aaSAndroid Build Coastguard Worker         SkDOM::Node* parent = fParentStack.back();
250*c8dee2aaSAndroid Build Coastguard Worker         fParentStack.pop_back();
251*c8dee2aaSAndroid Build Coastguard Worker 
252*c8dee2aaSAndroid Build Coastguard Worker         SkDOM::Node* child = parent->fFirstChild;
253*c8dee2aaSAndroid Build Coastguard Worker         SkDOM::Node* prev = nullptr;
254*c8dee2aaSAndroid Build Coastguard Worker         while (child) {
255*c8dee2aaSAndroid Build Coastguard Worker             SkDOM::Node* next = child->fNextSibling;
256*c8dee2aaSAndroid Build Coastguard Worker             child->fNextSibling = prev;
257*c8dee2aaSAndroid Build Coastguard Worker             prev = child;
258*c8dee2aaSAndroid Build Coastguard Worker             child = next;
259*c8dee2aaSAndroid Build Coastguard Worker         }
260*c8dee2aaSAndroid Build Coastguard Worker         parent->fFirstChild = prev;
261*c8dee2aaSAndroid Build Coastguard Worker         return false;
262*c8dee2aaSAndroid Build Coastguard Worker     }
263*c8dee2aaSAndroid Build Coastguard Worker 
onText(const char text[],int len)264*c8dee2aaSAndroid Build Coastguard Worker     bool onText(const char text[], int len) override {
265*c8dee2aaSAndroid Build Coastguard Worker         this->startCommon(text, len, SkDOM::kText_Type);
266*c8dee2aaSAndroid Build Coastguard Worker         this->SkDOMParser::onEndElement(fElemName);
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker         return false;
269*c8dee2aaSAndroid Build Coastguard Worker     }
270*c8dee2aaSAndroid Build Coastguard Worker 
271*c8dee2aaSAndroid Build Coastguard Worker private:
startCommon(const char elem[],size_t elemSize,SkDOM::Type type)272*c8dee2aaSAndroid Build Coastguard Worker     void startCommon(const char elem[], size_t elemSize, SkDOM::Type type) {
273*c8dee2aaSAndroid Build Coastguard Worker         if (fLevel > 0 && fNeedToFlush) {
274*c8dee2aaSAndroid Build Coastguard Worker             this->flushAttributes();
275*c8dee2aaSAndroid Build Coastguard Worker         }
276*c8dee2aaSAndroid Build Coastguard Worker         fNeedToFlush = true;
277*c8dee2aaSAndroid Build Coastguard Worker         fElemName = dupstr(fAlloc, elem, elemSize);
278*c8dee2aaSAndroid Build Coastguard Worker         fElemType = type;
279*c8dee2aaSAndroid Build Coastguard Worker         ++fLevel;
280*c8dee2aaSAndroid Build Coastguard Worker     }
281*c8dee2aaSAndroid Build Coastguard Worker 
282*c8dee2aaSAndroid Build Coastguard Worker     SkTDArray<SkDOM::Node*> fParentStack;
283*c8dee2aaSAndroid Build Coastguard Worker     SkArenaAllocWithReset*  fAlloc;
284*c8dee2aaSAndroid Build Coastguard Worker     SkDOM::Node*            fRoot;
285*c8dee2aaSAndroid Build Coastguard Worker     bool                    fNeedToFlush;
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker     // state needed for flushAttributes()
288*c8dee2aaSAndroid Build Coastguard Worker     SkTDArray<SkDOM::Attr>  fAttrs;
289*c8dee2aaSAndroid Build Coastguard Worker     char*                   fElemName;
290*c8dee2aaSAndroid Build Coastguard Worker     SkDOM::Type             fElemType;
291*c8dee2aaSAndroid Build Coastguard Worker     int                     fLevel;
292*c8dee2aaSAndroid Build Coastguard Worker };
293*c8dee2aaSAndroid Build Coastguard Worker 
build(SkStream & docStream)294*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Node* SkDOM::build(SkStream& docStream) {
295*c8dee2aaSAndroid Build Coastguard Worker     SkDOMParser parser(&fAlloc);
296*c8dee2aaSAndroid Build Coastguard Worker     if (!parser.parse(docStream))
297*c8dee2aaSAndroid Build Coastguard Worker     {
298*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
299*c8dee2aaSAndroid Build Coastguard Worker         fRoot = nullptr;
300*c8dee2aaSAndroid Build Coastguard Worker         fAlloc.reset();
301*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
302*c8dee2aaSAndroid Build Coastguard Worker     }
303*c8dee2aaSAndroid Build Coastguard Worker     fRoot = parser.getRoot();
304*c8dee2aaSAndroid Build Coastguard Worker     return fRoot;
305*c8dee2aaSAndroid Build Coastguard Worker }
306*c8dee2aaSAndroid Build Coastguard Worker 
307*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////
308*c8dee2aaSAndroid Build Coastguard Worker 
walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)309*c8dee2aaSAndroid Build Coastguard Worker static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
310*c8dee2aaSAndroid Build Coastguard Worker     const char* elem = dom.getName(node);
311*c8dee2aaSAndroid Build Coastguard Worker     if (dom.getType(node) == SkDOM::kText_Type) {
312*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(dom.countChildren(node) == 0);
313*c8dee2aaSAndroid Build Coastguard Worker         parser->text(elem, SkToInt(strlen(elem)));
314*c8dee2aaSAndroid Build Coastguard Worker         return;
315*c8dee2aaSAndroid Build Coastguard Worker     }
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker     parser->startElement(elem);
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker     SkDOM::AttrIter iter(dom, node);
320*c8dee2aaSAndroid Build Coastguard Worker     const char*     name;
321*c8dee2aaSAndroid Build Coastguard Worker     const char*     value;
322*c8dee2aaSAndroid Build Coastguard Worker     while ((name = iter.next(&value)) != nullptr)
323*c8dee2aaSAndroid Build Coastguard Worker         parser->addAttribute(name, value);
324*c8dee2aaSAndroid Build Coastguard Worker 
325*c8dee2aaSAndroid Build Coastguard Worker     node = dom.getFirstChild(node, nullptr);
326*c8dee2aaSAndroid Build Coastguard Worker     while (node)
327*c8dee2aaSAndroid Build Coastguard Worker     {
328*c8dee2aaSAndroid Build Coastguard Worker         walk_dom(dom, node, parser);
329*c8dee2aaSAndroid Build Coastguard Worker         node = dom.getNextSibling(node, nullptr);
330*c8dee2aaSAndroid Build Coastguard Worker     }
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker     parser->endElement(elem);
333*c8dee2aaSAndroid Build Coastguard Worker }
334*c8dee2aaSAndroid Build Coastguard Worker 
copy(const SkDOM & dom,const SkDOM::Node * node)335*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
336*c8dee2aaSAndroid Build Coastguard Worker     SkDOMParser parser(&fAlloc);
337*c8dee2aaSAndroid Build Coastguard Worker 
338*c8dee2aaSAndroid Build Coastguard Worker     walk_dom(dom, node, &parser);
339*c8dee2aaSAndroid Build Coastguard Worker 
340*c8dee2aaSAndroid Build Coastguard Worker     fRoot = parser.getRoot();
341*c8dee2aaSAndroid Build Coastguard Worker     return fRoot;
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker 
beginParsing()344*c8dee2aaSAndroid Build Coastguard Worker SkXMLParser* SkDOM::beginParsing() {
345*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fParser);
346*c8dee2aaSAndroid Build Coastguard Worker     fParser = std::make_unique<SkDOMParser>(&fAlloc);
347*c8dee2aaSAndroid Build Coastguard Worker 
348*c8dee2aaSAndroid Build Coastguard Worker     return fParser.get();
349*c8dee2aaSAndroid Build Coastguard Worker }
350*c8dee2aaSAndroid Build Coastguard Worker 
finishParsing()351*c8dee2aaSAndroid Build Coastguard Worker const SkDOM::Node* SkDOM::finishParsing() {
352*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fParser);
353*c8dee2aaSAndroid Build Coastguard Worker     fRoot = fParser->getRoot();
354*c8dee2aaSAndroid Build Coastguard Worker     fParser.reset();
355*c8dee2aaSAndroid Build Coastguard Worker 
356*c8dee2aaSAndroid Build Coastguard Worker     return fRoot;
357*c8dee2aaSAndroid Build Coastguard Worker }
358*c8dee2aaSAndroid Build Coastguard Worker 
359*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////
360*c8dee2aaSAndroid Build Coastguard Worker 
countChildren(const Node * node,const char elem[]) const361*c8dee2aaSAndroid Build Coastguard Worker int SkDOM::countChildren(const Node* node, const char elem[]) const {
362*c8dee2aaSAndroid Build Coastguard Worker     int count = 0;
363*c8dee2aaSAndroid Build Coastguard Worker 
364*c8dee2aaSAndroid Build Coastguard Worker     node = this->getFirstChild(node, elem);
365*c8dee2aaSAndroid Build Coastguard Worker     while (node) {
366*c8dee2aaSAndroid Build Coastguard Worker         count += 1;
367*c8dee2aaSAndroid Build Coastguard Worker         node = this->getNextSibling(node, elem);
368*c8dee2aaSAndroid Build Coastguard Worker     }
369*c8dee2aaSAndroid Build Coastguard Worker     return count;
370*c8dee2aaSAndroid Build Coastguard Worker }
371*c8dee2aaSAndroid Build Coastguard Worker 
372*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////
373*c8dee2aaSAndroid Build Coastguard Worker 
374*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkParse.h"
375*c8dee2aaSAndroid Build Coastguard Worker 
findS32(const Node * node,const char name[],int32_t * value) const376*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
377*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
378*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindS32(vstr, value);
379*c8dee2aaSAndroid Build Coastguard Worker }
380*c8dee2aaSAndroid Build Coastguard Worker 
findScalars(const Node * node,const char name[],SkScalar value[],int count) const381*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
382*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
383*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindScalars(vstr, value, count);
384*c8dee2aaSAndroid Build Coastguard Worker }
385*c8dee2aaSAndroid Build Coastguard Worker 
findHex(const Node * node,const char name[],uint32_t * value) const386*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
387*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
388*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindHex(vstr, value);
389*c8dee2aaSAndroid Build Coastguard Worker }
390*c8dee2aaSAndroid Build Coastguard Worker 
findBool(const Node * node,const char name[],bool * value) const391*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
392*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
393*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindBool(vstr, value);
394*c8dee2aaSAndroid Build Coastguard Worker }
395*c8dee2aaSAndroid Build Coastguard Worker 
findList(const Node * node,const char name[],const char list[]) const396*c8dee2aaSAndroid Build Coastguard Worker int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
397*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
398*c8dee2aaSAndroid Build Coastguard Worker     return vstr ? SkParse::FindList(vstr, list) : -1;
399*c8dee2aaSAndroid Build Coastguard Worker }
400*c8dee2aaSAndroid Build Coastguard Worker 
hasAttr(const Node * node,const char name[],const char value[]) const401*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
402*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
403*c8dee2aaSAndroid Build Coastguard Worker     return vstr && !strcmp(vstr, value);
404*c8dee2aaSAndroid Build Coastguard Worker }
405*c8dee2aaSAndroid Build Coastguard Worker 
hasS32(const Node * node,const char name[],int32_t target) const406*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
407*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
408*c8dee2aaSAndroid Build Coastguard Worker     int32_t     value;
409*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindS32(vstr, &value) && value == target;
410*c8dee2aaSAndroid Build Coastguard Worker }
411*c8dee2aaSAndroid Build Coastguard Worker 
hasScalar(const Node * node,const char name[],SkScalar target) const412*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
413*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
414*c8dee2aaSAndroid Build Coastguard Worker     SkScalar    value;
415*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindScalar(vstr, &value) && value == target;
416*c8dee2aaSAndroid Build Coastguard Worker }
417*c8dee2aaSAndroid Build Coastguard Worker 
hasHex(const Node * node,const char name[],uint32_t target) const418*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
419*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
420*c8dee2aaSAndroid Build Coastguard Worker     uint32_t    value;
421*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindHex(vstr, &value) && value == target;
422*c8dee2aaSAndroid Build Coastguard Worker }
423*c8dee2aaSAndroid Build Coastguard Worker 
hasBool(const Node * node,const char name[],bool target) const424*c8dee2aaSAndroid Build Coastguard Worker bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
425*c8dee2aaSAndroid Build Coastguard Worker     const char* vstr = this->findAttr(node, name);
426*c8dee2aaSAndroid Build Coastguard Worker     bool        value;
427*c8dee2aaSAndroid Build Coastguard Worker     return vstr && SkParse::FindBool(vstr, &value) && value == target;
428*c8dee2aaSAndroid Build Coastguard Worker }
429