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 | |
39 | namespace 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. |
45 | namespace JSONImpl { |
46 | |
47 | class Array; |
48 | class ArrayBase; |
49 | class Object; |
50 | class ObjectBase; |
51 | |
52 | // FIXME: unify this JSON parser with JSONParse in JavaScriptCore. |
53 | class WTF_EXPORT_PRIVATE Value : public RefCounted<Value> { |
54 | public: |
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 | |
117 | protected: |
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 | |
163 | private: |
164 | Type m_type { Type::Null }; |
165 | union { |
166 | bool boolean; |
167 | double number; |
168 | StringImpl* string; |
169 | } m_value; |
170 | }; |
171 | |
172 | class WTF_EXPORT_PRIVATE ObjectBase : public Value { |
173 | private: |
174 | typedef HashMap<String, RefPtr<Value>> Dictionary; |
175 | |
176 | public: |
177 | typedef Dictionary::iterator iterator; |
178 | typedef Dictionary::const_iterator const_iterator; |
179 | |
180 | Object* openAccessors(); |
181 | |
182 | size_t memoryCost() const final; |
183 | |
184 | protected: |
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 | |
249 | protected: |
250 | ObjectBase(); |
251 | |
252 | private: |
253 | Dictionary m_map; |
254 | Vector<String> m_order; |
255 | }; |
256 | |
257 | class Object : public ObjectBase { |
258 | public: |
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 | |
291 | class WTF_EXPORT_PRIVATE ArrayBase : public Value { |
292 | public: |
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 | |
302 | protected: |
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 | |
322 | protected: |
323 | ArrayBase(); |
324 | |
325 | private: |
326 | Vector<RefPtr<Value>> m_map; |
327 | }; |
328 | |
329 | class Array : public ArrayBase { |
330 | public: |
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 | |
351 | inline ObjectBase::iterator ObjectBase::find(const String& name) |
352 | { |
353 | return m_map.find(name); |
354 | } |
355 | |
356 | inline ObjectBase::const_iterator ObjectBase::find(const String& name) const |
357 | { |
358 | return m_map.find(name); |
359 | } |
360 | |
361 | inline void ObjectBase::setBoolean(const String& name, bool value) |
362 | { |
363 | setValue(name, Value::create(value)); |
364 | } |
365 | |
366 | inline void ObjectBase::setInteger(const String& name, int value) |
367 | { |
368 | setValue(name, Value::create(value)); |
369 | } |
370 | |
371 | inline void ObjectBase::setDouble(const String& name, double value) |
372 | { |
373 | setValue(name, Value::create(value)); |
374 | } |
375 | |
376 | inline void ObjectBase::setString(const String& name, const String& value) |
377 | { |
378 | setValue(name, Value::create(value)); |
379 | } |
380 | |
381 | inline 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 | |
388 | inline 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 | |
395 | inline 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 | |
402 | inline void ArrayBase::pushBoolean(bool value) |
403 | { |
404 | m_map.append(Value::create(value)); |
405 | } |
406 | |
407 | inline void ArrayBase::pushInteger(int value) |
408 | { |
409 | m_map.append(Value::create(value)); |
410 | } |
411 | |
412 | inline void ArrayBase::pushDouble(double value) |
413 | { |
414 | m_map.append(Value::create(value)); |
415 | } |
416 | |
417 | inline void ArrayBase::pushString(const String& value) |
418 | { |
419 | m_map.append(Value::create(value)); |
420 | } |
421 | |
422 | inline void ArrayBase::pushValue(RefPtr<Value>&& value) |
423 | { |
424 | ASSERT(value); |
425 | m_map.append(WTFMove(value)); |
426 | } |
427 | |
428 | inline void ArrayBase::pushObject(RefPtr<ObjectBase>&& value) |
429 | { |
430 | ASSERT(value); |
431 | m_map.append(WTFMove(value)); |
432 | } |
433 | |
434 | inline void ArrayBase::pushArray(RefPtr<ArrayBase>&& value) |
435 | { |
436 | ASSERT(value); |
437 | m_map.append(WTFMove(value)); |
438 | } |
439 | |
440 | template<typename T> |
441 | class ArrayOf : public ArrayBase { |
442 | private: |
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 | |
451 | public: |
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 | |
486 | namespace JSON { |
487 | using namespace WTF::JSONImpl; |
488 | } |
489 | |
490 | |