1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3 * Copyright (C) 2021-2024 Cyril Hrubis <metan@ucw.cz>
4 */
5
6 #include <string.h>
7 #include <stdarg.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13
14 #include "ujson_utf.h"
15 #include "ujson_writer.h"
16
get_depth_bit(ujson_writer * self,char * mask)17 static inline int get_depth_bit(ujson_writer *self, char *mask)
18 {
19 int depth = self->depth - 1;
20
21 if (depth < 0)
22 return -1;
23
24 return !!(mask[depth/8] & (1<<(depth%8)));
25 }
26
set_depth_bit(ujson_writer * self,int val)27 static inline void set_depth_bit(ujson_writer *self, int val)
28 {
29 if (val)
30 self->depth_type[self->depth/8] |= (1<<(self->depth%8));
31 else
32 self->depth_type[self->depth/8] &= ~(1<<(self->depth%8));
33
34 self->depth_first[self->depth/8] |= (1<<(self->depth%8));
35
36 self->depth++;
37 }
38
clear_depth_bit(ujson_writer * self)39 static inline void clear_depth_bit(ujson_writer *self)
40 {
41 self->depth--;
42 }
43
in_arr(ujson_writer * self)44 static inline int in_arr(ujson_writer *self)
45 {
46 return !get_depth_bit(self, self->depth_type);
47 }
48
in_obj(ujson_writer * self)49 static inline int in_obj(ujson_writer *self)
50 {
51 return get_depth_bit(self, self->depth_type);
52 }
53
clear_depth_first(ujson_writer * self)54 static inline void clear_depth_first(ujson_writer *self)
55 {
56 int depth = self->depth - 1;
57
58 self->depth_first[depth/8] &= ~(1<<(depth%8));
59 }
60
is_first(ujson_writer * self)61 static inline int is_first(ujson_writer *self)
62 {
63 int ret = get_depth_bit(self, self->depth_first);
64
65 if (ret == 1)
66 clear_depth_first(self);
67
68 return ret;
69 }
70
err(ujson_writer * buf,const char * fmt,...)71 static inline void err(ujson_writer *buf, const char *fmt, ...)
72 {
73 va_list va;
74
75 va_start(va, fmt);
76 vsnprintf(buf->err, UJSON_ERR_MAX, fmt, va);
77 va_end(va);
78 }
79
is_err(ujson_writer * buf)80 static inline int is_err(ujson_writer *buf)
81 {
82 return buf->err[0];
83 }
84
out(ujson_writer * self,const char * buf,size_t len)85 static inline int out(ujson_writer *self, const char *buf, size_t len)
86 {
87 return self->out(self, buf, len);
88 }
89
out_str(ujson_writer * self,const char * str)90 static inline int out_str(ujson_writer *self, const char *str)
91 {
92 return out(self, str, strlen(str));
93 }
94
out_ch(ujson_writer * self,char ch)95 static inline int out_ch(ujson_writer *self, char ch)
96 {
97 return out(self, &ch, 1);
98 }
99
100 #define ESC_FLUSH(esc_char) do {\
101 out(self, val, i); \
102 val += i + 1; \
103 i = 0; \
104 out_str(self, esc_char); \
105 } while (0)
106
out_esc_str(ujson_writer * self,const char * val)107 static inline int out_esc_str(ujson_writer *self, const char *val)
108 {
109 if (out_ch(self, '"'))
110 return 1;
111
112 size_t i = 0;
113 int8_t next_chsz;
114
115 do {
116 next_chsz = ujson_utf8_next_chsz(val, i);
117
118 if (next_chsz == 1) {
119 switch (val[i]) {
120 case '\"':
121 ESC_FLUSH("\\\"");
122 break;
123 case '\\':
124 ESC_FLUSH("\\\\");
125 break;
126 case '/':
127 ESC_FLUSH("\\/");
128 break;
129 case '\b':
130 ESC_FLUSH("\\b");
131 break;
132 case '\f':
133 ESC_FLUSH("\\f");
134 break;
135 case '\n':
136 ESC_FLUSH("\\n");
137 break;
138 case '\r':
139 ESC_FLUSH("\\r");
140 break;
141 case '\t':
142 ESC_FLUSH("\\t");
143 break;
144 default:
145 i += next_chsz;
146 }
147 } else {
148 i += next_chsz;
149 }
150 } while (next_chsz);
151
152 if (i) {
153 if (out(self, val, i))
154 return 1;
155 }
156
157 if (out_ch(self, '"'))
158 return 1;
159
160 return 0;
161 }
162
do_padd(ujson_writer * self)163 static int do_padd(ujson_writer *self)
164 {
165 unsigned int i;
166
167 for (i = 0; i < self->depth; i++) {
168 if (out_ch(self, ' '))
169 return 1;
170 }
171
172 return 0;
173 }
174
newline(ujson_writer * self)175 static int newline(ujson_writer *self)
176 {
177 if (out_ch(self, '\n'))
178 return 0;
179
180 if (do_padd(self))
181 return 1;
182
183 return 0;
184 }
185
add_common(ujson_writer * self,const char * id)186 static int add_common(ujson_writer *self, const char *id)
187 {
188 if (is_err(self))
189 return 1;
190
191 if (!self->depth) {
192 err(self, "Object/Array has to be started first");
193 return 1;
194 }
195
196 if (in_arr(self)) {
197 if (id) {
198 err(self, "Array entries can't have id");
199 return 1;
200 }
201 } else {
202 if (!id) {
203 err(self, "Object entries must have id");
204 return 1;
205 }
206 }
207
208 if (!is_first(self) && out_ch(self, ','))
209 return 1;
210
211 if (self->depth && newline(self))
212 return 1;
213
214 if (id) {
215 if (out_esc_str(self, id))
216 return 1;
217
218 if (out_str(self, ": "))
219 return 1;
220 }
221
222 return 0;
223 }
224
ujson_obj_start(ujson_writer * self,const char * id)225 int ujson_obj_start(ujson_writer *self, const char *id)
226 {
227 if (self->depth >= UJSON_RECURSION_MAX)
228 return 1;
229
230 if (!self->depth && id) {
231 err(self, "Top level object cannot have id");
232 return 1;
233 }
234
235 if (self->depth && add_common(self, id))
236 return 1;
237
238 if (out_ch(self, '{'))
239 return 1;
240
241 set_depth_bit(self, 1);
242
243 return 0;
244 }
245
ujson_obj_finish(ujson_writer * self)246 int ujson_obj_finish(ujson_writer *self)
247 {
248 if (is_err(self))
249 return 1;
250
251 if (!in_obj(self)) {
252 err(self, "Not in object!");
253 return 1;
254 }
255
256 int first = is_first(self);
257
258 clear_depth_bit(self);
259
260 if (!first)
261 newline(self);
262
263 return out_ch(self, '}');
264 }
265
ujson_arr_start(ujson_writer * self,const char * id)266 int ujson_arr_start(ujson_writer *self, const char *id)
267 {
268 if (self->depth >= UJSON_RECURSION_MAX) {
269 err(self, "Recursion too deep");
270 return 1;
271 }
272
273 if (!self->depth && id) {
274 err(self, "Top level array cannot have id");
275 return 1;
276 }
277
278 if (self->depth && add_common(self, id))
279 return 1;
280
281 if (out_ch(self, '['))
282 return 1;
283
284 set_depth_bit(self, 0);
285
286 return 0;
287 }
288
ujson_arr_finish(ujson_writer * self)289 int ujson_arr_finish(ujson_writer *self)
290 {
291 if (is_err(self))
292 return 1;
293
294 if (!in_arr(self)) {
295 err(self, "Not in array!");
296 return 1;
297 }
298
299 int first = is_first(self);
300
301 clear_depth_bit(self);
302
303 if (!first)
304 newline(self);
305
306 return out_ch(self, ']');
307 }
308
ujson_null_add(ujson_writer * self,const char * id)309 int ujson_null_add(ujson_writer *self, const char *id)
310 {
311 if (add_common(self, id))
312 return 1;
313
314 return out_str(self, "null");
315 }
316
ujson_int_add(ujson_writer * self,const char * id,long val)317 int ujson_int_add(ujson_writer *self, const char *id, long val)
318 {
319 char buf[64];
320
321 if (add_common(self, id))
322 return 1;
323
324 snprintf(buf, sizeof(buf), "%li", val);
325
326 return out_str(self, buf);
327 }
328
ujson_bool_add(ujson_writer * self,const char * id,int val)329 int ujson_bool_add(ujson_writer *self, const char *id, int val)
330 {
331 if (add_common(self, id))
332 return 1;
333
334 if (val)
335 return out_str(self, "true");
336 else
337 return out_str(self, "false");
338 }
339
ujson_str_add(ujson_writer * self,const char * id,const char * val)340 int ujson_str_add(ujson_writer *self, const char *id, const char *val)
341 {
342 if (add_common(self, id))
343 return 1;
344
345 if (out_esc_str(self, val))
346 return 1;
347
348 return 0;
349 }
350
ujson_float_add(ujson_writer * self,const char * id,double val)351 int ujson_float_add(ujson_writer *self, const char *id, double val)
352 {
353 char buf[64];
354
355 if (add_common(self, id))
356 return 1;
357
358 snprintf(buf, sizeof(buf), "%lg", val);
359
360 return out_str(self, buf);
361 }
362
ujson_writer_finish(ujson_writer * self)363 int ujson_writer_finish(ujson_writer *self)
364 {
365 if (is_err(self))
366 goto err;
367
368 if (self->depth) {
369 err(self, "Objects and/or Arrays not finished");
370 goto err;
371 }
372
373 if (newline(self))
374 return 1;
375
376 return 0;
377 err:
378 if (self->err_print)
379 self->err_print(self->err_print_priv, self->err);
380
381 return 1;
382 }
383
384 struct json_writer_file {
385 int fd;
386 size_t buf_used;
387 char buf[1024];
388 };
389
out_writer_file_write(ujson_writer * self,int fd,const char * buf,ssize_t buf_len)390 static int out_writer_file_write(ujson_writer *self, int fd, const char *buf, ssize_t buf_len)
391 {
392 do {
393 ssize_t ret = write(fd, buf, buf_len);
394 if (ret <= 0) {
395 err(self, "Failed to write to a file");
396 return 1;
397 }
398
399 if (ret > buf_len) {
400 err(self, "Wrote more bytes than requested?!");
401 return 1;
402 }
403
404 buf_len -= ret;
405 } while (buf_len);
406
407 return 0;
408 }
409
out_writer_file(ujson_writer * self,const char * buf,size_t buf_len)410 static int out_writer_file(ujson_writer *self, const char *buf, size_t buf_len)
411 {
412 struct json_writer_file *writer_file = self->out_priv;
413 size_t buf_size = sizeof(writer_file->buf);
414 size_t buf_avail = buf_size - writer_file->buf_used;
415
416 if (buf_len > buf_size/4)
417 return out_writer_file_write(self, writer_file->fd, buf, buf_len);
418
419 if (buf_len >= buf_avail) {
420 if (out_writer_file_write(self, writer_file->fd,
421 writer_file->buf, writer_file->buf_used))
422 return 1;
423
424 memcpy(writer_file->buf, buf, buf_len);
425 writer_file->buf_used = buf_len;
426 return 0;
427 }
428
429 memcpy(writer_file->buf + writer_file->buf_used, buf, buf_len);
430 writer_file->buf_used += buf_len;
431
432 return 0;
433 }
434
ujson_writer_file_close(ujson_writer * self)435 int ujson_writer_file_close(ujson_writer *self)
436 {
437 struct json_writer_file *writer_file = self->out_priv;
438 int saved_errno = 0;
439
440 if (writer_file->buf_used) {
441 if (out_writer_file_write(self, writer_file->fd,
442 writer_file->buf, writer_file->buf_used))
443
444 saved_errno = errno;
445 }
446
447 if (close(writer_file->fd)) {
448 if (!saved_errno)
449 saved_errno = errno;
450 }
451
452 free(self);
453
454 if (saved_errno) {
455 errno = saved_errno;
456 return 1;
457 }
458
459 return 0;
460 }
461
ujson_writer_file_open(const char * path)462 ujson_writer *ujson_writer_file_open(const char *path)
463 {
464 ujson_writer *ret;
465 struct json_writer_file *writer_file;
466
467 ret = malloc(sizeof(ujson_writer) + sizeof(struct json_writer_file));
468 if (!ret)
469 return NULL;
470
471 writer_file = (void*)ret + sizeof(ujson_writer);
472
473 writer_file->fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0664);
474 if (!writer_file->fd) {
475 free(ret);
476 return NULL;
477 }
478
479 writer_file->buf_used = 0;
480
481 memset(ret, 0, sizeof(*ret));
482
483 ret->err_print = UJSON_ERR_PRINT;
484 ret->err_print_priv = UJSON_ERR_PRINT_PRIV;
485 ret->out = out_writer_file;
486 ret->out_priv = writer_file;
487
488 return ret;
489 }
490