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