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
dupstr(SkArenaAlloc * chunk,const char src[],size_t srcLen)68 static char* dupstr(SkArenaAlloc* chunk, const char src[], size_t srcLen) {
69 SkASSERT(chunk && src);
70 char* dst = chunk->makeArrayDefault<char>(srcLen + 1);
71 memcpy(dst, src, srcLen);
72 dst[srcLen] = '\0';
73 return dst;
74 }
75
76 class SkDOMParser : public SkXMLParser {
77 public:
SkDOMParser(SkArenaAllocWithReset * chunk)78 SkDOMParser(SkArenaAllocWithReset* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
79 fAlloc->reset();
80 fRoot = nullptr;
81 fLevel = 0;
82 fNeedToFlush = true;
83 }
getRoot() const84 SkDOM::Node* getRoot() const { return fRoot; }
85 SkXMLParserError fParserError;
86
87 protected:
flushAttributes()88 void flushAttributes() {
89 SkASSERT(fLevel > 0);
90
91 int attrCount = fAttrs.size();
92
93 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
94 SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
95
96 node->fName = fElemName;
97 node->fFirstChild = nullptr;
98 node->fAttrCount = SkToU16(attrCount);
99 node->fAttrs = attrs;
100 node->fType = fElemType;
101
102 if (fRoot == nullptr) {
103 node->fNextSibling = nullptr;
104 fRoot = node;
105 } else { // this adds siblings in reverse order. gets corrected in onEndElement()
106 SkDOM::Node* parent = fParentStack.back();
107 SkASSERT(fRoot && parent);
108 node->fNextSibling = parent->fFirstChild;
109 parent->fFirstChild = node;
110 }
111 *fParentStack.append() = node;
112
113 sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
114 fAttrs.reset();
115 }
116
onStartElement(const char elem[])117 bool onStartElement(const char elem[]) override {
118 this->startCommon(elem, strlen(elem), SkDOM::kElement_Type);
119 return false;
120 }
121
onAddAttribute(const char name[],const char value[])122 bool onAddAttribute(const char name[], const char value[]) override {
123 SkDOM::Attr* attr = fAttrs.append();
124 attr->fName = dupstr(fAlloc, name, strlen(name));
125 attr->fValue = dupstr(fAlloc, value, strlen(value));
126 return false;
127 }
128
onEndElement(const char elem[])129 bool onEndElement(const char elem[]) override {
130 if (fNeedToFlush)
131 this->flushAttributes();
132 fNeedToFlush = false;
133 --fLevel;
134
135 SkDOM::Node* parent = fParentStack.back();
136 fParentStack.pop_back();
137
138 SkDOM::Node* child = parent->fFirstChild;
139 SkDOM::Node* prev = nullptr;
140 while (child) {
141 SkDOM::Node* next = child->fNextSibling;
142 child->fNextSibling = prev;
143 prev = child;
144 child = next;
145 }
146 parent->fFirstChild = prev;
147 return false;
148 }
149
onText(const char text[],int len)150 bool onText(const char text[], int len) override {
151 this->startCommon(text, len, SkDOM::kText_Type);
152 this->SkDOMParser::onEndElement(fElemName);
153
154 return false;
155 }
156
157 private:
startCommon(const char elem[],size_t elemSize,SkDOM::Type type)158 void startCommon(const char elem[], size_t elemSize, SkDOM::Type type) {
159 if (fLevel > 0 && fNeedToFlush) {
160 this->flushAttributes();
161 }
162 fNeedToFlush = true;
163 fElemName = dupstr(fAlloc, elem, elemSize);
164 fElemType = type;
165 ++fLevel;
166 }
167
168 SkTDArray<SkDOM::Node*> fParentStack;
169 SkArenaAllocWithReset* fAlloc;
170 SkDOM::Node* fRoot;
171 bool fNeedToFlush;
172
173 // state needed for flushAttributes()
174 SkTDArray<SkDOM::Attr> fAttrs;
175 char* fElemName;
176 SkDOM::Type fElemType;
177 int fLevel;
178 };
179
180 /////////////////////////////////////////////////////////////////////////
181
182 #define kMinChunkSize 4096
183
SkDOM()184 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
185
~SkDOM()186 SkDOM::~SkDOM() {}
187
getRootNode() const188 const SkDOM::Node* SkDOM::getRootNode() const {
189 return fRoot;
190 }
191
getFirstChild(const Node * node,const char name[]) const192 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
193 SkASSERT(node);
194 const Node* child = node->fFirstChild;
195
196 if (name) {
197 for (; child != nullptr; child = child->fNextSibling) {
198 if (!strcmp(name, child->fName)) {
199 break;
200 }
201 }
202 }
203 return child;
204 }
205
getNextSibling(const Node * node,const char name[]) const206 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
207 SkASSERT(node);
208 const Node* sibling = node->fNextSibling;
209 if (name) {
210 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
211 if (!strcmp(name, sibling->fName)) {
212 break;
213 }
214 }
215 }
216 return sibling;
217 }
218
getType(const Node * node) const219 SkDOM::Type SkDOM::getType(const Node* node) const {
220 SkASSERT(node);
221 return (Type)node->fType;
222 }
223
getName(const Node * node) const224 const char* SkDOM::getName(const Node* node) const {
225 SkASSERT(node);
226 return node->fName;
227 }
228
findAttr(const Node * node,const char name[]) const229 const char* SkDOM::findAttr(const Node* node, const char name[]) const {
230 SkASSERT(node);
231 const Attr* attr = node->attrs();
232 const Attr* stop = attr + node->fAttrCount;
233
234 while (attr < stop) {
235 if (!strcmp(attr->fName, name)) {
236 return attr->fValue;
237 }
238 attr += 1;
239 }
240 return nullptr;
241 }
242
243 /////////////////////////////////////////////////////////////////////////////////////
244
getFirstAttr(const Node * node) const245 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
246 return node->fAttrCount ? node->attrs() : nullptr;
247 }
248
getNextAttr(const Node * node,const Attr * attr) const249 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
250 SkASSERT(node);
251 if (attr == nullptr) {
252 return nullptr;
253 }
254 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
255 }
256
getAttrName(const Node * node,const Attr * attr) const257 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
258 SkASSERT(node);
259 SkASSERT(attr);
260 return attr->fName;
261 }
262
getAttrValue(const Node * node,const Attr * attr) const263 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
264 SkASSERT(node);
265 SkASSERT(attr);
266 return attr->fValue;
267 }
268
269 /////////////////////////////////////////////////////////////////////////////////////
270
AttrIter(const SkDOM &,const SkDOM::Node * node)271 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
272 SkASSERT(node);
273 fAttr = node->attrs();
274 fStop = fAttr + node->fAttrCount;
275 }
276
next(const char ** value)277 const char* SkDOM::AttrIter::next(const char** value) {
278 const char* name = nullptr;
279
280 if (fAttr < fStop) {
281 name = fAttr->fName;
282 if (value)
283 *value = fAttr->fValue;
284 fAttr += 1;
285 }
286 return name;
287 }
288
289 //////////////////////////////////////////////////////////////////////////////
290
build(SkStream & docStream)291 const SkDOM::Node* SkDOM::build(SkStream& docStream) {
292 SkDOMParser parser(&fAlloc);
293 if (!parser.parse(docStream))
294 {
295 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
296 fRoot = nullptr;
297 fAlloc.reset();
298 return nullptr;
299 }
300 fRoot = parser.getRoot();
301 return fRoot;
302 }
303
304 ///////////////////////////////////////////////////////////////////////////
305
walk_dom(const SkDOM & dom,const SkDOM::Node * node,SkXMLParser * parser)306 static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
307 const char* elem = dom.getName(node);
308 if (dom.getType(node) == SkDOM::kText_Type) {
309 SkASSERT(dom.countChildren(node) == 0);
310 parser->text(elem, SkToInt(strlen(elem)));
311 return;
312 }
313
314 parser->startElement(elem);
315
316 SkDOM::AttrIter iter(dom, node);
317 const char* name;
318 const char* value;
319 while ((name = iter.next(&value)) != nullptr)
320 parser->addAttribute(name, value);
321
322 node = dom.getFirstChild(node, nullptr);
323 while (node)
324 {
325 walk_dom(dom, node, parser);
326 node = dom.getNextSibling(node, nullptr);
327 }
328
329 parser->endElement(elem);
330 }
331
copy(const SkDOM & dom,const SkDOM::Node * node)332 const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
333 SkDOMParser parser(&fAlloc);
334
335 walk_dom(dom, node, &parser);
336
337 fRoot = parser.getRoot();
338 return fRoot;
339 }
340
beginParsing()341 SkXMLParser* SkDOM::beginParsing() {
342 SkASSERT(!fParser);
343 fParser = std::make_unique<SkDOMParser>(&fAlloc);
344
345 return fParser.get();
346 }
347
finishParsing()348 const SkDOM::Node* SkDOM::finishParsing() {
349 SkASSERT(fParser);
350 fRoot = fParser->getRoot();
351 fParser.reset();
352
353 return fRoot;
354 }
355
356 //////////////////////////////////////////////////////////////////////////
357
countChildren(const Node * node,const char elem[]) const358 int SkDOM::countChildren(const Node* node, const char elem[]) const {
359 int count = 0;
360
361 node = this->getFirstChild(node, elem);
362 while (node) {
363 count += 1;
364 node = this->getNextSibling(node, elem);
365 }
366 return count;
367 }
368
369 //////////////////////////////////////////////////////////////////////////
370
371 #include "include/utils/SkParse.h"
372
findS32(const Node * node,const char name[],int32_t * value) const373 bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
374 const char* vstr = this->findAttr(node, name);
375 return vstr && SkParse::FindS32(vstr, value);
376 }
377
findScalars(const Node * node,const char name[],SkScalar value[],int count) const378 bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
379 const char* vstr = this->findAttr(node, name);
380 return vstr && SkParse::FindScalars(vstr, value, count);
381 }
382
findHex(const Node * node,const char name[],uint32_t * value) const383 bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
384 const char* vstr = this->findAttr(node, name);
385 return vstr && SkParse::FindHex(vstr, value);
386 }
387
findBool(const Node * node,const char name[],bool * value) const388 bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
389 const char* vstr = this->findAttr(node, name);
390 return vstr && SkParse::FindBool(vstr, value);
391 }
392
findList(const Node * node,const char name[],const char list[]) const393 int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
394 const char* vstr = this->findAttr(node, name);
395 return vstr ? SkParse::FindList(vstr, list) : -1;
396 }
397
hasAttr(const Node * node,const char name[],const char value[]) const398 bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
399 const char* vstr = this->findAttr(node, name);
400 return vstr && !strcmp(vstr, value);
401 }
402
hasS32(const Node * node,const char name[],int32_t target) const403 bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
404 const char* vstr = this->findAttr(node, name);
405 int32_t value;
406 return vstr && SkParse::FindS32(vstr, &value) && value == target;
407 }
408
hasScalar(const Node * node,const char name[],SkScalar target) const409 bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
410 const char* vstr = this->findAttr(node, name);
411 SkScalar value;
412 return vstr && SkParse::FindScalar(vstr, &value) && value == target;
413 }
414
hasHex(const Node * node,const char name[],uint32_t target) const415 bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
416 const char* vstr = this->findAttr(node, name);
417 uint32_t value;
418 return vstr && SkParse::FindHex(vstr, &value) && value == target;
419 }
420
hasBool(const Node * node,const char name[],bool target) const421 bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
422 const char* vstr = this->findAttr(node, name);
423 bool value;
424 return vstr && SkParse::FindBool(vstr, &value) && value == target;
425 }
426