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