transmission 2.83
[tomato.git] / release / src / router / transmission / libtransmission / variant-json.c
blob32771e4c6237f4844e411c5bb0dffef5bca8b34c
1 /*
2 * This file Copyright (C) 2008-2014 Mnemosyne LLC
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
7 * $Id: variant-json.c 14266 2014-04-27 23:10:01Z jordan $
8 */
10 #include <assert.h>
11 #include <ctype.h>
12 #include <math.h> /* fabs() */
13 #include <stdio.h>
14 #include <string.h>
15 #include <errno.h> /* EILSEQ, EINVAL */
17 #include <event2/buffer.h> /* evbuffer_add() */
18 #include <event2/util.h> /* evutil_strtoll () */
20 #define JSONSL_STATE_USER_FIELDS /* no fields */
21 #include "jsonsl.h"
22 #include "jsonsl.c"
24 #define __LIBTRANSMISSION_VARIANT_MODULE___
25 #include "transmission.h"
26 #include "ConvertUTF.h"
27 #include "list.h"
28 #include "log.h"
29 #include "ptrarray.h"
30 #include "utils.h"
31 #include "variant.h"
32 #include "variant-common.h"
34 /* arbitrary value... this is much deeper than our code goes */
35 #define MAX_DEPTH 64
37 struct json_wrapper_data
39 int error;
40 bool has_content;
41 tr_variant * top;
42 const char * key;
43 size_t keylen;
44 struct evbuffer * keybuf;
45 struct evbuffer * strbuf;
46 const char * source;
47 tr_ptrArray stack;
50 static tr_variant*
51 get_node (struct jsonsl_st * jsn)
53 tr_variant * parent;
54 tr_variant * node = NULL;
55 struct json_wrapper_data * data = jsn->data;
57 parent = tr_ptrArrayEmpty (&data->stack)
58 ? NULL
59 : tr_ptrArrayBack (&data->stack);
61 if (!parent)
63 node = data->top;
65 else if (tr_variantIsList (parent))
67 node = tr_variantListAdd (parent);
69 else if (tr_variantIsDict (parent) && (data->key!=NULL))
71 node = tr_variantDictAdd (parent, tr_quark_new (data->key, data->keylen));
73 data->key = NULL;
74 data->keylen = 0;
77 return node;
81 static void
82 error_handler (jsonsl_t jsn,
83 jsonsl_error_t error,
84 struct jsonsl_state_st * state UNUSED,
85 const jsonsl_char_t * buf)
87 struct json_wrapper_data * data = jsn->data;
89 if (data->source)
91 tr_logAddError ("JSON parse failed in %s at pos %"TR_PRIuSIZE": %s -- remaining text \"%.16s\"",
92 data->source,
93 jsn->pos,
94 jsonsl_strerror (error),
95 buf);
97 else
99 tr_logAddError ("JSON parse failed at pos %"TR_PRIuSIZE": %s -- remaining text \"%.16s\"",
100 jsn->pos,
101 jsonsl_strerror (error),
102 buf);
105 data->error = EILSEQ;
108 static int
109 error_callback (jsonsl_t jsn,
110 jsonsl_error_t error,
111 struct jsonsl_state_st * state,
112 jsonsl_char_t * at)
114 error_handler (jsn, error, state, at);
115 return 0; /* bail */
118 static void
119 action_callback_PUSH (jsonsl_t jsn,
120 jsonsl_action_t action UNUSED,
121 struct jsonsl_state_st * state,
122 const jsonsl_char_t * buf UNUSED)
124 tr_variant * node;
125 struct json_wrapper_data * data = jsn->data;
127 switch (state->type)
129 case JSONSL_T_LIST:
130 data->has_content = true;
131 node = get_node (jsn);
132 tr_variantInitList (node, 0);
133 tr_ptrArrayAppend (&data->stack, node);
134 break;
136 case JSONSL_T_OBJECT:
137 data->has_content = true;
138 node = get_node (jsn);
139 tr_variantInitDict (node, 0);
140 tr_ptrArrayAppend (&data->stack, node);
141 break;
143 default:
144 /* nothing else interesting on push */
145 break;
149 /* like sscanf(in+2, "%4x", &val) but less slow */
150 static bool
151 decode_hex_string (const char * in, unsigned int * setme)
153 unsigned int val = 0;
154 const char * const end = in + 6;
156 assert (in != NULL);
157 assert (in[0] == '\\');
158 assert (in[1] == 'u');
159 in += 2;
163 val <<= 4;
164 if (('0'<=*in) && (*in<='9'))
165 val += (*in-'0');
166 else if (('a'<=*in) && (*in<='f'))
167 val += (*in-'a') + 10u;
168 else if (('A'<=*in) && (*in<='F'))
169 val += (*in-'A') + 10u;
170 else
171 return false;
173 while (++in != end);
175 *setme = val;
176 return true;
179 static char*
180 extract_escaped_string (const char * in,
181 size_t in_len,
182 size_t * len,
183 struct evbuffer * buf)
185 const char * const in_end = in + in_len;
187 evbuffer_drain (buf, evbuffer_get_length (buf));
189 while (in < in_end)
191 bool unescaped = false;
193 if (*in=='\\' && in_end-in>=2)
195 switch (in[1])
197 case 'b' : evbuffer_add (buf, "\b", 1); in+=2; unescaped = true; break;
198 case 'f' : evbuffer_add (buf, "\f", 1); in+=2; unescaped = true; break;
199 case 'n' : evbuffer_add (buf, "\n", 1); in+=2; unescaped = true; break;
200 case 'r' : evbuffer_add (buf, "\r", 1); in+=2; unescaped = true; break;
201 case 't' : evbuffer_add (buf, "\t", 1); in+=2; unescaped = true; break;
202 case '/' : evbuffer_add (buf, "/" , 1); in+=2; unescaped = true; break;
203 case '"' : evbuffer_add (buf, "\"" , 1); in+=2; unescaped = true; break;
204 case '\\': evbuffer_add (buf, "\\", 1); in+=2; unescaped = true; break;
205 case 'u':
207 if (in_end - in >= 6)
209 unsigned int val = 0;
211 if (decode_hex_string (in, &val))
213 UTF32 str32_buf[2] = { val, 0 };
214 const UTF32 * str32_walk = str32_buf;
215 const UTF32 * str32_end = str32_buf + 1;
216 UTF8 str8_buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
217 UTF8 * str8_walk = str8_buf;
218 UTF8 * str8_end = str8_buf + 8;
220 if (ConvertUTF32toUTF8 (&str32_walk, str32_end, &str8_walk, str8_end, 0) == 0)
222 const size_t len = str8_walk - str8_buf;
223 evbuffer_add (buf, str8_buf, len);
224 unescaped = true;
227 in += 6;
228 break;
235 if (!unescaped)
237 evbuffer_add (buf, in, 1);
238 ++in;
242 *len = evbuffer_get_length (buf);
243 return (char*) evbuffer_pullup (buf, -1);
246 static const char *
247 extract_string (jsonsl_t jsn,
248 struct jsonsl_state_st * state,
249 size_t * len,
250 struct evbuffer * buf)
252 const char * ret;
253 const char * in_begin;
254 const char * in_end;
255 size_t in_len;
257 /* figure out where the string is */
258 in_begin = jsn->base + state->pos_begin;
259 if (*in_begin == '"')
260 in_begin++;
261 in_end = jsn->base + state->pos_cur;
262 in_len = in_end - in_begin;
264 if (memchr (in_begin, '\\', in_len) == NULL)
266 /* it's not escaped */
267 ret = in_begin;
268 *len = in_len;
270 else
272 ret = extract_escaped_string (in_begin, in_len, len, buf);
275 return ret;
278 static void
279 action_callback_POP (jsonsl_t jsn,
280 jsonsl_action_t action UNUSED,
281 struct jsonsl_state_st * state,
282 const jsonsl_char_t * buf UNUSED)
284 struct json_wrapper_data * data = jsn->data;
286 if (state->type == JSONSL_T_STRING)
288 size_t len;
289 const char * str = extract_string (jsn, state, &len, data->strbuf);
290 tr_variantInitStr (get_node (jsn), str, len);
291 data->has_content = true;
293 else if (state->type == JSONSL_T_HKEY)
295 data->has_content = true;
296 data->key = extract_string (jsn, state, &data->keylen, data->keybuf);
298 else if ((state->type == JSONSL_T_LIST) || (state->type == JSONSL_T_OBJECT))
300 tr_ptrArrayPop (&data->stack);
302 else if (state->type == JSONSL_T_SPECIAL)
304 if (state->special_flags & JSONSL_SPECIALf_NUMNOINT)
306 const char * begin = jsn->base + state->pos_begin;
307 data->has_content = true;
308 tr_variantInitReal (get_node (jsn), strtod (begin, NULL));
310 else if (state->special_flags & JSONSL_SPECIALf_NUMERIC)
312 const char * begin = jsn->base + state->pos_begin;
313 data->has_content = true;
314 tr_variantInitInt (get_node (jsn), evutil_strtoll (begin, NULL, 10));
316 else if (state->special_flags & JSONSL_SPECIALf_BOOLEAN)
318 const bool b = (state->special_flags & JSONSL_SPECIALf_TRUE) != 0;
319 data->has_content = true;
320 tr_variantInitBool (get_node (jsn), b);
322 else if (state->special_flags & JSONSL_SPECIALf_NULL)
324 data->has_content = true;
325 tr_variantInitQuark (get_node (jsn), TR_KEY_NONE);
331 tr_jsonParse (const char * source,
332 const void * vbuf,
333 size_t len,
334 tr_variant * setme_variant,
335 const char ** setme_end)
337 int error;
338 jsonsl_t jsn;
339 struct json_wrapper_data data;
341 jsn = jsonsl_new (MAX_DEPTH);
342 jsn->action_callback_PUSH = action_callback_PUSH;
343 jsn->action_callback_POP = action_callback_POP;
344 jsn->error_callback = error_callback;
345 jsn->data = &data;
346 jsonsl_enable_all_callbacks (jsn);
348 data.error = 0;
349 data.has_content = false;
350 data.key = NULL;
351 data.top = setme_variant;
352 data.stack = TR_PTR_ARRAY_INIT;
353 data.source = source;
354 data.keybuf = evbuffer_new ();
355 data.strbuf = evbuffer_new ();
357 /* parse it */
358 jsonsl_feed (jsn, vbuf, len);
360 /* EINVAL if there was no content */
361 if (!data.error && !data.has_content)
362 data.error = EINVAL;
364 /* maybe set the end ptr */
365 if (setme_end)
366 *setme_end = ((const char*)vbuf) + jsn->pos;
368 /* cleanup */
369 error = data.error;
370 evbuffer_free (data.keybuf);
371 evbuffer_free (data.strbuf);
372 tr_ptrArrayDestruct (&data.stack, NULL);
373 jsonsl_destroy (jsn);
374 return error;
377 /****
378 *****
379 ****/
381 struct ParentState
383 int variantType;
384 int childIndex;
385 int childCount;
388 struct jsonWalk
390 bool doIndent;
391 tr_list * parents;
392 struct evbuffer * out;
395 static void
396 jsonIndent (struct jsonWalk * data)
398 static char buf[1024] = { '\0' };
399 if (!*buf)
401 memset (buf, ' ', sizeof(buf));
402 buf[0] = '\n';
405 if (data->doIndent)
406 evbuffer_add (data->out, buf, tr_list_size(data->parents)*4 + 1);
409 static void
410 jsonChildFunc (struct jsonWalk * data)
412 if (data->parents && data->parents->data)
414 struct ParentState * pstate = data->parents->data;
416 switch (pstate->variantType)
418 case TR_VARIANT_TYPE_DICT:
420 const int i = pstate->childIndex++;
421 if (! (i % 2))
423 evbuffer_add (data->out, ": ", data->doIndent ? 2 : 1);
425 else
427 const bool isLast = pstate->childIndex == pstate->childCount;
429 if (!isLast)
431 evbuffer_add (data->out, ", ", data->doIndent ? 2 : 1);
432 jsonIndent (data);
435 break;
438 case TR_VARIANT_TYPE_LIST:
440 const bool isLast = ++pstate->childIndex == pstate->childCount;
441 if (!isLast)
443 evbuffer_add (data->out, ", ", data->doIndent ? 2 : 1);
444 jsonIndent (data);
446 break;
449 default:
450 break;
455 static void
456 jsonPushParent (struct jsonWalk * data,
457 const tr_variant * v)
459 struct ParentState * pstate = tr_new (struct ParentState, 1);
461 pstate->variantType = v->type;
462 pstate->childIndex = 0;
463 pstate->childCount = v->val.l.count;
464 if (tr_variantIsDict (v))
465 pstate->childCount *= 2;
467 tr_list_prepend (&data->parents, pstate);
470 static void
471 jsonPopParent (struct jsonWalk * data)
473 tr_free (tr_list_pop_front (&data->parents));
476 static void
477 jsonIntFunc (const tr_variant * val, void * vdata)
479 struct jsonWalk * data = vdata;
480 evbuffer_add_printf (data->out, "%" PRId64, val->val.i);
481 jsonChildFunc (data);
484 static void
485 jsonBoolFunc (const tr_variant * val,
486 void * vdata)
488 struct jsonWalk * data = vdata;
490 if (val->val.b)
491 evbuffer_add (data->out, "true", 4);
492 else
493 evbuffer_add (data->out, "false", 5);
495 jsonChildFunc (data);
498 static void
499 jsonRealFunc (const tr_variant * val,
500 void * vdata)
502 struct jsonWalk * data = vdata;
504 if (fabs (val->val.d - (int)val->val.d) < 0.00001)
505 evbuffer_add_printf (data->out, "%d", (int)val->val.d);
506 else
507 evbuffer_add_printf (data->out, "%.4f", tr_truncd (val->val.d, 4));
509 jsonChildFunc (data);
512 static void
513 jsonStringFunc (const tr_variant * val,
514 void * vdata)
516 char * out;
517 char * outwalk;
518 char * outend;
519 struct evbuffer_iovec vec[1];
520 struct jsonWalk * data = vdata;
521 const char * str;
522 size_t len;
523 const unsigned char * it;
524 const unsigned char * end;
526 tr_variantGetStr (val, &str, &len);
527 it = (const unsigned char *) str;
528 end = it + len;
530 evbuffer_reserve_space (data->out, len * 4, vec, 1);
531 out = vec[0].iov_base;
532 outend = out + vec[0].iov_len;
534 outwalk = out;
535 *outwalk++ = '"';
537 for (; it!=end; ++it)
539 switch (*it)
541 case '\b': *outwalk++ = '\\'; *outwalk++ = 'b'; break;
542 case '\f': *outwalk++ = '\\'; *outwalk++ = 'f'; break;
543 case '\n': *outwalk++ = '\\'; *outwalk++ = 'n'; break;
544 case '\r': *outwalk++ = '\\'; *outwalk++ = 'r'; break;
545 case '\t': *outwalk++ = '\\'; *outwalk++ = 't'; break;
546 case '"' : *outwalk++ = '\\'; *outwalk++ = '"'; break;
547 case '\\': *outwalk++ = '\\'; *outwalk++ = '\\'; break;
549 default:
550 if (isascii (*it))
552 *outwalk++ = *it;
554 else
556 const UTF8 * tmp = it;
557 UTF32 buf[1] = { 0 };
558 UTF32 * u32 = buf;
559 ConversionResult result = ConvertUTF8toUTF32 (&tmp, end, &u32, buf + 1, 0);
560 if (((result==conversionOK) || (result==targetExhausted)) && (tmp!=it))
562 outwalk += tr_snprintf (outwalk, outend-outwalk, "\\u%04x", (unsigned int)buf[0]);
563 it = tmp - 1;
566 break;
570 *outwalk++ = '"';
571 vec[0].iov_len = outwalk - out;
572 evbuffer_commit_space (data->out, vec, 1);
574 jsonChildFunc (data);
577 static void
578 jsonDictBeginFunc (const tr_variant * val,
579 void * vdata)
581 struct jsonWalk * data = vdata;
583 jsonPushParent (data, val);
584 evbuffer_add (data->out, "{", 1);
585 if (val->val.l.count)
586 jsonIndent (data);
589 static void
590 jsonListBeginFunc (const tr_variant * val,
591 void * vdata)
593 const size_t nChildren = tr_variantListSize (val);
594 struct jsonWalk * data = vdata;
596 jsonPushParent (data, val);
597 evbuffer_add (data->out, "[", 1);
598 if (nChildren)
599 jsonIndent (data);
602 static void
603 jsonContainerEndFunc (const tr_variant * val,
604 void * vdata)
606 struct jsonWalk * data = vdata;
607 bool emptyContainer = false;
609 jsonPopParent (data);
611 if (!emptyContainer)
612 jsonIndent (data);
613 if (tr_variantIsDict (val))
614 evbuffer_add (data->out, "}", 1);
615 else /* list */
616 evbuffer_add (data->out, "]", 1);
618 jsonChildFunc (data);
621 static const struct VariantWalkFuncs walk_funcs = { jsonIntFunc,
622 jsonBoolFunc,
623 jsonRealFunc,
624 jsonStringFunc,
625 jsonDictBeginFunc,
626 jsonListBeginFunc,
627 jsonContainerEndFunc };
629 void
630 tr_variantToBufJson (const tr_variant * top, struct evbuffer * buf, bool lean)
632 struct jsonWalk data;
634 data.doIndent = !lean;
635 data.out = buf;
636 data.parents = NULL;
638 tr_variantWalk (top, &walk_funcs, &data, true);
640 if (evbuffer_get_length (buf))
641 evbuffer_add_printf (buf, "\n");