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 "include/core/SkStream.h"
11 #include "include/private/SkTo.h"
12 #include "src/xml/SkXMLParser.h"
13 #include "src/xml/SkXMLWriter.h"
14
parse(const SkDOM & dom,const SkDOMNode * node)15 bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
16 const char* elemName = dom.getName(node);
17
18 if (this->startElement(elemName)) {
19 return false;
20 }
21
22 SkDOM::AttrIter iter(dom, node);
23 const char* name, *value;
24
25 while ((name = iter.next(&value)) != nullptr) {
26 if (this->addAttribute(name, value)) {
27 return false;
28 }
29 }
30
31 if ((node = dom.getFirstChild(node)) != nullptr) {
32 do {
33 if (!this->parse(dom, node)) {
34 return false;
35 }
36 } while ((node = dom.getNextSibling(node)) != nullptr);
37 }
38 return !this->endElement(elemName);
39 }
40
41 /////////////////////////////////////////////////////////////////////////
42
43 struct SkDOMAttr {
44 const char* fName;
45 const char* fValue;
46 };
47
48 struct SkDOMNode {
49 const char* fName;
50 SkDOMNode* fFirstChild;
51 SkDOMNode* fNextSibling;
52 SkDOMAttr* fAttrs;
53 uint16_t fAttrCount;
54 uint8_t fType;
55 uint8_t fPad;
56
attrsSkDOMNode57 const SkDOMAttr* attrs() const {
58 return fAttrs;
59 }
60
attrsSkDOMNode61 SkDOMAttr* attrs() {
62 return fAttrs;
63 }
64 };
65
66 /////////////////////////////////////////////////////////////////////////
67
68 #define kMinChunkSize 4096
69
SkDOM()70 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
71
~SkDOM()72 SkDOM::~SkDOM() {}
73
getRootNode() const74 const SkDOM::Node* SkDOM::getRootNode() const {
75 return fRoot;
76 }
77
getFirstChild(const Node * node,const char name[]) const78 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
79 SkASSERT(node);
80 const Node* child = node->fFirstChild;
81
82 if (name) {
83 for (; child != nullptr; child = child->fNextSibling) {
84 if (!strcmp(name, child->fName)) {
85 break;
86 }
87 }
88 }
89 return child;
90 }
91
getNextSibling(const Node * node,const char name[]) const92 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
93 SkASSERT(node);
94 const Node* sibling = node->fNextSibling;
95 if (name) {
96 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
97 if (!strcmp(name, sibling->fName)) {
98 break;
99 }
100 }
101 }
102 return sibling;
103 }
104
getType(const Node * node) const105 SkDOM::Type SkDOM::getType(const Node* node) const {
106 SkASSERT(node);
107 return (Type)node->fType;
108 }
109
getName(const Node * node) const110 const char* SkDOM::getName(const Node* node) const {
111 SkASSERT(node);
112 return node->fName;
113 }
114
findAttr(const Node * node,const char name[]) const115 const char* SkDOM::findAttr(const Node* node, const char name[]) const {
116 SkASSERT(node);
117 const Attr* attr = node->attrs();
118 const Attr* stop = attr + node->fAttrCount;
119
120 while (attr < stop) {
121 if (!strcmp(attr->fName, name)) {
122 return attr->fValue;
123 }
124 attr += 1;
125 }
126 return nullptr;
127 }
128
129 /////////////////////////////////////////////////////////////////////////////////////
130
getFirstAttr(const Node * node) const131 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
132 return node->fAttrCount ? node->attrs() : nullptr;
133 }
134
getNextAttr(const Node * node,const Attr * attr) const135 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
136 SkASSERT(node);
137 if (attr == nullptr) {
138 return nullptr;
139 }
140 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
141 }
142
getAttrName(const Node * node,const Attr * attr) const143 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
144 SkASSERT(node);
145 SkASSERT(attr);
146 return attr->fName;
147 }
148
getAttrValue(const Node * node,const Attr * attr) const149 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
150 SkASSERT(node);
151 SkASSERT(attr);
152 return attr->fValue;
153 }
154
155 /////////////////////////////////////////////////////////////////////////////////////
156
AttrIter(const SkDOM &,const SkDOM::Node * node)157 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
158 SkASSERT(node);
159 fAttr = node->attrs();
160 fStop = fAttr + node->fAttrCount;
161 }
162
next(const char ** value)163 const char* SkDOM::AttrIter::next(const char** value) {
164 const char* name = nullptr;
165
166 if (fAttr < fStop) {
167 name = fAttr->fName;
168 if (value)
169 *value = fAttr->fValue;
170 fAttr += 1;
171 }
172 return name;
173 }
174
175 //////////////////////////////////////////////////////////////////////////////
176
177 #include "include/private/SkTDArray.h"
178 #include "src/xml/SkXMLParser.h"
179
dupstr(SkArenaAlloc * chunk,const char src[])180 static char* dupstr(SkArenaAlloc* chunk, const char src[]) {
181 SkASSERT(chunk && src);
182 size_t len = strlen(src);
183 char* dst = chunk->makeArrayDefault<char>(len + 1);
184 memcpy(dst, src, len + 1);
185 return dst;
186 }
187
188 class SkDOMParser : public SkXMLParser {
189 public:
SkDOMParser(SkArenaAlloc * chunk)190 SkDOMParser(SkArenaAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
191 fAlloc->reset();
192 fRoot = nullptr;
193 fLevel = 0;
194 fNeedToFlush = true;
195 }
getRoot() const196 SkDOM::Node* getRoot() const { return fRoot; }
197 SkXMLParserError fParserError;
198
199 protected:
flushAttributes()200 virtual void flushAttributes() {
201 SkASSERT(fLevel > 0);
202 SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
203 flushAttributesWithNode(node);
204 }
205
flushAttributesWithNode(SkDOM::Node * node)206 void flushAttributesWithNode(SkDOM::Node* node) {
207 int attrCount = fAttrs.count();
208 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
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
onStartElement(const char elem[])231 bool onStartElement(const char elem[]) override {
232 this->startCommon(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);
239 attr->fValue = dupstr(fAlloc, value);
240 return false;
241 }
242
onEndElement(const char elem[])243 bool onEndElement(const char elem[]) override {
244 --fLevel;
245 if (fNeedToFlush)
246 this->flushAttributes();
247 fNeedToFlush = false;
248
249 SkDOM::Node* parent;
250
251 fParentStack.pop(&parent);
252
253 SkDOM::Node* child = parent->fFirstChild;
254 SkDOM::Node* prev = nullptr;
255 while (child) {
256 SkDOM::Node* next = child->fNextSibling;
257 child->fNextSibling = prev;
258 prev = child;
259 child = next;
260 }
261 parent->fFirstChild = prev;
262 return false;
263 }
264
onText(const char text[],int len)265 bool onText(const char text[], int len) override {
266 SkString str(text, len);
267 this->startCommon(str.c_str(), SkDOM::kText_Type);
268 this->SkDOMParser::onEndElement(str.c_str());
269
270 return false;
271 }
272
startCommon(const char elem[],SkDOM::Type type)273 void startCommon(const char elem[], SkDOM::Type type) {
274 if (fLevel > 0 && fNeedToFlush) {
275 this->flushAttributes();
276 }
277 fNeedToFlush = true;
278 fElemName = dupstr(fAlloc, elem);
279 fElemType = type;
280 ++fLevel;
281 }
282
283 SkTDArray<SkDOM::Node*> fParentStack;
284 SkArenaAlloc* fAlloc;
285 SkDOM::Node* fRoot;
286 bool fNeedToFlush;
287
288 // state needed for flushAttributes()
289 SkTDArray<SkDOM::Attr> fAttrs;
290 char* fElemName;
291 SkDOM::Type fElemType;
292 int fLevel;
293 };
294
build(SkStream & docStream)295 const SkDOM::Node* SkDOM::build(SkStream& docStream) {
296 SkDOMParser parser(&fAlloc);
297 if (!parser.parse(docStream))
298 {
299 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
300 fRoot = nullptr;
301 fAlloc.reset();
302 return nullptr;
303 }
304 fRoot = parser.getRoot();
305 return fRoot;
306 }
307
308 ///////////////////////////////////////////////////////////////////////////
309
walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)310 static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
311 const char* elem = dom.getName(node);
312 if (dom.getType(node) == SkDOM::kText_Type) {
313 SkASSERT(dom.countChildren(node) == 0);
314 parser->text(elem, SkToInt(strlen(elem)));
315 return;
316 }
317
318 parser->startElement(elem);
319
320 SkDOM::AttrIter iter(dom, node);
321 const char* name;
322 const char* value;
323 while ((name = iter.next(&value)) != nullptr)
324 parser->addAttribute(name, value);
325
326 node = dom.getFirstChild(node, nullptr);
327 while (node)
328 {
329 walk_dom(dom, node, parser);
330 node = dom.getNextSibling(node, nullptr);
331 }
332
333 parser->endElement(elem);
334 }
335
copy(const SkDOM & dom,const SkDOM::Node * node)336 const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
337 SkDOMParser parser(&fAlloc);
338
339 walk_dom(dom, node, &parser);
340
341 fRoot = parser.getRoot();
342 return fRoot;
343 }
344
beginParsing()345 SkXMLParser* SkDOM::beginParsing() {
346 SkASSERT(!fParser);
347 fParser.reset(new SkDOMParser(&fAlloc));
348
349 return fParser.get();
350 }
351
finishParsing()352 const SkDOM::Node* SkDOM::finishParsing() {
353 SkASSERT(fParser);
354 fRoot = fParser->getRoot();
355 fParser.reset();
356
357 return fRoot;
358 }
359
360 //////////////////////////////////////////////////////////////////////////
361
countChildren(const Node * node,const char elem[]) const362 int SkDOM::countChildren(const Node* node, const char elem[]) const {
363 int count = 0;
364
365 node = this->getFirstChild(node, elem);
366 while (node) {
367 count += 1;
368 node = this->getNextSibling(node, elem);
369 }
370 return count;
371 }
372
373 //////////////////////////////////////////////////////////////////////////
374
375 #include "include/utils/SkParse.h"
376
findS32(const Node * node,const char name[],int32_t * value) const377 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
378 const char* vstr = this->findAttr(node, name);
379 return vstr && SkParse::FindS32(vstr, value);
380 }
381
findScalars(const Node * node,const char name[],SkScalar value[],int count) const382 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
383 const char* vstr = this->findAttr(node, name);
384 return vstr && SkParse::FindScalars(vstr, value, count);
385 }
386
findHex(const Node * node,const char name[],uint32_t * value) const387 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
388 const char* vstr = this->findAttr(node, name);
389 return vstr && SkParse::FindHex(vstr, value);
390 }
391
findBool(const Node * node,const char name[],bool * value) const392 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
393 const char* vstr = this->findAttr(node, name);
394 return vstr && SkParse::FindBool(vstr, value);
395 }
396
findList(const Node * node,const char name[],const char list[]) const397 int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
398 const char* vstr = this->findAttr(node, name);
399 return vstr ? SkParse::FindList(vstr, list) : -1;
400 }
401
hasAttr(const Node * node,const char name[],const char value[]) const402 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
403 const char* vstr = this->findAttr(node, name);
404 return vstr && !strcmp(vstr, value);
405 }
406
hasS32(const Node * node,const char name[],int32_t target) const407 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
408 const char* vstr = this->findAttr(node, name);
409 int32_t value;
410 return vstr && SkParse::FindS32(vstr, &value) && value == target;
411 }
412
hasScalar(const Node * node,const char name[],SkScalar target) const413 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
414 const char* vstr = this->findAttr(node, name);
415 SkScalar value;
416 return vstr && SkParse::FindScalar(vstr, &value) && value == target;
417 }
418
hasHex(const Node * node,const char name[],uint32_t target) const419 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
420 const char* vstr = this->findAttr(node, name);
421 uint32_t value;
422 return vstr && SkParse::FindHex(vstr, &value) && value == target;
423 }
424
hasBool(const Node * node,const char name[],bool target) const425 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
426 const char* vstr = this->findAttr(node, name);
427 bool value;
428 return vstr && SkParse::FindBool(vstr, &value) && value == target;
429 }
430