Commit | Line | Data |
---|---|---|
cc372b17 SL |
1 | #include <stdlib.h> |
2 | #include <string.h> | |
3 | #include <stdio.h> | |
4 | #include <errno.h> | |
5 | #include <stdarg.h> | |
6 | #include "json.h" | |
7 | #include "log.h" | |
8 | ||
9 | struct json_object *json_create_object(void) | |
10 | { | |
e75cc8f3 | 11 | return calloc(1, sizeof(struct json_object)); |
cc372b17 SL |
12 | } |
13 | ||
14 | struct json_array *json_create_array(void) | |
15 | { | |
e75cc8f3 | 16 | return calloc(1, sizeof(struct json_array)); |
cc372b17 SL |
17 | } |
18 | ||
19 | static struct json_pair *json_create_pair(const char *name, struct json_value *value) | |
20 | { | |
21 | struct json_pair *pair = malloc(sizeof(struct json_pair)); | |
22 | if (pair) { | |
23 | pair->name = strdup(name); | |
24 | pair->value = value; | |
25 | ||
26 | value->parent_type = JSON_PARENT_TYPE_PAIR; | |
27 | value->parent_pair = pair; | |
28 | } | |
29 | return pair; | |
30 | } | |
31 | ||
ee2e5717 | 32 | static struct json_value *json_create_value_int(long long number) |
cc372b17 SL |
33 | { |
34 | struct json_value *value = malloc(sizeof(struct json_value)); | |
35 | ||
36 | if (value) { | |
37 | value->type = JSON_TYPE_INTEGER; | |
38 | value->integer_number = number; | |
39 | } | |
40 | return value; | |
41 | } | |
42 | ||
a2972f96 | 43 | static struct json_value *json_create_value_float(double number) |
cc372b17 SL |
44 | { |
45 | struct json_value *value = malloc(sizeof(struct json_value)); | |
46 | ||
47 | if (value) { | |
48 | value->type = JSON_TYPE_FLOAT; | |
49 | value->float_number = number; | |
50 | } | |
51 | return value; | |
52 | } | |
53 | ||
d366a95e JA |
54 | static char *strdup_escape(const char *str) |
55 | { | |
56 | const char *input = str; | |
57 | char *p, *ret; | |
58 | int escapes; | |
59 | ||
a5725153 JA |
60 | if (!strlen(str)) |
61 | return NULL; | |
62 | ||
d366a95e JA |
63 | escapes = 0; |
64 | while ((input = strpbrk(input, "\\\"")) != NULL) { | |
65 | escapes++; | |
66 | input++; | |
67 | } | |
68 | ||
a5725153 | 69 | p = ret = malloc(strlen(str) + escapes + 1); |
d366a95e JA |
70 | while (*str) { |
71 | if (*str == '\\' || *str == '\"') | |
72 | *p++ = '\\'; | |
73 | *p++ = *str++; | |
74 | } | |
a5725153 | 75 | *p = '\0'; |
d366a95e JA |
76 | |
77 | return ret; | |
78 | } | |
79 | ||
80 | /* | |
de8f6de9 | 81 | * Valid JSON strings must escape '"' and '/' with a preceding '/' |
d366a95e | 82 | */ |
cc372b17 SL |
83 | static struct json_value *json_create_value_string(const char *str) |
84 | { | |
85 | struct json_value *value = malloc(sizeof(struct json_value)); | |
86 | ||
87 | if (value) { | |
88 | value->type = JSON_TYPE_STRING; | |
d366a95e | 89 | value->string = strdup_escape(str); |
cc372b17 SL |
90 | if (!value->string) { |
91 | free(value); | |
92 | value = NULL; | |
93 | } | |
94 | } | |
95 | return value; | |
96 | } | |
97 | ||
98 | static struct json_value *json_create_value_object(struct json_object *obj) | |
99 | { | |
100 | struct json_value *value = malloc(sizeof(struct json_value)); | |
101 | ||
102 | if (value) { | |
103 | value->type = JSON_TYPE_OBJECT; | |
104 | value->object = obj; | |
105 | obj->parent = value; | |
106 | } | |
107 | return value; | |
108 | } | |
109 | ||
110 | static struct json_value *json_create_value_array(struct json_array *array) | |
111 | { | |
112 | struct json_value *value = malloc(sizeof(struct json_value)); | |
113 | ||
114 | if (value) { | |
115 | value->type = JSON_TYPE_ARRAY; | |
116 | value->array = array; | |
117 | array->parent = value; | |
118 | } | |
119 | return value; | |
120 | } | |
121 | ||
cc372b17 SL |
122 | static void json_free_pair(struct json_pair *pair); |
123 | static void json_free_value(struct json_value *value); | |
f3afa57e | 124 | |
cc372b17 SL |
125 | void json_free_object(struct json_object *obj) |
126 | { | |
127 | int i; | |
128 | ||
129 | for (i = 0; i < obj->pair_cnt; i++) | |
130 | json_free_pair(obj->pairs[i]); | |
131 | free(obj->pairs); | |
132 | free(obj); | |
133 | } | |
134 | ||
135 | static void json_free_array(struct json_array *array) | |
136 | { | |
137 | int i; | |
138 | ||
139 | for (i = 0; i < array->value_cnt; i++) | |
140 | json_free_value(array->values[i]); | |
141 | free(array->values); | |
142 | free(array); | |
143 | } | |
144 | ||
145 | static void json_free_pair(struct json_pair *pair) | |
146 | { | |
147 | json_free_value(pair->value); | |
148 | free(pair->name); | |
149 | free(pair); | |
150 | } | |
151 | ||
152 | static void json_free_value(struct json_value *value) | |
153 | { | |
154 | switch (value->type) { | |
155 | case JSON_TYPE_STRING: | |
156 | free(value->string); | |
157 | break; | |
158 | case JSON_TYPE_OBJECT: | |
159 | json_free_object(value->object); | |
160 | break; | |
161 | case JSON_TYPE_ARRAY: | |
162 | json_free_array(value->array); | |
163 | break; | |
164 | } | |
165 | free(value); | |
166 | } | |
167 | ||
168 | static int json_array_add_value(struct json_array *array, struct json_value *value) | |
169 | { | |
170 | struct json_value **values = realloc(array->values, | |
171 | sizeof(struct json_value *) * (array->value_cnt + 1)); | |
172 | ||
173 | if (!values) | |
174 | return ENOMEM; | |
175 | values[array->value_cnt] = value; | |
176 | array->value_cnt++; | |
177 | array->values = values; | |
178 | ||
179 | value->parent_type = JSON_PARENT_TYPE_ARRAY; | |
180 | value->parent_array = array; | |
181 | return 0; | |
182 | } | |
183 | ||
184 | static int json_object_add_pair(struct json_object *obj, struct json_pair *pair) | |
185 | { | |
186 | struct json_pair **pairs = realloc(obj->pairs, | |
187 | sizeof(struct json_pair *) * (obj->pair_cnt + 1)); | |
188 | if (!pairs) | |
189 | return ENOMEM; | |
190 | pairs[obj->pair_cnt] = pair; | |
191 | obj->pair_cnt++; | |
192 | obj->pairs = pairs; | |
193 | ||
194 | pair->parent = obj; | |
195 | return 0; | |
196 | } | |
197 | ||
198 | int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...) | |
199 | { | |
200 | struct json_value *value; | |
201 | struct json_pair *pair; | |
202 | va_list args; | |
203 | int ret; | |
204 | ||
205 | va_start(args, type); | |
206 | if (type == JSON_TYPE_STRING) | |
207 | value = json_create_value_string(va_arg(args, char *)); | |
208 | else if (type == JSON_TYPE_INTEGER) | |
ee2e5717 | 209 | value = json_create_value_int(va_arg(args, long long)); |
cc372b17 SL |
210 | else if (type == JSON_TYPE_FLOAT) |
211 | value = json_create_value_float(va_arg(args, double)); | |
212 | else if (type == JSON_TYPE_OBJECT) | |
213 | value = json_create_value_object(va_arg(args, struct json_object *)); | |
214 | else | |
215 | value = json_create_value_array(va_arg(args, struct json_array *)); | |
216 | va_end(args); | |
217 | ||
218 | if (!value) | |
219 | return ENOMEM; | |
220 | ||
221 | pair = json_create_pair(name, value); | |
222 | if (!pair) { | |
223 | json_free_value(value); | |
224 | return ENOMEM; | |
225 | } | |
226 | ret = json_object_add_pair(obj, pair); | |
227 | if (ret) { | |
228 | json_free_pair(pair); | |
229 | return ENOMEM; | |
230 | } | |
231 | return 0; | |
232 | } | |
233 | ||
a666cab8 | 234 | static void json_print_array(struct json_array *array, struct buf_output *); |
cc372b17 SL |
235 | int json_array_add_value_type(struct json_array *array, int type, ...) |
236 | { | |
237 | struct json_value *value; | |
238 | va_list args; | |
239 | int ret; | |
240 | ||
241 | va_start(args, type); | |
242 | if (type == JSON_TYPE_STRING) | |
243 | value = json_create_value_string(va_arg(args, char *)); | |
244 | else if (type == JSON_TYPE_INTEGER) | |
ee2e5717 | 245 | value = json_create_value_int(va_arg(args, long long)); |
cc372b17 SL |
246 | else if (type == JSON_TYPE_FLOAT) |
247 | value = json_create_value_float(va_arg(args, double)); | |
248 | else if (type == JSON_TYPE_OBJECT) | |
249 | value = json_create_value_object(va_arg(args, struct json_object *)); | |
250 | else | |
251 | value = json_create_value_array(va_arg(args, struct json_array *)); | |
252 | va_end(args); | |
253 | ||
254 | if (!value) | |
255 | return ENOMEM; | |
256 | ||
257 | ret = json_array_add_value(array, value); | |
258 | if (ret) { | |
259 | json_free_value(value); | |
260 | return ENOMEM; | |
261 | } | |
262 | return 0; | |
263 | } | |
264 | ||
265 | static int json_value_level(struct json_value *value); | |
266 | static int json_pair_level(struct json_pair *pair); | |
267 | static int json_array_level(struct json_array *array); | |
268 | static int json_object_level(struct json_object *object) | |
269 | { | |
270 | if (object->parent == NULL) | |
271 | return 0; | |
272 | return json_value_level(object->parent); | |
273 | } | |
274 | ||
275 | static int json_pair_level(struct json_pair *pair) | |
276 | { | |
277 | return json_object_level(pair->parent) + 1; | |
278 | } | |
279 | ||
280 | static int json_array_level(struct json_array *array) | |
281 | { | |
282 | return json_value_level(array->parent); | |
283 | } | |
284 | ||
285 | static int json_value_level(struct json_value *value) | |
286 | { | |
287 | if (value->parent_type == JSON_PARENT_TYPE_PAIR) | |
288 | return json_pair_level(value->parent_pair); | |
289 | else | |
290 | return json_array_level(value->parent_array) + 1; | |
291 | } | |
292 | ||
a666cab8 | 293 | static void json_print_level(int level, struct buf_output *out) |
cc372b17 SL |
294 | { |
295 | while (level-- > 0) | |
a666cab8 | 296 | log_buf(out, " "); |
cc372b17 SL |
297 | } |
298 | ||
a666cab8 JA |
299 | static void json_print_pair(struct json_pair *pair, struct buf_output *); |
300 | static void json_print_array(struct json_array *array, struct buf_output *); | |
301 | static void json_print_value(struct json_value *value, struct buf_output *); | |
302 | void json_print_object(struct json_object *obj, struct buf_output *out) | |
cc372b17 SL |
303 | { |
304 | int i; | |
305 | ||
a666cab8 | 306 | log_buf(out, "{\n"); |
cc372b17 SL |
307 | for (i = 0; i < obj->pair_cnt; i++) { |
308 | if (i > 0) | |
a666cab8 JA |
309 | log_buf(out, ",\n"); |
310 | json_print_pair(obj->pairs[i], out); | |
cc372b17 | 311 | } |
a666cab8 JA |
312 | log_buf(out, "\n"); |
313 | json_print_level(json_object_level(obj), out); | |
314 | log_buf(out, "}"); | |
cc372b17 SL |
315 | } |
316 | ||
a666cab8 | 317 | static void json_print_pair(struct json_pair *pair, struct buf_output *out) |
cc372b17 | 318 | { |
a666cab8 JA |
319 | json_print_level(json_pair_level(pair), out); |
320 | log_buf(out, "\"%s\" : ", pair->name); | |
321 | json_print_value(pair->value, out); | |
cc372b17 SL |
322 | } |
323 | ||
a666cab8 | 324 | static void json_print_array(struct json_array *array, struct buf_output *out) |
cc372b17 SL |
325 | { |
326 | int i; | |
327 | ||
a666cab8 | 328 | log_buf(out, "[\n"); |
cc372b17 SL |
329 | for (i = 0; i < array->value_cnt; i++) { |
330 | if (i > 0) | |
a666cab8 JA |
331 | log_buf(out, ",\n"); |
332 | json_print_level(json_value_level(array->values[i]), out); | |
333 | json_print_value(array->values[i], out); | |
cc372b17 | 334 | } |
a666cab8 JA |
335 | log_buf(out, "\n"); |
336 | json_print_level(json_array_level(array), out); | |
337 | log_buf(out, "]"); | |
cc372b17 SL |
338 | } |
339 | ||
a666cab8 | 340 | static void json_print_value(struct json_value *value, struct buf_output *out) |
cc372b17 SL |
341 | { |
342 | switch (value->type) { | |
2374148c JA |
343 | case JSON_TYPE_STRING: |
344 | log_buf(out, "\"%s\"", value->string); | |
345 | break; | |
cc372b17 | 346 | case JSON_TYPE_INTEGER: |
a666cab8 | 347 | log_buf(out, "%lld", value->integer_number); |
cc372b17 SL |
348 | break; |
349 | case JSON_TYPE_FLOAT: | |
817720e1 | 350 | log_buf(out, "%f", value->float_number); |
cc372b17 SL |
351 | break; |
352 | case JSON_TYPE_OBJECT: | |
a666cab8 | 353 | json_print_object(value->object, out); |
cc372b17 SL |
354 | break; |
355 | case JSON_TYPE_ARRAY: | |
a666cab8 | 356 | json_print_array(value->array, out); |
cc372b17 SL |
357 | break; |
358 | } | |
359 | } |