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