Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Side by Side Diff: third_party/WebKit/Source/platform/JSONParser.cpp

Issue 2205933002: Add JSON parser to Source/platform (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Switch to unique_ptr version of JSONValue classes Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "platform/inspector_protocol/Parser.h" 5 #include "platform/JSONParser.h"
6 6
7 #include "platform/inspector_protocol/String16.h" 7 #include "platform/Decimal.h"
8 #include "platform/inspector_protocol/Values.h" 8 #include "platform/JSONValues.h"
9 #include "wtf/text/StringBuilder.h"
10 #include "wtf/text/StringToNumber.h"
9 11
10 namespace blink { 12 namespace blink {
11 namespace protocol {
12 13
13 namespace { 14 namespace {
14 15
15 const int stackLimit = 1000; 16 const int stackLimit = 1000;
16 17
17 enum Token { 18 enum Token {
18 ObjectBegin, 19 ObjectBegin,
19 ObjectEnd, 20 ObjectEnd,
20 ArrayBegin, 21 ArrayBegin,
21 ArrayEnd, 22 ArrayEnd,
22 StringLiteral, 23 StringLiteral,
23 Number, 24 Number,
24 BoolTrue, 25 BoolTrue,
25 BoolFalse, 26 BoolFalse,
26 NullToken, 27 NullToken,
27 ListSeparator, 28 ListSeparator,
28 ObjectPairSeparator, 29 ObjectPairSeparator,
29 InvalidToken, 30 InvalidToken,
30 }; 31 };
31 32
32 const char* const nullString = "null"; 33 const char* const nullString = "null";
33 const char* const trueString = "true"; 34 const char* const trueString = "true";
34 const char* const falseString = "false"; 35 const char* const falseString = "false";
35 36
36 bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEn d, const char* token) 37 template<typename CharType>
38 bool parseConstToken(const CharType* start, const CharType* end, const CharType* * tokenEnd, const char* token)
37 { 39 {
38 while (start < end && *token != '\0' && *start++ == *token++) { } 40 while (start < end && *token != '\0' && *start++ == *token++) { }
39 if (*token != '\0') 41 if (*token != '\0')
40 return false; 42 return false;
41 *tokenEnd = start; 43 *tokenEnd = start;
42 return true; 44 return true;
43 } 45 }
44 46
45 bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros) 47 template<typename CharType>
48 bool readInt(const CharType* start, const CharType* end, const CharType** tokenE nd, bool canHaveLeadingZeros)
46 { 49 {
47 if (start == end) 50 if (start == end)
48 return false; 51 return false;
49 bool haveLeadingZero = '0' == *start; 52 bool haveLeadingZero = '0' == *start;
50 int length = 0; 53 int length = 0;
51 while (start < end && '0' <= *start && *start <= '9') { 54 while (start < end && '0' <= *start && *start <= '9') {
52 ++start; 55 ++start;
53 ++length; 56 ++length;
54 } 57 }
55 if (!length) 58 if (!length)
56 return false; 59 return false;
57 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) 60 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
58 return false; 61 return false;
59 *tokenEnd = start; 62 *tokenEnd = start;
60 return true; 63 return true;
61 } 64 }
62 65
63 bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenE nd) 66 template<typename CharType>
67 bool parseNumberToken(const CharType* start, const CharType* end, const CharType ** tokenEnd)
64 { 68 {
65 // We just grab the number here. We validate the size in DecodeNumber. 69 // We just grab the number here. We validate the size in DecodeNumber.
66 // According to RFC4627, a valid number is: [minus] int [frac] [exp] 70 // According to RFC4627, a valid number is: [minus] int [frac] [exp]
67 if (start == end) 71 if (start == end)
68 return false; 72 return false;
69 UChar c = *start; 73 CharType c = *start;
70 if ('-' == c) 74 if ('-' == c)
71 ++start; 75 ++start;
72 76
73 if (!readInt(start, end, &start, false)) 77 if (!readInt(start, end, &start, false))
74 return false; 78 return false;
75 if (start == end) { 79 if (start == end) {
76 *tokenEnd = start; 80 *tokenEnd = start;
77 return true; 81 return true;
78 } 82 }
79 83
(...skipping 22 matching lines...) Expand all
102 return false; 106 return false;
103 } 107 }
104 if (!readInt(start, end, &start, true)) 108 if (!readInt(start, end, &start, true))
105 return false; 109 return false;
106 } 110 }
107 111
108 *tokenEnd = start; 112 *tokenEnd = start;
109 return true; 113 return true;
110 } 114 }
111 115
112 bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits) 116 template<typename CharType>
117 bool readHexDigits(const CharType* start, const CharType* end, const CharType** tokenEnd, int digits)
113 { 118 {
114 if (end - start < digits) 119 if (end - start < digits)
115 return false; 120 return false;
116 for (int i = 0; i < digits; ++i) { 121 for (int i = 0; i < digits; ++i) {
117 UChar c = *start++; 122 CharType c = *start++;
118 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))) 123 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
119 return false; 124 return false;
120 } 125 }
121 *tokenEnd = start; 126 *tokenEnd = start;
122 return true; 127 return true;
123 } 128 }
124 129
125 bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenE nd) 130 template<typename CharType>
131 bool parseStringToken(const CharType* start, const CharType* end, const CharType ** tokenEnd)
126 { 132 {
127 while (start < end) { 133 while (start < end) {
128 UChar c = *start++; 134 CharType c = *start++;
129 if ('\\' == c) { 135 if ('\\' == c) {
130 c = *start++; 136 c = *start++;
131 // Make sure the escaped char is valid. 137 // Make sure the escaped char is valid.
132 switch (c) { 138 switch (c) {
133 case 'x': 139 case 'x':
134 if (!readHexDigits(start, end, &start, 2)) 140 if (!readHexDigits(start, end, &start, 2))
135 return false; 141 return false;
136 break; 142 break;
137 case 'u': 143 case 'u':
138 if (!readHexDigits(start, end, &start, 4)) 144 if (!readHexDigits(start, end, &start, 4))
(...skipping 13 matching lines...) Expand all
152 return false; 158 return false;
153 } 159 }
154 } else if ('"' == c) { 160 } else if ('"' == c) {
155 *tokenEnd = start; 161 *tokenEnd = start;
156 return true; 162 return true;
157 } 163 }
158 } 164 }
159 return false; 165 return false;
160 } 166 }
161 167
162 bool skipComment(const UChar* start, const UChar* end, const UChar** commentEnd) 168 template<typename CharType>
169 bool skipComment(const CharType* start, const CharType* end, const CharType** co mmentEnd)
163 { 170 {
164 if (start == end) 171 if (start == end)
165 return false; 172 return false;
166 173
167 if (*start != '/' || start + 1 >= end) 174 if (*start != '/' || start + 1 >= end)
168 return false; 175 return false;
169 ++start; 176 ++start;
170 177
171 if (*start == '/') { 178 if (*start == '/') {
172 // Single line comment, read to newline. 179 // Single line comment, read to newline.
173 for (++start; start < end; ++start) { 180 for (++start; start < end; ++start) {
174 if (*start == '\n' || *start == '\r') { 181 if (*start == '\n' || *start == '\r') {
175 *commentEnd = start + 1; 182 *commentEnd = start + 1;
176 return true; 183 return true;
177 } 184 }
178 } 185 }
179 *commentEnd = end; 186 *commentEnd = end;
180 // Comment reaches end-of-input, which is fine. 187 // Comment reaches end-of-input, which is fine.
181 return true; 188 return true;
182 } 189 }
183 190
184 if (*start == '*') { 191 if (*start == '*') {
185 UChar previous = '\0'; 192 CharType previous = '\0';
186 // Block comment, read until end marker. 193 // Block comment, read until end marker.
187 for (++start; start < end; previous = *start++) { 194 for (++start; start < end; previous = *start++) {
188 if (previous == '*' && *start == '/') { 195 if (previous == '*' && *start == '/') {
189 *commentEnd = start + 1; 196 *commentEnd = start + 1;
190 return true; 197 return true;
191 } 198 }
192 } 199 }
193 // Block comment must close before end-of-input. 200 // Block comment must close before end-of-input.
194 return false; 201 return false;
195 } 202 }
196 203
197 return false; 204 return false;
198 } 205 }
199 206
200 void skipWhitespaceAndComments(const UChar* start, const UChar* end, const UChar ** whitespaceEnd) 207 template<typename CharType>
208 void skipWhitespaceAndComments(const CharType* start, const CharType* end, const CharType** whitespaceEnd)
201 { 209 {
202 while (start < end) { 210 while (start < end) {
203 if (isSpaceOrNewline(*start)) { 211 if (isSpaceOrNewline(*start)) {
204 ++start; 212 ++start;
205 } else if (*start == '/') { 213 } else if (*start == '/') {
206 const UChar* commentEnd; 214 const CharType* commentEnd;
207 if (!skipComment(start, end, &commentEnd)) 215 if (!skipComment(start, end, &commentEnd))
208 break; 216 break;
209 start = commentEnd; 217 start = commentEnd;
210 } else { 218 } else {
211 break; 219 break;
212 } 220 }
213 } 221 }
214 *whitespaceEnd = start; 222 *whitespaceEnd = start;
215 } 223 }
216 224
217 Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart, const UChar** tokenEnd) 225 template<typename CharType>
226 Token parseToken(const CharType* start, const CharType* end, const CharType** to kenStart, const CharType** tokenEnd)
218 { 227 {
219 skipWhitespaceAndComments(start, end, tokenStart); 228 skipWhitespaceAndComments(start, end, tokenStart);
220 start = *tokenStart; 229 start = *tokenStart;
221 230
222 if (start == end) 231 if (start == end)
223 return InvalidToken; 232 return InvalidToken;
224 233
225 switch (*start) { 234 switch (*start) {
226 case 'n': 235 case 'n':
227 if (parseConstToken(start, end, tokenEnd, nullString)) 236 if (parseConstToken(start, end, tokenEnd, nullString))
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 return Number; 277 return Number;
269 break; 278 break;
270 case '"': 279 case '"':
271 if (parseStringToken(start + 1, end, tokenEnd)) 280 if (parseStringToken(start + 1, end, tokenEnd))
272 return StringLiteral; 281 return StringLiteral;
273 break; 282 break;
274 } 283 }
275 return InvalidToken; 284 return InvalidToken;
276 } 285 }
277 286
278 inline int hexToInt(UChar c) 287 template<typename CharType>
288 inline int hexToInt(CharType c)
279 { 289 {
280 if ('0' <= c && c <= '9') 290 if ('0' <= c && c <= '9')
281 return c - '0'; 291 return c - '0';
282 if ('A' <= c && c <= 'F') 292 if ('A' <= c && c <= 'F')
283 return c - 'A' + 10; 293 return c - 'A' + 10;
284 if ('a' <= c && c <= 'f') 294 if ('a' <= c && c <= 'f')
285 return c - 'a' + 10; 295 return c - 'a' + 10;
286 NOTREACHED(); 296 NOTREACHED();
287 return 0; 297 return 0;
288 } 298 }
289 299
290 bool decodeString(const UChar* start, const UChar* end, String16Builder* output) 300 template<typename CharType>
301 bool decodeString(const CharType* start, const CharType* end, StringBuilder* out put)
291 { 302 {
292 while (start < end) { 303 while (start < end) {
293 UChar c = *start++; 304 UChar c = *start++;
294 if ('\\' != c) { 305 if ('\\' != c) {
295 output->append(c); 306 output->append(c);
296 continue; 307 continue;
297 } 308 }
298 c = *start++; 309 c = *start++;
299 310
300 if (c == 'x') { 311 if (c == 'x') {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 start += 4; 344 start += 4;
334 break; 345 break;
335 default: 346 default:
336 return false; 347 return false;
337 } 348 }
338 output->append(c); 349 output->append(c);
339 } 350 }
340 return true; 351 return true;
341 } 352 }
342 353
343 bool decodeString(const UChar* start, const UChar* end, String16* output) 354 template<typename CharType>
355 bool decodeString(const CharType* start, const CharType* end, String* output)
344 { 356 {
345 if (start == end) { 357 if (start == end) {
346 *output = ""; 358 *output = "";
347 return true; 359 return true;
348 } 360 }
349 if (start > end) 361 if (start > end)
350 return false; 362 return false;
351 String16Builder buffer; 363 StringBuilder buffer;
352 buffer.reserveCapacity(end - start); 364 buffer.reserveCapacity(end - start);
353 if (!decodeString(start, end, &buffer)) 365 if (!decodeString(start, end, &buffer))
354 return false; 366 return false;
355 *output = buffer.toString(); 367 *output = buffer.toString();
368 // Validate constructed utf16 string.
369 if (output->utf8(StrictUTF8Conversion).isNull())
370 return false;
356 return true; 371 return true;
357 } 372 }
358 373
359 std::unique_ptr<Value> buildValue(const UChar* start, const UChar* end, const UC har** valueTokenEnd, int depth) 374 template<typename CharType>
375 std::unique_ptr<JSONValue> buildValue(const CharType* start, const CharType* end , const CharType** valueTokenEnd, int depth)
360 { 376 {
361 if (depth > stackLimit) 377 if (depth > stackLimit)
362 return nullptr; 378 return nullptr;
363 379
364 std::unique_ptr<Value> result; 380 std::unique_ptr<JSONValue> result;
365 const UChar* tokenStart; 381 const CharType* tokenStart;
366 const UChar* tokenEnd; 382 const CharType* tokenEnd;
367 Token token = parseToken(start, end, &tokenStart, &tokenEnd); 383 Token token = parseToken(start, end, &tokenStart, &tokenEnd);
368 switch (token) { 384 switch (token) {
369 case InvalidToken: 385 case InvalidToken:
370 return nullptr; 386 return nullptr;
371 case NullToken: 387 case NullToken:
372 result = Value::null(); 388 result = JSONValue::null();
373 break; 389 break;
374 case BoolTrue: 390 case BoolTrue:
375 result = FundamentalValue::create(true); 391 result = JSONBasicValue::create(true);
376 break; 392 break;
377 case BoolFalse: 393 case BoolFalse:
378 result = FundamentalValue::create(false); 394 result = JSONBasicValue::create(false);
379 break; 395 break;
380 case Number: { 396 case Number: {
381 bool ok; 397 bool ok;
382 double value = String16::charactersToDouble(tokenStart, tokenEnd - token Start, &ok); 398 double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok );
399 if (Decimal::fromDouble(value).isInfinity())
400 ok = false;
383 if (!ok) 401 if (!ok)
384 return nullptr; 402 return nullptr;
385 int number = static_cast<int>(value); 403 int number = static_cast<int>(value);
386 if (number == value) 404 if (number == value)
387 result = FundamentalValue::create(number); 405 result = JSONBasicValue::create(number);
388 else 406 else
389 result = FundamentalValue::create(value); 407 result = JSONBasicValue::create(value);
390 break; 408 break;
391 } 409 }
392 case StringLiteral: { 410 case StringLiteral: {
393 String16 value; 411 String value;
394 bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value); 412 bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value);
395 if (!ok) 413 if (!ok)
396 return nullptr; 414 return nullptr;
397 result = StringValue::create(value); 415 result = JSONString::create(value);
398 break; 416 break;
399 } 417 }
400 case ArrayBegin: { 418 case ArrayBegin: {
401 std::unique_ptr<ListValue> array = ListValue::create(); 419 std::unique_ptr<JSONArray> array = JSONArray::create();
402 start = tokenEnd; 420 start = tokenEnd;
403 token = parseToken(start, end, &tokenStart, &tokenEnd); 421 token = parseToken(start, end, &tokenStart, &tokenEnd);
404 while (token != ArrayEnd) { 422 while (token != ArrayEnd) {
405 std::unique_ptr<Value> arrayNode = buildValue(start, end, &tokenEnd, depth + 1); 423 std::unique_ptr<JSONValue> arrayNode = buildValue(start, end, &token End, depth + 1);
406 if (!arrayNode) 424 if (!arrayNode)
407 return nullptr; 425 return nullptr;
408 array->pushValue(std::move(arrayNode)); 426 array->pushValue(std::move(arrayNode));
409 427
410 // After a list value, we expect a comma or the end of the list. 428 // After a list value, we expect a comma or the end of the list.
411 start = tokenEnd; 429 start = tokenEnd;
412 token = parseToken(start, end, &tokenStart, &tokenEnd); 430 token = parseToken(start, end, &tokenStart, &tokenEnd);
413 if (token == ListSeparator) { 431 if (token == ListSeparator) {
414 start = tokenEnd; 432 start = tokenEnd;
415 token = parseToken(start, end, &tokenStart, &tokenEnd); 433 token = parseToken(start, end, &tokenStart, &tokenEnd);
416 if (token == ArrayEnd) 434 if (token == ArrayEnd)
417 return nullptr; 435 return nullptr;
418 } else if (token != ArrayEnd) { 436 } else if (token != ArrayEnd) {
419 // Unexpected value after list value. Bail out. 437 // Unexpected value after list value. Bail out.
420 return nullptr; 438 return nullptr;
421 } 439 }
422 } 440 }
423 if (token != ArrayEnd) 441 if (token != ArrayEnd)
424 return nullptr; 442 return nullptr;
425 result = std::move(array); 443 result = std::move(array);
426 break; 444 break;
427 } 445 }
428 case ObjectBegin: { 446 case ObjectBegin: {
429 std::unique_ptr<DictionaryValue> object = DictionaryValue::create(); 447 std::unique_ptr<JSONObject> object = JSONObject::create();
430 start = tokenEnd; 448 start = tokenEnd;
431 token = parseToken(start, end, &tokenStart, &tokenEnd); 449 token = parseToken(start, end, &tokenStart, &tokenEnd);
432 while (token != ObjectEnd) { 450 while (token != ObjectEnd) {
433 if (token != StringLiteral) 451 if (token != StringLiteral)
434 return nullptr; 452 return nullptr;
435 String16 key; 453 String key;
436 if (!decodeString(tokenStart + 1, tokenEnd - 1, &key)) 454 if (!decodeString(tokenStart + 1, tokenEnd - 1, &key))
437 return nullptr; 455 return nullptr;
438 start = tokenEnd; 456 start = tokenEnd;
439 457
440 token = parseToken(start, end, &tokenStart, &tokenEnd); 458 token = parseToken(start, end, &tokenStart, &tokenEnd);
441 if (token != ObjectPairSeparator) 459 if (token != ObjectPairSeparator)
442 return nullptr; 460 return nullptr;
443 start = tokenEnd; 461 start = tokenEnd;
444 462
445 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, dep th + 1); 463 std::unique_ptr<JSONValue> value = buildValue(start, end, &tokenEnd, depth + 1);
446 if (!value) 464 if (!value)
447 return nullptr; 465 return nullptr;
448 object->setValue(key, std::move(value)); 466 object->setValue(key, std::move(value));
449 start = tokenEnd; 467 start = tokenEnd;
450 468
451 // After a key/value pair, we expect a comma or the end of the 469 // After a key/value pair, we expect a comma or the end of the
452 // object. 470 // object.
453 token = parseToken(start, end, &tokenStart, &tokenEnd); 471 token = parseToken(start, end, &tokenStart, &tokenEnd);
454 if (token == ListSeparator) { 472 if (token == ListSeparator) {
455 start = tokenEnd; 473 start = tokenEnd;
(...skipping 13 matching lines...) Expand all
469 487
470 default: 488 default:
471 // We got a token that's not a value. 489 // We got a token that's not a value.
472 return nullptr; 490 return nullptr;
473 } 491 }
474 492
475 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd); 493 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd);
476 return result; 494 return result;
477 } 495 }
478 496
479 std::unique_ptr<Value> parseJSONInternal(const UChar* start, unsigned length) 497 template<typename CharType>
498 std::unique_ptr<JSONValue> parseJSONInternal(const CharType* start, unsigned len gth)
480 { 499 {
481 const UChar* end = start + length; 500 const CharType* end = start + length;
482 const UChar *tokenEnd; 501 const CharType *tokenEnd;
483 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0); 502 std::unique_ptr<JSONValue> value = buildValue(start, end, &tokenEnd, 0);
484 if (!value || tokenEnd != end) 503 if (!value || tokenEnd != end)
485 return nullptr; 504 return nullptr;
486 return value; 505 return value;
487 } 506 }
488 507
489 } // anonymous namespace 508 } // anonymous namespace
490 509
491 std::unique_ptr<Value> parseJSON(const String16& json) 510 std::unique_ptr<JSONValue> parseJSON(const String& json)
492 { 511 {
493 if (json.isEmpty()) 512 if (json.isEmpty())
494 return nullptr; 513 return nullptr;
514 if (json.is8Bit())
515 return parseJSONInternal(json.characters8(), json.length());
495 return parseJSONInternal(json.characters16(), json.length()); 516 return parseJSONInternal(json.characters16(), json.length());
496 } 517 }
497 518
498 } // namespace protocol
499 } // namespace blink 519 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/JSONParser.h ('k') | third_party/WebKit/Source/platform/JSONParserTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698