1/*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * Copyright (C) 2014 University of Washington. All rights reserved.
4 * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#pragma once
34
35#include <wtf/HashMap.h>
36#include <wtf/text/StringHash.h>
37#include <wtf/text/WTFString.h>
38
39namespace WTF {
40
41// Make sure compiled symbols contain the WTF namespace prefix, but
42// use a different inner namespace name so that JSON::Value is not ambigious.
43// Otherwise, the compiler would have both WTF::JSON::Value and JSON::Value
44// in scope and client code would have to use WTF::JSON::Value, which is tedious.
45namespace JSONImpl {
46
47class Array;
48class ArrayBase;
49class Object;
50class ObjectBase;
51
52// FIXME: unify this JSON parser with JSONParse in JavaScriptCore.
53class WTF_EXPORT_PRIVATE Value : public RefCounted<Value> {
54public:
55 static constexpr int maxDepth = 1000;
56
57 virtual ~Value()
58 {
59 switch (m_type) {
60 case Type::Null:
61 case Type::Boolean:
62 case Type::Double:
63 case Type::Integer:
64 break;
65 case Type::String:
66 if (m_value.string)
67 m_value.string->deref();
68 break;
69 case Type::Object:
70 case Type::Array:
71 break;
72 }
73 }
74
75 static Ref<Value> null();
76 static Ref<Value> create(bool);
77 static Ref<Value> create(int);
78 static Ref<Value> create(double);
79 static Ref<Value> create(const String&);
80 static Ref<Value> create(const char*);
81
82 enum class Type {
83 Null = 0,
84 Boolean,
85 Double,
86 Integer,
87 String,
88 Object,
89 Array,
90 };
91
92 Type type() const { return m_type; }
93 bool isNull() const { return m_type == Type::Null; }
94
95 bool asBoolean(bool&) const;
96 bool asInteger(int&) const;
97 bool asInteger(unsigned&) const;
98 bool asInteger(long&) const;
99 bool asInteger(long long&) const;
100 bool asInteger(unsigned long&) const;
101 bool asInteger(unsigned long long&) const;
102 bool asDouble(double&) const;
103 bool asDouble(float&) const;
104 bool asString(String&) const;
105 bool asValue(RefPtr<Value>&);
106
107 virtual bool asObject(RefPtr<Object>&);
108 virtual bool asArray(RefPtr<Array>&);
109
110 static bool parseJSON(const String& jsonInput, RefPtr<Value>& output);
111
112 String toJSONString() const;
113 virtual void writeJSON(StringBuilder& output) const;
114
115 virtual size_t memoryCost() const;
116
117protected:
118 Value()
119 : m_type { Type::Null }
120 {
121 }
122
123 explicit Value(Type type)
124 : m_type(type)
125 {
126 }
127
128 explicit Value(bool value)
129 : m_type { Type::Boolean }
130 {
131 m_value.boolean = value;
132 }
133
134 explicit Value(int value)
135 : m_type { Type::Integer }
136 {
137 m_value.number = static_cast<double>(value);
138 }
139
140 explicit Value(double value)
141 : m_type(Type::Double)
142 {
143 m_value.number = value;
144 }
145
146 explicit Value(const String& value)
147 : m_type { Type::String }
148 {
149 m_value.string = value.impl();
150 if (m_value.string)
151 m_value.string->ref();
152 }
153
154 explicit Value(const char* value)
155 : m_type { Type::String }
156 {
157 String wrapper(value);
158 m_value.string = wrapper.impl();
159 if (m_value.string)
160 m_value.string->ref();
161 }
162
163private:
164 Type m_type { Type::Null };
165 union {
166 bool boolean;
167 double number;
168 StringImpl* string;
169 } m_value;
170};
171
172class WTF_EXPORT_PRIVATE ObjectBase : public Value {
173private:
174 typedef HashMap<String, RefPtr<Value>> Dictionary;
175
176public:
177 typedef Dictionary::iterator iterator;
178 typedef Dictionary::const_iterator const_iterator;
179
180 Object* openAccessors();
181
182 size_t memoryCost() const final;
183
184protected:
185 virtual ~ObjectBase();
186
187 bool asObject(RefPtr<Object>& output) override;
188
189 // FIXME: use templates to reduce the amount of duplicated set*() methods.
190 void setBoolean(const String& name, bool);
191 void setInteger(const String& name, int);
192 void setDouble(const String& name, double);
193 void setString(const String& name, const String&);
194 void setValue(const String& name, RefPtr<Value>&&);
195 void setObject(const String& name, RefPtr<ObjectBase>&&);
196 void setArray(const String& name, RefPtr<ArrayBase>&&);
197
198 iterator find(const String& name);
199 const_iterator find(const String& name) const;
200
201 // FIXME: use templates to reduce the amount of duplicated get*() methods.
202 bool getBoolean(const String& name, bool& output) const;
203 template<class T> bool getDouble(const String& name, T& output) const
204 {
205 RefPtr<Value> value;
206 if (!getValue(name, value))
207 return false;
208
209 return value->asDouble(output);
210 }
211 template<class T> bool getInteger(const String& name, T& output) const
212 {
213 RefPtr<Value> value;
214 if (!getValue(name, value))
215 return false;
216
217 return value->asInteger(output);
218 }
219
220 template<class T> Optional<T> getNumber(const String& name) const
221 {
222 RefPtr<Value> value;
223 if (!getValue(name, value))
224 return WTF::nullopt;
225
226 T result;
227 if (!value->asDouble(result))
228 return WTF::nullopt;
229
230 return result;
231 }
232
233 bool getString(const String& name, String& output) const;
234 bool getObject(const String& name, RefPtr<Object>&) const;
235 bool getArray(const String& name, RefPtr<Array>&) const;
236 bool getValue(const String& name, RefPtr<Value>&) const;
237
238 void remove(const String& name);
239
240 void writeJSON(StringBuilder& output) const override;
241
242 iterator begin() { return m_map.begin(); }
243 iterator end() { return m_map.end(); }
244 const_iterator begin() const { return m_map.begin(); }
245 const_iterator end() const { return m_map.end(); }
246
247 int size() const { return m_map.size(); }
248
249protected:
250 ObjectBase();
251
252private:
253 Dictionary m_map;
254 Vector<String> m_order;
255};
256
257class Object : public ObjectBase {
258public:
259 static WTF_EXPORT_PRIVATE Ref<Object> create();
260
261 using ObjectBase::asObject;
262
263 // This class expected non-cyclic values, as we cannot serialize cycles in JSON.
264 using ObjectBase::setBoolean;
265 using ObjectBase::setInteger;
266 using ObjectBase::setDouble;
267 using ObjectBase::setString;
268 using ObjectBase::setValue;
269 using ObjectBase::setObject;
270 using ObjectBase::setArray;
271
272 using ObjectBase::find;
273 using ObjectBase::getBoolean;
274 using ObjectBase::getInteger;
275 using ObjectBase::getDouble;
276 using ObjectBase::getNumber;
277 using ObjectBase::getString;
278 using ObjectBase::getObject;
279 using ObjectBase::getArray;
280 using ObjectBase::getValue;
281
282 using ObjectBase::remove;
283
284 using ObjectBase::begin;
285 using ObjectBase::end;
286
287 using ObjectBase::size;
288};
289
290
291class WTF_EXPORT_PRIVATE ArrayBase : public Value {
292public:
293 typedef Vector<RefPtr<Value>>::iterator iterator;
294 typedef Vector<RefPtr<Value>>::const_iterator const_iterator;
295
296 unsigned length() const { return static_cast<unsigned>(m_map.size()); }
297
298 RefPtr<Value> get(size_t index) const;
299
300 size_t memoryCost() const final;
301
302protected:
303 virtual ~ArrayBase();
304
305 bool asArray(RefPtr<Array>&) override;
306
307 void pushBoolean(bool);
308 void pushInteger(int);
309 void pushDouble(double);
310 void pushString(const String&);
311 void pushValue(RefPtr<Value>&&);
312 void pushObject(RefPtr<ObjectBase>&&);
313 void pushArray(RefPtr<ArrayBase>&&);
314
315 void writeJSON(StringBuilder& output) const override;
316
317 iterator begin() { return m_map.begin(); }
318 iterator end() { return m_map.end(); }
319 const_iterator begin() const { return m_map.begin(); }
320 const_iterator end() const { return m_map.end(); }
321
322protected:
323 ArrayBase();
324
325private:
326 Vector<RefPtr<Value>> m_map;
327};
328
329class Array : public ArrayBase {
330public:
331 static WTF_EXPORT_PRIVATE Ref<Array> create();
332
333 using ArrayBase::asArray;
334
335 // This class expected non-cyclic values, as we cannot serialize cycles in JSON.
336 using ArrayBase::pushBoolean;
337 using ArrayBase::pushInteger;
338 using ArrayBase::pushDouble;
339 using ArrayBase::pushString;
340 using ArrayBase::pushValue;
341 using ArrayBase::pushObject;
342 using ArrayBase::pushArray;
343
344 using ArrayBase::get;
345
346 using ArrayBase::begin;
347 using ArrayBase::end;
348};
349
350
351inline ObjectBase::iterator ObjectBase::find(const String& name)
352{
353 return m_map.find(name);
354}
355
356inline ObjectBase::const_iterator ObjectBase::find(const String& name) const
357{
358 return m_map.find(name);
359}
360
361inline void ObjectBase::setBoolean(const String& name, bool value)
362{
363 setValue(name, Value::create(value));
364}
365
366inline void ObjectBase::setInteger(const String& name, int value)
367{
368 setValue(name, Value::create(value));
369}
370
371inline void ObjectBase::setDouble(const String& name, double value)
372{
373 setValue(name, Value::create(value));
374}
375
376inline void ObjectBase::setString(const String& name, const String& value)
377{
378 setValue(name, Value::create(value));
379}
380
381inline void ObjectBase::setValue(const String& name, RefPtr<Value>&& value)
382{
383 ASSERT(value);
384 if (m_map.set(name, WTFMove(value)).isNewEntry)
385 m_order.append(name);
386}
387
388inline void ObjectBase::setObject(const String& name, RefPtr<ObjectBase>&& value)
389{
390 ASSERT(value);
391 if (m_map.set(name, WTFMove(value)).isNewEntry)
392 m_order.append(name);
393}
394
395inline void ObjectBase::setArray(const String& name, RefPtr<ArrayBase>&& value)
396{
397 ASSERT(value);
398 if (m_map.set(name, WTFMove(value)).isNewEntry)
399 m_order.append(name);
400}
401
402inline void ArrayBase::pushBoolean(bool value)
403{
404 m_map.append(Value::create(value));
405}
406
407inline void ArrayBase::pushInteger(int value)
408{
409 m_map.append(Value::create(value));
410}
411
412inline void ArrayBase::pushDouble(double value)
413{
414 m_map.append(Value::create(value));
415}
416
417inline void ArrayBase::pushString(const String& value)
418{
419 m_map.append(Value::create(value));
420}
421
422inline void ArrayBase::pushValue(RefPtr<Value>&& value)
423{
424 ASSERT(value);
425 m_map.append(WTFMove(value));
426}
427
428inline void ArrayBase::pushObject(RefPtr<ObjectBase>&& value)
429{
430 ASSERT(value);
431 m_map.append(WTFMove(value));
432}
433
434inline void ArrayBase::pushArray(RefPtr<ArrayBase>&& value)
435{
436 ASSERT(value);
437 m_map.append(WTFMove(value));
438}
439
440template<typename T>
441class ArrayOf : public ArrayBase {
442private:
443 ArrayOf() { }
444
445 Array& castedArray()
446 {
447 COMPILE_ASSERT(sizeof(Array) == sizeof(ArrayOf<T>), cannot_cast);
448 return *static_cast<Array*>(static_cast<ArrayBase*>(this));
449 }
450
451public:
452 void addItem(RefPtr<T>&& value)
453 {
454 castedArray().pushValue(WTFMove(value));
455 }
456
457 void addItem(const String& value)
458 {
459 castedArray().pushString(value);
460 }
461
462 void addItem(int value)
463 {
464 castedArray().pushInteger(value);
465 }
466
467 void addItem(double value)
468 {
469 castedArray().pushDouble(value);
470 }
471
472 static Ref<ArrayOf<T>> create()
473 {
474 return adoptRef(*new ArrayOf<T>());
475 }
476
477 using ArrayBase::get;
478 using ArrayBase::begin;
479 using ArrayBase::end;
480};
481
482} // namespace JSONImpl
483
484} // namespace WTF
485
486namespace JSON {
487using namespace WTF::JSONImpl;
488}
489
490