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

Side by Side Diff: third_party/WebKit/Source/platform/inspector_protocol/lib/Parser_cpp.template

Issue 2452853002: [inspector] use own version of third_party/inspector_protocol (Closed)
Patch Set: supported new inspector_protocol location in components/ui_devtools/BUILD.gn Created 4 years, 1 month 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
(Empty)
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
3 // found in the LICENSE file.
4
5 {% for namespace in config.protocol.namespace %}
6 namespace {{namespace}} {
7 {% endfor %}
8
9 namespace {
10
11 const int stackLimit = 1000;
12
13 enum Token {
14 ObjectBegin,
15 ObjectEnd,
16 ArrayBegin,
17 ArrayEnd,
18 StringLiteral,
19 Number,
20 BoolTrue,
21 BoolFalse,
22 NullToken,
23 ListSeparator,
24 ObjectPairSeparator,
25 InvalidToken,
26 };
27
28 const char* const nullString = "null";
29 const char* const trueString = "true";
30 const char* const falseString = "false";
31
32 bool isASCII(uint16_t c)
33 {
34 return !(c & ~0x7F);
35 }
36
37 bool isSpaceOrNewLine(uint16_t c)
38 {
39 return isASCII(c) && c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
40 }
41
42 double charactersToDouble(const uint16_t* characters, size_t length, bool* ok)
43 {
44 std::vector<char> buffer;
45 buffer.reserve(length + 1);
46 for (size_t i = 0; i < length; ++i) {
47 if (!isASCII(characters[i])) {
48 *ok = false;
49 return 0;
50 }
51 buffer.push_back(static_cast<char>(characters[i]));
52 }
53 buffer.push_back('\0');
54 char* endptr;
55 double result = std::strtod(buffer.data(), &endptr);
56 *ok = !(*endptr);
57 return result;
58 }
59
60 double charactersToDouble(const uint8_t* characters, size_t length, bool* ok)
61 {
62 std::string buffer(reinterpret_cast<const char*>(characters), length);
63 char* endptr;
64 double result = std::strtod(buffer.data(), &endptr);
65 *ok = !(*endptr);
66 return result;
67 }
68
69 template<typename Char>
70 bool parseConstToken(const Char* start, const Char* end, const Char** tokenEnd, const char* token)
71 {
72 while (start < end && *token != '\0' && *start++ == *token++) { }
73 if (*token != '\0')
74 return false;
75 *tokenEnd = start;
76 return true;
77 }
78
79 template<typename Char>
80 bool readInt(const Char* start, const Char* end, const Char** tokenEnd, bool can HaveLeadingZeros)
81 {
82 if (start == end)
83 return false;
84 bool haveLeadingZero = '0' == *start;
85 int length = 0;
86 while (start < end && '0' <= *start && *start <= '9') {
87 ++start;
88 ++length;
89 }
90 if (!length)
91 return false;
92 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
93 return false;
94 *tokenEnd = start;
95 return true;
96 }
97
98 template<typename Char>
99 bool parseNumberToken(const Char* start, const Char* end, const Char** tokenEnd)
100 {
101 // We just grab the number here. We validate the size in DecodeNumber.
102 // According to RFC4627, a valid number is: [minus] int [frac] [exp]
103 if (start == end)
104 return false;
105 Char c = *start;
106 if ('-' == c)
107 ++start;
108
109 if (!readInt(start, end, &start, false))
110 return false;
111 if (start == end) {
112 *tokenEnd = start;
113 return true;
114 }
115
116 // Optional fraction part
117 c = *start;
118 if ('.' == c) {
119 ++start;
120 if (!readInt(start, end, &start, true))
121 return false;
122 if (start == end) {
123 *tokenEnd = start;
124 return true;
125 }
126 c = *start;
127 }
128
129 // Optional exponent part
130 if ('e' == c || 'E' == c) {
131 ++start;
132 if (start == end)
133 return false;
134 c = *start;
135 if ('-' == c || '+' == c) {
136 ++start;
137 if (start == end)
138 return false;
139 }
140 if (!readInt(start, end, &start, true))
141 return false;
142 }
143
144 *tokenEnd = start;
145 return true;
146 }
147
148 template<typename Char>
149 bool readHexDigits(const Char* start, const Char* end, const Char** tokenEnd, in t digits)
150 {
151 if (end - start < digits)
152 return false;
153 for (int i = 0; i < digits; ++i) {
154 Char c = *start++;
155 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
156 return false;
157 }
158 *tokenEnd = start;
159 return true;
160 }
161
162 template<typename Char>
163 bool parseStringToken(const Char* start, const Char* end, const Char** tokenEnd)
164 {
165 while (start < end) {
166 Char c = *start++;
167 if ('\\' == c) {
168 if (start == end)
169 return false;
170 c = *start++;
171 // Make sure the escaped char is valid.
172 switch (c) {
173 case 'x':
174 if (!readHexDigits(start, end, &start, 2))
175 return false;
176 break;
177 case 'u':
178 if (!readHexDigits(start, end, &start, 4))
179 return false;
180 break;
181 case '\\':
182 case '/':
183 case 'b':
184 case 'f':
185 case 'n':
186 case 'r':
187 case 't':
188 case 'v':
189 case '"':
190 break;
191 default:
192 return false;
193 }
194 } else if ('"' == c) {
195 *tokenEnd = start;
196 return true;
197 }
198 }
199 return false;
200 }
201
202 template<typename Char>
203 bool skipComment(const Char* start, const Char* end, const Char** commentEnd)
204 {
205 if (start == end)
206 return false;
207
208 if (*start != '/' || start + 1 >= end)
209 return false;
210 ++start;
211
212 if (*start == '/') {
213 // Single line comment, read to newline.
214 for (++start; start < end; ++start) {
215 if (*start == '\n' || *start == '\r') {
216 *commentEnd = start + 1;
217 return true;
218 }
219 }
220 *commentEnd = end;
221 // Comment reaches end-of-input, which is fine.
222 return true;
223 }
224
225 if (*start == '*') {
226 Char previous = '\0';
227 // Block comment, read until end marker.
228 for (++start; start < end; previous = *start++) {
229 if (previous == '*' && *start == '/') {
230 *commentEnd = start + 1;
231 return true;
232 }
233 }
234 // Block comment must close before end-of-input.
235 return false;
236 }
237
238 return false;
239 }
240
241 template<typename Char>
242 void skipWhitespaceAndComments(const Char* start, const Char* end, const Char** whitespaceEnd)
243 {
244 while (start < end) {
245 if (isSpaceOrNewLine(*start)) {
246 ++start;
247 } else if (*start == '/') {
248 const Char* commentEnd;
249 if (!skipComment(start, end, &commentEnd))
250 break;
251 start = commentEnd;
252 } else {
253 break;
254 }
255 }
256 *whitespaceEnd = start;
257 }
258
259 template<typename Char>
260 Token parseToken(const Char* start, const Char* end, const Char** tokenStart, co nst Char** tokenEnd)
261 {
262 skipWhitespaceAndComments(start, end, tokenStart);
263 start = *tokenStart;
264
265 if (start == end)
266 return InvalidToken;
267
268 switch (*start) {
269 case 'n':
270 if (parseConstToken(start, end, tokenEnd, nullString))
271 return NullToken;
272 break;
273 case 't':
274 if (parseConstToken(start, end, tokenEnd, trueString))
275 return BoolTrue;
276 break;
277 case 'f':
278 if (parseConstToken(start, end, tokenEnd, falseString))
279 return BoolFalse;
280 break;
281 case '[':
282 *tokenEnd = start + 1;
283 return ArrayBegin;
284 case ']':
285 *tokenEnd = start + 1;
286 return ArrayEnd;
287 case ',':
288 *tokenEnd = start + 1;
289 return ListSeparator;
290 case '{':
291 *tokenEnd = start + 1;
292 return ObjectBegin;
293 case '}':
294 *tokenEnd = start + 1;
295 return ObjectEnd;
296 case ':':
297 *tokenEnd = start + 1;
298 return ObjectPairSeparator;
299 case '0':
300 case '1':
301 case '2':
302 case '3':
303 case '4':
304 case '5':
305 case '6':
306 case '7':
307 case '8':
308 case '9':
309 case '-':
310 if (parseNumberToken(start, end, tokenEnd))
311 return Number;
312 break;
313 case '"':
314 if (parseStringToken(start + 1, end, tokenEnd))
315 return StringLiteral;
316 break;
317 }
318 return InvalidToken;
319 }
320
321 template<typename Char>
322 int hexToInt(Char c)
323 {
324 if ('0' <= c && c <= '9')
325 return c - '0';
326 if ('A' <= c && c <= 'F')
327 return c - 'A' + 10;
328 if ('a' <= c && c <= 'f')
329 return c - 'a' + 10;
330 DCHECK(false);
331 return 0;
332 }
333
334 template<typename Char>
335 bool decodeString(const Char* start, const Char* end, StringBuilder* output)
336 {
337 while (start < end) {
338 uint16_t c = *start++;
339 if ('\\' != c) {
340 output->append(c);
341 continue;
342 }
343 if (start == end)
344 return false;
345 c = *start++;
346
347 if (c == 'x') {
348 // \x is not supported.
349 return false;
350 }
351
352 switch (c) {
353 case '"':
354 case '/':
355 case '\\':
356 break;
357 case 'b':
358 c = '\b';
359 break;
360 case 'f':
361 c = '\f';
362 break;
363 case 'n':
364 c = '\n';
365 break;
366 case 'r':
367 c = '\r';
368 break;
369 case 't':
370 c = '\t';
371 break;
372 case 'v':
373 c = '\v';
374 break;
375 case 'u':
376 c = (hexToInt(*start) << 12) +
377 (hexToInt(*(start + 1)) << 8) +
378 (hexToInt(*(start + 2)) << 4) +
379 hexToInt(*(start + 3));
380 start += 4;
381 break;
382 default:
383 return false;
384 }
385 output->append(c);
386 }
387 return true;
388 }
389
390 template<typename Char>
391 bool decodeString(const Char* start, const Char* end, String* output)
392 {
393 if (start == end) {
394 *output = "";
395 return true;
396 }
397 if (start > end)
398 return false;
399 StringBuilder buffer;
400 StringUtil::builderReserve(buffer, end - start);
401 if (!decodeString(start, end, &buffer))
402 return false;
403 *output = buffer.toString();
404 return true;
405 }
406
407 template<typename Char>
408 std::unique_ptr<Value> buildValue(const Char* start, const Char* end, const Char ** valueTokenEnd, int depth)
409 {
410 if (depth > stackLimit)
411 return nullptr;
412
413 std::unique_ptr<Value> result;
414 const Char* tokenStart;
415 const Char* tokenEnd;
416 Token token = parseToken(start, end, &tokenStart, &tokenEnd);
417 switch (token) {
418 case InvalidToken:
419 return nullptr;
420 case NullToken:
421 result = Value::null();
422 break;
423 case BoolTrue:
424 result = FundamentalValue::create(true);
425 break;
426 case BoolFalse:
427 result = FundamentalValue::create(false);
428 break;
429 case Number: {
430 bool ok;
431 double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok );
432 if (!ok)
433 return nullptr;
434 int number = static_cast<int>(value);
435 if (number == value)
436 result = FundamentalValue::create(number);
437 else
438 result = FundamentalValue::create(value);
439 break;
440 }
441 case StringLiteral: {
442 String value;
443 bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value);
444 if (!ok)
445 return nullptr;
446 result = StringValue::create(value);
447 break;
448 }
449 case ArrayBegin: {
450 std::unique_ptr<ListValue> array = ListValue::create();
451 start = tokenEnd;
452 token = parseToken(start, end, &tokenStart, &tokenEnd);
453 while (token != ArrayEnd) {
454 std::unique_ptr<Value> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
455 if (!arrayNode)
456 return nullptr;
457 array->pushValue(std::move(arrayNode));
458
459 // After a list value, we expect a comma or the end of the list.
460 start = tokenEnd;
461 token = parseToken(start, end, &tokenStart, &tokenEnd);
462 if (token == ListSeparator) {
463 start = tokenEnd;
464 token = parseToken(start, end, &tokenStart, &tokenEnd);
465 if (token == ArrayEnd)
466 return nullptr;
467 } else if (token != ArrayEnd) {
468 // Unexpected value after list value. Bail out.
469 return nullptr;
470 }
471 }
472 if (token != ArrayEnd)
473 return nullptr;
474 result = std::move(array);
475 break;
476 }
477 case ObjectBegin: {
478 std::unique_ptr<DictionaryValue> object = DictionaryValue::create();
479 start = tokenEnd;
480 token = parseToken(start, end, &tokenStart, &tokenEnd);
481 while (token != ObjectEnd) {
482 if (token != StringLiteral)
483 return nullptr;
484 String key;
485 if (!decodeString(tokenStart + 1, tokenEnd - 1, &key))
486 return nullptr;
487 start = tokenEnd;
488
489 token = parseToken(start, end, &tokenStart, &tokenEnd);
490 if (token != ObjectPairSeparator)
491 return nullptr;
492 start = tokenEnd;
493
494 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, dep th + 1);
495 if (!value)
496 return nullptr;
497 object->setValue(key, std::move(value));
498 start = tokenEnd;
499
500 // After a key/value pair, we expect a comma or the end of the
501 // object.
502 token = parseToken(start, end, &tokenStart, &tokenEnd);
503 if (token == ListSeparator) {
504 start = tokenEnd;
505 token = parseToken(start, end, &tokenStart, &tokenEnd);
506 if (token == ObjectEnd)
507 return nullptr;
508 } else if (token != ObjectEnd) {
509 // Unexpected value after last object value. Bail out.
510 return nullptr;
511 }
512 }
513 if (token != ObjectEnd)
514 return nullptr;
515 result = std::move(object);
516 break;
517 }
518
519 default:
520 // We got a token that's not a value.
521 return nullptr;
522 }
523
524 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd);
525 return result;
526 }
527
528 template<typename Char>
529 std::unique_ptr<Value> parseJSONInternal(const Char* start, unsigned length)
530 {
531 const Char* end = start + length;
532 const Char *tokenEnd;
533 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0);
534 if (!value || tokenEnd != end)
535 return nullptr;
536 return value;
537 }
538
539 } // anonymous namespace
540
541 std::unique_ptr<Value> parseJSON(const uint16_t* characters, unsigned length)
542 {
543 return parseJSONInternal<uint16_t>(characters, length);
544 }
545
546 std::unique_ptr<Value> parseJSON(const uint8_t* characters, unsigned length)
547 {
548 return parseJSONInternal<uint8_t>(characters, length);
549 }
550
551 {% for namespace in config.protocol.namespace %}
552 } // namespace {{namespace}}
553 {% endfor %}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698