]>
Commit | Line | Data |
---|---|---|
ff28b140 TL |
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 |