Directory: | src/ |
---|---|
File: | src/json.c |
Date: | 2024-04-25 03:45:42 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 112 | 153 | 73.2% |
Branches: | 22 | 70 | 31.4% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2023 Egor Tensin <egor@tensin.name> | ||
3 | * This file is part of the "cimple" project. | ||
4 | * For details, see https://github.com/egor-tensin/cimple. | ||
5 | * Distributed under the MIT License. | ||
6 | */ | ||
7 | |||
8 | #include "json.h" | ||
9 | #include "buf.h" | ||
10 | #include "log.h" | ||
11 | #include "net.h" | ||
12 | |||
13 | #include <json-c/json_object.h> | ||
14 | #include <json-c/json_tokener.h> | ||
15 | |||
16 | #include <errno.h> | ||
17 | #include <stdint.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | |||
21 | #define libjson_errno(fn) \ | ||
22 | do { \ | ||
23 | log_err("JSON: %s failed\n", fn); \ | ||
24 | } while (0) | ||
25 | |||
26 | 110424 | void libjson_free(struct json_object *obj) | |
27 | { | ||
28 | 110424 | json_object_put(obj); | |
29 | 110424 | } | |
30 | |||
31 | 55212 | static const char *libjson_to_string_internal(struct json_object *obj, int flags) | |
32 | { | ||
33 | 55212 | const char *result = json_object_to_json_string_ext(obj, flags); | |
34 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55212 times.
|
55212 | if (!result) { |
35 | ✗ | libjson_errno("json_object_to_json_string"); | |
36 | ✗ | return NULL; | |
37 | } | ||
38 | 55212 | return result; | |
39 | } | ||
40 | |||
41 | 46006 | const char *libjson_to_string(struct json_object *obj) | |
42 | { | ||
43 | 46006 | return libjson_to_string_internal(obj, JSON_C_TO_STRING_SPACED); | |
44 | } | ||
45 | |||
46 | 9206 | const char *libjson_to_string_pretty(struct json_object *obj) | |
47 | { | ||
48 | 9206 | return libjson_to_string_internal(obj, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY); | |
49 | } | ||
50 | |||
51 | 46006 | struct json_object *libjson_from_string(const char *src) | |
52 | { | ||
53 | enum json_tokener_error error; | ||
54 | |||
55 | 46006 | struct json_object *result = json_tokener_parse_verbose(src, &error); | |
56 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46006 times.
|
46006 | if (!result) { |
57 | ✗ | libjson_errno("json_tokener_parse_verbose"); | |
58 | ✗ | log_err("JSON: parsing failed: %s\n", json_tokener_error_desc(error)); | |
59 | ✗ | return NULL; | |
60 | } | ||
61 | |||
62 | 46006 | return result; | |
63 | } | ||
64 | |||
65 | 27618 | int libjson_clone(const struct json_object *obj, const char *key, struct json_object **_value) | |
66 | { | ||
67 | 27618 | int ret = 0; | |
68 | |||
69 | 27618 | struct json_object *old_value = NULL; | |
70 | 27618 | ret = libjson_get(obj, key, &old_value); | |
71 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27618 times.
|
27618 | if (ret < 0) |
72 | ✗ | return ret; | |
73 | |||
74 | 27618 | struct json_object *new_value = NULL; | |
75 | 27618 | ret = json_object_deep_copy(old_value, &new_value, NULL); | |
76 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27618 times.
|
27618 | if (ret < 0) |
77 | ✗ | return ret; | |
78 | |||
79 | 27618 | *_value = new_value; | |
80 | 27618 | return ret; | |
81 | } | ||
82 | |||
83 | 46006 | int libjson_send(struct json_object *obj, int fd) | |
84 | { | ||
85 | 46006 | int ret = 0; | |
86 | |||
87 | 46006 | const char *str = libjson_to_string(obj); | |
88 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46006 times.
|
46006 | if (!str) |
89 | ✗ | return -1; | |
90 | |||
91 | 46006 | struct buf *buf = NULL; | |
92 | 46006 | ret = buf_create_from_string(&buf, str); | |
93 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46006 times.
|
46006 | if (ret < 0) |
94 | ✗ | return ret; | |
95 | |||
96 | 46006 | ret = net_send_buf(fd, buf); | |
97 | 46006 | buf_destroy(buf); | |
98 | 46006 | return ret; | |
99 | } | ||
100 | |||
101 | 46006 | struct json_object *libjson_recv(int fd) | |
102 | { | ||
103 | 46006 | struct json_object *result = NULL; | |
104 | 46006 | int ret = 0; | |
105 | |||
106 | 46006 | struct buf *buf = NULL; | |
107 | 46006 | ret = net_recv_buf(fd, &buf); | |
108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46006 times.
|
46006 | if (ret < 0) |
109 | ✗ | return NULL; | |
110 | |||
111 | 46006 | result = libjson_from_string((const char *)buf_get_data(buf)); | |
112 |
1/2✓ Branch 0 taken 46006 times.
✗ Branch 1 not taken.
|
46006 | if (!result) |
113 | ✗ | goto destroy_buf; | |
114 | |||
115 | 46006 | destroy_buf: | |
116 | 46006 | free((void *)buf_get_data(buf)); | |
117 | 46006 | buf_destroy(buf); | |
118 | |||
119 | 46006 | return result; | |
120 | } | ||
121 | |||
122 | 110344 | int libjson_new_object(struct json_object **_obj) | |
123 | { | ||
124 | 110344 | struct json_object *obj = json_object_new_object(); | |
125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110344 times.
|
110344 | if (!obj) { |
126 | ✗ | libjson_errno("json_object_new_object"); | |
127 | ✗ | return -1; | |
128 | } | ||
129 | 110344 | *_obj = obj; | |
130 | 110344 | return 0; | |
131 | } | ||
132 | |||
133 | 26 | int libjson_new_array(struct json_object **_arr) | |
134 | { | ||
135 | 26 | struct json_object *arr = json_object_new_array(); | |
136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (!arr) { |
137 | ✗ | libjson_errno("json_object_new_array"); | |
138 | ✗ | return -1; | |
139 | } | ||
140 | 26 | *_arr = arr; | |
141 | 26 | return 0; | |
142 | } | ||
143 | |||
144 | 606620 | int libjson_has(const struct json_object *obj, const char *key) | |
145 | { | ||
146 | 606620 | return json_object_object_get_ex(obj, key, NULL); | |
147 | } | ||
148 | |||
149 | 385956 | int libjson_get(const struct json_object *obj, const char *key, struct json_object **value) | |
150 | { | ||
151 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 385956 times.
|
385956 | if (!libjson_has(obj, key)) { |
152 | ✗ | log_err("JSON: key is missing: %s\n", key); | |
153 | ✗ | return -1; | |
154 | } | ||
155 | |||
156 | 385956 | return json_object_object_get_ex(obj, key, value); | |
157 | } | ||
158 | |||
159 | 165506 | int libjson_get_string(const struct json_object *obj, const char *key, const char **_value) | |
160 | { | ||
161 | 165506 | struct json_object *value = NULL; | |
162 | |||
163 | 165506 | int ret = libjson_get(obj, key, &value); | |
164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 165506 times.
|
165506 | if (ret < 0) |
165 | ✗ | return ret; | |
166 | |||
167 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 165506 times.
|
165506 | if (!json_object_is_type(value, json_type_string)) { |
168 | ✗ | log_err("JSON: key is not a string: %s\n", key); | |
169 | ✗ | return -1; | |
170 | } | ||
171 | |||
172 | 165506 | *_value = json_object_get_string(value); | |
173 | 165506 | return 0; | |
174 | } | ||
175 | |||
176 | 27540 | int libjson_get_int(const struct json_object *obj, const char *key, int64_t *_value) | |
177 | { | ||
178 | 27540 | struct json_object *value = NULL; | |
179 | |||
180 | 27540 | int ret = libjson_get(obj, key, &value); | |
181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
182 | ✗ | return ret; | |
183 | |||
184 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 27540 times.
|
27540 | if (!json_object_is_type(value, json_type_int)) { |
185 | ✗ | log_err("JSON: key is not an integer: %s\n", key); | |
186 | ✗ | return -1; | |
187 | } | ||
188 | |||
189 | 27540 | errno = 0; | |
190 | 27540 | int64_t tmp = json_object_get_int64(value); | |
191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (errno) { |
192 | ✗ | log_err("JSON: failed to parse integer from key: %s\n", key); | |
193 | ✗ | return -1; | |
194 | } | ||
195 | |||
196 | 27540 | *_value = tmp; | |
197 | 27540 | return 0; | |
198 | } | ||
199 | |||
200 | 321772 | static int libjson_set_internal(struct json_object *obj, const char *key, struct json_object *value, | |
201 | unsigned flags) | ||
202 | { | ||
203 | 321772 | int ret = 0; | |
204 | |||
205 | 321772 | ret = json_object_object_add_ex(obj, key, value, flags); | |
206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 321772 times.
|
321772 | if (ret < 0) { |
207 | ✗ | libjson_errno("json_object_object_add_ex"); | |
208 | ✗ | return ret; | |
209 | } | ||
210 | |||
211 | 321772 | return 0; | |
212 | } | ||
213 | |||
214 | 174684 | static int libjson_set_string_internal(struct json_object *obj, const char *key, const char *_value, | |
215 | unsigned flags) | ||
216 | { | ||
217 | 174684 | struct json_object *value = json_object_new_string(_value); | |
218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 174684 times.
|
174684 | if (!value) { |
219 | ✗ | libjson_errno("json_object_new_string"); | |
220 | ✗ | return -1; | |
221 | } | ||
222 | |||
223 | 174684 | int ret = libjson_set_internal(obj, key, value, flags); | |
224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 174684 times.
|
174684 | if (ret < 0) |
225 | ✗ | goto free_value; | |
226 | |||
227 | 174684 | return ret; | |
228 | |||
229 | ✗ | free_value: | |
230 | ✗ | json_object_put(value); | |
231 | |||
232 | ✗ | return ret; | |
233 | } | ||
234 | |||
235 | 64312 | static int libjson_set_int_internal(struct json_object *obj, const char *key, int64_t _value, | |
236 | unsigned flags) | ||
237 | { | ||
238 | 64312 | struct json_object *value = json_object_new_int64(_value); | |
239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64312 times.
|
64312 | if (!value) { |
240 | ✗ | libjson_errno("json_object_new_int"); | |
241 | ✗ | return -1; | |
242 | } | ||
243 | |||
244 | 64312 | int ret = libjson_set_internal(obj, key, value, flags); | |
245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64312 times.
|
64312 | if (ret < 0) |
246 | ✗ | goto free_value; | |
247 | |||
248 | 64312 | return ret; | |
249 | |||
250 | ✗ | free_value: | |
251 | ✗ | json_object_put(value); | |
252 | |||
253 | ✗ | return ret; | |
254 | } | ||
255 | |||
256 | 55158 | int libjson_set(struct json_object *obj, const char *key, struct json_object *value) | |
257 | { | ||
258 | 55158 | return libjson_set_internal(obj, key, value, 0); | |
259 | } | ||
260 | |||
261 | 45900 | int libjson_set_string(struct json_object *obj, const char *key, const char *value) | |
262 | { | ||
263 | 45900 | return libjson_set_string_internal(obj, key, value, 0); | |
264 | } | ||
265 | |||
266 | 27540 | int libjson_set_int(struct json_object *obj, const char *key, int64_t value) | |
267 | { | ||
268 | 27540 | return libjson_set_int_internal(obj, key, value, 0); | |
269 | } | ||
270 | |||
271 | #ifndef JSON_C_OBJECT_ADD_CONSTANT_KEY | ||
272 | #define JSON_C_OBJECT_ADD_CONSTANT_KEY JSON_C_OBJECT_KEY_IS_CONSTANT | ||
273 | #endif | ||
274 | static const unsigned json_const_key_flags = JSON_C_OBJECT_ADD_CONSTANT_KEY; | ||
275 | |||
276 | 27618 | int libjson_set_const_key(struct json_object *obj, const char *key, struct json_object *value) | |
277 | { | ||
278 | 27618 | return libjson_set_internal(obj, key, value, json_const_key_flags); | |
279 | } | ||
280 | |||
281 | 128784 | int libjson_set_string_const_key(struct json_object *obj, const char *key, const char *value) | |
282 | { | ||
283 | 128784 | return libjson_set_string_internal(obj, key, value, json_const_key_flags); | |
284 | } | ||
285 | |||
286 | 36772 | int libjson_set_int_const_key(struct json_object *obj, const char *key, int64_t value) | |
287 | { | ||
288 | 36772 | return libjson_set_int_internal(obj, key, value, json_const_key_flags); | |
289 | } | ||
290 | |||
291 | 9180 | int libjson_append(struct json_object *arr, struct json_object *elem) | |
292 | { | ||
293 | 9180 | int ret = json_object_array_add(arr, elem); | |
294 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) { |
295 | ✗ | libjson_errno("json_object_array_add"); | |
296 | ✗ | return ret; | |
297 | } | ||
298 | 9180 | return ret; | |
299 | } | ||
300 |