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 | |
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 | |
57 | const SkDOMAttr* attrs() const { |
58 | return fAttrs; |
59 | } |
60 | |
61 | SkDOMAttr* attrs() { |
62 | return fAttrs; |
63 | } |
64 | }; |
65 | |
66 | ///////////////////////////////////////////////////////////////////////// |
67 | |
68 | #define kMinChunkSize 4096 |
69 | |
70 | SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {} |
71 | |
72 | SkDOM::~SkDOM() {} |
73 | |
74 | const SkDOM::Node* SkDOM::getRootNode() const { |
75 | return fRoot; |
76 | } |
77 | |
78 | 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 | |
92 | 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 | |
105 | SkDOM::Type SkDOM::getType(const Node* node) const { |
106 | SkASSERT(node); |
107 | return (Type)node->fType; |
108 | } |
109 | |
110 | const char* SkDOM::getName(const Node* node) const { |
111 | SkASSERT(node); |
112 | return node->fName; |
113 | } |
114 | |
115 | 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 | |
131 | const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const { |
132 | return node->fAttrCount ? node->attrs() : nullptr; |
133 | } |
134 | |
135 | 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 | |
143 | const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const { |
144 | SkASSERT(node); |
145 | SkASSERT(attr); |
146 | return attr->fName; |
147 | } |
148 | |
149 | 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 | |
157 | SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) { |
158 | SkASSERT(node); |
159 | fAttr = node->attrs(); |
160 | fStop = fAttr + node->fAttrCount; |
161 | } |
162 | |
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 | |
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: |
190 | SkDOMParser(SkArenaAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) { |
191 | fAlloc->reset(); |
192 | fRoot = nullptr; |
193 | fLevel = 0; |
194 | fNeedToFlush = true; |
195 | } |
196 | SkDOM::Node* getRoot() const { return fRoot; } |
197 | SkXMLParserError fParserError; |
198 | |
199 | protected: |
200 | void flushAttributes() { |
201 | SkASSERT(fLevel > 0); |
202 | |
203 | int attrCount = fAttrs.count(); |
204 | |
205 | SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount); |
206 | SkDOM::Node* node = fAlloc->make<SkDOM::Node>(); |
207 | |
208 | node->fName = fElemName; |
209 | node->fFirstChild = nullptr; |
210 | node->fAttrCount = SkToU16(attrCount); |
211 | node->fAttrs = attrs; |
212 | node->fType = fElemType; |
213 | |
214 | if (fRoot == nullptr) { |
215 | node->fNextSibling = nullptr; |
216 | fRoot = node; |
217 | } else { // this adds siblings in reverse order. gets corrected in onEndElement() |
218 | SkDOM::Node* parent = fParentStack.top(); |
219 | SkASSERT(fRoot && parent); |
220 | node->fNextSibling = parent->fFirstChild; |
221 | parent->fFirstChild = node; |
222 | } |
223 | *fParentStack.push() = node; |
224 | |
225 | sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr)); |
226 | fAttrs.reset(); |
227 | |
228 | } |
229 | |
230 | bool onStartElement(const char elem[]) override { |
231 | this->startCommon(elem, SkDOM::kElement_Type); |
232 | return false; |
233 | } |
234 | |
235 | bool onAddAttribute(const char name[], const char value[]) override { |
236 | SkDOM::Attr* attr = fAttrs.append(); |
237 | attr->fName = dupstr(fAlloc, name); |
238 | attr->fValue = dupstr(fAlloc, value); |
239 | return false; |
240 | } |
241 | |
242 | bool onEndElement(const char elem[]) override { |
243 | --fLevel; |
244 | if (fNeedToFlush) |
245 | this->flushAttributes(); |
246 | fNeedToFlush = false; |
247 | |
248 | SkDOM::Node* parent; |
249 | |
250 | fParentStack.pop(&parent); |
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 | |
264 | bool onText(const char text[], int len) override { |
265 | SkString str(text, len); |
266 | this->startCommon(str.c_str(), SkDOM::kText_Type); |
267 | this->SkDOMParser::onEndElement(str.c_str()); |
268 | |
269 | return false; |
270 | } |
271 | |
272 | private: |
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 | |
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 | |
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 | |
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 | |
345 | SkXMLParser* SkDOM::beginParsing() { |
346 | SkASSERT(!fParser); |
347 | fParser.reset(new SkDOMParser(&fAlloc)); |
348 | |
349 | return fParser.get(); |
350 | } |
351 | |
352 | const SkDOM::Node* SkDOM::finishParsing() { |
353 | SkASSERT(fParser); |
354 | fRoot = fParser->getRoot(); |
355 | fParser.reset(); |
356 | |
357 | return fRoot; |
358 | } |
359 | |
360 | ////////////////////////////////////////////////////////////////////////// |
361 | |
362 | 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 | |
377 | 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 | |
382 | 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 | |
387 | 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 | |
392 | 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 | |
397 | 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 | |
402 | 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 | |
407 | 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 | |
413 | 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 | |
419 | 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 | |
425 | 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 | |