]> git.saurik.com Git - apple/javascriptcore.git/blame - inspector/InspectorValues.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / inspector / InspectorValues.cpp
CommitLineData
81345200
A
1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
ed1e77d3 3 * Copyright (C) 2014 University of Washington. All rights reserved.
81345200
A
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "config.h"
33#include "InspectorValues.h"
34
35#include <wtf/DecimalNumber.h>
36#include <wtf/dtoa.h>
37#include <wtf/text/StringBuilder.h>
38
39namespace Inspector {
40
41namespace {
42
43static const int stackLimit = 1000;
44
45enum Token {
46 OBJECT_BEGIN,
47 OBJECT_END,
48 ARRAY_BEGIN,
49 ARRAY_END,
50 STRING,
51 NUMBER,
52 BOOL_TRUE,
53 BOOL_FALSE,
54 NULL_TOKEN,
55 LIST_SEPARATOR,
56 OBJECT_PAIR_SEPARATOR,
57 INVALID_TOKEN,
58};
59
60const char* const nullString = "null";
61const char* const trueString = "true";
62const char* const falseString = "false";
63
64bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token)
65{
66 while (start < end && *token != '\0' && *start++ == *token++) { }
ed1e77d3 67
81345200
A
68 if (*token != '\0')
69 return false;
ed1e77d3 70
81345200
A
71 *tokenEnd = start;
72 return true;
73}
74
75bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros)
76{
77 if (start == end)
78 return false;
ed1e77d3 79
81345200
A
80 bool haveLeadingZero = '0' == *start;
81 int length = 0;
82 while (start < end && '0' <= *start && *start <= '9') {
83 ++start;
84 ++length;
85 }
ed1e77d3 86
81345200
A
87 if (!length)
88 return false;
ed1e77d3 89
81345200
A
90 if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
91 return false;
ed1e77d3 92
81345200
A
93 *tokenEnd = start;
94 return true;
95}
96
97bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
98{
99 // We just grab the number here. We validate the size in DecodeNumber.
100 // According to RFC4627, a valid number is: [minus] int [frac] [exp]
101 if (start == end)
102 return false;
ed1e77d3 103
81345200
A
104 UChar c = *start;
105 if ('-' == c)
106 ++start;
107
108 if (!readInt(start, end, &start, false))
109 return false;
ed1e77d3 110
81345200
A
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
148bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits)
149{
150 if (end - start < digits)
151 return false;
ed1e77d3 152
81345200
A
153 for (int i = 0; i < digits; ++i) {
154 UChar c = *start++;
155 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
156 return false;
157 }
ed1e77d3 158
81345200
A
159 *tokenEnd = start;
160 return true;
161}
162
163bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
164{
165 while (start < end) {
166 UChar 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 }
ed1e77d3 197
81345200
A
198 return false;
199}
200
201Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart, const UChar** tokenEnd)
202{
203 while (start < end && isSpaceOrNewline(*start))
204 ++start;
205
206 if (start == end)
207 return INVALID_TOKEN;
208
209 *tokenStart = start;
210
211 switch (*start) {
212 case 'n':
213 if (parseConstToken(start, end, tokenEnd, nullString))
214 return NULL_TOKEN;
215 break;
216 case 't':
217 if (parseConstToken(start, end, tokenEnd, trueString))
218 return BOOL_TRUE;
219 break;
220 case 'f':
221 if (parseConstToken(start, end, tokenEnd, falseString))
222 return BOOL_FALSE;
223 break;
224 case '[':
225 *tokenEnd = start + 1;
226 return ARRAY_BEGIN;
227 case ']':
228 *tokenEnd = start + 1;
229 return ARRAY_END;
230 case ',':
231 *tokenEnd = start + 1;
232 return LIST_SEPARATOR;
233 case '{':
234 *tokenEnd = start + 1;
235 return OBJECT_BEGIN;
236 case '}':
237 *tokenEnd = start + 1;
238 return OBJECT_END;
239 case ':':
240 *tokenEnd = start + 1;
241 return OBJECT_PAIR_SEPARATOR;
242 case '0':
243 case '1':
244 case '2':
245 case '3':
246 case '4':
247 case '5':
248 case '6':
249 case '7':
250 case '8':
251 case '9':
252 case '-':
253 if (parseNumberToken(start, end, tokenEnd))
254 return NUMBER;
255 break;
256 case '"':
257 if (parseStringToken(start + 1, end, tokenEnd))
258 return STRING;
259 break;
260 }
ed1e77d3 261
81345200
A
262 return INVALID_TOKEN;
263}
264
265inline int hexToInt(UChar c)
266{
267 if ('0' <= c && c <= '9')
268 return c - '0';
269 if ('A' <= c && c <= 'F')
270 return c - 'A' + 10;
271 if ('a' <= c && c <= 'f')
272 return c - 'a' + 10;
ed1e77d3 273
81345200
A
274 ASSERT_NOT_REACHED();
275 return 0;
276}
277
ed1e77d3 278bool decodeString(const UChar* start, const UChar* end, StringBuilder& output)
81345200
A
279{
280 while (start < end) {
281 UChar c = *start++;
282 if ('\\' != c) {
ed1e77d3 283 output.append(c);
81345200
A
284 continue;
285 }
286 c = *start++;
287 switch (c) {
288 case '"':
289 case '/':
290 case '\\':
291 break;
292 case 'b':
293 c = '\b';
294 break;
295 case 'f':
296 c = '\f';
297 break;
298 case 'n':
299 c = '\n';
300 break;
301 case 'r':
302 c = '\r';
303 break;
304 case 't':
305 c = '\t';
306 break;
307 case 'v':
308 c = '\v';
309 break;
310 case 'x':
311 c = (hexToInt(*start) << 4) +
312 hexToInt(*(start + 1));
313 start += 2;
314 break;
315 case 'u':
316 c = (hexToInt(*start) << 12) +
317 (hexToInt(*(start + 1)) << 8) +
318 (hexToInt(*(start + 2)) << 4) +
319 hexToInt(*(start + 3));
320 start += 4;
321 break;
322 default:
323 return false;
324 }
ed1e77d3 325 output.append(c);
81345200 326 }
ed1e77d3 327
81345200
A
328 return true;
329}
330
ed1e77d3 331bool decodeString(const UChar* start, const UChar* end, String& output)
81345200
A
332{
333 if (start == end) {
ed1e77d3 334 output = emptyString();
81345200
A
335 return true;
336 }
ed1e77d3 337
81345200
A
338 if (start > end)
339 return false;
ed1e77d3 340
81345200
A
341 StringBuilder buffer;
342 buffer.reserveCapacity(end - start);
ed1e77d3 343 if (!decodeString(start, end, buffer))
81345200 344 return false;
ed1e77d3
A
345
346 output = buffer.toString();
81345200
A
347 return true;
348}
349
ed1e77d3 350RefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth)
81345200
A
351{
352 if (depth > stackLimit)
353 return nullptr;
354
355 RefPtr<InspectorValue> result;
356 const UChar* tokenStart;
357 const UChar* tokenEnd;
358 Token token = parseToken(start, end, &tokenStart, &tokenEnd);
359 switch (token) {
360 case INVALID_TOKEN:
361 return nullptr;
362 case NULL_TOKEN:
363 result = InspectorValue::null();
364 break;
365 case BOOL_TRUE:
366 result = InspectorBasicValue::create(true);
367 break;
368 case BOOL_FALSE:
369 result = InspectorBasicValue::create(false);
370 break;
371 case NUMBER: {
372 bool ok;
373 double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok);
374 if (!ok)
375 return nullptr;
376 result = InspectorBasicValue::create(value);
377 break;
378 }
379 case STRING: {
380 String value;
ed1e77d3 381 bool ok = decodeString(tokenStart + 1, tokenEnd - 1, value);
81345200
A
382 if (!ok)
383 return nullptr;
384 result = InspectorString::create(value);
385 break;
386 }
387 case ARRAY_BEGIN: {
ed1e77d3 388 Ref<InspectorArray> array = InspectorArray::create();
81345200
A
389 start = tokenEnd;
390 token = parseToken(start, end, &tokenStart, &tokenEnd);
391 while (token != ARRAY_END) {
392 RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
393 if (!arrayNode)
394 return nullptr;
ed1e77d3 395 array->pushValue(WTF::move(arrayNode));
81345200
A
396
397 // After a list value, we expect a comma or the end of the list.
398 start = tokenEnd;
399 token = parseToken(start, end, &tokenStart, &tokenEnd);
400 if (token == LIST_SEPARATOR) {
401 start = tokenEnd;
402 token = parseToken(start, end, &tokenStart, &tokenEnd);
403 if (token == ARRAY_END)
404 return nullptr;
405 } else if (token != ARRAY_END) {
406 // Unexpected value after list value. Bail out.
407 return nullptr;
408 }
409 }
410 if (token != ARRAY_END)
411 return nullptr;
ed1e77d3 412 result = WTF::move(array);
81345200
A
413 break;
414 }
415 case OBJECT_BEGIN: {
ed1e77d3 416 Ref<InspectorObject> object = InspectorObject::create();
81345200
A
417 start = tokenEnd;
418 token = parseToken(start, end, &tokenStart, &tokenEnd);
419 while (token != OBJECT_END) {
420 if (token != STRING)
421 return nullptr;
422 String key;
ed1e77d3 423 if (!decodeString(tokenStart + 1, tokenEnd - 1, key))
81345200
A
424 return nullptr;
425 start = tokenEnd;
426
427 token = parseToken(start, end, &tokenStart, &tokenEnd);
428 if (token != OBJECT_PAIR_SEPARATOR)
429 return nullptr;
430 start = tokenEnd;
431
432 RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1);
433 if (!value)
434 return nullptr;
ed1e77d3 435 object->setValue(key, WTF::move(value));
81345200
A
436 start = tokenEnd;
437
438 // After a key/value pair, we expect a comma or the end of the
439 // object.
440 token = parseToken(start, end, &tokenStart, &tokenEnd);
441 if (token == LIST_SEPARATOR) {
442 start = tokenEnd;
443 token = parseToken(start, end, &tokenStart, &tokenEnd);
444 if (token == OBJECT_END)
445 return nullptr;
446 } else if (token != OBJECT_END) {
447 // Unexpected value after last object value. Bail out.
448 return nullptr;
449 }
450 }
451 if (token != OBJECT_END)
452 return nullptr;
ed1e77d3 453 result = WTF::move(object);
81345200
A
454 break;
455 }
456
457 default:
458 // We got a token that's not a value.
459 return nullptr;
460 }
461 *valueTokenEnd = tokenEnd;
462 return result.release();
463}
464
ed1e77d3 465inline bool escapeChar(UChar c, StringBuilder& dst)
81345200
A
466{
467 switch (c) {
ed1e77d3
A
468 case '\b': dst.appendLiteral("\\b"); break;
469 case '\f': dst.appendLiteral("\\f"); break;
470 case '\n': dst.appendLiteral("\\n"); break;
471 case '\r': dst.appendLiteral("\\r"); break;
472 case '\t': dst.appendLiteral("\\t"); break;
473 case '\\': dst.appendLiteral("\\\\"); break;
474 case '"': dst.appendLiteral("\\\""); break;
81345200
A
475 default:
476 return false;
477 }
478 return true;
479}
480
ed1e77d3 481inline void doubleQuoteString(const String& str, StringBuilder& dst)
81345200 482{
ed1e77d3 483 dst.append('"');
81345200
A
484 for (unsigned i = 0; i < str.length(); ++i) {
485 UChar c = str[i];
486 if (!escapeChar(c, dst)) {
487 if (c < 32 || c > 126 || c == '<' || c == '>') {
488 // 1. Escaping <, > to prevent script execution.
489 // 2. Technically, we could also pass through c > 126 as UTF8, but this
490 // is also optional. It would also be a pain to implement here.
ed1e77d3 491 dst.append(String::format("\\u%04X", c));
81345200 492 } else
ed1e77d3 493 dst.append(c);
81345200
A
494 }
495 }
ed1e77d3 496 dst.append('"');
81345200
A
497}
498
499} // anonymous namespace
500
ed1e77d3 501bool InspectorValue::asBoolean(bool&) const
81345200
A
502{
503 return false;
504}
505
ed1e77d3 506bool InspectorValue::asDouble(double&) const
81345200
A
507{
508 return false;
509}
510
ed1e77d3 511bool InspectorValue::asDouble(float&) const
81345200
A
512{
513 return false;
514}
515
ed1e77d3 516bool InspectorValue::asInteger(int&) const
81345200
A
517{
518 return false;
519}
520
ed1e77d3 521bool InspectorValue::asInteger(unsigned&) const
81345200
A
522{
523 return false;
524}
525
ed1e77d3 526bool InspectorValue::asInteger(long&) const
81345200
A
527{
528 return false;
529}
530
ed1e77d3 531bool InspectorValue::asInteger(long long&) const
81345200
A
532{
533 return false;
534}
535
ed1e77d3 536bool InspectorValue::asInteger(unsigned long&) const
81345200
A
537{
538 return false;
539}
540
ed1e77d3 541bool InspectorValue::asInteger(unsigned long long&) const
81345200
A
542{
543 return false;
544}
545
ed1e77d3 546bool InspectorValue::asString(String&) const
81345200
A
547{
548 return false;
549}
550
ed1e77d3 551bool InspectorValue::asValue(RefPtr<InspectorValue>& output)
81345200 552{
ed1e77d3 553 output = this;
81345200
A
554 return true;
555}
556
ed1e77d3 557bool InspectorValue::asObject(RefPtr<InspectorObject>&)
81345200
A
558{
559 return false;
560}
561
ed1e77d3 562bool InspectorValue::asArray(RefPtr<InspectorArray>&)
81345200
A
563{
564 return false;
565}
566
ed1e77d3 567bool InspectorValue::parseJSON(const String& jsonInput, RefPtr<InspectorValue>& output)
81345200
A
568{
569 // FIXME: This whole file should just use StringView instead of UChar/length and avoid upconverting.
ed1e77d3 570 auto characters = StringView(jsonInput).upconvertedCharacters();
81345200 571 const UChar* start = characters;
ed1e77d3 572 const UChar* end = start + jsonInput.length();
81345200 573 const UChar* tokenEnd;
ed1e77d3
A
574 RefPtr<InspectorValue> result = buildValue(start, end, &tokenEnd, 0);
575 if (!result || tokenEnd != end)
576 return false;
577
578 output = result.release();
579 return true;
81345200
A
580}
581
582String InspectorValue::toJSONString() const
583{
584 StringBuilder result;
585 result.reserveCapacity(512);
ed1e77d3 586 writeJSON(result);
81345200
A
587 return result.toString();
588}
589
ed1e77d3 590void InspectorValue::writeJSON(StringBuilder& output) const
81345200 591{
ed1e77d3
A
592 ASSERT(m_type == Type::Null);
593
594 output.appendLiteral("null");
81345200
A
595}
596
ed1e77d3 597bool InspectorBasicValue::asBoolean(bool& output) const
81345200 598{
ed1e77d3 599 if (type() != Type::Boolean)
81345200 600 return false;
ed1e77d3
A
601
602 output = m_booleanValue;
81345200
A
603 return true;
604}
605
ed1e77d3 606bool InspectorBasicValue::asDouble(double& output) const
81345200 607{
ed1e77d3 608 if (type() != Type::Double)
81345200 609 return false;
ed1e77d3
A
610
611 output = m_doubleValue;
81345200
A
612 return true;
613}
614
ed1e77d3 615bool InspectorBasicValue::asDouble(float& output) const
81345200 616{
ed1e77d3 617 if (type() != Type::Double)
81345200 618 return false;
ed1e77d3
A
619
620 output = static_cast<float>(m_doubleValue);
81345200
A
621 return true;
622}
623
ed1e77d3 624bool InspectorBasicValue::asInteger(int& output) const
81345200 625{
ed1e77d3 626 if (type() != Type::Integer && type() != Type::Double)
81345200 627 return false;
ed1e77d3
A
628
629 output = static_cast<int>(m_doubleValue);
81345200
A
630 return true;
631}
632
ed1e77d3 633bool InspectorBasicValue::asInteger(unsigned& output) const
81345200 634{
ed1e77d3 635 if (type() != Type::Integer && type() != Type::Double)
81345200 636 return false;
ed1e77d3
A
637
638 output = static_cast<unsigned>(m_doubleValue);
81345200
A
639 return true;
640}
641
ed1e77d3 642bool InspectorBasicValue::asInteger(long& output) const
81345200 643{
ed1e77d3 644 if (type() != Type::Integer && type() != Type::Double)
81345200 645 return false;
ed1e77d3
A
646
647 output = static_cast<long>(m_doubleValue);
81345200
A
648 return true;
649}
650
ed1e77d3 651bool InspectorBasicValue::asInteger(long long& output) const
81345200 652{
ed1e77d3 653 if (type() != Type::Integer && type() != Type::Double)
81345200 654 return false;
ed1e77d3
A
655
656 output = static_cast<long long>(m_doubleValue);
81345200
A
657 return true;
658}
659
ed1e77d3 660bool InspectorBasicValue::asInteger(unsigned long& output) const
81345200 661{
ed1e77d3 662 if (type() != Type::Integer && type() != Type::Double)
81345200 663 return false;
ed1e77d3
A
664
665 output = static_cast<unsigned long>(m_doubleValue);
81345200
A
666 return true;
667}
668
ed1e77d3 669bool InspectorBasicValue::asInteger(unsigned long long& output) const
81345200 670{
ed1e77d3 671 if (type() != Type::Integer && type() != Type::Double)
81345200 672 return false;
ed1e77d3
A
673
674 output = static_cast<unsigned long long>(m_doubleValue);
81345200
A
675 return true;
676}
677
ed1e77d3 678void InspectorBasicValue::writeJSON(StringBuilder& output) const
81345200 679{
ed1e77d3
A
680 ASSERT(type() == Type::Boolean || type() == Type::Double || type() == Type::Integer);
681
682 if (type() == Type::Boolean) {
683 if (m_booleanValue)
684 output.appendLiteral("true");
81345200 685 else
ed1e77d3
A
686 output.appendLiteral("false");
687 } else if (type() == Type::Double || type() == Type::Integer) {
81345200
A
688 NumberToLStringBuffer buffer;
689 if (!std::isfinite(m_doubleValue)) {
ed1e77d3 690 output.appendLiteral("null");
81345200
A
691 return;
692 }
693 DecimalNumber decimal = m_doubleValue;
694 unsigned length = 0;
695 if (decimal.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength) {
696 // Not enough room for decimal. Use exponential format.
697 if (decimal.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength) {
698 // Fallback for an abnormal case if it's too little even for exponential.
ed1e77d3 699 output.appendLiteral("NaN");
81345200
A
700 return;
701 }
702 length = decimal.toStringExponential(buffer, WTF::NumberToStringBufferLength);
703 } else
704 length = decimal.toStringDecimal(buffer, WTF::NumberToStringBufferLength);
ed1e77d3 705 output.append(buffer, length);
81345200
A
706 }
707}
708
ed1e77d3 709bool InspectorString::asString(String& output) const
81345200 710{
ed1e77d3 711 output = m_stringValue;
81345200
A
712 return true;
713}
714
ed1e77d3 715void InspectorString::writeJSON(StringBuilder& output) const
81345200 716{
ed1e77d3 717 ASSERT(type() == Type::String);
81345200
A
718 doubleQuoteString(m_stringValue, output);
719}
720
721InspectorObjectBase::~InspectorObjectBase()
722{
723}
724
ed1e77d3 725bool InspectorObjectBase::asObject(RefPtr<InspectorObject>& output)
81345200
A
726{
727 COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast);
81345200 728
ed1e77d3
A
729 output = static_cast<InspectorObject*>(this);
730 return true;
81345200
A
731}
732
733InspectorObject* InspectorObjectBase::openAccessors()
734{
735 COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast);
ed1e77d3 736
81345200
A
737 return static_cast<InspectorObject*>(this);
738}
739
ed1e77d3 740bool InspectorObjectBase::getBoolean(const String& name, bool& output) const
81345200 741{
ed1e77d3
A
742 RefPtr<InspectorValue> value;
743 if (!getValue(name, value))
81345200 744 return false;
ed1e77d3 745
81345200
A
746 return value->asBoolean(output);
747}
748
ed1e77d3 749bool InspectorObjectBase::getString(const String& name, String& output) const
81345200 750{
ed1e77d3
A
751 RefPtr<InspectorValue> value;
752 if (!getValue(name, value))
81345200 753 return false;
ed1e77d3 754
81345200
A
755 return value->asString(output);
756}
757
ed1e77d3 758bool InspectorObjectBase::getObject(const String& name, RefPtr<InspectorObject>& output) const
81345200 759{
ed1e77d3
A
760 RefPtr<InspectorValue> value;
761 if (!getValue(name, value))
762 return false;
763
764 return value->asObject(output);
81345200
A
765}
766
ed1e77d3 767bool InspectorObjectBase::getArray(const String& name, RefPtr<InspectorArray>& output) const
81345200 768{
ed1e77d3
A
769 RefPtr<InspectorValue> value;
770 if (!getValue(name, value))
771 return false;
772
773 return value->asArray(output);
81345200
A
774}
775
ed1e77d3 776bool InspectorObjectBase::getValue(const String& name, RefPtr<InspectorValue>& output) const
81345200 777{
ed1e77d3
A
778 Dictionary::const_iterator findResult = m_data.find(name);
779 if (findResult == m_data.end())
780 return false;
781
782 output = findResult->value;
783 return true;
81345200
A
784}
785
786void InspectorObjectBase::remove(const String& name)
787{
788 m_data.remove(name);
ed1e77d3 789 m_order.removeFirst(name);
81345200
A
790}
791
ed1e77d3 792void InspectorObjectBase::writeJSON(StringBuilder& output) const
81345200 793{
ed1e77d3 794 output.append('{');
81345200 795 for (size_t i = 0; i < m_order.size(); ++i) {
ed1e77d3
A
796 auto findResult = m_data.find(m_order[i]);
797 ASSERT(findResult != m_data.end());
81345200 798 if (i)
ed1e77d3
A
799 output.append(',');
800 doubleQuoteString(findResult->key, output);
801 output.append(':');
802 findResult->value->writeJSON(output);
81345200 803 }
ed1e77d3 804 output.append('}');
81345200
A
805}
806
807InspectorObjectBase::InspectorObjectBase()
ed1e77d3 808 : InspectorValue(Type::Object)
81345200
A
809 , m_data()
810 , m_order()
811{
812}
813
814InspectorArrayBase::~InspectorArrayBase()
815{
816}
817
ed1e77d3 818bool InspectorArrayBase::asArray(RefPtr<InspectorArray>& output)
81345200
A
819{
820 COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast);
ed1e77d3 821 output = static_cast<InspectorArray*>(this);
81345200
A
822 return true;
823}
824
ed1e77d3 825void InspectorArrayBase::writeJSON(StringBuilder& output) const
81345200 826{
ed1e77d3 827 output.append('[');
81345200
A
828 for (Vector<RefPtr<InspectorValue>>::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
829 if (it != m_data.begin())
ed1e77d3 830 output.append(',');
81345200
A
831 (*it)->writeJSON(output);
832 }
ed1e77d3 833 output.append(']');
81345200
A
834}
835
836InspectorArrayBase::InspectorArrayBase()
ed1e77d3 837 : InspectorValue(Type::Array)
81345200
A
838 , m_data()
839{
840}
841
ed1e77d3 842RefPtr<InspectorValue> InspectorArrayBase::get(size_t index) const
81345200
A
843{
844 ASSERT_WITH_SECURITY_IMPLICATION(index < m_data.size());
845 return m_data[index];
846}
847
ed1e77d3 848Ref<InspectorObject> InspectorObject::create()
81345200 849{
ed1e77d3 850 return adoptRef(*new InspectorObject);
81345200
A
851}
852
ed1e77d3 853Ref<InspectorArray> InspectorArray::create()
81345200 854{
ed1e77d3 855 return adoptRef(*new InspectorArray);
81345200
A
856}
857
ed1e77d3 858Ref<InspectorValue> InspectorValue::null()
81345200 859{
ed1e77d3 860 return adoptRef(*new InspectorValue);
81345200
A
861}
862
ed1e77d3 863Ref<InspectorString> InspectorString::create(const String& value)
81345200 864{
ed1e77d3 865 return adoptRef(*new InspectorString(value));
81345200
A
866}
867
ed1e77d3 868Ref<InspectorString> InspectorString::create(const char* value)
81345200 869{
ed1e77d3 870 return adoptRef(*new InspectorString(value));
81345200
A
871}
872
ed1e77d3 873Ref<InspectorBasicValue> InspectorBasicValue::create(bool value)
81345200 874{
ed1e77d3 875 return adoptRef(*new InspectorBasicValue(value));
81345200
A
876}
877
ed1e77d3 878Ref<InspectorBasicValue> InspectorBasicValue::create(int value)
81345200 879{
ed1e77d3 880 return adoptRef(*new InspectorBasicValue(value));
81345200
A
881}
882
ed1e77d3 883Ref<InspectorBasicValue> InspectorBasicValue::create(double value)
81345200 884{
ed1e77d3 885 return adoptRef(*new InspectorBasicValue(value));
81345200
A
886}
887
888} // namespace Inspector