1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
29 // TODO: Ensure UBJ format is compatible with the latest specification. I'm using the spec from late 2011.
38 #include "vogl_core.h"
39 #include "vogl_strutils.h"
41 #include "vogl_object_pool.h"
43 #define VOGL_TEXT_JSON_EXTENSION "json"
44 #define VOGL_BINARY_JSON_EXTENSION "ubj"
49 class json_growable_char_buf;
50 class json_deserialize_buf_ptr;
53 template <typename T, uint N>
56 template <typename Key, typename Value, typename Hasher, typename Equals>
59 template <typename Key, typename Value, typename Hasher, typename Equals, typename Allocator>
62 template <typename Key, typename Value, typename LessComp, typename EqualComp, uint MaxLevels>
65 enum json_value_type_t
67 cJSONValueTypeNull = 0,
69 cJSONValueTypeInt, // 64-bit signed integer
72 cJSONValueTypeNode // A node is a JSON object or array.
77 CMaxLineLenDefault = 160
82 // A simple value variant.
83 union json_value_data_t
91 // Parsing error coordinate.
92 struct json_error_info_t
95 dynamic_string m_error_msg;
97 void set_error(uint line, const char *pMsg, ...) VOGL_ATTRIBUTE_PRINTF(3, 4);
101 typedef object_pool<json_node, object_pool_spinlock_locking_policy> json_node_object_pool;
102 extern json_node_object_pool *g_pJSON_node_pool;
104 void json_node_pool_init();
106 inline json_node_object_pool *get_json_node_pool()
108 if (!g_pJSON_node_pool)
109 json_node_pool_init();
110 return g_pJSON_node_pool;
113 // A json_value is a null, bool, int64_t, double, a heap pointer to a null terminated string, or a heap pointer to a json_node (which is either a object or array).
114 // A json_value owns any string/node it points to, so the referenced strings/json_node is deleted upon destruction.
117 friend class json_node;
121 inline json_value(bool val);
122 inline json_value(int32 nVal);
123 inline json_value(uint32 nVal);
124 inline json_value(int64_t nVal);
125 // Note uint64_t values may be encoded as hex strings or int64_t
126 inline json_value(uint64_t nVal);
127 inline json_value(double flVal);
128 inline json_value(char *pStr);
129 inline json_value(const char *pStr);
130 inline json_value(const dynamic_string &str);
131 inline json_value(const json_node *pNode);
132 inline json_value(json_value_type_t type);
133 inline ~json_value();
135 json_value(const json_value &other);
136 json_value &operator=(const json_value &rhs);
138 inline json_value_type_t get_type() const;
140 inline const json_value_data_t &get_raw_data() const;
142 json_value_data_t &get_raw_data();
144 inline bool is_null() const;
145 inline bool is_valid() const;
146 inline bool is_bool() const;
147 inline bool is_int() const;
148 inline bool is_double() const;
149 inline bool is_numeric() const;
150 inline bool is_string() const;
151 inline bool is_node() const;
152 inline bool is_object_or_array() const;
153 inline bool is_object() const;
154 inline bool is_array() const;
156 inline const json_node *get_node_ptr() const;
158 inline json_node *get_node_ptr();
162 inline void assume_ownership(json_value &src_val);
164 inline void release_ownership(json_value &dst_value);
166 inline void init(json_value_type_t type);
167 inline json_node *init_object();
168 inline json_node *init_array();
170 inline json_node *set_value_to_object(json_node *pParent = NULL);
171 inline json_node *set_value_to_array(json_node *pParent = NULL);
172 inline json_node *set_value_to_node(bool is_object, json_node *pParent = NULL);
174 inline void set_value_to_null();
175 inline void set_value(bool val);
176 inline void set_value(int8 nVal);
177 inline void set_value(int16 nVal);
178 inline void set_value(int32 nVal);
179 inline void set_value(int64_t nVal);
181 inline void set_value(uint8 nVal);
182 inline void set_value(uint16 nVal);
183 inline void set_value(uint32 nVal);
185 // Note uint64_t values may be encoded as hex strings or int64_t
186 void set_value(uint64_t nVal);
188 inline void set_value(double flVal);
189 inline void set_value(const char *pStr);
190 inline void set_value(const dynamic_string &str);
192 // copies contents of *pNode into a new node, sets value to point to new node.
193 inline void set_value(const json_node *pNode);
195 inline void set_value_assume_ownership(char *pStr);
196 inline void set_value_assume_ownership(json_node *pNode);
198 inline json_value &operator=(bool val);
199 inline json_value &operator=(int32 nVal);
200 inline json_value &operator=(uint32 nVal);
201 inline json_value &operator=(int64_t nVal);
202 inline json_value &operator=(uint64_t nVal);
203 inline json_value &operator=(double flVal);
204 inline json_value &operator=(const char *pStr);
206 // Attempts to convert a JSON value to each type.
207 // Returns false and sets val to def if the value cannot be converted (out of range, or type is obviously incompatible).
208 // Note that if trying to convert a negative value to an unsigned type, or a value which is too large will fail and you'll get the default.
209 inline bool get_bool(bool &val, bool def = false) const;
210 bool get_numeric(int8 &val, int8 def = 0) const;
211 bool get_numeric(int16 &val, int16 def = 0) const;
212 inline bool get_numeric(int32 &val, int32 def = 0) const;
213 inline bool get_numeric(int64_t &val, int64_t def = 0) const;
215 bool get_numeric(uint8 &val, uint8 def = 0) const;
216 bool get_numeric(uint16 &val, uint16 def = 0) const;
217 bool get_numeric(uint32 &val, uint32 def = 0) const;
218 inline bool get_numeric(uint64_t &val, uint64_t def = 0) const;
220 inline bool get_numeric(float &val, float def = 0.0f) const;
221 inline bool get_numeric(double &val, double def = 0.0f) const;
223 inline bool get_string(dynamic_string &val, const char *pDef = "") const;
224 bool get_enum(const char **pStringList, int &val, int def) const;
226 inline bool as_bool(bool def = false) const;
227 inline int as_int(int def = 0) const;
228 inline int as_int32(int32 def = 0) const;
229 inline uint32 as_uint32(uint32 def = 0) const;
230 inline int64_t as_int64(int64_t def = 0) const;
231 inline uint64_t as_uint64(uint64_t def = 0) const;
232 inline float as_float(float def = 0.0f) const;
233 inline double as_double(double def = 0.0f) const;
235 // Returns value as a string, or the default string if the value cannot be converted.
236 inline dynamic_string as_string(const char *pDef = "") const;
238 // Returns pointer to null terminated string or NULL if the value is not a string.
239 inline const char *as_string_ptr(const char *pDef = NULL) const;
241 inline bool operator==(const json_value &other) const;
242 inline bool operator!=(const json_value &other) const;
244 inline void swap(json_value &other);
246 // Deserialize value from a UTF8 file, null terminated string or buffer.
247 bool deserialize_file(const char *pFilename, json_error_info_t *pError_info = NULL);
248 bool deserialize(FILE *pFile, json_error_info_t *pError_info = NULL);
249 bool deserialize(const vogl::vector<char> &buf, json_error_info_t *pError_info = NULL);
250 bool deserialize(const char *pStr, json_error_info_t *pError_info = NULL);
251 bool deserialize(const dynamic_string &str, json_error_info_t *pError_info = NULL);
252 bool deserialize(const char *pBuf, size_t buf_size, json_error_info_t *pError_info = NULL);
254 // Serialize to a UTF8 file, a growable buffer, or a string
255 bool serialize_to_file(const char *pFilename, bool formatted = true, uint max_line_len = CMaxLineLenDefault) const;
256 bool serialize(FILE *pFile, bool formatted = true, uint max_line_len = CMaxLineLenDefault) const;
257 void serialize(vogl::vector<char> &buf, bool formatted = true, uint cur_indent = 0, bool null_terminate = true, uint max_line_len = CMaxLineLenDefault) const;
258 // Serializes to a dynamic_string
259 dynamic_string &serialize(dynamic_string &str, bool formatted = true, uint cur_indent = 0, uint max_line_len = CMaxLineLenDefault) const;
260 // Serialize to stdout.
261 void print(bool formatted = true, uint cur_indent = 0, uint max_line_len = CMaxLineLenDefault) const;
263 // Deserialize from Universal Binary JSON (UBJ).
264 bool binary_deserialize(const uint8 *pBuf, size_t buf_size);
265 bool binary_deserialize_file(const char *pFilename);
266 bool binary_deserialize(FILE *pFile);
267 bool binary_deserialize(const vogl::vector<uint8> &buf);
269 // Serialize from UBJ.
270 void binary_serialize(vogl::vector<uint8> &buf) const;
271 bool binary_serialize_to_file(const char *pFilename);
272 bool binary_serialize(FILE *pFile);
274 bool is_equal(const json_value &other, double tol = 1e-8) const;
276 // Returns true if all parent pointers are correct.
277 bool validate(const json_node *pParent = NULL) const;
279 void set_line(uint line);
281 uint get_line() const;
284 json_value_data_t m_data;
285 json_value_type_t m_type;
288 bool convert_to_bool(bool &val, bool def) const;
289 bool convert_to_int32(int32 &val, int32 def) const;
290 bool convert_to_int64(int64_t &val, int64_t def) const;
291 bool convert_to_uint64(uint64_t &val, uint64_t def) const;
292 bool convert_to_float(float &val, float def) const;
293 bool convert_to_double(double &val, double def) const;
294 bool convert_to_string(dynamic_string &val, const char *pDef) const;
296 inline void free_data()
298 if (m_type == cJSONValueTypeString)
299 vogl_free(m_data.m_pStr);
300 else if (m_type == cJSONValueTypeNode)
301 get_json_node_pool()->destroy(m_data.m_pNode);
304 bool deserialize_node(json_deserialize_buf_ptr &pStr, json_node *pParent, uint level, json_error_info_t &error_info);
305 bool estimate_deserialized_string_size(json_deserialize_buf_ptr &pStr, json_error_info_t &error_info, uint &size);
306 bool deserialize_quoted_string_to_buf(char *&pBuf, uint buf_size, json_deserialize_buf_ptr &pStr, json_error_info_t &error_info);
307 bool deserialize_string(json_deserialize_buf_ptr &pStr, json_error_info_t &error_info);
308 bool deserialize_number(json_deserialize_buf_ptr &pStr, json_error_info_t &error_info);
309 bool deserialize(json_deserialize_buf_ptr &pStr, json_node *pParent, uint level, json_error_info_t &error_info);
311 void binary_serialize_value(vogl::vector<uint8> &buf) const;
312 bool binary_deserialize(const uint8 *&pBuf, const uint8 *pBuf_end, json_node *pParent, uint depth);
315 // Optional: Forbid (the super annoying) implicit conversions of all pointers/const pointers to bool, except for the specializations below.
316 // Purposely unimplemented. Constructor will be caught at compile time, and operator= at link time.
317 // TODO: Is this confusing crap needed anymore?
318 template <typename T>
320 template <typename T>
321 json_value(const T *);
322 template <typename T>
323 json_value &operator=(T *);
324 template <typename T>
325 json_value &operator=(const T *);
328 VOGL_DEFINE_BITWISE_MOVABLE(json_value);
330 extern json_value g_null_json_value;
332 typedef vogl::vector<dynamic_string> dynamic_string_array;
333 typedef vogl::vector<json_value> json_value_array;
335 // A json_node can be either a JSON object (key/values) or array (values only).
336 // It contains one or two separate unsorted arrays: one for keys (JSON objects only), and another for values (JSON objects or arrays).
337 // json_node's are multisets, not sets, so duplicate keys do not cause errors, although the find() helpers will only find the first key.
338 // The order of the key/value arrays is preserved in this design, but find()'s in large objects/array can be slow.
339 // json_value's may point to other child json_nodes, which are allocated and freed from the heap.
340 // The keys are simple zero terminated strings, and the values are instances of the json_value class above.
341 // This design allows all keys/values at each object/array level to be stored in simple contiguous arrays.
342 // Each json_node has a pointer to its parent, or NULL for the root.
343 // Note that json_values which are not json_node's don't have pointers to their owners nodes, which can be annoying.
346 friend class json_value;
350 json_node(const json_node &other);
351 json_node(const json_node *pParent, bool is_object);
354 json_node &operator=(const json_node &rhs);
356 // Serialize to buffer.
357 void serialize(vogl::vector<char> &buf, bool formatted = true, uint cur_index = 0, bool null_terminate = true, uint max_line_len = CMaxLineLenDefault) const;
359 void serialize(dynamic_string &str, bool formatted = true, uint cur_index = 0, uint max_line_len = CMaxLineLenDefault) const;
361 void binary_serialize(vogl::vector<uint8> &buf) const;
363 // Parent/child retrieval
364 inline const json_node *get_parent() const;
366 // true if the value at the specified index is an object or array.
367 inline bool is_child(uint index) const;
369 // true if the value at the specified index is an object.
370 inline bool is_child_object(uint index) const;
372 // true if the value at the specified index is an array.
373 inline bool is_child_array(uint index) const;
375 // Finds the specified child (case insensitive), or NULL if the child cannot be found.
376 const json_node *find_child(const char *pKey) const;
377 json_node *find_child(const char *pKey);
379 // Finds the specified child object (case insensitive), or NULL if the child cannot be found or if the child is not an object.
380 const json_node *find_child_object(const char *pKey) const;
381 json_node *find_child_object(const char *pKey);
383 // Finds the specified child object (case insensitive), or NULL if the child cannot be found or if the child is not an array.
384 const json_node *find_child_array(const char *pKey) const;
385 json_node *find_child_array(const char *pKey);
387 // true if all children are plain values (i.e. not arrays or objects)
388 bool are_all_children_values() const;
390 // true if all children are objects
391 bool are_all_children_objects() const;
393 // true if all children are arrays
394 bool are_all_children_arrays() const;
396 // true if all children are objects or arrays
397 bool are_all_children_objects_or_arrays() const;
399 // Returns pointer to the child array or object at the specified index, or NULL if the value is not an array or object.
400 inline const json_node *get_child(uint index) const;
401 inline json_node *get_child(uint index);
403 // true if any of the values in this node are objects or arrays.
404 bool has_children() const;
407 inline bool is_object() const;
408 inline bool is_array() const;
409 inline uint size() const;
411 // Key retrieval/finding
413 // Returns cInvalidIndex (-1) if key was not found. Search is case insensitive.
414 int find_key(const char *pKey) const;
416 int find_child(const json_node *pNode) const;
418 inline bool has_key(const char *pKey) const;
420 // true if the value associated with the specified key is an object
421 inline bool has_object(const char *pKey) const;
423 // true if the value associated with the specified key is an array
424 inline bool has_array(const char *pKey) const;
426 inline const dynamic_string &get_key(uint index) const;
428 // returns g_null_json_value if the key does not exist
429 const json_value &find_value(const char *pKey) const;
430 inline const json_value &operator[](const char *pKey) const;
432 json_value_type_t find_value_type(const char *pKey) const;
434 // Value retrieval/finding
435 inline json_value_type_t get_value_type(uint index) const;
436 inline const json_value &get_value(uint index) const;
437 inline const json_value &operator[](uint index) const;
439 // Returns NULL if the value is not an object or array.
440 inline const json_node *get_value_as_object_or_array(uint index) const;
441 inline const json_node *get_value_as_object(uint index) const;
442 inline const json_node *get_value_as_array(uint index) const;
444 // get() variants returns true if key was found and the JSON value could be losslessly converted to the destination type.
445 bool get_value_as_string(const char *pKey, dynamic_string &val, const char *pDef = "") const;
446 bool get_value_as_enum(const char *pKey, const char **pStringList, int &val, int def = 0) const;
448 // T may be int8, int16, int32 or uint8, uint16, uint32
449 // Internally this fetches the value as int64_t and attempts to convert. Returns false and sets val to def if out of range.
450 template <typename T>
451 bool get_value_as_int(const char *pKey, T &val, T def = 0) const;
453 bool get_value_as_int64(const char *pKey, int64_t &val, int64_t def = 0) const;
454 bool get_value_as_uint32(const char *pKey, uint32 &val, uint32 def = 0) const;
455 bool get_value_as_uint64(const char *pKey, uint64_t &val, uint64_t def = 0) const;
456 bool get_value_as_float(const char *pKey, float &val, float def = 0) const;
457 bool get_value_as_double(const char *pKey, double &val, double def = 0) const;
458 bool get_value_as_bool(const char *pKey, bool &val, bool def = false) const;
460 // The value_as() variants find the first key matching pKey and return its value, or the default if key was not found.
461 // Note that if trying to convert a negative value to an unsigned type, or a value which is too large will fail and you'll get the default.
462 dynamic_string value_as_string(const char *pKey, const char *pDef = "") const;
463 const char *value_as_string_ptr(const char *pKey, const char *pDef = "") const;
464 int value_as_int(const char *pKey, int def = 0) const;
465 int32 value_as_int32(const char *pKey, int32 def = 0) const;
466 int64_t value_as_int64(const char *pKey, int64_t def = 0) const;
467 uint32 value_as_uint32(const char *pKey, uint32 def = 0) const;
468 uint64_t value_as_uint64(const char *pKey, uint64_t def = 0) const;
469 float value_as_float(const char *pKey, float def = 0) const;
470 double value_as_double(const char *pKey, double def = 0) const;
471 bool value_as_bool(const char *pKey, bool def = false) const;
473 // The value_as() variants return the value, or the default if key can't be converted to the desired type.
474 // Note that if trying to convert a negative value to an unsigned type, or a value which is too large will fail and you'll get the default.
475 dynamic_string value_as_string(uint index, const char *pDef = "") const;
476 // Returns NULL if value is not a string.
477 const char *value_as_string_ptr(uint index, const char *pDef = "") const;
478 int value_as_int(uint index, int def = 0) const;
479 int32 value_as_int32(uint index, int32 def = 0) const;
480 int64_t value_as_int64(uint index, int64_t def = 0) const;
481 uint32 value_as_uint32(uint index, uint32 def = 0) const;
482 uint64_t value_as_uint64(uint index, uint64_t def = 0) const;
483 float value_as_float(uint index, float def = 0) const;
484 double value_as_double(uint index, double def = 0) const;
485 bool value_as_bool(uint index, bool def = false) const;
487 inline bool operator==(const json_node &other) const;
488 inline bool operator!=(const json_node &other) const;
491 // TODO: Add splicing, insert
493 // Retrieves the json_value at the specified index.
494 inline json_value &get_value(uint index);
495 inline json_value &operator[](uint index);
497 // Sets the parent node of this node.
498 void set_parent(const json_node *pParent);
500 // Completely clears the node.
503 // Sets this node to an object. If the node is an array it will be upgraded to an object with an array of empty keys.
504 void set_is_object(bool is_object);
508 // Changes the number of elements in this node. Enlarging will add empty keys (for objects), and values of type cJSONValueTypeNull.
509 void resize(uint new_size);
510 inline uint enlarge(uint n);
512 void reserve(uint new_capacity);
514 // Retrieves the json_value associated with a key, or adds a new named key/value to the node, which must be an object. The newly added json_value will have type cJSONValueTypeNull.
515 json_value &get_or_add(const char *pKey);
516 json_value &get_or_add(const dynamic_string &key);
518 // Adds a named key/value to the node. The json_value will have type cJSONValueTypeNull. If the node is not an object it will be upgraded to an object.
519 json_value &add(const char *pKey);
520 json_value &add(const dynamic_string &key);
522 // Adds a named child object to the node. If the node is not an object it will be upgraded to an object.
523 json_node &add_object(const char *pKey);
524 json_node &add_object(const dynamic_string &key);
526 // Adds an unnamed object to the node.
527 json_node &add_object();
529 // Adds a named child array to the node. If the node is not an object it will be upgraded to an object.
530 json_node &add_array(const char *pKey);
531 json_node &add_array(const dynamic_string &key);
533 // Adds an unnamed array to the node.
534 json_node &add_array();
536 // Adds a key/value to a node. If the node is not an object it will be upgraded to an object.
537 json_value &add_key_value(const char *pKey, const json_value &val);
538 json_value &add_key_value(const dynamic_string &key, const json_value &val);
540 // Adds a new value to a node. If the node is an object then an empty key will be associated with the newly added value.
541 json_value &add_value();
542 json_value &add_value(const json_value &val);
544 // Adds a new key/value to a node. pValueToParse must be JSON text.
545 bool add_key_and_parsed_value(const char *pKey, const char *pValueToParse);
546 bool add_key_and_parsed_value(const dynamic_string &key, const char *pValueToParse);
548 // Adds a new value to a node. pValueToParse must be JSON text.
549 bool add_parsed_value(const char *pValueToParse);
551 // Retrieves a node's key. Asserts and returns a ref to g_empty_dynamic_string if the node is an array.
552 dynamic_string &get_key(uint index);
554 // Sets the key/value at the specified index. If the node is not an object it will be upgraded to one.
555 void set_key_value(uint index, const char *pKey, const json_value &val);
556 void set_key(uint index, const char *pKey);
557 void set_value(uint index, const json_value &val);
559 // Sets the value at the specified index. Takes ownership of any node pointed to by val. val will be cleared.
560 void set_value_assume_ownership(uint index, json_value &val);
561 void add_value_assume_ownership(json_value &val);
562 void add_key_value_assume_ownership(const char *pKey, json_value &val);
564 // Removes the specified key (case insensitive), returns true if the key is found.
565 bool erase(const char *pKey);
566 bool erase(const dynamic_string &key);
568 // Removes the specified key at index.
569 void erase(uint index);
571 // true if the node passes some basic tests for validity.
572 bool basic_validation(const json_node *pParent) const;
574 // true if the node, and its children, pass some basic tests for validity.
575 bool validate(const json_node *pParent) const;
577 // Returns a path string to this node, i.e. [root]/blah/[5]/cool, where cool is the current node, [5] is cool's parent (array item 5), etc.
578 dynamic_string get_path_to_node() const;
580 // pKey is not validated.
581 dynamic_string get_path_to_key(const char *pKey) const;
583 // index is not range checked.
584 dynamic_string get_path_to_item(uint index) const;
586 // Returns true if one or more keys has the same name, which is not valid JSON to many readers (although this seems to be a grey area of the spec).
587 // Recursively checks children nodes.
588 bool check_for_duplicate_keys() const;
590 // Set the line number associated with this node.
591 void set_line(uint line);
593 // Gets the line number associated with this node.
594 uint get_line() const;
596 // High-level container serialization/deserialization to/from JSON nodes.
597 // These methods add or retrieve entire containers (vectors, growable_array's, hash_map's, or map's) or user objects to/from JSON nodes.
598 // They assume the object, element or key/value types have overloaded "json_serialize" and "json_deserialize" functions defined, or you've defined overloaded json_serialize/json_deserialize members in the voglcore namespace.
600 // Adds a named or unnamed object to this node.
601 template <typename T>
602 bool add_object(const char *pKey, const T &obj);
604 // Retrieves a named object from this node.
605 template <typename T>
606 bool get_object(const char *pKey, T &obj) const;
608 // Retrieves the object at the specified index from this node.
609 template <typename T>
610 bool get_object(uint index, T &obj) const;
612 // add_vector() and get_vector() are compatible with vogl::vector or vogl::growable_array.
613 // If pKey is NULL, the hash map is read from the current node, otherwise it's read from the child object named pKey.
614 template <typename T>
615 bool add_vector(const char *pKey, const T &vec);
617 // If pKey is NULL, the hash mode is added to the current node, otherwise it's added to a child named pKey.
618 template <typename T>
619 bool get_vector(const char *pKey, T &vec) const;
621 // add_map() and get_map() are compatible with vogl::map and vogl::hash_map.
622 // If pKey is NULL, the hash mode is added to the current node, otherwise it's added to a child named pKey.
623 template <typename T>
624 bool add_map(const char *pKey, const T &hash_map);
626 // If pKey is NULL, the hash map is read from the current node, otherwise it's read from the child object named pKey.
627 template <typename T>
628 bool get_map(const char *pKey, T &hash_map) const;
631 const json_node *m_pParent;
633 dynamic_string_array m_keys;
634 json_value_array m_values;
640 void ensure_is_object();
641 void serialize(json_growable_char_buf &buf, bool formatted, uint cur_index, uint max_line_len = CMaxLineLenDefault) const;
644 // json_document is an optional helper class that derives from json_value.
645 // It may optionally have been parsed from a file, string, or buffer and contains filename/error/line information.
646 // It's not derived from json_node because a valid JSON document may be a single value and not necessarily an object or array, although in practice it will be an object or maybe an array (and NOT a plain value) 99.999% of the time.
647 class json_document : public json_value
649 typedef json_value base;
653 explicit json_document(const json_value &other);
654 json_document(const json_document &other);
655 json_document(const char *pStr, const char *pFilename = "<string>");
656 json_document(const char *pBuf, uint n, const char *pFilename = "<buffer>");
657 json_document(json_value_type_t value_type);
660 json_document &operator=(const json_document &rhs);
661 json_document &operator=(const json_value &rhs);
663 // root value manipulation
664 inline const json_value &get_value() const;
665 inline json_value &get_value();
667 // This returns a pointer because a valid JSON document can be a single value (in which case the document's value is not a node pointer).
668 inline const json_node *get_root() const;
669 inline json_node *get_root();
671 inline void clear(bool reinitialize_to_object = true);
673 // Swaps two documents.
674 void swap(json_document &other);
676 // Deserialize UTF8 text from files, buffer, or a string.
677 bool deserialize_file(const char *pFilename);
678 bool deserialize(FILE *pFile, const char *pFilename = "<FILE>");
679 bool deserialize(const vogl::vector<char> &buf, const char *pFilename = "<buffer>");
680 bool deserialize(const char *pBuf, size_t n, const char *pFilename = "<buffer>");
681 bool deserialize(const char *pStr, const char *pFilename = "<string>");
682 bool deserialize(const dynamic_string &str, const char *pFilename = "<string>");
684 // document's filename
685 inline const dynamic_string &get_filename() const;
686 inline void set_filename(const char *pFilename);
688 // error messages due to failed parses
689 const dynamic_string &get_error_msg() const;
690 uint get_error_line() const;
694 dynamic_string m_filename;
696 dynamic_string m_error_msg;
704 #include "vogl_json.inl"
706 #endif // VOGL_JSON_DOC_H