Directory: | src/ |
---|---|
File: | src/json.c |
Date: | 2023-08-28 07:33:56 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 91 | 126 | 72.2% |
Branches: | 19 | 58 | 32.8% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2023 Egor Tensin <Egor.Tensin@gmail.com> | ||
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 "log.h" | ||
10 | #include "net.h" | ||
11 | |||
12 | #include <json-c/json_object.h> | ||
13 | #include <json-c/json_tokener.h> | ||
14 | |||
15 | #include <errno.h> | ||
16 | #include <stdint.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | |||
20 | 45954 | const char *json_to_string(struct json_object *obj) | |
21 | { | ||
22 | 45954 | const char *result = json_object_to_json_string(obj); | |
23 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (!result) { |
24 | ✗ | json_errno("json_object_to_json_string"); | |
25 | ✗ | return NULL; | |
26 | } | ||
27 | 45954 | return result; | |
28 | } | ||
29 | |||
30 | 45954 | struct json_object *json_from_string(const char *src) | |
31 | { | ||
32 | enum json_tokener_error error; | ||
33 | |||
34 | 45954 | struct json_object *result = json_tokener_parse_verbose(src, &error); | |
35 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (!result) { |
36 | ✗ | json_errno("json_tokener_parse_verbose"); | |
37 | ✗ | log_err("JSON: parsing failed: %s\n", json_tokener_error_desc(error)); | |
38 | ✗ | return NULL; | |
39 | } | ||
40 | |||
41 | 45954 | return result; | |
42 | } | ||
43 | |||
44 | 27540 | int json_clone(const struct json_object *obj, const char *key, struct json_object **_value) | |
45 | { | ||
46 | 27540 | int ret = 0; | |
47 | |||
48 | 27540 | struct json_object *old_value = NULL; | |
49 | 27540 | ret = json_get(obj, key, &old_value); | |
50 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
51 | ✗ | return ret; | |
52 | |||
53 | 27540 | struct json_object *new_value = NULL; | |
54 | 27540 | ret = json_object_deep_copy(old_value, &new_value, NULL); | |
55 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
56 | ✗ | return ret; | |
57 | |||
58 | 27540 | *_value = new_value; | |
59 | 27540 | return ret; | |
60 | } | ||
61 | |||
62 | 45954 | int json_send(struct json_object *obj, int fd) | |
63 | { | ||
64 | 45954 | int ret = 0; | |
65 | |||
66 | 45954 | const char *str = json_to_string(obj); | |
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (!str) |
68 | ✗ | return -1; | |
69 | |||
70 | 45954 | struct buf *buf = NULL; | |
71 | 45954 | ret = buf_create_from_string(&buf, str); | |
72 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) |
73 | ✗ | return ret; | |
74 | |||
75 | 45954 | ret = net_send_buf(fd, buf); | |
76 | 45954 | buf_destroy(buf); | |
77 | 45954 | return ret; | |
78 | } | ||
79 | |||
80 | 45954 | struct json_object *json_recv(int fd) | |
81 | { | ||
82 | 45954 | struct json_object *result = NULL; | |
83 | 45954 | int ret = 0; | |
84 | |||
85 | 45954 | struct buf *buf = NULL; | |
86 | 45954 | ret = net_recv_buf(fd, &buf); | |
87 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) |
88 | ✗ | return NULL; | |
89 | |||
90 | 45954 | result = json_from_string((const char *)buf_get_data(buf)); | |
91 |
1/2✓ Branch 0 taken 45954 times.
✗ Branch 1 not taken.
|
45954 | if (!result) |
92 | ✗ | goto destroy_buf; | |
93 | |||
94 | 45954 | destroy_buf: | |
95 | 45954 | free((void *)buf_get_data(buf)); | |
96 | 45954 | buf_destroy(buf); | |
97 | |||
98 | 45954 | return result; | |
99 | } | ||
100 | |||
101 | 606204 | int json_has(const struct json_object *obj, const char *key) | |
102 | { | ||
103 | 606204 | return json_object_object_get_ex(obj, key, NULL); | |
104 | } | ||
105 | |||
106 | 385722 | int json_get(const struct json_object *obj, const char *key, struct json_object **value) | |
107 | { | ||
108 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 385722 times.
|
385722 | if (!json_has(obj, key)) { |
109 | ✗ | log_err("JSON: key is missing: %s\n", key); | |
110 | ✗ | return -1; | |
111 | } | ||
112 | |||
113 | 385722 | return json_object_object_get_ex(obj, key, value); | |
114 | } | ||
115 | |||
116 | 165402 | int json_get_string(const struct json_object *obj, const char *key, const char **_value) | |
117 | { | ||
118 | 165402 | struct json_object *value = NULL; | |
119 | |||
120 | 165402 | int ret = json_get(obj, key, &value); | |
121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 165402 times.
|
165402 | if (ret < 0) |
122 | ✗ | return ret; | |
123 | |||
124 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 165402 times.
|
165402 | if (!json_object_is_type(value, json_type_string)) { |
125 | ✗ | log_err("JSON: key is not a string: %s\n", key); | |
126 | ✗ | return -1; | |
127 | } | ||
128 | |||
129 | 165402 | *_value = json_object_get_string(value); | |
130 | 165402 | return 0; | |
131 | } | ||
132 | |||
133 | 27540 | int json_get_int(const struct json_object *obj, const char *key, int64_t *_value) | |
134 | { | ||
135 | 27540 | struct json_object *value = NULL; | |
136 | |||
137 | 27540 | int ret = json_get(obj, key, &value); | |
138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
139 | ✗ | return ret; | |
140 | |||
141 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 27540 times.
|
27540 | if (!json_object_is_type(value, json_type_int)) { |
142 | ✗ | log_err("JSON: key is not an integer: %s\n", key); | |
143 | ✗ | return -1; | |
144 | } | ||
145 | |||
146 | 27540 | errno = 0; | |
147 | 27540 | int64_t tmp = json_object_get_int64(value); | |
148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (errno) { |
149 | ✗ | log_err("JSON: failed to parse integer from key: %s\n", key); | |
150 | ✗ | return -1; | |
151 | } | ||
152 | |||
153 | 27540 | *_value = tmp; | |
154 | 27540 | return 0; | |
155 | } | ||
156 | |||
157 | 284688 | static int json_set_internal(struct json_object *obj, const char *key, struct json_object *value, | |
158 | unsigned flags) | ||
159 | { | ||
160 | 284688 | int ret = 0; | |
161 | |||
162 | 284688 | ret = json_object_object_add_ex(obj, key, value, flags); | |
163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 284688 times.
|
284688 | if (ret < 0) { |
164 | ✗ | json_errno("json_object_object_add_ex"); | |
165 | ✗ | return ret; | |
166 | } | ||
167 | |||
168 | 284688 | return 0; | |
169 | } | ||
170 | |||
171 | 156168 | static int json_set_string_internal(struct json_object *obj, const char *key, const char *_value, | |
172 | unsigned flags) | ||
173 | { | ||
174 | 156168 | struct json_object *value = json_object_new_string(_value); | |
175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156168 times.
|
156168 | if (!value) { |
176 | ✗ | json_errno("json_object_new_string"); | |
177 | ✗ | return -1; | |
178 | } | ||
179 | |||
180 | 156168 | int ret = json_set_internal(obj, key, value, flags); | |
181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156168 times.
|
156168 | if (ret < 0) |
182 | ✗ | goto free_value; | |
183 | |||
184 | 156168 | return ret; | |
185 | |||
186 | ✗ | free_value: | |
187 | ✗ | json_object_put(value); | |
188 | |||
189 | ✗ | return ret; | |
190 | } | ||
191 | |||
192 | 45900 | static int json_set_int_internal(struct json_object *obj, const char *key, int64_t _value, | |
193 | unsigned flags) | ||
194 | { | ||
195 | 45900 | struct json_object *value = json_object_new_int64(_value); | |
196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45900 times.
|
45900 | if (!value) { |
197 | ✗ | json_errno("json_object_new_int"); | |
198 | ✗ | return -1; | |
199 | } | ||
200 | |||
201 | 45900 | int ret = json_set_internal(obj, key, value, flags); | |
202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45900 times.
|
45900 | if (ret < 0) |
203 | ✗ | goto free_value; | |
204 | |||
205 | 45900 | return ret; | |
206 | |||
207 | ✗ | free_value: | |
208 | ✗ | json_object_put(value); | |
209 | |||
210 | ✗ | return ret; | |
211 | } | ||
212 | |||
213 | 55080 | int json_set(struct json_object *obj, const char *key, struct json_object *value) | |
214 | { | ||
215 | 55080 | return json_set_internal(obj, key, value, 0); | |
216 | } | ||
217 | |||
218 | 45900 | int json_set_string(struct json_object *obj, const char *key, const char *value) | |
219 | { | ||
220 | 45900 | return json_set_string_internal(obj, key, value, 0); | |
221 | } | ||
222 | |||
223 | 27540 | int json_set_int(struct json_object *obj, const char *key, int64_t value) | |
224 | { | ||
225 | 27540 | return json_set_int_internal(obj, key, value, 0); | |
226 | } | ||
227 | |||
228 | #ifndef JSON_C_OBJECT_ADD_CONSTANT_KEY | ||
229 | #define JSON_C_OBJECT_ADD_CONSTANT_KEY JSON_C_OBJECT_KEY_IS_CONSTANT | ||
230 | #endif | ||
231 | static const unsigned json_const_key_flags = JSON_C_OBJECT_ADD_CONSTANT_KEY; | ||
232 | |||
233 | 27540 | int json_set_const_key(struct json_object *obj, const char *key, struct json_object *value) | |
234 | { | ||
235 | 27540 | return json_set_internal(obj, key, value, json_const_key_flags); | |
236 | } | ||
237 | |||
238 | 110268 | int json_set_string_const_key(struct json_object *obj, const char *key, const char *value) | |
239 | { | ||
240 | 110268 | return json_set_string_internal(obj, key, value, json_const_key_flags); | |
241 | } | ||
242 | |||
243 | 18360 | int json_set_int_const_key(struct json_object *obj, const char *key, int64_t value) | |
244 | { | ||
245 | 18360 | return json_set_int_internal(obj, key, value, json_const_key_flags); | |
246 | } | ||
247 |