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