]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - json.h
import smartmontools 7.0
[mirror_smartmontools-debian.git] / json.h
1 /*
2 * json.h
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2017-18 Christian Franke
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #ifndef JSON_H_CVSID
12 #define JSON_H_CVSID "$Id: json.h 4825 2018-10-25 19:47:35Z chrfranke $"
13
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <string>
17 #include <vector>
18 #include <map>
19
20 /// Create and print JSON output.
21 class json
22 {
23 private:
24 struct node_info
25 {
26 std::string key;
27 int index;
28
29 node_info()
30 : index(0) { }
31 explicit node_info(const char * key_)
32 : key(key_), index(0) { }
33 explicit node_info(int index_)
34 : index(index_) { }
35 };
36
37 typedef std::vector<node_info> node_path;
38
39 public:
40 /// Return true if value is a safe JSON integer.
41 /// Same as Number.isSafeInteger(value) in JavaScript.
42 static bool is_safe_uint(unsigned long long value)
43 { return (value < (1ULL << 53)); }
44
45 json();
46
47 /// Reference to a JSON element.
48 class ref
49 {
50 public:
51 /// Return reference to object element.
52 ref operator[](const char * key) const
53 { return ref(*this, key); };
54
55 /// Return reference to array element.
56 ref operator[](int index) const
57 { return ref(*this, index); };
58
59 // Assignment operators create or change element.
60 void operator=(bool value);
61
62 void operator=(int value);
63 void operator=(unsigned value);
64 void operator=(long value);
65 void operator=(unsigned long value);
66 void operator=(long long value);
67 void operator=(unsigned long long value);
68
69 void operator=(const char * value);
70 void operator=(const std::string & value);
71
72 /// Return reference to element with KEY_SUFFIX appended to last key.
73 ref with_suffix(const char * key_suffix) const
74 { return ref(*this, "", key_suffix); }
75
76 void set_uint128(uint64_t value_hi, uint64_t value_lo);
77
78 // Output only if safe integer.
79 bool set_if_safe_uint64(uint64_t value);
80 bool set_if_safe_uint128(uint64_t value_hi, uint64_t value_lo);
81 bool set_if_safe_le128(const void * pvalue);
82
83 // If unsafe integer, output also as string with key "NUMBER_s".
84 void set_unsafe_uint64(uint64_t value);
85 void set_unsafe_uint128(uint64_t value_hi, uint64_t value_lo);
86 void set_unsafe_le128(const void * pvalue);
87
88 private:
89 friend class json;
90 ref(json & js, const char * key);
91 ref(const ref & base, const char * key);
92 ref(const ref & base, int index);
93 ref(const ref & base, const char * /*dummy*/, const char * key_suffix);
94
95 json & m_js;
96 node_path m_path;
97 };
98
99 /// Return reference to element of top level object.
100 ref operator[](const char * key)
101 { return ref(*this, key); };
102
103 /// Enable/disable JSON output.
104 void enable(bool yes = true)
105 { m_enabled = yes; }
106
107 /// Return true if enabled.
108 bool is_enabled() const
109 { return m_enabled; }
110
111 /// Enable/disable extra string output for safe integers also.
112 void set_verbose(bool yes = true)
113 { m_verbose = yes; }
114
115 /// Return true if any 128-bit value has been output.
116 bool has_uint128_output() const
117 { return m_uint128_output; }
118
119 /// Options for print().
120 struct print_options {
121 bool pretty; //< Pretty-print output.
122 bool sorted; //< Sort object keys.
123 bool flat; //< Print flat format.
124 print_options()
125 : pretty(false), sorted(false), flat(false) { }
126 };
127
128 /// Print JSON tree to a file.
129 void print(FILE * f, const print_options & options) const;
130
131 private:
132 enum node_type {
133 nt_unset, nt_object, nt_array,
134 nt_bool, nt_int, nt_uint, nt_uint128, nt_string
135 };
136
137 struct node
138 {
139 node();
140 explicit node(const std::string & key_);
141 ~node();
142
143 node_type type;
144
145 uint64_t intval, intval_hi;
146 std::string strval;
147
148 std::string key;
149 std::vector<node *> childs;
150 typedef std::map<std::string, unsigned> keymap;
151 keymap key2index;
152
153 class const_iterator
154 {
155 public:
156 const_iterator(const node * node_p, bool sorted);
157 bool at_end() const;
158 unsigned array_index() const;
159 void operator++();
160 const node * operator*() const;
161
162 private:
163 const node * m_node_p;
164 bool m_use_map;
165 unsigned m_child_idx;
166 keymap::const_iterator m_key_iter;
167 };
168
169 #if __cplusplus >= 201103
170 node(const node &) = delete;
171 void operator=(const node &) = delete;
172 #else
173 private: node(const node &); void operator=(const node &);
174 #endif
175 };
176
177 bool m_enabled;
178 bool m_verbose;
179 bool m_uint128_output;
180
181 node m_root_node;
182
183 node * find_or_create_node(const node_path & path, node_type type);
184
185 void set_bool(const node_path & path, bool value);
186 void set_int64(const node_path & path, int64_t value);
187 void set_uint64(const node_path & path, uint64_t value);
188 void set_uint128(const node_path & path, uint64_t value_hi, uint64_t value_lo);
189 void set_string(const node_path & path, const std::string & value);
190
191 static void print_json(FILE * f, bool pretty, bool sorted, const node * p, int level);
192 static void print_flat(FILE * f, bool sorted, const node * p, std::string & path);
193 };
194
195 #endif // JSON_H_CVSID