Coverage Report

Created: 2021-08-22 09:07

/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
}