1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/utils/SkJSON.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
11cb93a386Sopenharmony_ci#include "include/core/SkString.h"
12cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h"
13cb93a386Sopenharmony_ci#include "include/utils/SkParse.h"
14cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#include <cmath>
17cb93a386Sopenharmony_ci#include <tuple>
18cb93a386Sopenharmony_ci#include <vector>
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_cinamespace skjson {
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci// #define SK_JSON_REPORT_ERRORS
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cistatic_assert( sizeof(Value) == 8, "");
25cb93a386Sopenharmony_cistatic_assert(alignof(Value) == 8, "");
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_cistatic constexpr size_t kRecAlign = alignof(Value);
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_civoid Value::init_tagged(Tag t) {
30cb93a386Sopenharmony_ci    memset(fData8, 0, sizeof(fData8));
31cb93a386Sopenharmony_ci    fData8[0] = SkTo<uint8_t>(t);
32cb93a386Sopenharmony_ci    SkASSERT(this->getTag() == t);
33cb93a386Sopenharmony_ci}
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci// Pointer values store a type (in the lower kTagBits bits) and a pointer.
36cb93a386Sopenharmony_civoid Value::init_tagged_pointer(Tag t, void* p) {
37cb93a386Sopenharmony_ci    if (sizeof(Value) == sizeof(uintptr_t)) {
38cb93a386Sopenharmony_ci        *this->cast<uintptr_t>() = reinterpret_cast<uintptr_t>(p);
39cb93a386Sopenharmony_ci        // For 64-bit, we rely on the pointer lower bits being zero.
40cb93a386Sopenharmony_ci        SkASSERT(!(fData8[0] & kTagMask));
41cb93a386Sopenharmony_ci        fData8[0] |= SkTo<uint8_t>(t);
42cb93a386Sopenharmony_ci    } else {
43cb93a386Sopenharmony_ci        // For 32-bit, we store the pointer in the upper word
44cb93a386Sopenharmony_ci        SkASSERT(sizeof(Value) == sizeof(uintptr_t) * 2);
45cb93a386Sopenharmony_ci        this->init_tagged(t);
46cb93a386Sopenharmony_ci        *this->cast<uintptr_t>() = reinterpret_cast<uintptr_t>(p);
47cb93a386Sopenharmony_ci    }
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci    SkASSERT(this->getTag()    == t);
50cb93a386Sopenharmony_ci    SkASSERT(this->ptr<void>() == p);
51cb93a386Sopenharmony_ci}
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ciNullValue::NullValue() {
54cb93a386Sopenharmony_ci    this->init_tagged(Tag::kNull);
55cb93a386Sopenharmony_ci    SkASSERT(this->getTag() == Tag::kNull);
56cb93a386Sopenharmony_ci}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ciBoolValue::BoolValue(bool b) {
59cb93a386Sopenharmony_ci    this->init_tagged(Tag::kBool);
60cb93a386Sopenharmony_ci    *this->cast<bool>() = b;
61cb93a386Sopenharmony_ci    SkASSERT(this->getTag() == Tag::kBool);
62cb93a386Sopenharmony_ci}
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciNumberValue::NumberValue(int32_t i) {
65cb93a386Sopenharmony_ci    this->init_tagged(Tag::kInt);
66cb93a386Sopenharmony_ci    *this->cast<int32_t>() = i;
67cb93a386Sopenharmony_ci    SkASSERT(this->getTag() == Tag::kInt);
68cb93a386Sopenharmony_ci}
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ciNumberValue::NumberValue(float f) {
71cb93a386Sopenharmony_ci    this->init_tagged(Tag::kFloat);
72cb93a386Sopenharmony_ci    *this->cast<float>() = f;
73cb93a386Sopenharmony_ci    SkASSERT(this->getTag() == Tag::kFloat);
74cb93a386Sopenharmony_ci}
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci// Vector recs point to externally allocated slabs with the following layout:
77cb93a386Sopenharmony_ci//
78cb93a386Sopenharmony_ci//   [size_t n] [REC_0] ... [REC_n-1] [optional extra trailing storage]
79cb93a386Sopenharmony_ci//
80cb93a386Sopenharmony_ci// Long strings use extra_alloc_size == 1 to store the \0 terminator.
81cb93a386Sopenharmony_ci//
82cb93a386Sopenharmony_citemplate <typename T, size_t extra_alloc_size = 0>
83cb93a386Sopenharmony_cistatic void* MakeVector(const void* src, size_t size, SkArenaAlloc& alloc) {
84cb93a386Sopenharmony_ci    // The Ts are already in memory, so their size should be safe.
85cb93a386Sopenharmony_ci    const auto total_size = sizeof(size_t) + size * sizeof(T) + extra_alloc_size;
86cb93a386Sopenharmony_ci    auto* size_ptr = reinterpret_cast<size_t*>(alloc.makeBytesAlignedTo(total_size, kRecAlign));
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci    *size_ptr = size;
89cb93a386Sopenharmony_ci    sk_careful_memcpy(size_ptr + 1, src, size * sizeof(T));
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci    return size_ptr;
92cb93a386Sopenharmony_ci}
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ciArrayValue::ArrayValue(const Value* src, size_t size, SkArenaAlloc& alloc) {
95cb93a386Sopenharmony_ci    this->init_tagged_pointer(Tag::kArray, MakeVector<Value>(src, size, alloc));
96cb93a386Sopenharmony_ci    SkASSERT(this->getTag() == Tag::kArray);
97cb93a386Sopenharmony_ci}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci// Strings have two flavors:
100cb93a386Sopenharmony_ci//
101cb93a386Sopenharmony_ci// -- short strings (len <= 7) -> these are stored inline, in the record
102cb93a386Sopenharmony_ci//    (one byte reserved for null terminator/type):
103cb93a386Sopenharmony_ci//
104cb93a386Sopenharmony_ci//        [str] [\0]|[max_len - actual_len]
105cb93a386Sopenharmony_ci//
106cb93a386Sopenharmony_ci//    Storing [max_len - actual_len] allows the 'len' field to double-up as a
107cb93a386Sopenharmony_ci//    null terminator when size == max_len (this works 'cause kShortString == 0).
108cb93a386Sopenharmony_ci//
109cb93a386Sopenharmony_ci// -- long strings (len > 7) -> these are externally allocated vectors (VectorRec<char>).
110cb93a386Sopenharmony_ci//
111cb93a386Sopenharmony_ci// The string data plus a null-char terminator are copied over.
112cb93a386Sopenharmony_ci//
113cb93a386Sopenharmony_cinamespace {
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci// An internal string builder with a fast 8 byte short string load path
116cb93a386Sopenharmony_ci// (for the common case where the string is not at the end of the stream).
117cb93a386Sopenharmony_ciclass FastString final : public Value {
118cb93a386Sopenharmony_cipublic:
119cb93a386Sopenharmony_ci    FastString(const char* src, size_t size, const char* eos, SkArenaAlloc& alloc) {
120cb93a386Sopenharmony_ci        SkASSERT(src <= eos);
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ci        if (size > kMaxInlineStringSize) {
123cb93a386Sopenharmony_ci            this->initLongString(src, size, alloc);
124cb93a386Sopenharmony_ci            SkASSERT(this->getTag() == Tag::kString);
125cb93a386Sopenharmony_ci            return;
126cb93a386Sopenharmony_ci        }
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci        // initFastShortString is faster (doh), but requires access to 6 chars past src.
129cb93a386Sopenharmony_ci        if (src && src + 6 <= eos) {
130cb93a386Sopenharmony_ci            this->initFastShortString(src, size);
131cb93a386Sopenharmony_ci        } else {
132cb93a386Sopenharmony_ci            this->initShortString(src, size);
133cb93a386Sopenharmony_ci        }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci        SkASSERT(this->getTag() == Tag::kShortString);
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ciprivate:
139cb93a386Sopenharmony_ci    // first byte reserved for tagging, \0 terminator => 6 usable chars
140cb93a386Sopenharmony_ci    inline static constexpr size_t kMaxInlineStringSize = sizeof(Value) - 2;
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci    void initLongString(const char* src, size_t size, SkArenaAlloc& alloc) {
143cb93a386Sopenharmony_ci        SkASSERT(size > kMaxInlineStringSize);
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci        this->init_tagged_pointer(Tag::kString, MakeVector<char, 1>(src, size, alloc));
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci        auto* data = this->cast<VectorValue<char, Value::Type::kString>>()->begin();
148cb93a386Sopenharmony_ci        const_cast<char*>(data)[size] = '\0';
149cb93a386Sopenharmony_ci    }
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    void initShortString(const char* src, size_t size) {
152cb93a386Sopenharmony_ci        SkASSERT(size <= kMaxInlineStringSize);
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci        this->init_tagged(Tag::kShortString);
155cb93a386Sopenharmony_ci        sk_careful_memcpy(this->cast<char>(), src, size);
156cb93a386Sopenharmony_ci        // Null terminator provided by init_tagged() above (fData8 is zero-initialized).
157cb93a386Sopenharmony_ci    }
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci    void initFastShortString(const char* src, size_t size) {
160cb93a386Sopenharmony_ci        SkASSERT(size <= kMaxInlineStringSize);
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci        uint64_t* s64 = this->cast<uint64_t>();
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci        // Load 8 chars and mask out the tag and \0 terminator.
165cb93a386Sopenharmony_ci        // Note: we picked kShortString == 0 to avoid setting explicitly below.
166cb93a386Sopenharmony_ci        static_assert(SkToU8(Tag::kShortString) == 0, "please don't break this");
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ci        // Since the first byte is occupied by the tag, we want the string chars [0..5] to land
169cb93a386Sopenharmony_ci        // on bytes [1..6] => the fastest way is to read8 @(src - 1) (always safe, because the
170cb93a386Sopenharmony_ci        // string requires a " prefix at the very least).
171cb93a386Sopenharmony_ci        memcpy(s64, src - 1, 8);
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci#if defined(SK_CPU_LENDIAN)
174cb93a386Sopenharmony_ci        // The mask for a max-length string (6), with a leading tag and trailing \0 is
175cb93a386Sopenharmony_ci        // 0x00ffffffffffff00.  Accounting for the final left-shift, this becomes
176cb93a386Sopenharmony_ci        // 0x0000ffffffffffff.
177cb93a386Sopenharmony_ci        *s64 &= (0x0000ffffffffffffULL >> ((kMaxInlineStringSize - size) * 8)) // trailing \0s
178cb93a386Sopenharmony_ci                    << 8;                                                      // tag byte
179cb93a386Sopenharmony_ci#else
180cb93a386Sopenharmony_ci        static_assert(false, "Big-endian builds are not supported at this time.");
181cb93a386Sopenharmony_ci#endif
182cb93a386Sopenharmony_ci    }
183cb93a386Sopenharmony_ci};
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci} // namespace
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ciStringValue::StringValue(const char* src, size_t size, SkArenaAlloc& alloc) {
188cb93a386Sopenharmony_ci    new (this) FastString(src, size, src, alloc);
189cb93a386Sopenharmony_ci}
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ciObjectValue::ObjectValue(const Member* src, size_t size, SkArenaAlloc& alloc) {
192cb93a386Sopenharmony_ci    this->init_tagged_pointer(Tag::kObject, MakeVector<Member>(src, size, alloc));
193cb93a386Sopenharmony_ci    SkASSERT(this->getTag() == Tag::kObject);
194cb93a386Sopenharmony_ci}
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ci// Boring public Value glue.
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_cistatic int inline_strcmp(const char a[], const char b[]) {
200cb93a386Sopenharmony_ci    for (;;) {
201cb93a386Sopenharmony_ci        char c = *a++;
202cb93a386Sopenharmony_ci        if (c == 0) {
203cb93a386Sopenharmony_ci            break;
204cb93a386Sopenharmony_ci        }
205cb93a386Sopenharmony_ci        if (c != *b++) {
206cb93a386Sopenharmony_ci            return 1;
207cb93a386Sopenharmony_ci        }
208cb93a386Sopenharmony_ci    }
209cb93a386Sopenharmony_ci    return *b != 0;
210cb93a386Sopenharmony_ci}
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ciconst Value& ObjectValue::operator[](const char* key) const {
213cb93a386Sopenharmony_ci    // Reverse search for duplicates resolution (policy: return last).
214cb93a386Sopenharmony_ci    const auto* begin  = this->begin();
215cb93a386Sopenharmony_ci    const auto* member = this->end();
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci    while (member > begin) {
218cb93a386Sopenharmony_ci        --member;
219cb93a386Sopenharmony_ci        if (0 == inline_strcmp(key, member->fKey.as<StringValue>().begin())) {
220cb93a386Sopenharmony_ci            return member->fValue;
221cb93a386Sopenharmony_ci        }
222cb93a386Sopenharmony_ci    }
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    static const Value g_null = NullValue();
225cb93a386Sopenharmony_ci    return g_null;
226cb93a386Sopenharmony_ci}
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_cinamespace {
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci// Lexer/parser inspired by rapidjson [1], sajson [2] and pjson [3].
231cb93a386Sopenharmony_ci//
232cb93a386Sopenharmony_ci// [1] https://github.com/Tencent/rapidjson/
233cb93a386Sopenharmony_ci// [2] https://github.com/chadaustin/sajson
234cb93a386Sopenharmony_ci// [3] https://pastebin.com/hnhSTL3h
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci// bit 0 (0x01) - plain ASCII string character
238cb93a386Sopenharmony_ci// bit 1 (0x02) - whitespace
239cb93a386Sopenharmony_ci// bit 2 (0x04) - string terminator (" \\ \0 [control chars] **AND } ]** <- see matchString notes)
240cb93a386Sopenharmony_ci// bit 3 (0x08) - 0-9
241cb93a386Sopenharmony_ci// bit 4 (0x10) - 0-9 e E .
242cb93a386Sopenharmony_ci// bit 5 (0x20) - scope terminator (} ])
243cb93a386Sopenharmony_cistatic constexpr uint8_t g_token_flags[256] = {
244cb93a386Sopenharmony_ci // 0    1    2    3    4    5    6    7      8    9    A    B    C    D    E    F
245cb93a386Sopenharmony_ci    4,   4,   4,   4,   4,   4,   4,   4,     4,   6,   6,   4,   4,   6,   4,   4, // 0
246cb93a386Sopenharmony_ci    4,   4,   4,   4,   4,   4,   4,   4,     4,   4,   4,   4,   4,   4,   4,   4, // 1
247cb93a386Sopenharmony_ci    3,   1,   4,   1,   1,   1,   1,   1,     1,   1,   1,   1,   1,   1,   0x11,1, // 2
248cb93a386Sopenharmony_ci 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,  0x19,0x19,   1,   1,   1,   1,   1,   1, // 3
249cb93a386Sopenharmony_ci    1,   1,   1,   1,   1,   0x11,1,   1,     1,   1,   1,   1,   1,   1,   1,   1, // 4
250cb93a386Sopenharmony_ci    1,   1,   1,   1,   1,   1,   1,   1,     1,   1,   1,   1,   4,0x25,   1,   1, // 5
251cb93a386Sopenharmony_ci    1,   1,   1,   1,   1,   0x11,1,   1,     1,   1,   1,   1,   1,   1,   1,   1, // 6
252cb93a386Sopenharmony_ci    1,   1,   1,   1,   1,   1,   1,   1,     1,   1,   1,   1,   1,0x25,   1,   1, // 7
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci // 128-255
255cb93a386Sopenharmony_ci    0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,
256cb93a386Sopenharmony_ci    0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,
257cb93a386Sopenharmony_ci    0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,
258cb93a386Sopenharmony_ci    0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0
259cb93a386Sopenharmony_ci};
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_cistatic inline bool is_ws(char c)       { return g_token_flags[static_cast<uint8_t>(c)] & 0x02; }
262cb93a386Sopenharmony_cistatic inline bool is_eostring(char c) { return g_token_flags[static_cast<uint8_t>(c)] & 0x04; }
263cb93a386Sopenharmony_cistatic inline bool is_digit(char c)    { return g_token_flags[static_cast<uint8_t>(c)] & 0x08; }
264cb93a386Sopenharmony_cistatic inline bool is_numeric(char c)  { return g_token_flags[static_cast<uint8_t>(c)] & 0x10; }
265cb93a386Sopenharmony_cistatic inline bool is_eoscope(char c)  { return g_token_flags[static_cast<uint8_t>(c)] & 0x20; }
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_cistatic inline const char* skip_ws(const char* p) {
268cb93a386Sopenharmony_ci    while (is_ws(*p)) ++p;
269cb93a386Sopenharmony_ci    return p;
270cb93a386Sopenharmony_ci}
271cb93a386Sopenharmony_ci
272cb93a386Sopenharmony_cistatic inline float pow10(int32_t exp) {
273cb93a386Sopenharmony_ci    static constexpr float g_pow10_table[63] =
274cb93a386Sopenharmony_ci    {
275cb93a386Sopenharmony_ci       1.e-031f, 1.e-030f, 1.e-029f, 1.e-028f, 1.e-027f, 1.e-026f, 1.e-025f, 1.e-024f,
276cb93a386Sopenharmony_ci       1.e-023f, 1.e-022f, 1.e-021f, 1.e-020f, 1.e-019f, 1.e-018f, 1.e-017f, 1.e-016f,
277cb93a386Sopenharmony_ci       1.e-015f, 1.e-014f, 1.e-013f, 1.e-012f, 1.e-011f, 1.e-010f, 1.e-009f, 1.e-008f,
278cb93a386Sopenharmony_ci       1.e-007f, 1.e-006f, 1.e-005f, 1.e-004f, 1.e-003f, 1.e-002f, 1.e-001f, 1.e+000f,
279cb93a386Sopenharmony_ci       1.e+001f, 1.e+002f, 1.e+003f, 1.e+004f, 1.e+005f, 1.e+006f, 1.e+007f, 1.e+008f,
280cb93a386Sopenharmony_ci       1.e+009f, 1.e+010f, 1.e+011f, 1.e+012f, 1.e+013f, 1.e+014f, 1.e+015f, 1.e+016f,
281cb93a386Sopenharmony_ci       1.e+017f, 1.e+018f, 1.e+019f, 1.e+020f, 1.e+021f, 1.e+022f, 1.e+023f, 1.e+024f,
282cb93a386Sopenharmony_ci       1.e+025f, 1.e+026f, 1.e+027f, 1.e+028f, 1.e+029f, 1.e+030f, 1.e+031f
283cb93a386Sopenharmony_ci    };
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_ci    static constexpr int32_t k_exp_offset = SK_ARRAY_COUNT(g_pow10_table) / 2;
286cb93a386Sopenharmony_ci
287cb93a386Sopenharmony_ci    // We only support negative exponents for now.
288cb93a386Sopenharmony_ci    SkASSERT(exp <= 0);
289cb93a386Sopenharmony_ci
290cb93a386Sopenharmony_ci    return (exp >= -k_exp_offset) ? g_pow10_table[exp + k_exp_offset]
291cb93a386Sopenharmony_ci                                  : std::pow(10.0f, static_cast<float>(exp));
292cb93a386Sopenharmony_ci}
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ciclass DOMParser {
295cb93a386Sopenharmony_cipublic:
296cb93a386Sopenharmony_ci    explicit DOMParser(SkArenaAlloc& alloc)
297cb93a386Sopenharmony_ci        : fAlloc(alloc) {
298cb93a386Sopenharmony_ci        fValueStack.reserve(kValueStackReserve);
299cb93a386Sopenharmony_ci        fUnescapeBuffer.reserve(kUnescapeBufferReserve);
300cb93a386Sopenharmony_ci    }
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci    Value parse(const char* p, size_t size) {
303cb93a386Sopenharmony_ci        if (!size) {
304cb93a386Sopenharmony_ci            return this->error(NullValue(), p, "invalid empty input");
305cb93a386Sopenharmony_ci        }
306cb93a386Sopenharmony_ci
307cb93a386Sopenharmony_ci        const char* p_stop = p + size - 1;
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci        // We're only checking for end-of-stream on object/array close('}',']'),
310cb93a386Sopenharmony_ci        // so we must trim any whitespace from the buffer tail.
311cb93a386Sopenharmony_ci        while (p_stop > p && is_ws(*p_stop)) --p_stop;
312cb93a386Sopenharmony_ci
313cb93a386Sopenharmony_ci        SkASSERT(p_stop >= p && p_stop < p + size);
314cb93a386Sopenharmony_ci        if (!is_eoscope(*p_stop)) {
315cb93a386Sopenharmony_ci            return this->error(NullValue(), p_stop, "invalid top-level value");
316cb93a386Sopenharmony_ci        }
317cb93a386Sopenharmony_ci
318cb93a386Sopenharmony_ci        p = skip_ws(p);
319cb93a386Sopenharmony_ci
320cb93a386Sopenharmony_ci        switch (*p) {
321cb93a386Sopenharmony_ci        case '{':
322cb93a386Sopenharmony_ci            goto match_object;
323cb93a386Sopenharmony_ci        case '[':
324cb93a386Sopenharmony_ci            goto match_array;
325cb93a386Sopenharmony_ci        default:
326cb93a386Sopenharmony_ci            return this->error(NullValue(), p, "invalid top-level value");
327cb93a386Sopenharmony_ci        }
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci    match_object:
330cb93a386Sopenharmony_ci        SkASSERT(*p == '{');
331cb93a386Sopenharmony_ci        p = skip_ws(p + 1);
332cb93a386Sopenharmony_ci
333cb93a386Sopenharmony_ci        this->pushObjectScope();
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci        if (*p == '}') goto pop_object;
336cb93a386Sopenharmony_ci
337cb93a386Sopenharmony_ci        // goto match_object_key;
338cb93a386Sopenharmony_ci    match_object_key:
339cb93a386Sopenharmony_ci        p = skip_ws(p);
340cb93a386Sopenharmony_ci        if (*p != '"') return this->error(NullValue(), p, "expected object key");
341cb93a386Sopenharmony_ci
342cb93a386Sopenharmony_ci        p = this->matchString(p, p_stop, [this](const char* key, size_t size, const char* eos) {
343cb93a386Sopenharmony_ci            this->pushObjectKey(key, size, eos);
344cb93a386Sopenharmony_ci        });
345cb93a386Sopenharmony_ci        if (!p) return NullValue();
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci        p = skip_ws(p);
348cb93a386Sopenharmony_ci        if (*p != ':') return this->error(NullValue(), p, "expected ':' separator");
349cb93a386Sopenharmony_ci
350cb93a386Sopenharmony_ci        ++p;
351cb93a386Sopenharmony_ci
352cb93a386Sopenharmony_ci        // goto match_value;
353cb93a386Sopenharmony_ci    match_value:
354cb93a386Sopenharmony_ci        p = skip_ws(p);
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci        switch (*p) {
357cb93a386Sopenharmony_ci        case '\0':
358cb93a386Sopenharmony_ci            return this->error(NullValue(), p, "unexpected input end");
359cb93a386Sopenharmony_ci        case '"':
360cb93a386Sopenharmony_ci            p = this->matchString(p, p_stop, [this](const char* str, size_t size, const char* eos) {
361cb93a386Sopenharmony_ci                this->pushString(str, size, eos);
362cb93a386Sopenharmony_ci            });
363cb93a386Sopenharmony_ci            break;
364cb93a386Sopenharmony_ci        case '[':
365cb93a386Sopenharmony_ci            goto match_array;
366cb93a386Sopenharmony_ci        case 'f':
367cb93a386Sopenharmony_ci            p = this->matchFalse(p);
368cb93a386Sopenharmony_ci            break;
369cb93a386Sopenharmony_ci        case 'n':
370cb93a386Sopenharmony_ci            p = this->matchNull(p);
371cb93a386Sopenharmony_ci            break;
372cb93a386Sopenharmony_ci        case 't':
373cb93a386Sopenharmony_ci            p = this->matchTrue(p);
374cb93a386Sopenharmony_ci            break;
375cb93a386Sopenharmony_ci        case '{':
376cb93a386Sopenharmony_ci            goto match_object;
377cb93a386Sopenharmony_ci        default:
378cb93a386Sopenharmony_ci            p = this->matchNumber(p);
379cb93a386Sopenharmony_ci            break;
380cb93a386Sopenharmony_ci        }
381cb93a386Sopenharmony_ci
382cb93a386Sopenharmony_ci        if (!p) return NullValue();
383cb93a386Sopenharmony_ci
384cb93a386Sopenharmony_ci        // goto match_post_value;
385cb93a386Sopenharmony_ci    match_post_value:
386cb93a386Sopenharmony_ci        SkASSERT(!this->inTopLevelScope());
387cb93a386Sopenharmony_ci
388cb93a386Sopenharmony_ci        p = skip_ws(p);
389cb93a386Sopenharmony_ci        switch (*p) {
390cb93a386Sopenharmony_ci        case ',':
391cb93a386Sopenharmony_ci            ++p;
392cb93a386Sopenharmony_ci            if (this->inObjectScope()) {
393cb93a386Sopenharmony_ci                goto match_object_key;
394cb93a386Sopenharmony_ci            } else {
395cb93a386Sopenharmony_ci                SkASSERT(this->inArrayScope());
396cb93a386Sopenharmony_ci                goto match_value;
397cb93a386Sopenharmony_ci            }
398cb93a386Sopenharmony_ci        case ']':
399cb93a386Sopenharmony_ci            goto pop_array;
400cb93a386Sopenharmony_ci        case '}':
401cb93a386Sopenharmony_ci            goto pop_object;
402cb93a386Sopenharmony_ci        default:
403cb93a386Sopenharmony_ci            return this->error(NullValue(), p - 1, "unexpected value-trailing token");
404cb93a386Sopenharmony_ci        }
405cb93a386Sopenharmony_ci
406cb93a386Sopenharmony_ci        // unreachable
407cb93a386Sopenharmony_ci        SkASSERT(false);
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_ci    pop_object:
410cb93a386Sopenharmony_ci        SkASSERT(*p == '}');
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci        if (this->inArrayScope()) {
413cb93a386Sopenharmony_ci            return this->error(NullValue(), p, "unexpected object terminator");
414cb93a386Sopenharmony_ci        }
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci        this->popObjectScope();
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_ci        // goto pop_common
419cb93a386Sopenharmony_ci    pop_common:
420cb93a386Sopenharmony_ci        SkASSERT(is_eoscope(*p));
421cb93a386Sopenharmony_ci
422cb93a386Sopenharmony_ci        if (this->inTopLevelScope()) {
423cb93a386Sopenharmony_ci            SkASSERT(fValueStack.size() == 1);
424cb93a386Sopenharmony_ci
425cb93a386Sopenharmony_ci            // Success condition: parsed the top level element and reached the stop token.
426cb93a386Sopenharmony_ci            return p == p_stop
427cb93a386Sopenharmony_ci                ? fValueStack.front()
428cb93a386Sopenharmony_ci                : this->error(NullValue(), p + 1, "trailing root garbage");
429cb93a386Sopenharmony_ci        }
430cb93a386Sopenharmony_ci
431cb93a386Sopenharmony_ci        if (p == p_stop) {
432cb93a386Sopenharmony_ci            return this->error(NullValue(), p, "unexpected end-of-input");
433cb93a386Sopenharmony_ci        }
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_ci        ++p;
436cb93a386Sopenharmony_ci
437cb93a386Sopenharmony_ci        goto match_post_value;
438cb93a386Sopenharmony_ci
439cb93a386Sopenharmony_ci    match_array:
440cb93a386Sopenharmony_ci        SkASSERT(*p == '[');
441cb93a386Sopenharmony_ci        p = skip_ws(p + 1);
442cb93a386Sopenharmony_ci
443cb93a386Sopenharmony_ci        this->pushArrayScope();
444cb93a386Sopenharmony_ci
445cb93a386Sopenharmony_ci        if (*p != ']') goto match_value;
446cb93a386Sopenharmony_ci
447cb93a386Sopenharmony_ci        // goto pop_array;
448cb93a386Sopenharmony_ci    pop_array:
449cb93a386Sopenharmony_ci        SkASSERT(*p == ']');
450cb93a386Sopenharmony_ci
451cb93a386Sopenharmony_ci        if (this->inObjectScope()) {
452cb93a386Sopenharmony_ci            return this->error(NullValue(), p, "unexpected array terminator");
453cb93a386Sopenharmony_ci        }
454cb93a386Sopenharmony_ci
455cb93a386Sopenharmony_ci        this->popArrayScope();
456cb93a386Sopenharmony_ci
457cb93a386Sopenharmony_ci        goto pop_common;
458cb93a386Sopenharmony_ci
459cb93a386Sopenharmony_ci        SkASSERT(false);
460cb93a386Sopenharmony_ci        return NullValue();
461cb93a386Sopenharmony_ci    }
462cb93a386Sopenharmony_ci
463cb93a386Sopenharmony_ci    std::tuple<const char*, const SkString> getError() const {
464cb93a386Sopenharmony_ci        return std::make_tuple(fErrorToken, fErrorMessage);
465cb93a386Sopenharmony_ci    }
466cb93a386Sopenharmony_ci
467cb93a386Sopenharmony_ciprivate:
468cb93a386Sopenharmony_ci    SkArenaAlloc&         fAlloc;
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ci    // Pending values stack.
471cb93a386Sopenharmony_ci    inline static constexpr size_t kValueStackReserve = 256;
472cb93a386Sopenharmony_ci    std::vector<Value>    fValueStack;
473cb93a386Sopenharmony_ci
474cb93a386Sopenharmony_ci    // String unescape buffer.
475cb93a386Sopenharmony_ci    inline static constexpr size_t kUnescapeBufferReserve = 512;
476cb93a386Sopenharmony_ci    std::vector<char>     fUnescapeBuffer;
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_ci    // Tracks the current object/array scope, as an index into fStack:
479cb93a386Sopenharmony_ci    //
480cb93a386Sopenharmony_ci    //   - for objects: fScopeIndex =  (index of first value in scope)
481cb93a386Sopenharmony_ci    //   - for arrays : fScopeIndex = -(index of first value in scope)
482cb93a386Sopenharmony_ci    //
483cb93a386Sopenharmony_ci    // fScopeIndex == 0 IFF we are at the top level (no current/active scope).
484cb93a386Sopenharmony_ci    intptr_t              fScopeIndex = 0;
485cb93a386Sopenharmony_ci
486cb93a386Sopenharmony_ci    // Error reporting.
487cb93a386Sopenharmony_ci    const char*           fErrorToken = nullptr;
488cb93a386Sopenharmony_ci    SkString              fErrorMessage;
489cb93a386Sopenharmony_ci
490cb93a386Sopenharmony_ci    bool inTopLevelScope() const { return fScopeIndex == 0; }
491cb93a386Sopenharmony_ci    bool inObjectScope()   const { return fScopeIndex >  0; }
492cb93a386Sopenharmony_ci    bool inArrayScope()    const { return fScopeIndex <  0; }
493cb93a386Sopenharmony_ci
494cb93a386Sopenharmony_ci    // Helper for masquerading raw primitive types as Values (bypassing tagging, etc).
495cb93a386Sopenharmony_ci    template <typename T>
496cb93a386Sopenharmony_ci    class RawValue final : public Value {
497cb93a386Sopenharmony_ci    public:
498cb93a386Sopenharmony_ci        explicit RawValue(T v) {
499cb93a386Sopenharmony_ci            static_assert(sizeof(T) <= sizeof(Value), "");
500cb93a386Sopenharmony_ci            *this->cast<T>() = v;
501cb93a386Sopenharmony_ci        }
502cb93a386Sopenharmony_ci
503cb93a386Sopenharmony_ci        T operator *() const { return *this->cast<T>(); }
504cb93a386Sopenharmony_ci    };
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ci    template <typename VectorT>
507cb93a386Sopenharmony_ci    void popScopeAsVec(size_t scope_start) {
508cb93a386Sopenharmony_ci        SkASSERT(scope_start > 0);
509cb93a386Sopenharmony_ci        SkASSERT(scope_start <= fValueStack.size());
510cb93a386Sopenharmony_ci
511cb93a386Sopenharmony_ci        using T = typename VectorT::ValueT;
512cb93a386Sopenharmony_ci        static_assert( sizeof(T) >=  sizeof(Value), "");
513cb93a386Sopenharmony_ci        static_assert( sizeof(T)  %  sizeof(Value) == 0, "");
514cb93a386Sopenharmony_ci        static_assert(alignof(T) == alignof(Value), "");
515cb93a386Sopenharmony_ci
516cb93a386Sopenharmony_ci        const auto scope_count = fValueStack.size() - scope_start,
517cb93a386Sopenharmony_ci                         count = scope_count / (sizeof(T) / sizeof(Value));
518cb93a386Sopenharmony_ci        SkASSERT(scope_count % (sizeof(T) / sizeof(Value)) == 0);
519cb93a386Sopenharmony_ci
520cb93a386Sopenharmony_ci        const auto* begin = reinterpret_cast<const T*>(fValueStack.data() + scope_start);
521cb93a386Sopenharmony_ci
522cb93a386Sopenharmony_ci        // Restore the previous scope index from saved placeholder value,
523cb93a386Sopenharmony_ci        // and instantiate as a vector of values in scope.
524cb93a386Sopenharmony_ci        auto& placeholder = fValueStack[scope_start - 1];
525cb93a386Sopenharmony_ci        fScopeIndex = *static_cast<RawValue<intptr_t>&>(placeholder);
526cb93a386Sopenharmony_ci        placeholder = VectorT(begin, count, fAlloc);
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci        // Drop the (consumed) values in scope.
529cb93a386Sopenharmony_ci        fValueStack.resize(scope_start);
530cb93a386Sopenharmony_ci    }
531cb93a386Sopenharmony_ci
532cb93a386Sopenharmony_ci    void pushObjectScope() {
533cb93a386Sopenharmony_ci        // Save a scope index now, and then later we'll overwrite this value as the Object itself.
534cb93a386Sopenharmony_ci        fValueStack.push_back(RawValue<intptr_t>(fScopeIndex));
535cb93a386Sopenharmony_ci
536cb93a386Sopenharmony_ci        // New object scope.
537cb93a386Sopenharmony_ci        fScopeIndex = SkTo<intptr_t>(fValueStack.size());
538cb93a386Sopenharmony_ci    }
539cb93a386Sopenharmony_ci
540cb93a386Sopenharmony_ci    void popObjectScope() {
541cb93a386Sopenharmony_ci        SkASSERT(this->inObjectScope());
542cb93a386Sopenharmony_ci        this->popScopeAsVec<ObjectValue>(SkTo<size_t>(fScopeIndex));
543cb93a386Sopenharmony_ci
544cb93a386Sopenharmony_ci        SkDEBUGCODE(
545cb93a386Sopenharmony_ci            const auto& obj = fValueStack.back().as<ObjectValue>();
546cb93a386Sopenharmony_ci            SkASSERT(obj.is<ObjectValue>());
547cb93a386Sopenharmony_ci            for (const auto& member : obj) {
548cb93a386Sopenharmony_ci                SkASSERT(member.fKey.is<StringValue>());
549cb93a386Sopenharmony_ci            }
550cb93a386Sopenharmony_ci        )
551cb93a386Sopenharmony_ci    }
552cb93a386Sopenharmony_ci
553cb93a386Sopenharmony_ci    void pushArrayScope() {
554cb93a386Sopenharmony_ci        // Save a scope index now, and then later we'll overwrite this value as the Array itself.
555cb93a386Sopenharmony_ci        fValueStack.push_back(RawValue<intptr_t>(fScopeIndex));
556cb93a386Sopenharmony_ci
557cb93a386Sopenharmony_ci        // New array scope.
558cb93a386Sopenharmony_ci        fScopeIndex = -SkTo<intptr_t>(fValueStack.size());
559cb93a386Sopenharmony_ci    }
560cb93a386Sopenharmony_ci
561cb93a386Sopenharmony_ci    void popArrayScope() {
562cb93a386Sopenharmony_ci        SkASSERT(this->inArrayScope());
563cb93a386Sopenharmony_ci        this->popScopeAsVec<ArrayValue>(SkTo<size_t>(-fScopeIndex));
564cb93a386Sopenharmony_ci
565cb93a386Sopenharmony_ci        SkDEBUGCODE(
566cb93a386Sopenharmony_ci            const auto& arr = fValueStack.back().as<ArrayValue>();
567cb93a386Sopenharmony_ci            SkASSERT(arr.is<ArrayValue>());
568cb93a386Sopenharmony_ci        )
569cb93a386Sopenharmony_ci    }
570cb93a386Sopenharmony_ci
571cb93a386Sopenharmony_ci    void pushObjectKey(const char* key, size_t size, const char* eos) {
572cb93a386Sopenharmony_ci        SkASSERT(this->inObjectScope());
573cb93a386Sopenharmony_ci        SkASSERT(fValueStack.size() >= SkTo<size_t>(fScopeIndex));
574cb93a386Sopenharmony_ci        SkASSERT(!((fValueStack.size() - SkTo<size_t>(fScopeIndex)) & 1));
575cb93a386Sopenharmony_ci        this->pushString(key, size, eos);
576cb93a386Sopenharmony_ci    }
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_ci    void pushTrue() {
579cb93a386Sopenharmony_ci        fValueStack.push_back(BoolValue(true));
580cb93a386Sopenharmony_ci    }
581cb93a386Sopenharmony_ci
582cb93a386Sopenharmony_ci    void pushFalse() {
583cb93a386Sopenharmony_ci        fValueStack.push_back(BoolValue(false));
584cb93a386Sopenharmony_ci    }
585cb93a386Sopenharmony_ci
586cb93a386Sopenharmony_ci    void pushNull() {
587cb93a386Sopenharmony_ci        fValueStack.push_back(NullValue());
588cb93a386Sopenharmony_ci    }
589cb93a386Sopenharmony_ci
590cb93a386Sopenharmony_ci    void pushString(const char* s, size_t size, const char* eos) {
591cb93a386Sopenharmony_ci        fValueStack.push_back(FastString(s, size, eos, fAlloc));
592cb93a386Sopenharmony_ci    }
593cb93a386Sopenharmony_ci
594cb93a386Sopenharmony_ci    void pushInt32(int32_t i) {
595cb93a386Sopenharmony_ci        fValueStack.push_back(NumberValue(i));
596cb93a386Sopenharmony_ci    }
597cb93a386Sopenharmony_ci
598cb93a386Sopenharmony_ci    void pushFloat(float f) {
599cb93a386Sopenharmony_ci        fValueStack.push_back(NumberValue(f));
600cb93a386Sopenharmony_ci    }
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ci    template <typename T>
603cb93a386Sopenharmony_ci    T error(T&& ret_val, const char* p, const char* msg) {
604cb93a386Sopenharmony_ci#if defined(SK_JSON_REPORT_ERRORS)
605cb93a386Sopenharmony_ci        fErrorToken = p;
606cb93a386Sopenharmony_ci        fErrorMessage.set(msg);
607cb93a386Sopenharmony_ci#endif
608cb93a386Sopenharmony_ci        return ret_val;
609cb93a386Sopenharmony_ci    }
610cb93a386Sopenharmony_ci
611cb93a386Sopenharmony_ci    const char* matchTrue(const char* p) {
612cb93a386Sopenharmony_ci        SkASSERT(p[0] == 't');
613cb93a386Sopenharmony_ci
614cb93a386Sopenharmony_ci        if (p[1] == 'r' && p[2] == 'u' && p[3] == 'e') {
615cb93a386Sopenharmony_ci            this->pushTrue();
616cb93a386Sopenharmony_ci            return p + 4;
617cb93a386Sopenharmony_ci        }
618cb93a386Sopenharmony_ci
619cb93a386Sopenharmony_ci        return this->error(nullptr, p, "invalid token");
620cb93a386Sopenharmony_ci    }
621cb93a386Sopenharmony_ci
622cb93a386Sopenharmony_ci    const char* matchFalse(const char* p) {
623cb93a386Sopenharmony_ci        SkASSERT(p[0] == 'f');
624cb93a386Sopenharmony_ci
625cb93a386Sopenharmony_ci        if (p[1] == 'a' && p[2] == 'l' && p[3] == 's' && p[4] == 'e') {
626cb93a386Sopenharmony_ci            this->pushFalse();
627cb93a386Sopenharmony_ci            return p + 5;
628cb93a386Sopenharmony_ci        }
629cb93a386Sopenharmony_ci
630cb93a386Sopenharmony_ci        return this->error(nullptr, p, "invalid token");
631cb93a386Sopenharmony_ci    }
632cb93a386Sopenharmony_ci
633cb93a386Sopenharmony_ci    const char* matchNull(const char* p) {
634cb93a386Sopenharmony_ci        SkASSERT(p[0] == 'n');
635cb93a386Sopenharmony_ci
636cb93a386Sopenharmony_ci        if (p[1] == 'u' && p[2] == 'l' && p[3] == 'l') {
637cb93a386Sopenharmony_ci            this->pushNull();
638cb93a386Sopenharmony_ci            return p + 4;
639cb93a386Sopenharmony_ci        }
640cb93a386Sopenharmony_ci
641cb93a386Sopenharmony_ci        return this->error(nullptr, p, "invalid token");
642cb93a386Sopenharmony_ci    }
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_ci    const std::vector<char>* unescapeString(const char* begin, const char* end) {
645cb93a386Sopenharmony_ci        fUnescapeBuffer.clear();
646cb93a386Sopenharmony_ci
647cb93a386Sopenharmony_ci        for (const auto* p = begin; p != end; ++p) {
648cb93a386Sopenharmony_ci            if (*p != '\\') {
649cb93a386Sopenharmony_ci                fUnescapeBuffer.push_back(*p);
650cb93a386Sopenharmony_ci                continue;
651cb93a386Sopenharmony_ci            }
652cb93a386Sopenharmony_ci
653cb93a386Sopenharmony_ci            if (++p == end) {
654cb93a386Sopenharmony_ci                return nullptr;
655cb93a386Sopenharmony_ci            }
656cb93a386Sopenharmony_ci
657cb93a386Sopenharmony_ci            switch (*p) {
658cb93a386Sopenharmony_ci            case  '"': fUnescapeBuffer.push_back( '"'); break;
659cb93a386Sopenharmony_ci            case '\\': fUnescapeBuffer.push_back('\\'); break;
660cb93a386Sopenharmony_ci            case  '/': fUnescapeBuffer.push_back( '/'); break;
661cb93a386Sopenharmony_ci            case  'b': fUnescapeBuffer.push_back('\b'); break;
662cb93a386Sopenharmony_ci            case  'f': fUnescapeBuffer.push_back('\f'); break;
663cb93a386Sopenharmony_ci            case  'n': fUnescapeBuffer.push_back('\n'); break;
664cb93a386Sopenharmony_ci            case  'r': fUnescapeBuffer.push_back('\r'); break;
665cb93a386Sopenharmony_ci            case  't': fUnescapeBuffer.push_back('\t'); break;
666cb93a386Sopenharmony_ci            case  'u': {
667cb93a386Sopenharmony_ci                if (p + 4 >= end) {
668cb93a386Sopenharmony_ci                    return nullptr;
669cb93a386Sopenharmony_ci                }
670cb93a386Sopenharmony_ci
671cb93a386Sopenharmony_ci                uint32_t hexed;
672cb93a386Sopenharmony_ci                const char hex_str[] = {p[1], p[2], p[3], p[4], '\0'};
673cb93a386Sopenharmony_ci                const auto* eos = SkParse::FindHex(hex_str, &hexed);
674cb93a386Sopenharmony_ci                if (!eos || *eos) {
675cb93a386Sopenharmony_ci                    return nullptr;
676cb93a386Sopenharmony_ci                }
677cb93a386Sopenharmony_ci
678cb93a386Sopenharmony_ci                char utf8[SkUTF::kMaxBytesInUTF8Sequence];
679cb93a386Sopenharmony_ci                const auto utf8_len = SkUTF::ToUTF8(SkTo<SkUnichar>(hexed), utf8);
680cb93a386Sopenharmony_ci                fUnescapeBuffer.insert(fUnescapeBuffer.end(), utf8, utf8 + utf8_len);
681cb93a386Sopenharmony_ci                p += 4;
682cb93a386Sopenharmony_ci            } break;
683cb93a386Sopenharmony_ci            default: return nullptr;
684cb93a386Sopenharmony_ci            }
685cb93a386Sopenharmony_ci        }
686cb93a386Sopenharmony_ci
687cb93a386Sopenharmony_ci        return &fUnescapeBuffer;
688cb93a386Sopenharmony_ci    }
689cb93a386Sopenharmony_ci
690cb93a386Sopenharmony_ci    template <typename MatchFunc>
691cb93a386Sopenharmony_ci    const char* matchString(const char* p, const char* p_stop, MatchFunc&& func) {
692cb93a386Sopenharmony_ci        SkASSERT(*p == '"');
693cb93a386Sopenharmony_ci        const auto* s_begin = p + 1;
694cb93a386Sopenharmony_ci        bool requires_unescape = false;
695cb93a386Sopenharmony_ci
696cb93a386Sopenharmony_ci        do {
697cb93a386Sopenharmony_ci            // Consume string chars.
698cb93a386Sopenharmony_ci            // This is the fast path, and hopefully we only hit it once then quick-exit below.
699cb93a386Sopenharmony_ci            for (p = p + 1; !is_eostring(*p); ++p);
700cb93a386Sopenharmony_ci
701cb93a386Sopenharmony_ci            if (*p == '"') {
702cb93a386Sopenharmony_ci                // Valid string found.
703cb93a386Sopenharmony_ci                if (!requires_unescape) {
704cb93a386Sopenharmony_ci                    func(s_begin, p - s_begin, p_stop);
705cb93a386Sopenharmony_ci                } else {
706cb93a386Sopenharmony_ci                    // Slow unescape.  We could avoid this extra copy with some effort,
707cb93a386Sopenharmony_ci                    // but in practice escaped strings should be rare.
708cb93a386Sopenharmony_ci                    const auto* buf = this->unescapeString(s_begin, p);
709cb93a386Sopenharmony_ci                    if (!buf) {
710cb93a386Sopenharmony_ci                        break;
711cb93a386Sopenharmony_ci                    }
712cb93a386Sopenharmony_ci
713cb93a386Sopenharmony_ci                    SkASSERT(!buf->empty());
714cb93a386Sopenharmony_ci                    func(buf->data(), buf->size(), buf->data() + buf->size() - 1);
715cb93a386Sopenharmony_ci                }
716cb93a386Sopenharmony_ci                return p + 1;
717cb93a386Sopenharmony_ci            }
718cb93a386Sopenharmony_ci
719cb93a386Sopenharmony_ci            if (*p == '\\') {
720cb93a386Sopenharmony_ci                requires_unescape = true;
721cb93a386Sopenharmony_ci                ++p;
722cb93a386Sopenharmony_ci                continue;
723cb93a386Sopenharmony_ci            }
724cb93a386Sopenharmony_ci
725cb93a386Sopenharmony_ci            // End-of-scope chars are special: we use them to tag the end of the input.
726cb93a386Sopenharmony_ci            // Thus they cannot be consumed indiscriminately -- we need to check if we hit the
727cb93a386Sopenharmony_ci            // end of the input.  To that effect, we treat them as string terminators above,
728cb93a386Sopenharmony_ci            // then we catch them here.
729cb93a386Sopenharmony_ci            if (is_eoscope(*p)) {
730cb93a386Sopenharmony_ci                continue;
731cb93a386Sopenharmony_ci            }
732cb93a386Sopenharmony_ci
733cb93a386Sopenharmony_ci            // Invalid/unexpected char.
734cb93a386Sopenharmony_ci            break;
735cb93a386Sopenharmony_ci        } while (p != p_stop);
736cb93a386Sopenharmony_ci
737cb93a386Sopenharmony_ci        // Premature end-of-input, or illegal string char.
738cb93a386Sopenharmony_ci        return this->error(nullptr, s_begin - 1, "invalid string");
739cb93a386Sopenharmony_ci    }
740cb93a386Sopenharmony_ci
741cb93a386Sopenharmony_ci    const char* matchFastFloatDecimalPart(const char* p, int sign, float f, int exp) {
742cb93a386Sopenharmony_ci        SkASSERT(exp <= 0);
743cb93a386Sopenharmony_ci
744cb93a386Sopenharmony_ci        for (;;) {
745cb93a386Sopenharmony_ci            if (!is_digit(*p)) break;
746cb93a386Sopenharmony_ci            f = f * 10.f + (*p++ - '0'); --exp;
747cb93a386Sopenharmony_ci            if (!is_digit(*p)) break;
748cb93a386Sopenharmony_ci            f = f * 10.f + (*p++ - '0'); --exp;
749cb93a386Sopenharmony_ci        }
750cb93a386Sopenharmony_ci
751cb93a386Sopenharmony_ci        const auto decimal_scale = pow10(exp);
752cb93a386Sopenharmony_ci        if (is_numeric(*p) || !decimal_scale) {
753cb93a386Sopenharmony_ci            SkASSERT((*p == '.' || *p == 'e' || *p == 'E') || !decimal_scale);
754cb93a386Sopenharmony_ci            // Malformed input, or an (unsupported) exponent, or a collapsed decimal factor.
755cb93a386Sopenharmony_ci            return nullptr;
756cb93a386Sopenharmony_ci        }
757cb93a386Sopenharmony_ci
758cb93a386Sopenharmony_ci        this->pushFloat(sign * f * decimal_scale);
759cb93a386Sopenharmony_ci
760cb93a386Sopenharmony_ci        return p;
761cb93a386Sopenharmony_ci    }
762cb93a386Sopenharmony_ci
763cb93a386Sopenharmony_ci    const char* matchFastFloatPart(const char* p, int sign, float f) {
764cb93a386Sopenharmony_ci        for (;;) {
765cb93a386Sopenharmony_ci            if (!is_digit(*p)) break;
766cb93a386Sopenharmony_ci            f = f * 10.f + (*p++ - '0');
767cb93a386Sopenharmony_ci            if (!is_digit(*p)) break;
768cb93a386Sopenharmony_ci            f = f * 10.f + (*p++ - '0');
769cb93a386Sopenharmony_ci        }
770cb93a386Sopenharmony_ci
771cb93a386Sopenharmony_ci        if (!is_numeric(*p)) {
772cb93a386Sopenharmony_ci            // Matched (integral) float.
773cb93a386Sopenharmony_ci            this->pushFloat(sign * f);
774cb93a386Sopenharmony_ci            return p;
775cb93a386Sopenharmony_ci        }
776cb93a386Sopenharmony_ci
777cb93a386Sopenharmony_ci        return (*p == '.') ? this->matchFastFloatDecimalPart(p + 1, sign, f, 0)
778cb93a386Sopenharmony_ci                           : nullptr;
779cb93a386Sopenharmony_ci    }
780cb93a386Sopenharmony_ci
781cb93a386Sopenharmony_ci    const char* matchFast32OrFloat(const char* p) {
782cb93a386Sopenharmony_ci        int sign = 1;
783cb93a386Sopenharmony_ci        if (*p == '-') {
784cb93a386Sopenharmony_ci            sign = -1;
785cb93a386Sopenharmony_ci            ++p;
786cb93a386Sopenharmony_ci        }
787cb93a386Sopenharmony_ci
788cb93a386Sopenharmony_ci        const auto* digits_start = p;
789cb93a386Sopenharmony_ci
790cb93a386Sopenharmony_ci        int32_t n32 = 0;
791cb93a386Sopenharmony_ci
792cb93a386Sopenharmony_ci        // This is the largest absolute int32 value we can handle before
793cb93a386Sopenharmony_ci        // risking overflow *on the next digit* (214748363).
794cb93a386Sopenharmony_ci        static constexpr int32_t kMaxInt32 = (std::numeric_limits<int32_t>::max() - 9) / 10;
795cb93a386Sopenharmony_ci
796cb93a386Sopenharmony_ci        if (is_digit(*p)) {
797cb93a386Sopenharmony_ci            n32 = (*p++ - '0');
798cb93a386Sopenharmony_ci            for (;;) {
799cb93a386Sopenharmony_ci                if (!is_digit(*p) || n32 > kMaxInt32) break;
800cb93a386Sopenharmony_ci                n32 = n32 * 10 + (*p++ - '0');
801cb93a386Sopenharmony_ci            }
802cb93a386Sopenharmony_ci        }
803cb93a386Sopenharmony_ci
804cb93a386Sopenharmony_ci        if (!is_numeric(*p)) {
805cb93a386Sopenharmony_ci            // Did we actually match any digits?
806cb93a386Sopenharmony_ci            if (p > digits_start) {
807cb93a386Sopenharmony_ci                this->pushInt32(sign * n32);
808cb93a386Sopenharmony_ci                return p;
809cb93a386Sopenharmony_ci            }
810cb93a386Sopenharmony_ci            return nullptr;
811cb93a386Sopenharmony_ci        }
812cb93a386Sopenharmony_ci
813cb93a386Sopenharmony_ci        if (*p == '.') {
814cb93a386Sopenharmony_ci            const auto* decimals_start = ++p;
815cb93a386Sopenharmony_ci
816cb93a386Sopenharmony_ci            int exp = 0;
817cb93a386Sopenharmony_ci
818cb93a386Sopenharmony_ci            for (;;) {
819cb93a386Sopenharmony_ci                if (!is_digit(*p) || n32 > kMaxInt32) break;
820cb93a386Sopenharmony_ci                n32 = n32 * 10 + (*p++ - '0'); --exp;
821cb93a386Sopenharmony_ci                if (!is_digit(*p) || n32 > kMaxInt32) break;
822cb93a386Sopenharmony_ci                n32 = n32 * 10 + (*p++ - '0'); --exp;
823cb93a386Sopenharmony_ci            }
824cb93a386Sopenharmony_ci
825cb93a386Sopenharmony_ci            if (!is_numeric(*p)) {
826cb93a386Sopenharmony_ci                // Did we actually match any digits?
827cb93a386Sopenharmony_ci                if (p > decimals_start) {
828cb93a386Sopenharmony_ci                    this->pushFloat(sign * n32 * pow10(exp));
829cb93a386Sopenharmony_ci                    return p;
830cb93a386Sopenharmony_ci                }
831cb93a386Sopenharmony_ci                return nullptr;
832cb93a386Sopenharmony_ci            }
833cb93a386Sopenharmony_ci
834cb93a386Sopenharmony_ci            if (n32 > kMaxInt32) {
835cb93a386Sopenharmony_ci                // we ran out on n32 bits
836cb93a386Sopenharmony_ci                return this->matchFastFloatDecimalPart(p, sign, n32, exp);
837cb93a386Sopenharmony_ci            }
838cb93a386Sopenharmony_ci        }
839cb93a386Sopenharmony_ci
840cb93a386Sopenharmony_ci        return this->matchFastFloatPart(p, sign, n32);
841cb93a386Sopenharmony_ci    }
842cb93a386Sopenharmony_ci
843cb93a386Sopenharmony_ci    const char* matchNumber(const char* p) {
844cb93a386Sopenharmony_ci        if (const auto* fast = this->matchFast32OrFloat(p)) return fast;
845cb93a386Sopenharmony_ci
846cb93a386Sopenharmony_ci        // slow fallback
847cb93a386Sopenharmony_ci        char* matched;
848cb93a386Sopenharmony_ci        float f = strtof(p, &matched);
849cb93a386Sopenharmony_ci        if (matched > p) {
850cb93a386Sopenharmony_ci            this->pushFloat(f);
851cb93a386Sopenharmony_ci            return matched;
852cb93a386Sopenharmony_ci        }
853cb93a386Sopenharmony_ci        return this->error(nullptr, p, "invalid numeric token");
854cb93a386Sopenharmony_ci    }
855cb93a386Sopenharmony_ci};
856cb93a386Sopenharmony_ci
857cb93a386Sopenharmony_civoid Write(const Value& v, SkWStream* stream) {
858cb93a386Sopenharmony_ci    switch (v.getType()) {
859cb93a386Sopenharmony_ci    case Value::Type::kNull:
860cb93a386Sopenharmony_ci        stream->writeText("null");
861cb93a386Sopenharmony_ci        break;
862cb93a386Sopenharmony_ci    case Value::Type::kBool:
863cb93a386Sopenharmony_ci        stream->writeText(*v.as<BoolValue>() ? "true" : "false");
864cb93a386Sopenharmony_ci        break;
865cb93a386Sopenharmony_ci    case Value::Type::kNumber:
866cb93a386Sopenharmony_ci        stream->writeScalarAsText(*v.as<NumberValue>());
867cb93a386Sopenharmony_ci        break;
868cb93a386Sopenharmony_ci    case Value::Type::kString:
869cb93a386Sopenharmony_ci        stream->writeText("\"");
870cb93a386Sopenharmony_ci        stream->writeText(v.as<StringValue>().begin());
871cb93a386Sopenharmony_ci        stream->writeText("\"");
872cb93a386Sopenharmony_ci        break;
873cb93a386Sopenharmony_ci    case Value::Type::kArray: {
874cb93a386Sopenharmony_ci        const auto& array = v.as<ArrayValue>();
875cb93a386Sopenharmony_ci        stream->writeText("[");
876cb93a386Sopenharmony_ci        bool first_value = true;
877cb93a386Sopenharmony_ci        for (const auto& entry : array) {
878cb93a386Sopenharmony_ci            if (!first_value) stream->writeText(",");
879cb93a386Sopenharmony_ci            Write(entry, stream);
880cb93a386Sopenharmony_ci            first_value = false;
881cb93a386Sopenharmony_ci        }
882cb93a386Sopenharmony_ci        stream->writeText("]");
883cb93a386Sopenharmony_ci        break;
884cb93a386Sopenharmony_ci    }
885cb93a386Sopenharmony_ci    case Value::Type::kObject:
886cb93a386Sopenharmony_ci        const auto& object = v.as<ObjectValue>();
887cb93a386Sopenharmony_ci        stream->writeText("{");
888cb93a386Sopenharmony_ci        bool first_member = true;
889cb93a386Sopenharmony_ci        for (const auto& member : object) {
890cb93a386Sopenharmony_ci            SkASSERT(member.fKey.getType() == Value::Type::kString);
891cb93a386Sopenharmony_ci            if (!first_member) stream->writeText(",");
892cb93a386Sopenharmony_ci            Write(member.fKey, stream);
893cb93a386Sopenharmony_ci            stream->writeText(":");
894cb93a386Sopenharmony_ci            Write(member.fValue, stream);
895cb93a386Sopenharmony_ci            first_member = false;
896cb93a386Sopenharmony_ci        }
897cb93a386Sopenharmony_ci        stream->writeText("}");
898cb93a386Sopenharmony_ci        break;
899cb93a386Sopenharmony_ci    }
900cb93a386Sopenharmony_ci}
901cb93a386Sopenharmony_ci
902cb93a386Sopenharmony_ci} // namespace
903cb93a386Sopenharmony_ci
904cb93a386Sopenharmony_ciSkString Value::toString() const {
905cb93a386Sopenharmony_ci    SkDynamicMemoryWStream wstream;
906cb93a386Sopenharmony_ci    Write(*this, &wstream);
907cb93a386Sopenharmony_ci    const auto data = wstream.detachAsData();
908cb93a386Sopenharmony_ci    // TODO: is there a better way to pass data around without copying?
909cb93a386Sopenharmony_ci    return SkString(static_cast<const char*>(data->data()), data->size());
910cb93a386Sopenharmony_ci}
911cb93a386Sopenharmony_ci
912cb93a386Sopenharmony_cistatic constexpr size_t kMinChunkSize = 4096;
913cb93a386Sopenharmony_ci
914cb93a386Sopenharmony_ciDOM::DOM(const char* data, size_t size)
915cb93a386Sopenharmony_ci    : fAlloc(kMinChunkSize) {
916cb93a386Sopenharmony_ci    DOMParser parser(fAlloc);
917cb93a386Sopenharmony_ci
918cb93a386Sopenharmony_ci    fRoot = parser.parse(data, size);
919cb93a386Sopenharmony_ci}
920cb93a386Sopenharmony_ci
921cb93a386Sopenharmony_civoid DOM::write(SkWStream* stream) const {
922cb93a386Sopenharmony_ci    Write(fRoot, stream);
923cb93a386Sopenharmony_ci}
924cb93a386Sopenharmony_ci
925cb93a386Sopenharmony_ci} // namespace skjson
926