Serenity Operating System
at hosted 318 lines 8.1 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/JsonArray.h> 28#include <AK/JsonObject.h> 29#include <AK/JsonParser.h> 30#include <AK/Memory.h> 31 32namespace AK { 33 34static inline bool is_whitespace(char ch) 35{ 36 return ch == ' ' || ch == '\n' || ch == '\t' || ch == '\v' || ch == '\r'; 37} 38 39char JsonParser::peek() const 40{ 41 if (m_index < m_input.length()) 42 return m_input[m_index]; 43 return '\0'; 44} 45 46char JsonParser::consume() 47{ 48 if (m_index < m_input.length()) 49 return m_input[m_index++]; 50 return '\0'; 51} 52 53template<typename C> 54void JsonParser::consume_while(C condition) 55{ 56 while (condition(peek())) 57 consume(); 58} 59 60void JsonParser::consume_whitespace() 61{ 62 consume_while([](char ch) { return is_whitespace(ch); }); 63} 64 65void JsonParser::consume_specific(char expected_ch) 66{ 67 char consumed_ch = consume(); 68 ASSERT(consumed_ch == expected_ch); 69} 70 71String JsonParser::consume_quoted_string() 72{ 73 consume_specific('"'); 74 Vector<char, 1024> buffer; 75 76 for (;;) { 77 size_t peek_index = m_index; 78 char ch = 0; 79 for (;;) { 80 if (peek_index == m_input.length()) 81 break; 82 ch = m_input[peek_index]; 83 if (ch == '"' || ch == '\\') 84 break; 85 ++peek_index; 86 } 87 88 if (peek_index != m_index) { 89 buffer.append(m_input.characters_without_null_termination() + m_index, peek_index - m_index); 90 m_index = peek_index; 91 } 92 93 if (m_index == m_input.length()) 94 break; 95 if (ch == '"') 96 break; 97 if (ch != '\\') { 98 buffer.append(consume()); 99 continue; 100 } 101 consume(); 102 char escaped_ch = consume(); 103 switch (escaped_ch) { 104 case 'n': 105 buffer.append('\n'); 106 break; 107 case 'r': 108 buffer.append('\r'); 109 break; 110 case 't': 111 buffer.append('\t'); 112 break; 113 case 'b': 114 buffer.append('\b'); 115 break; 116 case 'f': 117 buffer.append('\f'); 118 break; 119 case 'u': 120 consume(); 121 consume(); 122 consume(); 123 consume(); 124 // FIXME: This is obviously not correct, but we don't have non-ASCII support so meh. 125 buffer.append('?'); 126 break; 127 default: 128 buffer.append(escaped_ch); 129 break; 130 } 131 } 132 consume_specific('"'); 133 134 if (buffer.is_empty()) 135 return String::empty(); 136 137 auto& last_string_starting_with_character = m_last_string_starting_with_character[(u8)buffer.first()]; 138 if (last_string_starting_with_character.length() == buffer.size()) { 139 if (!memcmp(last_string_starting_with_character.characters(), buffer.data(), buffer.size())) 140 return last_string_starting_with_character; 141 } 142 143 last_string_starting_with_character = String::copy(buffer); 144 return last_string_starting_with_character; 145} 146 147JsonObject JsonParser::parse_object() 148{ 149 JsonObject object; 150 consume_specific('{'); 151 for (;;) { 152 consume_whitespace(); 153 if (peek() == '}') 154 break; 155 consume_whitespace(); 156 auto name = consume_quoted_string(); 157 consume_whitespace(); 158 consume_specific(':'); 159 consume_whitespace(); 160 auto value = parse(); 161 object.set(name, move(value)); 162 consume_whitespace(); 163 if (peek() == '}') 164 break; 165 consume_specific(','); 166 } 167 consume_specific('}'); 168 return object; 169} 170 171JsonArray JsonParser::parse_array() 172{ 173 JsonArray array; 174 consume_specific('['); 175 for (;;) { 176 consume_whitespace(); 177 if (peek() == ']') 178 break; 179 array.append(parse()); 180 consume_whitespace(); 181 if (peek() == ']') 182 break; 183 consume_specific(','); 184 } 185 consume_whitespace(); 186 consume_specific(']'); 187 return array; 188} 189 190JsonValue JsonParser::parse_string() 191{ 192 return consume_quoted_string(); 193} 194 195JsonValue JsonParser::parse_number() 196{ 197 bool ok; 198 JsonValue value; 199 Vector<char, 128> number_buffer; 200 Vector<char, 128> fraction_buffer; 201 202 bool is_double = false; 203 for (;;) { 204 char ch = peek(); 205 if (ch == '.') { 206 is_double = true; 207 ++m_index; 208 continue; 209 } 210 if (ch == '-' || (ch >= '0' && ch <= '9')) { 211 if (is_double) 212 fraction_buffer.append(ch); 213 else 214 number_buffer.append(ch); 215 ++m_index; 216 continue; 217 } 218 break; 219 } 220 221 StringView number_string(number_buffer.data(), number_buffer.size()); 222 StringView fraction_string(fraction_buffer.data(), fraction_buffer.size()); 223 224#ifndef KERNEL 225 if (is_double) { 226 int whole = number_string.to_uint(ok); 227 if (!ok) 228 whole = number_string.to_int(ok); 229 ASSERT(ok); 230 231 int fraction = fraction_string.to_uint(ok); 232 fraction *= (whole < 0) ? -1 : 1; 233 ASSERT(ok); 234 235 auto divider = 1; 236 for (size_t i = 0; i < fraction_buffer.size(); ++i) { 237 divider *= 10; 238 } 239 value = JsonValue((double)whole + ((double)fraction / divider)); 240 } else { 241#endif 242 value = JsonValue(number_string.to_uint(ok)); 243 if (!ok) 244 value = JsonValue(number_string.to_int(ok)); 245 ASSERT(ok); 246#ifndef KERNEL 247 } 248#endif 249 250 return value; 251} 252 253void JsonParser::consume_string(const char* str) 254{ 255 for (size_t i = 0, length = strlen(str); i < length; ++i) 256 consume_specific(str[i]); 257} 258 259JsonValue JsonParser::parse_true() 260{ 261 consume_string("true"); 262 return JsonValue(true); 263} 264 265JsonValue JsonParser::parse_false() 266{ 267 consume_string("false"); 268 return JsonValue(false); 269} 270 271JsonValue JsonParser::parse_null() 272{ 273 consume_string("null"); 274 return JsonValue(JsonValue::Type::Null); 275} 276 277JsonValue JsonParser::parse_undefined() 278{ 279 consume_string("undefined"); 280 return JsonValue(JsonValue::Type::Undefined); 281} 282 283JsonValue JsonParser::parse() 284{ 285 consume_whitespace(); 286 auto type_hint = peek(); 287 switch (type_hint) { 288 case '{': 289 return parse_object(); 290 case '[': 291 return parse_array(); 292 case '"': 293 return parse_string(); 294 case '-': 295 case '0': 296 case '1': 297 case '2': 298 case '3': 299 case '4': 300 case '5': 301 case '6': 302 case '7': 303 case '8': 304 case '9': 305 return parse_number(); 306 case 'f': 307 return parse_false(); 308 case 't': 309 return parse_true(); 310 case 'n': 311 return parse_null(); 312 case 'u': 313 return parse_undefined(); 314 } 315 316 return JsonValue(); 317} 318}