1 /* Creation date: 2008-11-27T07:33:50Z
2  * Authors: Don
3  */
4 
5 /*
6 
7  Copyright (c) 2008-2010 Don Owens <don@regexguy.com>.  All rights reserved.
8 
9  This is free software; you can redistribute it and/or modify it under
10  the Perl Artistic license.  You should have received a copy of the
11  Artistic license with this distribution, in the file named
12  "Artistic".  You may also obtain a copy from
13  http://regexguy.com/license/Artistic
14 
15  This program is distributed in the hope that it will be useful, but
16  WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 
19 */
20 
21 /* $Header: /repository/projects/libjsonevt/json_writer.c,v 1.6 2009-04-21 06:21:44 don Exp $ */
22 
23 
24 
25 #include "jsonevt_private.h"
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 
33 #define WR_TYPE_PREFIX \
34     jsonevt_data_type type
35 
36 typedef enum {
37     unknown, str, array, hash, float_val, int_val, uint_val, bool_val, data
38 } jsonevt_data_type;
39 
40 struct jsonevt_writer_data_struct {
41     WR_TYPE_PREFIX;
42 };
43 
44 struct jsonevt_float_struct {
45     WR_TYPE_PREFIX;
46     double val;
47 };
48 
49 struct jsonevt_int_struct {
50     WR_TYPE_PREFIX;
51     long val;
52 };
53 
54 struct jsonevt_uint_struct {
55     WR_TYPE_PREFIX;
56     unsigned long val;
57 };
58 
59 struct jsonevt_bool_struct {
60     WR_TYPE_PREFIX;
61     int val;
62 };
63 
64 struct jsonevt_string_struct {
65     WR_TYPE_PREFIX;
66     size_t size;
67     char * data;
68 };
69 
70 typedef struct {
71     WR_TYPE_PREFIX; /* for debugging */
72     size_t max_size;
73     size_t used_size;
74     char * data;
75 } _jsonevt_buf;
76 
77 /* typedef struct jsonevt_str_struct json_str_ctx; */
78 
79 
80 struct json_array_flags {
81     int started:1;
82     int ended: 1;
83     int pad:30;
84 };
85 
86 struct jsonevt_array_struct {
87     WR_TYPE_PREFIX;
88     _jsonevt_buf * str_ctx;
89     size_t count;
90     struct json_array_flags flags;
91 };
92 
93 struct json_hash_flags {
94     int started:1;
95     int ended: 1;
96     int pad:30;
97 };
98 
99 struct jsonevt_hash_struct {
100     WR_TYPE_PREFIX;
101     _jsonevt_buf * str_ctx;
102     size_t count;
103     struct json_hash_flags flags;
104 };
105 
106 
107 static void *
_json_malloc(size_t size)108 _json_malloc(size_t size) {
109     return malloc(size);
110 }
111 
112 static void *
_json_realloc(void * buf,size_t size)113 _json_realloc(void *buf, size_t size) {
114     return realloc(buf, size);
115 }
116 
117 static char *
_json_ensure_buf_size(_jsonevt_buf * ctx,size_t size)118 _json_ensure_buf_size(_jsonevt_buf * ctx, size_t size) {
119     if (size == 0) {
120         size = 1;
121     }
122 
123     if (ctx->data == 0) {
124         ctx->data = _json_malloc(size);
125         ctx->max_size = size;
126     }
127     else if (size > ctx->max_size) {
128         ctx->data = _json_realloc(ctx->data, size);
129         ctx->max_size = size;
130     }
131 
132     return ctx->data;
133 }
134 
135 jsonevt_float *
jsonevt_new_float(double val)136 jsonevt_new_float(double val) {
137     jsonevt_float *ctx = _json_malloc(sizeof(jsonevt_float));
138 
139     memset(ctx, 0, sizeof(jsonevt_float));
140     ctx->type = float_val;
141     ctx->val = val;
142 
143     return ctx;
144 }
145 
146 jsonevt_int *
jsonevt_new_int(long val)147 jsonevt_new_int(long val) {
148     jsonevt_int *ctx = _json_malloc(sizeof(jsonevt_int));
149 
150     memset(ctx, 0, sizeof(jsonevt_int));
151     ctx->type = int_val;
152     ctx->val = val;
153 
154     return ctx;
155 }
156 
157 jsonevt_uint *
jsonevt_new_uint(unsigned long val)158 jsonevt_new_uint(unsigned long val) {
159     jsonevt_uint *ctx = _json_malloc(sizeof(jsonevt_uint));
160 
161     memset(ctx, 0, sizeof(jsonevt_uint));
162     ctx->type = uint_val;
163     ctx->val = val;
164 
165     return ctx;
166 }
167 
168 jsonevt_bool *
jsonevt_new_bool(int val)169 jsonevt_new_bool(int val) {
170     jsonevt_bool *ctx = _json_malloc(sizeof(jsonevt_bool));
171 
172     memset(ctx, 0, sizeof(jsonevt_bool));
173     ctx->type = bool_val;
174     ctx->val = val;
175 
176     return ctx;
177 }
178 
179 jsonevt_string *
jsonevt_new_string(char * buf,size_t size)180 jsonevt_new_string(char * buf, size_t size) {
181     jsonevt_string * ctx = _json_malloc(sizeof(jsonevt_string));
182 
183     UNLESS (buf) {
184         size = 0;
185     }
186 
187     memset(ctx, 0, sizeof(jsonevt_string));
188     ctx->type = str;
189     ctx->size = size;
190     ctx->data = (char *)_json_malloc(size + 1);
191 
192     memcpy(ctx->data, buf, size);
193     ctx->data[size] = 0;
194 
195     return ctx;
196 }
197 
198 
199 static _jsonevt_buf *
json_new_buf(size_t size)200 json_new_buf(size_t size) {
201     _jsonevt_buf * ctx = _json_malloc(sizeof(_jsonevt_buf));
202 
203     memset(ctx, 0, sizeof(_jsonevt_buf));
204     ctx->type = data;
205 
206     if (size > 0) {
207         _json_ensure_buf_size(ctx, size + 1);
208     }
209 
210     return ctx;
211 }
212 
213 static void
_json_free_buf(_jsonevt_buf * ctx)214 _json_free_buf(_jsonevt_buf * ctx) {
215 
216     if (! ctx) {
217         return;
218     }
219 
220     if (ctx->data) {
221         free(ctx->data);
222     }
223 
224     free(ctx);
225 }
226 
227 static void
json_str_disown_buffer(_jsonevt_buf * ctx)228 json_str_disown_buffer(_jsonevt_buf *ctx) {
229     if (ctx) {
230         memset(ctx, 0, sizeof(_jsonevt_buf));
231     }
232 }
233 
234 static int
json_append_bytes(_jsonevt_buf * ctx,char * data,size_t length)235 json_append_bytes(_jsonevt_buf * ctx, char * data, size_t length) {
236     size_t new_size;
237 
238     UNLESS (data) {
239         length = 0;
240     }
241 
242     if (ctx->max_size - ctx->used_size < length + 1) {
243         new_size = length + 1 + ctx->used_size;
244         _json_ensure_buf_size(ctx, new_size);
245     }
246 
247     memcpy(&(ctx->data[ctx->used_size]), data, length);
248     ctx->used_size += length;
249     ctx->data[ctx->used_size] = '\x00';
250 
251     return 1;
252 }
253 
254 static int
json_append_one_byte(_jsonevt_buf * ctx,char to_append)255 json_append_one_byte(_jsonevt_buf * ctx, char to_append) {
256     return json_append_bytes(ctx, &to_append, 1);
257 }
258 
259 static int
json_append_unicode_char(_jsonevt_buf * ctx,uint32_t code_point)260 json_append_unicode_char(_jsonevt_buf * ctx, uint32_t code_point)  {
261     uint32_t size = 0;
262     uint8_t bytes[4];
263 
264     size = utf8_unicode_to_bytes(code_point, bytes);
265 
266     return json_append_bytes(ctx, (char *)bytes, size);
267 }
268 
269 static char *
json_get_str_buffer(_jsonevt_buf * ctx,size_t * size)270 json_get_str_buffer(_jsonevt_buf * ctx, size_t * size) {
271     if (size) {
272         *size = ctx->used_size;
273     }
274 
275     return ctx->data;
276 }
277 
278 static _jsonevt_buf *
_json_escape_c_buffer(char * str,size_t length,unsigned long options)279 _json_escape_c_buffer(char * str, size_t length, unsigned long options) {
280     _jsonevt_buf * ctx = json_new_buf(length + 1);
281     size_t i;
282     uint32_t this_char;
283     char * tmp_buf = NULL;
284     uint32_t char_len = 0;
285 
286     /* opening quotes */
287     json_append_one_byte(ctx, '"');
288 
289     for (i = 0; i < length;) {
290         this_char = utf8_bytes_to_unicode((uint8_t *)str + i, length - i - 1, &char_len);
291         if (char_len == 0) {
292             /* bad utf-8 sequence */
293             /* for now, assume latin-1 and convert to utf-8 */
294             char_len = 1;
295             this_char = str[i];
296         }
297 
298         i += char_len;
299 
300         switch (this_char) {
301           case '\\':
302               json_append_bytes(ctx, "\\\\", 2);
303               break;
304 
305           case '"':
306               json_append_bytes(ctx, "\\\"", 2);
307               break;
308 
309           case '/':
310               json_append_bytes(ctx, "\\/", 2);
311               break;
312 
313           case 0x08:
314               json_append_bytes(ctx, "\\b", 2);
315               break;
316 
317           case 0x0c:
318               json_append_bytes(ctx, "\\f", 2);
319               break;
320 
321           case 0x0a:
322               json_append_bytes(ctx, "\\n", 2);
323               break;
324 
325           case 0x0d:
326               json_append_bytes(ctx, "\\r", 2);
327               break;
328 
329           case 0x09:
330               json_append_bytes(ctx, "\\t", 2);
331               break;
332 
333 
334           default:
335               if (this_char < 0x1f || ( this_char >= 0x80 && (options & JSON_EVT_OPTION_ASCII) ) ) {
336                   /* FIXME: don't use js_asprintf -- instead convert
337                      the bits directly to hex nibbles
338                   */
339                   js_asprintf(&tmp_buf, "\\u%04x", this_char);
340                   json_append_bytes(ctx, tmp_buf, strlen(tmp_buf));
341                   free(tmp_buf); tmp_buf = NULL;
342               }
343               else {
344                   json_append_unicode_char(ctx, this_char);
345               }
346 
347               break;
348         }
349     }
350 
351 
352     /* closing quotes */
353     json_append_one_byte(ctx, '"');
354 
355     return ctx;
356 }
357 
358 char *
jsonevt_escape_c_buffer(char * in_buf,size_t length_in,size_t * length_out,unsigned long options)359 jsonevt_escape_c_buffer(char * in_buf, size_t length_in, size_t *length_out,
360     unsigned long options) {
361 
362     _jsonevt_buf *str = _json_escape_c_buffer(in_buf, length_in, options);
363     char *ret_buf;
364 
365     ret_buf = json_get_str_buffer(str, length_out);
366     json_str_disown_buffer(str);
367     _json_free_buf(str);
368 
369     return ret_buf;
370 }
371 
372 jsonevt_array *
jsonevt_new_array()373 jsonevt_new_array() {
374     jsonevt_array * ctx = _json_malloc(sizeof(jsonevt_array));
375     memset(ctx, 0, sizeof(jsonevt_array));
376     ctx->type = array;
377 
378     return ctx;
379 }
380 
381 void
jsonevt_free_array(jsonevt_array * ctx)382 jsonevt_free_array(jsonevt_array * ctx) {
383      UNLESS (ctx) {
384         return;
385     }
386 
387     if (ctx->str_ctx) {
388         _json_free_buf(ctx->str_ctx);
389     }
390 
391     free(ctx);
392 }
393 
394 void
jsonevt_array_start(jsonevt_array * ctx)395 jsonevt_array_start(jsonevt_array * ctx) {
396     UNLESS (ctx->flags.started) {
397         ctx->str_ctx = json_new_buf(1);
398         json_append_one_byte(ctx->str_ctx, '[');
399 
400         ctx->flags.started = 1;
401     }
402 }
403 
404 void
jsonevt_array_end(jsonevt_array * ctx)405 jsonevt_array_end(jsonevt_array * ctx) {
406     json_append_one_byte(ctx->str_ctx, ']');
407     ctx->flags.ended = 1;
408 }
409 
410 
411 char *
jsonevt_array_get_string(jsonevt_array * ctx,size_t * length_ptr)412 jsonevt_array_get_string(jsonevt_array * ctx, size_t * length_ptr) {
413     UNLESS (ctx->str_ctx) {
414         return NULL;
415     }
416 
417     if (length_ptr) {
418         *length_ptr = ctx->str_ctx->used_size;
419     }
420 
421     return ctx->str_ctx->data;
422 }
423 
424 
425 int
jsonevt_array_append_raw_element(jsonevt_array * ctx,char * buf,size_t length)426 jsonevt_array_append_raw_element(jsonevt_array * ctx, char * buf, size_t length) {
427     UNLESS (ctx->flags.started) {
428         ctx->str_ctx = json_new_buf(1 + length);
429         json_append_one_byte(ctx->str_ctx, '[');
430         ctx->flags.started = 1;
431     }
432     else if (ctx->count > 0) {
433         json_append_one_byte(ctx->str_ctx, ',');
434     }
435 
436     json_append_bytes(ctx->str_ctx, buf, length);
437     ctx->count++;
438 
439     return 1;
440 }
441 
442 int
jsonevt_array_append_buffer(jsonevt_array * ctx,char * buf,size_t length)443 jsonevt_array_append_buffer(jsonevt_array * ctx, char * buf, size_t length) {
444     _jsonevt_buf * str_ctx = _json_escape_c_buffer(buf, length, JSON_EVT_OPTION_NONE);
445     int rv;
446 
447     rv = jsonevt_array_append_raw_element(ctx, str_ctx->data, str_ctx->used_size);
448     _json_free_buf(str_ctx);
449     return rv;
450 }
451 
452 int
jsonevt_array_append_string_buffer(jsonevt_array * array,char * buf)453 jsonevt_array_append_string_buffer(jsonevt_array * array, char * buf) {
454     return jsonevt_array_append_buffer(array, buf, strlen(buf));
455 }
456 
457 int
jsonevt_array_add_data(jsonevt_array * dest,jsonevt_writer_data * src)458 jsonevt_array_add_data(jsonevt_array *dest, jsonevt_writer_data *src) {
459 
460     size_t src_len = 0;
461     char *src_buf = 0;
462     int rv = 0;
463 
464     src_buf = jsonevt_get_data_string(src, &src_len);
465 
466     rv = jsonevt_array_append_raw_element(dest, src_buf, src_len);
467 
468     /* FIXME: decide here whether to free data in src */
469 
470     return rv;
471 }
472 
473 void
jsonevt_array_disown_buffer(jsonevt_array * array)474 jsonevt_array_disown_buffer(jsonevt_array *array) {
475     json_str_disown_buffer(array->str_ctx);
476 }
477 
478 jsonevt_hash *
jsonevt_new_hash()479 jsonevt_new_hash() {
480     jsonevt_hash * ctx = (jsonevt_hash *)_json_malloc(sizeof(jsonevt_hash));
481     memset(ctx, 0, sizeof(jsonevt_hash));
482     ctx->type = hash;
483 
484     return ctx;
485 }
486 
487 void
jsonevt_free_hash(jsonevt_hash * ctx)488 jsonevt_free_hash(jsonevt_hash * ctx) {
489     UNLESS (ctx) {
490         return;
491     }
492 
493     if (ctx->str_ctx) {
494         _json_free_buf(ctx->str_ctx);
495     }
496 
497     free(ctx);
498 }
499 
500 void
jsonevt_hash_start(jsonevt_hash * ctx)501 jsonevt_hash_start(jsonevt_hash * ctx) {
502     if (! ctx->flags.started) {
503         ctx->str_ctx = json_new_buf(0);
504         json_append_one_byte(ctx->str_ctx, '{');
505         ctx->flags.started = 1;
506     }
507 }
508 
509 void
jsonevt_hash_end(jsonevt_hash * ctx)510 jsonevt_hash_end(jsonevt_hash * ctx) {
511     json_append_one_byte(ctx->str_ctx, '}');
512 }
513 
514 char *
jsonevt_hash_get_string(jsonevt_hash * ctx,size_t * length_ptr)515 jsonevt_hash_get_string(jsonevt_hash * ctx, size_t * length_ptr) {
516     if (! ctx->str_ctx) {
517         return NULL;
518     }
519 
520     if (length_ptr) {
521         *length_ptr = ctx->str_ctx->used_size;
522     }
523 
524     return ctx->str_ctx->data;
525 }
526 
527 char *
jsonevt_string_get_string(jsonevt_string * ctx,size_t * length_ptr)528 jsonevt_string_get_string(jsonevt_string *ctx, size_t * length_ptr) {
529     UNLESS (ctx->data) {
530         return NULL;
531     }
532 
533     if (length_ptr) {
534         *length_ptr = ctx->size;
535     }
536 
537     return ctx->data;
538 }
539 
540 char *
jsonevt_get_data_string(jsonevt_writer_data * ctx,size_t * length_ptr)541 jsonevt_get_data_string(jsonevt_writer_data *ctx, size_t *length_ptr) {
542     UNLESS (ctx) {
543         *length_ptr = 0;
544         return NULL;
545     }
546 
547     if (ctx->type == array) {
548         return jsonevt_array_get_string((jsonevt_array *)ctx, length_ptr);
549     }
550     else if (ctx->type == hash) {
551         return jsonevt_hash_get_string((jsonevt_hash *)ctx, length_ptr);
552     }
553     else if (ctx->type == str) {
554         return jsonevt_string_get_string((jsonevt_string *)ctx, length_ptr);
555     }
556 
557     *length_ptr = 0;
558     return NULL;
559 }
560 
561 int
jsonevt_hash_append_raw_entry(jsonevt_hash * ctx,char * key,size_t key_size,char * val,size_t val_size)562 jsonevt_hash_append_raw_entry(jsonevt_hash * ctx, char * key, size_t key_size, char * val,
563     size_t val_size) {
564     _jsonevt_buf * key_ctx = _json_escape_c_buffer(key, key_size, JSON_EVT_OPTION_NONE);
565 
566     if (! ctx->flags.started) {
567         /* add 3 -- 1 for open brace, 1 for closing brace, one for the colon */
568         ctx->str_ctx = json_new_buf(3 + key_ctx->used_size + val_size);
569         json_append_one_byte(ctx->str_ctx, '{');
570         ctx->flags.started = 1;
571     }
572     else if (ctx->count > 0) {
573         json_append_one_byte(ctx->str_ctx, ',');
574     }
575 
576     json_append_bytes(ctx->str_ctx, key_ctx->data, key_ctx->used_size);
577     json_append_one_byte(ctx->str_ctx, ':');
578     json_append_bytes(ctx->str_ctx, val, val_size);
579     ctx->count++;
580 
581     _json_free_buf(key_ctx);
582 
583     return 1;
584 }
585 
586 int
jsonevt_hash_append_buffer(jsonevt_hash * ctx,char * key,size_t key_size,char * val,size_t val_size)587 jsonevt_hash_append_buffer(jsonevt_hash * ctx, char * key, size_t key_size, char * val,
588     size_t val_size) {
589     _jsonevt_buf * val_ctx = _json_escape_c_buffer(val, val_size, JSON_EVT_OPTION_NONE);
590     int rv;
591 
592     rv = jsonevt_hash_append_raw_entry(ctx, key, key_size, val_ctx->data, val_ctx->used_size);
593     _json_free_buf(val_ctx);
594     return rv;
595 }
596 
597 int
jsonevt_hash_append_string_buffer(jsonevt_hash * hash,char * key,char * val)598 jsonevt_hash_append_string_buffer(jsonevt_hash * hash, char * key, char * val) {
599     return jsonevt_hash_append_buffer(hash, key, strlen(key), val, strlen(val));
600 }
601 
602 void
jsonevt_hash_disown_buffer(jsonevt_hash * hash)603 jsonevt_hash_disown_buffer(jsonevt_hash *hash) {
604     json_str_disown_buffer(hash->str_ctx);
605 }
606 
607 int
jsonevt_hash_add_data(jsonevt_hash * dest,jsonevt_writer_data * src,char * key,size_t key_len)608 jsonevt_hash_add_data(jsonevt_hash *dest, jsonevt_writer_data *src, char *key, size_t key_len) {
609 
610     size_t src_len = 0;
611     char *src_buf = 0;
612     int rv = 0;
613 
614     src_buf = jsonevt_get_data_string(src, &src_len);
615     rv = jsonevt_hash_append_raw_entry(dest, key, key_len, src_buf, src_len);
616 
617     /* FIXME: decide here whether to free data in src */
618 
619     return rv;
620 }
621 
622 int
jsonevt_do_unit_tests()623 jsonevt_do_unit_tests() {
624     _jsonevt_buf * val_ctx;
625     char *test_buf = "foo \x0a \"\xe7\x81\xab\" bar";
626     char *expected_buf = NULL;
627     char *rv = NULL;
628     size_t length_in = 0;
629     size_t length_out = 0;
630 
631     /* internal function */
632     val_ctx = _json_escape_c_buffer(test_buf, strlen(test_buf), JSON_EVT_OPTION_NONE);
633 
634     expected_buf = "foo \x0a \\\"\xe7\x81\xab\\\" bar";
635 
636     printf("Internal: _json_escape_c_buffer()\n");
637     printf("\tin: %s\n", test_buf);
638     printf("\tout: %s\n", val_ctx->data);
639     printf("\n");
640 
641     /* public function */
642     printf("Public: jsonevt_escape_c_buffer()\n");
643 
644     length_in = strlen(test_buf);
645     rv = jsonevt_escape_c_buffer(test_buf, length_in, &length_out,
646         JSON_EVT_OPTION_NONE);
647     printf("\tin (%u bytes): %s\n", (unsigned int)length_in, test_buf);
648     printf("\tout (%u bytes): %s\n", (unsigned int)length_out, rv);
649 
650     return 0;
651 }
652