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

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

Issue 2282283002: [DevTools] Prepare inspector_protocol build to move. (Closed)
Patch Set: NOTREACHED Created 4 years, 3 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
(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 c = *start++;
169 // Make sure the escaped char is valid.
170 switch (c) {
171 case 'x':
172 if (!readHexDigits(start, end, &start, 2))
173 return false;
174 break;
175 case 'u':
176 if (!readHexDigits(start, end, &start, 4))
177 return false;
178 break;
179 case '\\':
180 case '/':
181 case 'b':
182 case 'f':
183 case 'n':
184 case 'r':
185 case 't':
186 case 'v':
187 case '"':
188 break;
189 default:
190 return false;
191 }
192 } else if ('"' == c) {
193 *tokenEnd = start;
194 return true;
195 }
196 }
197 return false;
198 }
199
200 template<typename Char>
201 bool skipComment(const Char* start, const Char* end, const Char** commentEnd)
202 {
203 if (start == end)
204 return false;
205
206 if (*start != '/' || start + 1 >= end)
207 return false;
208 ++start;
209
210 if (*start == '/') {
211 // Single line comment, read to newline.
212 for (++start; start < end; ++start) {
213 if (*start == '\n' || *start == '\r') {
214 *commentEnd = start + 1;
215 return true;
216 }
217 }
218 *commentEnd = end;
219 // Comment reaches end-of-input, which is fine.
220 return true;
221 }
222
223 if (*start == '*') {
224 Char previous = '\0';
225 // Block comment, read until end marker.
226 for (++start; start < end; previous = *start++) {
227 if (previous == '*' && *start == '/') {
228 *commentEnd = start + 1;
229 return true;
230 }
231 }
232 // Block comment must close before end-of-input.
233 return false;
234 }
235
236 return false;
237 }
238
239 template<typename Char>
240 void skipWhitespaceAndComments(const Char* start, const Char* end, const Char** whitespaceEnd)
241 {
242 while (start < end) {
243 if (isSpaceOrNewLine(*start)) {
244 ++start;
245 } else if (*start == '/') {
246 const Char* commentEnd;
247 if (!skipComment(start, end, &commentEnd))
248 break;
249 start = commentEnd;
250 } else {
251 break;
252 }
253 }
254 *whitespaceEnd = start;
255 }
256
257 template<typename Char>
258 Token parseToken(const Char* start, const Char* end, const Char** tokenStart, co nst Char** tokenEnd)
259 {
260 skipWhitespaceAndComments(start, end, tokenStart);
261 start = *tokenStart;
262
263 if (start == end)
264 return InvalidToken;
265
266 switch (*start) {
267 case 'n':
268 if (parseConstToken(start, end, tokenEnd, nullString))
269 return NullToken;
270 break;
271 case 't':
272 if (parseConstToken(start, end, tokenEnd, trueString))
273 return BoolTrue;
274 break;
275 case 'f':
276 if (parseConstToken(start, end, tokenEnd, falseString))
277 return BoolFalse;
278 break;
279 case '[':
280 *tokenEnd = start + 1;
281 return ArrayBegin;
282 case ']':
283 *tokenEnd = start + 1;
284 return ArrayEnd;
285 case ',':
286 *tokenEnd = start + 1;
287 return ListSeparator;
288 case '{':
289 *tokenEnd = start + 1;
290 return ObjectBegin;
291 case '}':
292 *tokenEnd = start + 1;
293 return ObjectEnd;
294 case ':':
295 *tokenEnd = start + 1;
296 return ObjectPairSeparator;
297 case '0':
298 case '1':
299 case '2':
300 case '3':
301 case '4':
302 case '5':
303 case '6':
304 case '7':
305 case '8':
306 case '9':
307 case '-':
308 if (parseNumberToken(start, end, tokenEnd))
309 return Number;
310 break;
311 case '"':
312 if (parseStringToken(start + 1, end, tokenEnd))
313 return StringLiteral;
314 break;
315 }
316 return InvalidToken;
317 }
318
319 template<typename Char>
320 int hexToInt(Char c)
321 {
322 if ('0' <= c && c <= '9')
323 return c - '0';
324 if ('A' <= c && c <= 'F')
325 return c - 'A' + 10;
326 if ('a' <= c && c <= 'f')
327 return c - 'a' + 10;
328 NOTREACHED();
329 return 0;
330 }
331
332 template<typename Char>
333 bool decodeString(const Char* start, const Char* end, StringBuilder* output)
334 {
335 while (start < end) {
336 uint16_t c = *start++;
337 if ('\\' != c) {
338 output->append(c);
339 continue;
340 }
341 c = *start++;
342
343 if (c == 'x') {
344 // \x is not supported.
345 return false;
346 }
347
348 switch (c) {
349 case '"':
350 case '/':
351 case '\\':
352 break;
353 case 'b':
354 c = '\b';
355 break;
356 case 'f':
357 c = '\f';
358 break;
359 case 'n':
360 c = '\n';
361 break;
362 case 'r':
363 c = '\r';
364 break;
365 case 't':
366 c = '\t';
367 break;
368 case 'v':
369 c = '\v';
370 break;
371 case 'u':
372 c = (hexToInt(*start) << 12) +
373 (hexToInt(*(start + 1)) << 8) +
374 (hexToInt(*(start + 2)) << 4) +
375 hexToInt(*(start + 3));
376 start += 4;
377 break;
378 default:
379 return false;
380 }
381 output->append(c);
382 }
383 return true;
384 }
385
386 template<typename Char>
387 bool decodeString(const Char* start, const Char* end, String* output)
388 {
389 if (start == end) {
390 *output = "";
391 return true;
392 }
393 if (start > end)
394 return false;
395 StringBuilder buffer;
396 StringUtil::builderReserve(buffer, end - start);
397 if (!decodeString(start, end, &buffer))
398 return false;
399 *output = buffer.toString();
400 return true;
401 }
402
403 template<typename Char>
404 std::unique_ptr<Value> buildValue(const Char* start, const Char* end, const Char ** valueTokenEnd, int depth)
405 {
406 if (depth > stackLimit)
407 return nullptr;
408
409 std::unique_ptr<Value> result;
410 const Char* tokenStart;
411 const Char* tokenEnd;
412 Token token = parseToken(start, end, &tokenStart, &tokenEnd);
413 switch (token) {
414 case InvalidToken:
415 return nullptr;
416 case NullToken:
417 result = Value::null();
418 break;
419 case BoolTrue:
420 result = FundamentalValue::create(true);
421 break;
422 case BoolFalse:
423 result = FundamentalValue::create(false);
424 break;
425 case Number: {
426 bool ok;
427 double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok );
428 if (!ok)
429 return nullptr;
430 int number = static_cast<int>(value);
431 if (number == value)
432 result = FundamentalValue::create(number);
433 else
434 result = FundamentalValue::create(value);
435 break;
436 }
437 case StringLiteral: {
438 String value;
439 bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value);
440 if (!ok)
441 return nullptr;
442 result = StringValue::create(value);
443 break;
444 }
445 case ArrayBegin: {
446 std::unique_ptr<ListValue> array = ListValue::create();
447 start = tokenEnd;
448 token = parseToken(start, end, &tokenStart, &tokenEnd);
449 while (token != ArrayEnd) {
450 std::unique_ptr<Value> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
451 if (!arrayNode)
452 return nullptr;
453 array->pushValue(std::move(arrayNode));
454
455 // After a list value, we expect a comma or the end of the list.
456 start = tokenEnd;
457 token = parseToken(start, end, &tokenStart, &tokenEnd);
458 if (token == ListSeparator) {
459 start = tokenEnd;
460 token = parseToken(start, end, &tokenStart, &tokenEnd);
461 if (token == ArrayEnd)
462 return nullptr;
463 } else if (token != ArrayEnd) {
464 // Unexpected value after list value. Bail out.
465 return nullptr;
466 }
467 }
468 if (token != ArrayEnd)
469 return nullptr;
470 result = std::move(array);
471 break;
472 }
473 case ObjectBegin: {
474 std::unique_ptr<DictionaryValue> object = DictionaryValue::create();
475 start = tokenEnd;
476 token = parseToken(start, end, &tokenStart, &tokenEnd);
477 while (token != ObjectEnd) {
478 if (token != StringLiteral)
479 return nullptr;
480 String key;
481 if (!decodeString(tokenStart + 1, tokenEnd - 1, &key))
482 return nullptr;
483 start = tokenEnd;
484
485 token = parseToken(start, end, &tokenStart, &tokenEnd);
486 if (token != ObjectPairSeparator)
487 return nullptr;
488 start = tokenEnd;
489
490 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, dep th + 1);
491 if (!value)
492 return nullptr;
493 object->setValue(key, std::move(value));
494 start = tokenEnd;
495
496 // After a key/value pair, we expect a comma or the end of the
497 // object.
498 token = parseToken(start, end, &tokenStart, &tokenEnd);
499 if (token == ListSeparator) {
500 start = tokenEnd;
501 token = parseToken(start, end, &tokenStart, &tokenEnd);
502 if (token == ObjectEnd)
503 return nullptr;
504 } else if (token != ObjectEnd) {
505 // Unexpected value after last object value. Bail out.
506 return nullptr;
507 }
508 }
509 if (token != ObjectEnd)
510 return nullptr;
511 result = std::move(object);
512 break;
513 }
514
515 default:
516 // We got a token that's not a value.
517 return nullptr;
518 }
519
520 skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd);
521 return result;
522 }
523
524 template<typename Char>
525 std::unique_ptr<Value> parseJSONInternal(const Char* start, unsigned length)
526 {
527 const Char* end = start + length;
528 const Char *tokenEnd;
529 std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0);
530 if (!value || tokenEnd != end)
531 return nullptr;
532 return value;
533 }
534
535 } // anonymous namespace
536
537 std::unique_ptr<Value> parseJSON(const uint16_t* characters, unsigned length)
538 {
539 return parseJSONInternal<uint16_t>(characters, length);
540 }
541
542 std::unique_ptr<Value> parseJSON(const uint8_t* characters, unsigned length)
543 {
544 return parseJSONInternal<uint8_t>(characters, length);
545 }
546
547 {% for namespace in config.protocol.namespace %}
548 } // namespace {{namespace}}
549 {% endfor %}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698