/* * json.h * * Home page of code is: https://www.smartmontools.org * * Copyright (C) 2017-18 Christian Franke * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef JSON_H_CVSID #define JSON_H_CVSID "$Id: json.h 4825 2018-10-25 19:47:35Z chrfranke $" #include #include #include #include #include /// Create and print JSON output. class json { private: struct node_info { std::string key; int index; node_info() : index(0) { } explicit node_info(const char * key_) : key(key_), index(0) { } explicit node_info(int index_) : index(index_) { } }; typedef std::vector node_path; public: /// Return true if value is a safe JSON integer. /// Same as Number.isSafeInteger(value) in JavaScript. static bool is_safe_uint(unsigned long long value) { return (value < (1ULL << 53)); } json(); /// Reference to a JSON element. class ref { public: /// Return reference to object element. ref operator[](const char * key) const { return ref(*this, key); }; /// Return reference to array element. ref operator[](int index) const { return ref(*this, index); }; // Assignment operators create or change element. void operator=(bool value); void operator=(int value); void operator=(unsigned value); void operator=(long value); void operator=(unsigned long value); void operator=(long long value); void operator=(unsigned long long value); void operator=(const char * value); void operator=(const std::string & value); /// Return reference to element with KEY_SUFFIX appended to last key. ref with_suffix(const char * key_suffix) const { return ref(*this, "", key_suffix); } void set_uint128(uint64_t value_hi, uint64_t value_lo); // Output only if safe integer. bool set_if_safe_uint64(uint64_t value); bool set_if_safe_uint128(uint64_t value_hi, uint64_t value_lo); bool set_if_safe_le128(const void * pvalue); // If unsafe integer, output also as string with key "NUMBER_s". void set_unsafe_uint64(uint64_t value); void set_unsafe_uint128(uint64_t value_hi, uint64_t value_lo); void set_unsafe_le128(const void * pvalue); private: friend class json; ref(json & js, const char * key); ref(const ref & base, const char * key); ref(const ref & base, int index); ref(const ref & base, const char * /*dummy*/, const char * key_suffix); json & m_js; node_path m_path; }; /// Return reference to element of top level object. ref operator[](const char * key) { return ref(*this, key); }; /// Enable/disable JSON output. void enable(bool yes = true) { m_enabled = yes; } /// Return true if enabled. bool is_enabled() const { return m_enabled; } /// Enable/disable extra string output for safe integers also. void set_verbose(bool yes = true) { m_verbose = yes; } /// Return true if any 128-bit value has been output. bool has_uint128_output() const { return m_uint128_output; } /// Options for print(). struct print_options { bool pretty; //< Pretty-print output. bool sorted; //< Sort object keys. bool flat; //< Print flat format. print_options() : pretty(false), sorted(false), flat(false) { } }; /// Print JSON tree to a file. void print(FILE * f, const print_options & options) const; private: enum node_type { nt_unset, nt_object, nt_array, nt_bool, nt_int, nt_uint, nt_uint128, nt_string }; struct node { node(); explicit node(const std::string & key_); ~node(); node_type type; uint64_t intval, intval_hi; std::string strval; std::string key; std::vector childs; typedef std::map keymap; keymap key2index; class const_iterator { public: const_iterator(const node * node_p, bool sorted); bool at_end() const; unsigned array_index() const; void operator++(); const node * operator*() const; private: const node * m_node_p; bool m_use_map; unsigned m_child_idx; keymap::const_iterator m_key_iter; }; #if __cplusplus >= 201103 node(const node &) = delete; void operator=(const node &) = delete; #else private: node(const node &); void operator=(const node &); #endif }; bool m_enabled; bool m_verbose; bool m_uint128_output; node m_root_node; node * find_or_create_node(const node_path & path, node_type type); void set_bool(const node_path & path, bool value); void set_int64(const node_path & path, int64_t value); void set_uint64(const node_path & path, uint64_t value); void set_uint128(const node_path & path, uint64_t value_hi, uint64_t value_lo); void set_string(const node_path & path, const std::string & value); static void print_json(FILE * f, bool pretty, bool sorted, const node * p, int level); static void print_flat(FILE * f, bool sorted, const node * p, std::string & path); }; #endif // JSON_H_CVSID