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
9 #include "SkDOM.h"
10 #include "SkStream.h"
11 #include "SkXMLParser.h"
12 #include "SkXMLWriter.h"
13
parse(const SkDOM & dom,const SkDOMNode * node)14 bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
15 const char* elemName = dom.getName(node);
16
17 if (this->startElement(elemName)) {
18 return false;
19 }
20
21 SkDOM::AttrIter iter(dom, node);
22 const char* name, *value;
23
24 while ((name = iter.next(&value)) != nullptr) {
25 if (this->addAttribute(name, value)) {
26 return false;
27 }
28 }
29
30 if ((node = dom.getFirstChild(node)) != nullptr) {
31 do {
32 if (!this->parse(dom, node)) {
33 return false;
34 }
35 } while ((node = dom.getNextSibling(node)) != nullptr);
36 }
37 return !this->endElement(elemName);
38 }
39
40 /////////////////////////////////////////////////////////////////////////
41
42 struct SkDOMAttr {
43 const char* fName;
44 const char* fValue;
45 };
46
47 struct SkDOMNode {
48 const char* fName;
49 SkDOMNode* fFirstChild;
50 SkDOMNode* fNextSibling;
51 SkDOMAttr* fAttrs;
52 uint16_t fAttrCount;
53 uint8_t fType;
54 uint8_t fPad;
55
attrsSkDOMNode56 const SkDOMAttr* attrs() const {
57 return fAttrs;
58 }
59
attrsSkDOMNode60 SkDOMAttr* attrs() {
61 return fAttrs;
62 }
63 };
64
65 /////////////////////////////////////////////////////////////////////////
66
67 #define kMinChunkSize 4096
68
SkDOM()69 SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
70
~SkDOM()71 SkDOM::~SkDOM() {}
72
getRootNode() const73 const SkDOM::Node* SkDOM::getRootNode() const {
74 return fRoot;
75 }
76
getFirstChild(const Node * node,const char name[]) const77 const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
78 SkASSERT(node);
79 const Node* child = node->fFirstChild;
80
81 if (name) {
82 for (; child != nullptr; child = child->fNextSibling) {
83 if (!strcmp(name, child->fName)) {
84 break;
85 }
86 }
87 }
88 return child;
89 }
90
getNextSibling(const Node * node,const char name[]) const91 const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
92 SkASSERT(node);
93 const Node* sibling = node->fNextSibling;
94 if (name) {
95 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
96 if (!strcmp(name, sibling->fName)) {
97 break;
98 }
99 }
100 }
101 return sibling;
102 }
103
getType(const Node * node) const104 SkDOM::Type SkDOM::getType(const Node* node) const {
105 SkASSERT(node);
106 return (Type)node->fType;
107 }
108
getName(const Node * node) const109 const char* SkDOM::getName(const Node* node) const {
110 SkASSERT(node);
111 return node->fName;
112 }
113
findAttr(const Node * node,const char name[]) const114 const char* SkDOM::findAttr(const Node* node, const char name[]) const {
115 SkASSERT(node);
116 const Attr* attr = node->attrs();
117 const Attr* stop = attr + node->fAttrCount;
118
119 while (attr < stop) {
120 if (!strcmp(attr->fName, name)) {
121 return attr->fValue;
122 }
123 attr += 1;
124 }
125 return nullptr;
126 }
127
128 /////////////////////////////////////////////////////////////////////////////////////
129
getFirstAttr(const Node * node) const130 const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
131 return node->fAttrCount ? node->attrs() : nullptr;
132 }
133
getNextAttr(const Node * node,const Attr * attr) const134 const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
135 SkASSERT(node);
136 if (attr == nullptr) {
137 return nullptr;
138 }
139 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
140 }
141
getAttrName(const Node * node,const Attr * attr) const142 const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
143 SkASSERT(node);
144 SkASSERT(attr);
145 return attr->fName;
146 }
147
getAttrValue(const Node * node,const Attr * attr) const148 const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
149 SkASSERT(node);
150 SkASSERT(attr);
151 return attr->fValue;
152 }
153
154 /////////////////////////////////////////////////////////////////////////////////////
155
AttrIter(const SkDOM &,const SkDOM::Node * node)156 SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
157 SkASSERT(node);
158 fAttr = node->attrs();
159 fStop = fAttr + node->fAttrCount;
160 }
161
next(const char ** value)162 const char* SkDOM::AttrIter::next(const char** value) {
163 const char* name = nullptr;
164
165 if (fAttr < fStop) {
166 name = fAttr->fName;
167 if (value)
168 *value = fAttr->fValue;
169 fAttr += 1;
170 }
171 return name;
172 }
173
174 //////////////////////////////////////////////////////////////////////////////
175
176 #include "SkXMLParser.h"
177 #include "SkTDArray.h"
178
dupstr(SkArenaAlloc * chunk,const char src[])179 static char* dupstr(SkArenaAlloc* chunk, const char src[]) {
180 SkASSERT(chunk && src);
181 size_t len = strlen(src);
182 char* dst = chunk->makeArrayDefault<char>(len + 1);
183 memcpy(dst, src, len + 1);
184 return dst;
185 }
186
187 class SkDOMParser : public SkXMLParser {
188 public:
SkDOMParser(SkArenaAlloc * chunk)189 SkDOMParser(SkArenaAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
190 fAlloc->reset();
191 fRoot = nullptr;
192 fLevel = 0;
193 fNeedToFlush = true;
194 }
getRoot() const195 SkDOM::Node* getRoot() const { return fRoot; }
196 SkXMLParserError fParserError;
197
198 protected:
flushAttributes()199 void flushAttributes() {
200 SkASSERT(fLevel > 0);
201
202 int attrCount = fAttrs.count();
203
204 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
205 SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
206
207 node->fName = fElemName;
208 node->fFirstChild = nullptr;
209 node->fAttrCount = SkToU16(attrCount);
210 node->fAttrs = attrs;
211 node->fType = fElemType;
212
213 if (fRoot == nullptr) {
214 node->fNextSibling = nullptr;
215 fRoot = node;
216 } else { // this adds siblings in reverse order. gets corrected in onEndElement()
217 SkDOM::Node* parent = fParentStack.top();
218 SkASSERT(fRoot && parent);
219 node->fNextSibling = parent->fFirstChild;
220 parent->fFirstChild = node;
221 }
222 *fParentStack.push() = node;
223
224 sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
225 fAttrs.reset();
226
227 }
228
onStartElement(const char elem[])229 bool onStartElement(const char elem[]) override {
230 this->startCommon(elem, SkDOM::kElement_Type);
231 return false;
232 }
233
onAddAttribute(const char name[],const char value[])234 bool onAddAttribute(const char name[], const char value[]) override {
235 SkDOM::Attr* attr = fAttrs.append();
236 attr->fName = dupstr(fAlloc, name);
237 attr->fValue = dupstr(fAlloc, value);
238 return false;
239 }
240
onEndElement(const char elem[])241 bool onEndElement(const char elem[]) override {
242 --fLevel;
243 if (fNeedToFlush)
244 this->flushAttributes();
245 fNeedToFlush = false;
246
247 SkDOM::Node* parent;
248
249 fParentStack.pop(&parent);
250
251 SkDOM::Node* child = parent->fFirstChild;
252 SkDOM::Node* prev = nullptr;
253 while (child) {
254 SkDOM::Node* next = child->fNextSibling;
255 child->fNextSibling = prev;
256 prev = child;
257 child = next;
258 }
259 parent->fFirstChild = prev;
260 return false;
261 }
262
onText(const char text[],int len)263 bool onText(const char text[], int len) override {
264 SkString str(text, len);
265 this->startCommon(str.c_str(), SkDOM::kText_Type);
266 this->SkDOMParser::onEndElement(str.c_str());
267
268 return false;
269 }
270
271 private:
startCommon(const char elem[],SkDOM::Type type)272 void startCommon(const char elem[], SkDOM::Type type) {
273 if (fLevel > 0 && fNeedToFlush) {
274 this->flushAttributes();
275 }
276 fNeedToFlush = true;
277 fElemName = dupstr(fAlloc, elem);
278 fElemType = type;
279 ++fLevel;
280 }
281
282 SkTDArray<SkDOM::Node*> fParentStack;
283 SkArenaAlloc* 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.reset(new 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 "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