• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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