]> git.saurik.com Git - apple/javascriptcore.git/blame - inspector/InspectorValues.cpp
JavaScriptCore-7600.1.4.13.1.tar.gz
[apple/javascriptcore.git] / inspector / InspectorValues.cpp
CommitLineData
81345200
A
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
38namespace Inspector {
39
40namespace {
41
42static const int stackLimit = 1000;
43
44enum 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
59const char* const nullString = "null";
60const char* const trueString = "true";
61const char* const falseString = "false";
62
63bool 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
72bool 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
90bool 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
139bool 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
152bool 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
189Token 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
252inline 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
264bool 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
316bool 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
332PassRefPtr<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
447inline 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
463inline 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
483bool InspectorValue::asBoolean(bool*) const
484{
485 return false;
486}
487
488bool InspectorValue::asNumber(double*) const
489{
490 return false;
491}
492
493bool InspectorValue::asNumber(float*) const
494{
495 return false;
496}
497
498bool InspectorValue::asNumber(int*) const
499{
500 return false;
501}
502
503bool InspectorValue::asNumber(unsigned*) const
504{
505 return false;
506}
507
508bool InspectorValue::asNumber(long*) const
509{
510 return false;
511}
512
513bool InspectorValue::asNumber(long long*) const
514{
515 return false;
516}
517
518bool InspectorValue::asNumber(unsigned long*) const
519{
520 return false;
521}
522
523bool InspectorValue::asNumber(unsigned long long*) const
524{
525 return false;
526}
527
528bool InspectorValue::asString(String*) const
529{
530 return false;
531}
532
533bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
534{
535 *output = this;
536 return true;
537}
538
539bool InspectorValue::asObject(RefPtr<InspectorObject>*)
540{
541 return false;
542}
543
544bool InspectorValue::asArray(RefPtr<InspectorArray>*)
545{
546 return false;
547}
548
549PassRefPtr<InspectorObject> InspectorValue::asObject()
550{
551 return nullptr;
552}
553
554PassRefPtr<InspectorArray> InspectorValue::asArray()
555{
556 return nullptr;
557}
558
559PassRefPtr<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
572String InspectorValue::toJSONString() const
573{
574 StringBuilder result;
575 result.reserveCapacity(512);
576 writeJSON(&result);
577 return result.toString();
578}
579
580void InspectorValue::writeJSON(StringBuilder* output) const
581{
582 ASSERT(m_type == TypeNull);
583 output->append(nullString, 4);
584}
585
586bool InspectorBasicValue::asBoolean(bool* output) const
587{
588 if (type() != TypeBoolean)
589 return false;
590 *output = m_boolValue;
591 return true;
592}
593
594bool InspectorBasicValue::asNumber(double* output) const
595{
596 if (type() != TypeNumber)
597 return false;
598 *output = m_doubleValue;
599 return true;
600}
601
602bool 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
610bool 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
618bool 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
626bool 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
634bool 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
642bool 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
650bool 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
658void 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
688bool InspectorString::asString(String* output) const
689{
690 *output = m_stringValue;
691 return true;
692}
693
694void InspectorString::writeJSON(StringBuilder* output) const
695{
696 ASSERT(type() == TypeString);
697 doubleQuoteString(m_stringValue, output);
698}
699
700InspectorObjectBase::~InspectorObjectBase()
701{
702}
703
704bool 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
711PassRefPtr<InspectorObject> InspectorObjectBase::asObject()
712{
713 return openAccessors();
714}
715
716InspectorObject* InspectorObjectBase::openAccessors()
717{
718 COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast);
719 return static_cast<InspectorObject*>(this);
720}
721
722bool 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
730bool 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
738PassRefPtr<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
746PassRefPtr<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
754PassRefPtr<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
762void 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
773void 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
788InspectorObjectBase::InspectorObjectBase()
789 : InspectorValue(TypeObject)
790 , m_data()
791 , m_order()
792{
793}
794
795InspectorArrayBase::~InspectorArrayBase()
796{
797}
798
799bool 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
806PassRefPtr<InspectorArray> InspectorArrayBase::asArray()
807{
808 COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast);
809 return static_cast<InspectorArray*>(this);
810}
811
812void 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
823InspectorArrayBase::InspectorArrayBase()
824 : InspectorValue(TypeArray)
825 , m_data()
826{
827}
828
829PassRefPtr<InspectorValue> InspectorArrayBase::get(size_t index)
830{
831 ASSERT_WITH_SECURITY_IMPLICATION(index < m_data.size());
832 return m_data[index];
833}
834
835PassRefPtr<InspectorObject> InspectorObject::create()
836{
837 return adoptRef(new InspectorObject);
838}
839
840PassRefPtr<InspectorArray> InspectorArray::create()
841{
842 return adoptRef(new InspectorArray);
843}
844
845PassRefPtr<InspectorValue> InspectorValue::null()
846{
847 return adoptRef(new InspectorValue);
848}
849
850PassRefPtr<InspectorString> InspectorString::create(const String& value)
851{
852 return adoptRef(new InspectorString(value));
853}
854
855PassRefPtr<InspectorString> InspectorString::create(const char* value)
856{
857 return adoptRef(new InspectorString(value));
858}
859
860PassRefPtr<InspectorBasicValue> InspectorBasicValue::create(bool value)
861{
862 return adoptRef(new InspectorBasicValue(value));
863}
864
865PassRefPtr<InspectorBasicValue> InspectorBasicValue::create(int value)
866{
867 return adoptRef(new InspectorBasicValue(value));
868}
869
870PassRefPtr<InspectorBasicValue> InspectorBasicValue::create(double value)
871{
872 return adoptRef(new InspectorBasicValue(value));
873}
874
875} // namespace Inspector