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