1 /*
2 * This file Copyright (C) 2008-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 */
8
9 #if defined(HAVE_USELOCALE) && (!defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 700)
10 #undef _XOPEN_SOURCE
11 #define _XOPEN_SOURCE 700
12 #endif
13
14 #if defined(HAVE_USELOCALE) && !defined(_GNU_SOURCE)
15 #define _GNU_SOURCE
16 #endif
17
18 #include <errno.h>
19 #include <stdlib.h> /* strtod(), realloc(), qsort() */
20 #include <string.h>
21
22 #ifdef _WIN32
23 #include <share.h>
24 #endif
25
26 #include <locale.h> /* setlocale() */
27
28 #if defined(HAVE_USELOCALE) && defined(HAVE_XLOCALE_H)
29 #include <xlocale.h>
30 #endif
31
32 #include <event2/buffer.h>
33
34 #define __LIBTRANSMISSION_VARIANT_MODULE__
35
36 #include "transmission.h"
37 #include "ConvertUTF.h"
38 #include "error.h"
39 #include "file.h"
40 #include "log.h"
41 #include "tr-assert.h"
42 #include "utils.h" /* tr_new(), tr_free() */
43 #include "variant.h"
44 #include "variant-common.h"
45
46 /* don't use newlocale/uselocale on old versions of uClibc because they're buggy.
47 * https://trac.transmissionbt.com/ticket/6006 */
48 #if defined(__UCLIBC__) && !TR_UCLIBC_CHECK_VERSION(0, 9, 34)
49 #undef HAVE_USELOCALE
50 #endif
51
52 /**
53 ***
54 **/
55
56 struct locale_context
57 {
58 #ifdef HAVE_USELOCALE
59 locale_t new_locale;
60 locale_t old_locale;
61 #else
62 #if defined(HAVE__CONFIGTHREADLOCALE) && defined(_ENABLE_PER_THREAD_LOCALE)
63 int old_thread_config;
64 #endif
65 int category;
66 char old_locale[128];
67 #endif
68 };
69
use_numeric_locale(struct locale_context * context,char const * locale_name)70 static void use_numeric_locale(struct locale_context* context, char const* locale_name)
71 {
72 #ifdef HAVE_USELOCALE
73
74 context->new_locale = newlocale(LC_NUMERIC_MASK, locale_name, NULL);
75 context->old_locale = uselocale(context->new_locale);
76
77 #else
78
79 #if defined(HAVE__CONFIGTHREADLOCALE) && defined(_ENABLE_PER_THREAD_LOCALE)
80 context->old_thread_config = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
81 #endif
82
83 context->category = LC_NUMERIC;
84 tr_strlcpy(context->old_locale, setlocale(context->category, NULL), sizeof(context->old_locale));
85 setlocale(context->category, locale_name);
86
87 #endif
88 }
89
restore_locale(struct locale_context * context)90 static void restore_locale(struct locale_context* context)
91 {
92 #ifdef HAVE_USELOCALE
93
94 uselocale(context->old_locale);
95 freelocale(context->new_locale);
96
97 #else
98
99 setlocale(context->category, context->old_locale);
100
101 #if defined(HAVE__CONFIGTHREADLOCALE) && defined(_ENABLE_PER_THREAD_LOCALE)
102 _configthreadlocale(context->old_thread_config);
103 #endif
104
105 #endif
106 }
107
108 /***
109 ****
110 ***/
111
tr_variantIsContainer(tr_variant const * v)112 static bool tr_variantIsContainer(tr_variant const* v)
113 {
114 return tr_variantIsList(v) || tr_variantIsDict(v);
115 }
116
tr_variantIsSomething(tr_variant const * v)117 static bool tr_variantIsSomething(tr_variant const* v)
118 {
119 return tr_variantIsContainer(v) || tr_variantIsInt(v) || tr_variantIsString(v) || tr_variantIsReal(v) ||
120 tr_variantIsBool(v);
121 }
122
tr_variantInit(tr_variant * v,char type)123 void tr_variantInit(tr_variant* v, char type)
124 {
125 v->type = type;
126 memset(&v->val, 0, sizeof(v->val));
127 }
128
129 /***
130 ****
131 ***/
132
133 static struct tr_variant_string const STRING_INIT =
134 {
135 .type = TR_STRING_TYPE_QUARK,
136 .quark = TR_KEY_NONE,
137 .len = 0,
138 .str.str = ""
139 };
140
tr_variant_string_clear(struct tr_variant_string * str)141 static void tr_variant_string_clear(struct tr_variant_string* str)
142 {
143 if (str->type == TR_STRING_TYPE_HEAP)
144 {
145 tr_free((char*)(str->str.str));
146 }
147
148 *str = STRING_INIT;
149 }
150
151 /* returns a const pointer to the variant's string */
tr_variant_string_get_string(struct tr_variant_string const * str)152 static char const* tr_variant_string_get_string(struct tr_variant_string const* str)
153 {
154 char const* ret;
155
156 switch (str->type)
157 {
158 case TR_STRING_TYPE_BUF:
159 ret = str->str.buf;
160 break;
161
162 case TR_STRING_TYPE_HEAP:
163 ret = str->str.str;
164 break;
165
166 case TR_STRING_TYPE_QUARK:
167 ret = str->str.str;
168 break;
169
170 default:
171 ret = NULL;
172 }
173
174 return ret;
175 }
176
tr_variant_string_set_quark(struct tr_variant_string * str,tr_quark const quark)177 static void tr_variant_string_set_quark(struct tr_variant_string* str, tr_quark const quark)
178 {
179 tr_variant_string_clear(str);
180
181 str->type = TR_STRING_TYPE_QUARK;
182 str->quark = quark;
183 str->str.str = tr_quark_get_string(quark, &str->len);
184 }
185
tr_variant_string_set_string(struct tr_variant_string * str,char const * bytes,size_t len)186 static void tr_variant_string_set_string(struct tr_variant_string* str, char const* bytes, size_t len)
187 {
188 tr_variant_string_clear(str);
189
190 if (bytes == NULL)
191 {
192 len = 0;
193 }
194 else if (len == TR_BAD_SIZE)
195 {
196 len = strlen(bytes);
197 }
198
199 if (len < sizeof(str->str.buf))
200 {
201 str->type = TR_STRING_TYPE_BUF;
202 memcpy(str->str.buf, bytes, len);
203 str->str.buf[len] = '\0';
204 str->len = len;
205 }
206 else
207 {
208 char* tmp = tr_new(char, len + 1);
209 memcpy(tmp, bytes, len);
210 tmp[len] = '\0';
211 str->type = TR_STRING_TYPE_HEAP;
212 str->str.str = tmp;
213 str->len = len;
214 }
215 }
216
217 /***
218 ****
219 ***/
220
getStr(tr_variant const * v)221 static inline char const* getStr(tr_variant const* v)
222 {
223 TR_ASSERT(tr_variantIsString(v));
224
225 return tr_variant_string_get_string(&v->val.s);
226 }
227
dictIndexOf(tr_variant const * dict,tr_quark const key)228 static int dictIndexOf(tr_variant const* dict, tr_quark const key)
229 {
230 if (tr_variantIsDict(dict))
231 {
232 for (size_t i = 0; i < dict->val.l.count; ++i)
233 {
234 if (dict->val.l.vals[i].key == key)
235 {
236 return (int)i;
237 }
238 }
239 }
240
241 return -1;
242 }
243
tr_variantDictFind(tr_variant * dict,tr_quark const key)244 tr_variant* tr_variantDictFind(tr_variant* dict, tr_quark const key)
245 {
246 int const i = dictIndexOf(dict, key);
247
248 return i < 0 ? NULL : dict->val.l.vals + i;
249 }
250
tr_variantDictFindType(tr_variant * dict,tr_quark const key,int type,tr_variant ** setme)251 static bool tr_variantDictFindType(tr_variant* dict, tr_quark const key, int type, tr_variant** setme)
252 {
253 *setme = tr_variantDictFind(dict, key);
254 return tr_variantIsType(*setme, type);
255 }
256
tr_variantListSize(tr_variant const * list)257 size_t tr_variantListSize(tr_variant const* list)
258 {
259 return tr_variantIsList(list) ? list->val.l.count : 0;
260 }
261
tr_variantListChild(tr_variant * v,size_t i)262 tr_variant* tr_variantListChild(tr_variant* v, size_t i)
263 {
264 tr_variant* ret = NULL;
265
266 if (tr_variantIsList(v) && i < v->val.l.count)
267 {
268 ret = v->val.l.vals + i;
269 }
270
271 return ret;
272 }
273
tr_variantListRemove(tr_variant * list,size_t i)274 bool tr_variantListRemove(tr_variant* list, size_t i)
275 {
276 bool removed = false;
277
278 if (tr_variantIsList(list) && i < list->val.l.count)
279 {
280 removed = true;
281 tr_variantFree(&list->val.l.vals[i]);
282 tr_removeElementFromArray(list->val.l.vals, i, sizeof(tr_variant), list->val.l.count);
283 --list->val.l.count;
284 }
285
286 return removed;
287 }
288
tr_variantGetInt(tr_variant const * v,int64_t * setme)289 bool tr_variantGetInt(tr_variant const* v, int64_t* setme)
290 {
291 bool success = false;
292
293 if (tr_variantIsInt(v))
294 {
295 if (setme != NULL)
296 {
297 *setme = v->val.i;
298 }
299
300 success = true;
301 }
302
303 if (!success && tr_variantIsBool(v))
304 {
305 if (setme != NULL)
306 {
307 *setme = v->val.b ? 1 : 0;
308 }
309
310 success = true;
311 }
312
313 return success;
314 }
315
tr_variantGetStr(tr_variant const * v,char const ** setme,size_t * len)316 bool tr_variantGetStr(tr_variant const* v, char const** setme, size_t* len)
317 {
318 bool const success = tr_variantIsString(v);
319
320 if (success)
321 {
322 *setme = getStr(v);
323 }
324
325 if (len != NULL)
326 {
327 *len = success ? v->val.s.len : 0;
328 }
329
330 return success;
331 }
332
tr_variantGetRaw(tr_variant const * v,uint8_t const ** setme_raw,size_t * setme_len)333 bool tr_variantGetRaw(tr_variant const* v, uint8_t const** setme_raw, size_t* setme_len)
334 {
335 bool const success = tr_variantIsString(v);
336
337 if (success)
338 {
339 *setme_raw = (uint8_t*)getStr(v);
340 *setme_len = v->val.s.len;
341 }
342
343 return success;
344 }
345
tr_variantGetBool(tr_variant const * v,bool * setme)346 bool tr_variantGetBool(tr_variant const* v, bool* setme)
347 {
348 char const* str;
349 bool success = false;
350
351 if (tr_variantIsBool(v))
352 {
353 *setme = v->val.b;
354 success = true;
355 }
356
357 if (!success && tr_variantIsInt(v))
358 {
359 if (v->val.i == 0 || v->val.i == 1)
360 {
361 *setme = v->val.i != 0;
362 success = true;
363 }
364 }
365
366 if (!success && tr_variantGetStr(v, &str, NULL))
367 {
368 if (strcmp(str, "true") == 0 || strcmp(str, "false") == 0)
369 {
370 *setme = strcmp(str, "true") == 0;
371 success = true;
372 }
373 }
374
375 return success;
376 }
377
tr_variantGetReal(tr_variant const * v,double * setme)378 bool tr_variantGetReal(tr_variant const* v, double* setme)
379 {
380 bool success = false;
381
382 if (tr_variantIsReal(v))
383 {
384 *setme = v->val.d;
385 success = true;
386 }
387
388 if (!success && tr_variantIsInt(v))
389 {
390 *setme = v->val.i;
391 success = true;
392 }
393
394 if (!success && tr_variantIsString(v))
395 {
396 char* endptr;
397 struct locale_context locale_ctx;
398 double d;
399
400 /* the json spec requires a '.' decimal point regardless of locale */
401 use_numeric_locale(&locale_ctx, "C");
402 d = strtod(getStr(v), &endptr);
403 restore_locale(&locale_ctx);
404
405 if (getStr(v) != endptr && *endptr == '\0')
406 {
407 *setme = d;
408 success = true;
409 }
410 }
411
412 return success;
413 }
414
tr_variantDictFindInt(tr_variant * dict,tr_quark const key,int64_t * setme)415 bool tr_variantDictFindInt(tr_variant* dict, tr_quark const key, int64_t* setme)
416 {
417 tr_variant* child = tr_variantDictFind(dict, key);
418 return tr_variantGetInt(child, setme);
419 }
420
tr_variantDictFindBool(tr_variant * dict,tr_quark const key,bool * setme)421 bool tr_variantDictFindBool(tr_variant* dict, tr_quark const key, bool* setme)
422 {
423 tr_variant* child = tr_variantDictFind(dict, key);
424 return tr_variantGetBool(child, setme);
425 }
426
tr_variantDictFindReal(tr_variant * dict,tr_quark const key,double * setme)427 bool tr_variantDictFindReal(tr_variant* dict, tr_quark const key, double* setme)
428 {
429 tr_variant* child = tr_variantDictFind(dict, key);
430 return tr_variantGetReal(child, setme);
431 }
432
tr_variantDictFindStr(tr_variant * dict,tr_quark const key,char const ** setme,size_t * len)433 bool tr_variantDictFindStr(tr_variant* dict, tr_quark const key, char const** setme, size_t* len)
434 {
435 tr_variant* child = tr_variantDictFind(dict, key);
436 return tr_variantGetStr(child, setme, len);
437 }
438
tr_variantDictFindList(tr_variant * dict,tr_quark const key,tr_variant ** setme)439 bool tr_variantDictFindList(tr_variant* dict, tr_quark const key, tr_variant** setme)
440 {
441 return tr_variantDictFindType(dict, key, TR_VARIANT_TYPE_LIST, setme);
442 }
443
tr_variantDictFindDict(tr_variant * dict,tr_quark const key,tr_variant ** setme)444 bool tr_variantDictFindDict(tr_variant* dict, tr_quark const key, tr_variant** setme)
445 {
446 return tr_variantDictFindType(dict, key, TR_VARIANT_TYPE_DICT, setme);
447 }
448
tr_variantDictFindRaw(tr_variant * dict,tr_quark const key,uint8_t const ** setme_raw,size_t * setme_len)449 bool tr_variantDictFindRaw(tr_variant* dict, tr_quark const key, uint8_t const** setme_raw, size_t* setme_len)
450 {
451 tr_variant* child = tr_variantDictFind(dict, key);
452 return tr_variantGetRaw(child, setme_raw, setme_len);
453 }
454
455 /***
456 ****
457 ***/
458
tr_variantInitRaw(tr_variant * v,void const * src,size_t byteCount)459 void tr_variantInitRaw(tr_variant* v, void const* src, size_t byteCount)
460 {
461 tr_variantInit(v, TR_VARIANT_TYPE_STR);
462 tr_variant_string_set_string(&v->val.s, src, byteCount);
463 }
464
tr_variantInitQuark(tr_variant * v,tr_quark const q)465 void tr_variantInitQuark(tr_variant* v, tr_quark const q)
466 {
467 tr_variantInit(v, TR_VARIANT_TYPE_STR);
468 tr_variant_string_set_quark(&v->val.s, q);
469 }
470
tr_variantInitStr(tr_variant * v,void const * str,size_t len)471 void tr_variantInitStr(tr_variant* v, void const* str, size_t len)
472 {
473 tr_variantInit(v, TR_VARIANT_TYPE_STR);
474 tr_variant_string_set_string(&v->val.s, str, len);
475 }
476
tr_variantInitBool(tr_variant * v,bool value)477 void tr_variantInitBool(tr_variant* v, bool value)
478 {
479 tr_variantInit(v, TR_VARIANT_TYPE_BOOL);
480 v->val.b = value != 0;
481 }
482
tr_variantInitReal(tr_variant * v,double value)483 void tr_variantInitReal(tr_variant* v, double value)
484 {
485 tr_variantInit(v, TR_VARIANT_TYPE_REAL);
486 v->val.d = value;
487 }
488
tr_variantInitInt(tr_variant * v,int64_t value)489 void tr_variantInitInt(tr_variant* v, int64_t value)
490 {
491 tr_variantInit(v, TR_VARIANT_TYPE_INT);
492 v->val.i = value;
493 }
494
tr_variantInitList(tr_variant * v,size_t reserve_count)495 void tr_variantInitList(tr_variant* v, size_t reserve_count)
496 {
497 tr_variantInit(v, TR_VARIANT_TYPE_LIST);
498 tr_variantListReserve(v, reserve_count);
499 }
500
containerReserve(tr_variant * v,size_t count)501 static void containerReserve(tr_variant* v, size_t count)
502 {
503 TR_ASSERT(tr_variantIsContainer(v));
504
505 size_t const needed = v->val.l.count + count;
506
507 if (needed > v->val.l.alloc)
508 {
509 /* scale the alloc size in powers-of-2 */
510 size_t n = v->val.l.alloc != 0 ? v->val.l.alloc : 8;
511
512 while (n < needed)
513 {
514 n *= 2U;
515 }
516
517 v->val.l.vals = tr_renew(tr_variant, v->val.l.vals, n);
518 v->val.l.alloc = n;
519 }
520 }
521
tr_variantListReserve(tr_variant * list,size_t count)522 void tr_variantListReserve(tr_variant* list, size_t count)
523 {
524 TR_ASSERT(tr_variantIsList(list));
525
526 containerReserve(list, count);
527 }
528
tr_variantInitDict(tr_variant * v,size_t reserve_count)529 void tr_variantInitDict(tr_variant* v, size_t reserve_count)
530 {
531 tr_variantInit(v, TR_VARIANT_TYPE_DICT);
532 tr_variantDictReserve(v, reserve_count);
533 }
534
tr_variantDictReserve(tr_variant * dict,size_t reserve_count)535 void tr_variantDictReserve(tr_variant* dict, size_t reserve_count)
536 {
537 TR_ASSERT(tr_variantIsDict(dict));
538
539 containerReserve(dict, reserve_count);
540 }
541
tr_variantListAdd(tr_variant * list)542 tr_variant* tr_variantListAdd(tr_variant* list)
543 {
544 TR_ASSERT(tr_variantIsList(list));
545
546 containerReserve(list, 1);
547
548 tr_variant* child = &list->val.l.vals[list->val.l.count++];
549 child->key = 0;
550 tr_variantInit(child, TR_VARIANT_TYPE_INT);
551
552 return child;
553 }
554
tr_variantListAddInt(tr_variant * list,int64_t val)555 tr_variant* tr_variantListAddInt(tr_variant* list, int64_t val)
556 {
557 tr_variant* child = tr_variantListAdd(list);
558 tr_variantInitInt(child, val);
559 return child;
560 }
561
tr_variantListAddReal(tr_variant * list,double val)562 tr_variant* tr_variantListAddReal(tr_variant* list, double val)
563 {
564 tr_variant* child = tr_variantListAdd(list);
565 tr_variantInitReal(child, val);
566 return child;
567 }
568
tr_variantListAddBool(tr_variant * list,bool val)569 tr_variant* tr_variantListAddBool(tr_variant* list, bool val)
570 {
571 tr_variant* child = tr_variantListAdd(list);
572 tr_variantInitBool(child, val);
573 return child;
574 }
575
tr_variantListAddStr(tr_variant * list,char const * val)576 tr_variant* tr_variantListAddStr(tr_variant* list, char const* val)
577 {
578 tr_variant* child = tr_variantListAdd(list);
579 tr_variantInitStr(child, val, TR_BAD_SIZE);
580 return child;
581 }
582
tr_variantListAddQuark(tr_variant * list,tr_quark const val)583 tr_variant* tr_variantListAddQuark(tr_variant* list, tr_quark const val)
584 {
585 tr_variant* child = tr_variantListAdd(list);
586 tr_variantInitQuark(child, val);
587 return child;
588 }
589
tr_variantListAddRaw(tr_variant * list,void const * val,size_t len)590 tr_variant* tr_variantListAddRaw(tr_variant* list, void const* val, size_t len)
591 {
592 tr_variant* child = tr_variantListAdd(list);
593 tr_variantInitRaw(child, val, len);
594 return child;
595 }
596
tr_variantListAddList(tr_variant * list,size_t reserve_count)597 tr_variant* tr_variantListAddList(tr_variant* list, size_t reserve_count)
598 {
599 tr_variant* child = tr_variantListAdd(list);
600 tr_variantInitList(child, reserve_count);
601 return child;
602 }
603
tr_variantListAddDict(tr_variant * list,size_t reserve_count)604 tr_variant* tr_variantListAddDict(tr_variant* list, size_t reserve_count)
605 {
606 tr_variant* child = tr_variantListAdd(list);
607 tr_variantInitDict(child, reserve_count);
608 return child;
609 }
610
tr_variantDictAdd(tr_variant * dict,tr_quark const key)611 tr_variant* tr_variantDictAdd(tr_variant* dict, tr_quark const key)
612 {
613 TR_ASSERT(tr_variantIsDict(dict));
614
615 containerReserve(dict, 1);
616
617 tr_variant* val = dict->val.l.vals + dict->val.l.count++;
618 tr_variantInit(val, TR_VARIANT_TYPE_INT);
619 val->key = key;
620
621 return val;
622 }
623
dictFindOrAdd(tr_variant * dict,tr_quark const key,int type)624 static tr_variant* dictFindOrAdd(tr_variant* dict, tr_quark const key, int type)
625 {
626 tr_variant* child;
627
628 /* see if it already exists, and if so, try to reuse it */
629 if ((child = tr_variantDictFind(dict, key)) != NULL)
630 {
631 if (!tr_variantIsType(child, type))
632 {
633 tr_variantDictRemove(dict, key);
634 child = NULL;
635 }
636 else if (child->type == TR_VARIANT_TYPE_STR)
637 {
638 tr_variant_string_clear(&child->val.s);
639 }
640 }
641
642 /* if it doesn't exist, create it */
643 if (child == NULL)
644 {
645 child = tr_variantDictAdd(dict, key);
646 }
647
648 return child;
649 }
650
tr_variantDictAddInt(tr_variant * dict,tr_quark const key,int64_t val)651 tr_variant* tr_variantDictAddInt(tr_variant* dict, tr_quark const key, int64_t val)
652 {
653 tr_variant* child = dictFindOrAdd(dict, key, TR_VARIANT_TYPE_INT);
654 tr_variantInitInt(child, val);
655 return child;
656 }
657
tr_variantDictAddBool(tr_variant * dict,tr_quark const key,bool val)658 tr_variant* tr_variantDictAddBool(tr_variant* dict, tr_quark const key, bool val)
659 {
660 tr_variant* child = dictFindOrAdd(dict, key, TR_VARIANT_TYPE_BOOL);
661 tr_variantInitBool(child, val);
662 return child;
663 }
664
tr_variantDictAddReal(tr_variant * dict,tr_quark const key,double val)665 tr_variant* tr_variantDictAddReal(tr_variant* dict, tr_quark const key, double val)
666 {
667 tr_variant* child = dictFindOrAdd(dict, key, TR_VARIANT_TYPE_REAL);
668 tr_variantInitReal(child, val);
669 return child;
670 }
671
tr_variantDictAddQuark(tr_variant * dict,tr_quark const key,tr_quark const val)672 tr_variant* tr_variantDictAddQuark(tr_variant* dict, tr_quark const key, tr_quark const val)
673 {
674 tr_variant* child = dictFindOrAdd(dict, key, TR_VARIANT_TYPE_STR);
675 tr_variantInitQuark(child, val);
676 return child;
677 }
678
tr_variantDictAddStr(tr_variant * dict,tr_quark const key,char const * val)679 tr_variant* tr_variantDictAddStr(tr_variant* dict, tr_quark const key, char const* val)
680 {
681 tr_variant* child = dictFindOrAdd(dict, key, TR_VARIANT_TYPE_STR);
682 tr_variantInitStr(child, val, TR_BAD_SIZE);
683 return child;
684 }
685
tr_variantDictAddRaw(tr_variant * dict,tr_quark const key,void const * src,size_t len)686 tr_variant* tr_variantDictAddRaw(tr_variant* dict, tr_quark const key, void const* src, size_t len)
687 {
688 tr_variant* child = dictFindOrAdd(dict, key, TR_VARIANT_TYPE_STR);
689 tr_variantInitRaw(child, src, len);
690 return child;
691 }
692
tr_variantDictAddList(tr_variant * dict,tr_quark const key,size_t reserve_count)693 tr_variant* tr_variantDictAddList(tr_variant* dict, tr_quark const key, size_t reserve_count)
694 {
695 tr_variant* child = tr_variantDictAdd(dict, key);
696 tr_variantInitList(child, reserve_count);
697 return child;
698 }
699
tr_variantDictAddDict(tr_variant * dict,tr_quark const key,size_t reserve_count)700 tr_variant* tr_variantDictAddDict(tr_variant* dict, tr_quark const key, size_t reserve_count)
701 {
702 tr_variant* child = tr_variantDictAdd(dict, key);
703 tr_variantInitDict(child, reserve_count);
704 return child;
705 }
706
tr_variantDictSteal(tr_variant * dict,tr_quark const key,tr_variant * value)707 tr_variant* tr_variantDictSteal(tr_variant* dict, tr_quark const key, tr_variant* value)
708 {
709 tr_variant* child = tr_variantDictAdd(dict, key);
710 *child = *value;
711 child->key = key;
712 tr_variantInit(value, value->type);
713 return child;
714 }
715
tr_variantDictRemove(tr_variant * dict,tr_quark const key)716 bool tr_variantDictRemove(tr_variant* dict, tr_quark const key)
717 {
718 bool removed = false;
719 int const i = dictIndexOf(dict, key);
720
721 if (i >= 0)
722 {
723 int const last = dict->val.l.count - 1;
724
725 tr_variantFree(&dict->val.l.vals[i]);
726
727 if (i != last)
728 {
729 dict->val.l.vals[i] = dict->val.l.vals[last];
730 }
731
732 --dict->val.l.count;
733
734 removed = true;
735 }
736
737 return removed;
738 }
739
740 /***
741 **** BENC WALKING
742 ***/
743
744 struct KeyIndex
745 {
746 char const* keystr;
747 tr_variant* val;
748 };
749
compareKeyIndex(void const * va,void const * vb)750 static int compareKeyIndex(void const* va, void const* vb)
751 {
752 struct KeyIndex const* a = va;
753 struct KeyIndex const* b = vb;
754
755 return strcmp(a->keystr, b->keystr);
756 }
757
758 struct SaveNode
759 {
760 tr_variant const* v;
761 tr_variant* sorted;
762 size_t childIndex;
763 bool isVisited;
764 };
765
nodeConstruct(struct SaveNode * node,tr_variant const * v,bool sort_dicts)766 static void nodeConstruct(struct SaveNode* node, tr_variant const* v, bool sort_dicts)
767 {
768 node->isVisited = false;
769 node->childIndex = 0;
770
771 if (sort_dicts && tr_variantIsDict(v))
772 {
773 /* make node->sorted a sorted version of this dictionary */
774
775 size_t const n = v->val.l.count;
776 struct KeyIndex* tmp = tr_new(struct KeyIndex, n);
777
778 for (size_t i = 0; i < n; i++)
779 {
780 tmp[i].val = v->val.l.vals + i;
781 tmp[i].keystr = tr_quark_get_string(tmp[i].val->key, NULL);
782 }
783
784 qsort(tmp, n, sizeof(struct KeyIndex), compareKeyIndex);
785
786 node->sorted = tr_new(tr_variant, 1);
787 tr_variantInitDict(node->sorted, n);
788
789 for (size_t i = 0; i < n; ++i)
790 {
791 node->sorted->val.l.vals[i] = *tmp[i].val;
792 }
793
794 node->sorted->val.l.count = n;
795
796 tr_free(tmp);
797
798 v = node->sorted;
799 }
800 else
801 {
802 node->sorted = NULL;
803 }
804
805 node->v = v;
806 }
807
nodeDestruct(struct SaveNode * node)808 static void nodeDestruct(struct SaveNode* node)
809 {
810 TR_ASSERT(node != NULL);
811
812 if (node->sorted != NULL)
813 {
814 tr_free(node->sorted->val.l.vals);
815 tr_free(node->sorted);
816 }
817 }
818
819 /**
820 * This function's previous recursive implementation was
821 * easier to read, but was vulnerable to a smash-stacking
822 * attack via maliciously-crafted data. (#667)
823 */
tr_variantWalk(tr_variant const * v,struct VariantWalkFuncs const * walkFuncs,void * user_data,bool sort_dicts)824 void tr_variantWalk(tr_variant const* v, struct VariantWalkFuncs const* walkFuncs, void* user_data, bool sort_dicts)
825 {
826 int stackSize = 0;
827 int stackAlloc = 64;
828 struct SaveNode* stack = tr_new(struct SaveNode, stackAlloc);
829
830 nodeConstruct(&stack[stackSize++], v, sort_dicts);
831
832 while (stackSize > 0)
833 {
834 struct SaveNode* node = &stack[stackSize - 1];
835 tr_variant const* v;
836
837 if (!node->isVisited)
838 {
839 v = node->v;
840 node->isVisited = true;
841 }
842 else if (tr_variantIsContainer(node->v) && node->childIndex < node->v->val.l.count)
843 {
844 int const index = node->childIndex;
845 ++node->childIndex;
846
847 v = node->v->val.l.vals + index;
848
849 if (tr_variantIsDict(node->v))
850 {
851 tr_variant tmp;
852 tr_variantInitQuark(&tmp, v->key);
853 walkFuncs->stringFunc(&tmp, user_data);
854 }
855 }
856 else /* done with this node */
857 {
858 if (tr_variantIsContainer(node->v))
859 {
860 walkFuncs->containerEndFunc(node->v, user_data);
861 }
862
863 --stackSize;
864 nodeDestruct(node);
865 continue;
866 }
867
868 if (v != NULL)
869 {
870 switch (v->type)
871 {
872 case TR_VARIANT_TYPE_INT:
873 walkFuncs->intFunc(v, user_data);
874 break;
875
876 case TR_VARIANT_TYPE_BOOL:
877 walkFuncs->boolFunc(v, user_data);
878 break;
879
880 case TR_VARIANT_TYPE_REAL:
881 walkFuncs->realFunc(v, user_data);
882 break;
883
884 case TR_VARIANT_TYPE_STR:
885 walkFuncs->stringFunc(v, user_data);
886 break;
887
888 case TR_VARIANT_TYPE_LIST:
889 if (v == node->v)
890 {
891 walkFuncs->listBeginFunc(v, user_data);
892 }
893 else
894 {
895 if (stackAlloc == stackSize)
896 {
897 stackAlloc *= 2;
898 stack = tr_renew(struct SaveNode, stack, stackAlloc);
899 }
900
901 nodeConstruct(&stack[stackSize++], v, sort_dicts);
902 }
903
904 break;
905
906 case TR_VARIANT_TYPE_DICT:
907 if (v == node->v)
908 {
909 walkFuncs->dictBeginFunc(v, user_data);
910 }
911 else
912 {
913 if (stackAlloc == stackSize)
914 {
915 stackAlloc *= 2;
916 stack = tr_renew(struct SaveNode, stack, stackAlloc);
917 }
918
919 nodeConstruct(&stack[stackSize++], v, sort_dicts);
920 }
921
922 break;
923
924 default:
925 /* did caller give us an uninitialized val? */
926 tr_logAddError("%s", _("Invalid metadata"));
927 break;
928 }
929 }
930 }
931
932 tr_free(stack);
933 }
934
935 /****
936 *****
937 ****/
938
freeDummyFunc(tr_variant const * v UNUSED,void * buf UNUSED)939 static void freeDummyFunc(tr_variant const* v UNUSED, void* buf UNUSED)
940 {
941 }
942
freeStringFunc(tr_variant const * v,void * unused UNUSED)943 static void freeStringFunc(tr_variant const* v, void* unused UNUSED)
944 {
945 tr_variant_string_clear(&((tr_variant*)v)->val.s);
946 }
947
freeContainerEndFunc(tr_variant const * v,void * unused UNUSED)948 static void freeContainerEndFunc(tr_variant const* v, void* unused UNUSED)
949 {
950 tr_free(v->val.l.vals);
951 }
952
953 static struct VariantWalkFuncs const freeWalkFuncs =
954 {
955 freeDummyFunc,
956 freeDummyFunc,
957 freeDummyFunc,
958 freeStringFunc,
959 freeDummyFunc,
960 freeDummyFunc,
961 freeContainerEndFunc
962 };
963
tr_variantFree(tr_variant * v)964 void tr_variantFree(tr_variant* v)
965 {
966 if (tr_variantIsSomething(v))
967 {
968 tr_variantWalk(v, &freeWalkFuncs, NULL, false);
969 }
970 }
971
972 /***
973 ****
974 ***/
975
tr_variantListCopy(tr_variant * target,tr_variant const * src)976 static void tr_variantListCopy(tr_variant* target, tr_variant const* src)
977 {
978 int i = 0;
979 tr_variant const* val;
980
981 while ((val = tr_variantListChild((tr_variant*)src, i)) != NULL)
982 {
983 if (tr_variantIsBool(val))
984 {
985 bool boolVal = false;
986 tr_variantGetBool(val, &boolVal);
987 tr_variantListAddBool(target, boolVal);
988 }
989 else if (tr_variantIsReal(val))
990 {
991 double realVal = 0;
992 tr_variantGetReal(val, &realVal);
993 tr_variantListAddReal(target, realVal);
994 }
995 else if (tr_variantIsInt(val))
996 {
997 int64_t intVal = 0;
998 tr_variantGetInt(val, &intVal);
999 tr_variantListAddInt(target, intVal);
1000 }
1001 else if (tr_variantIsString(val))
1002 {
1003 size_t len;
1004 char const* str;
1005 tr_variantGetStr(val, &str, &len);
1006 tr_variantListAddRaw(target, str, len);
1007 }
1008 else if (tr_variantIsDict(val))
1009 {
1010 tr_variantMergeDicts(tr_variantListAddDict(target, 0), val);
1011 }
1012 else if (tr_variantIsList(val))
1013 {
1014 tr_variantListCopy(tr_variantListAddList(target, 0), val);
1015 }
1016 else
1017 {
1018 tr_logAddError("tr_variantListCopy skipping item");
1019 }
1020
1021 ++i;
1022 }
1023 }
1024
tr_variantDictSize(tr_variant const * dict)1025 static size_t tr_variantDictSize(tr_variant const* dict)
1026 {
1027 return tr_variantIsDict(dict) ? dict->val.l.count : 0;
1028 }
1029
tr_variantDictChild(tr_variant * dict,size_t n,tr_quark * key,tr_variant ** val)1030 bool tr_variantDictChild(tr_variant* dict, size_t n, tr_quark* key, tr_variant** val)
1031 {
1032 TR_ASSERT(tr_variantIsDict(dict));
1033
1034 bool success = false;
1035
1036 if (tr_variantIsDict(dict) && n < dict->val.l.count)
1037 {
1038 *key = dict->val.l.vals[n].key;
1039 *val = dict->val.l.vals + n;
1040 success = true;
1041 }
1042
1043 return success;
1044 }
1045
tr_variantMergeDicts(tr_variant * target,tr_variant const * source)1046 void tr_variantMergeDicts(tr_variant* target, tr_variant const* source)
1047 {
1048 TR_ASSERT(tr_variantIsDict(target));
1049 TR_ASSERT(tr_variantIsDict(source));
1050
1051 size_t const sourceCount = tr_variantDictSize(source);
1052
1053 tr_variantDictReserve(target, sourceCount + tr_variantDictSize(target));
1054
1055 for (size_t i = 0; i < sourceCount; ++i)
1056 {
1057 tr_quark key;
1058 tr_variant* val;
1059 tr_variant* t;
1060
1061 if (tr_variantDictChild((tr_variant*)source, i, &key, &val))
1062 {
1063 if (tr_variantIsBool(val))
1064 {
1065 bool boolVal;
1066 tr_variantGetBool(val, &boolVal);
1067 tr_variantDictAddBool(target, key, boolVal);
1068 }
1069 else if (tr_variantIsReal(val))
1070 {
1071 double realVal = 0;
1072 tr_variantGetReal(val, &realVal);
1073 tr_variantDictAddReal(target, key, realVal);
1074 }
1075 else if (tr_variantIsInt(val))
1076 {
1077 int64_t intVal = 0;
1078 tr_variantGetInt(val, &intVal);
1079 tr_variantDictAddInt(target, key, intVal);
1080 }
1081 else if (tr_variantIsString(val))
1082 {
1083 size_t len;
1084 char const* str;
1085 tr_variantGetStr(val, &str, &len);
1086 tr_variantDictAddRaw(target, key, str, len);
1087 }
1088 else if (tr_variantIsDict(val) && tr_variantDictFindDict(target, key, &t))
1089 {
1090 tr_variantMergeDicts(t, val);
1091 }
1092 else if (tr_variantIsList(val))
1093 {
1094 if (tr_variantDictFind(target, key) == NULL)
1095 {
1096 tr_variantListCopy(tr_variantDictAddList(target, key, tr_variantListSize(val)), val);
1097 }
1098 }
1099 else if (tr_variantIsDict(val))
1100 {
1101 tr_variant* target_dict = tr_variantDictFind(target, key);
1102
1103 if (target_dict == NULL)
1104 {
1105 target_dict = tr_variantDictAddDict(target, key, tr_variantDictSize(val));
1106 }
1107
1108 if (tr_variantIsDict(target_dict))
1109 {
1110 tr_variantMergeDicts(target_dict, val);
1111 }
1112 }
1113 else
1114 {
1115 tr_logAddDebug("tr_variantMergeDicts skipping \"%s\"", tr_quark_get_string(key, NULL));
1116 }
1117 }
1118 }
1119 }
1120
1121 /***
1122 ****
1123 ***/
1124
tr_variantToBuf(tr_variant const * v,tr_variant_fmt fmt)1125 struct evbuffer* tr_variantToBuf(tr_variant const* v, tr_variant_fmt fmt)
1126 {
1127 struct locale_context locale_ctx;
1128 struct evbuffer* buf = evbuffer_new();
1129
1130 /* parse with LC_NUMERIC="C" to ensure a "." decimal separator */
1131 use_numeric_locale(&locale_ctx, "C");
1132
1133 evbuffer_expand(buf, 4096); /* alloc a little memory to start off with */
1134
1135 switch (fmt)
1136 {
1137 case TR_VARIANT_FMT_BENC:
1138 tr_variantToBufBenc(v, buf);
1139 break;
1140
1141 case TR_VARIANT_FMT_JSON:
1142 tr_variantToBufJson(v, buf, false);
1143 break;
1144
1145 case TR_VARIANT_FMT_JSON_LEAN:
1146 tr_variantToBufJson(v, buf, true);
1147 break;
1148 }
1149
1150 /* restore the previous locale */
1151 restore_locale(&locale_ctx);
1152 return buf;
1153 }
1154
tr_variantToStr(tr_variant const * v,tr_variant_fmt fmt,size_t * len)1155 char* tr_variantToStr(tr_variant const* v, tr_variant_fmt fmt, size_t* len)
1156 {
1157 struct evbuffer* buf = tr_variantToBuf(v, fmt);
1158 return evbuffer_free_to_str(buf, len);
1159 }
1160
tr_variantToFile(tr_variant const * v,tr_variant_fmt fmt,char const * filename)1161 int tr_variantToFile(tr_variant const* v, tr_variant_fmt fmt, char const* filename)
1162 {
1163 char* tmp;
1164 tr_sys_file_t fd;
1165 int err = 0;
1166 char* real_filename;
1167 tr_error* error = NULL;
1168
1169 /* follow symlinks to find the "real" file, to make sure the temporary
1170 * we build with tr_sys_file_open_temp() is created on the right partition */
1171 if ((real_filename = tr_sys_path_resolve(filename, NULL)) != NULL)
1172 {
1173 filename = real_filename;
1174 }
1175
1176 /* if the file already exists, try to move it out of the way & keep it as a backup */
1177 tmp = tr_strdup_printf("%s.tmp.XXXXXX", filename);
1178 fd = tr_sys_file_open_temp(tmp, &error);
1179
1180 if (fd != TR_BAD_SYS_FILE)
1181 {
1182 uint64_t nleft;
1183
1184 /* save the variant to a temporary file */
1185 {
1186 struct evbuffer* buf = tr_variantToBuf(v, fmt);
1187 char const* walk = (char const*)evbuffer_pullup(buf, -1);
1188 nleft = evbuffer_get_length(buf);
1189
1190 while (nleft > 0)
1191 {
1192 uint64_t n;
1193
1194 if (!tr_sys_file_write(fd, walk, nleft, &n, &error))
1195 {
1196 err = error->code;
1197 break;
1198 }
1199
1200 nleft -= n;
1201 walk += n;
1202 }
1203
1204 evbuffer_free(buf);
1205 }
1206
1207 tr_sys_file_close(fd, NULL);
1208
1209 if (nleft > 0)
1210 {
1211 tr_logAddError(_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, error->message);
1212 tr_sys_path_remove(tmp, NULL);
1213 tr_error_free(error);
1214 }
1215 else
1216 {
1217 tr_error_clear(&error);
1218
1219 if (tr_sys_path_rename(tmp, filename, &error))
1220 {
1221 tr_logAddInfo(_("Saved \"%s\""), filename);
1222 }
1223 else
1224 {
1225 err = error->code;
1226 tr_logAddError(_("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
1227 tr_sys_path_remove(tmp, NULL);
1228 tr_error_free(error);
1229 }
1230 }
1231 }
1232 else
1233 {
1234 err = error->code;
1235 tr_logAddError(_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, error->message);
1236 tr_error_free(error);
1237 }
1238
1239 tr_free(tmp);
1240 tr_free(real_filename);
1241 return err;
1242 }
1243
1244 /***
1245 ****
1246 ***/
1247
tr_variantFromFile(tr_variant * setme,tr_variant_fmt fmt,char const * filename,tr_error ** error)1248 bool tr_variantFromFile(tr_variant* setme, tr_variant_fmt fmt, char const* filename, tr_error** error)
1249 {
1250 bool ret = false;
1251 uint8_t* buf;
1252 size_t buflen;
1253
1254 buf = tr_loadFile(filename, &buflen, error);
1255
1256 if (buf != NULL)
1257 {
1258 if (tr_variantFromBuf(setme, fmt, buf, buflen, filename, NULL) == 0)
1259 {
1260 ret = true;
1261 }
1262 else
1263 {
1264 tr_error_set_literal(error, 0, _("Unable to parse file content"));
1265 }
1266
1267 tr_free(buf);
1268 }
1269
1270 return ret;
1271 }
1272
tr_variantFromBuf(tr_variant * setme,tr_variant_fmt fmt,void const * buf,size_t buflen,char const * optional_source,char const ** setme_end)1273 int tr_variantFromBuf(tr_variant* setme, tr_variant_fmt fmt, void const* buf, size_t buflen, char const* optional_source,
1274 char const** setme_end)
1275 {
1276 int err;
1277 struct locale_context locale_ctx;
1278
1279 /* parse with LC_NUMERIC="C" to ensure a "." decimal separator */
1280 use_numeric_locale(&locale_ctx, "C");
1281
1282 switch (fmt)
1283 {
1284 case TR_VARIANT_FMT_JSON:
1285 case TR_VARIANT_FMT_JSON_LEAN:
1286 err = tr_jsonParse(optional_source, buf, buflen, setme, setme_end);
1287 break;
1288
1289 default /* TR_VARIANT_FMT_BENC */:
1290 err = tr_variantParseBenc(buf, (char const*)buf + buflen, setme, setme_end);
1291 break;
1292 }
1293
1294 /* restore the previous locale */
1295 restore_locale(&locale_ctx);
1296 return err;
1297 }
1298