1 /* hb_dict.c
2 
3    Copyright (c) 2003-2021 HandBrake Team
4    This file is part of the HandBrake source code
5    Homepage: <http://handbrake.fr/>.
6    It may be used under the terms of the GNU General Public License v2.
7    For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8  */
9 
10 #include <ctype.h>
11 #include <stdio.h>
12 #include "handbrake/handbrake.h"
13 #include "handbrake/hb_dict.h"
14 
hb_value_type(const hb_value_t * value)15 hb_value_type_t hb_value_type(const hb_value_t *value)
16 {
17    if (value == NULL)
18         return HB_VALUE_TYPE_NULL;
19     hb_value_type_t type = json_typeof(value);
20     if (type == JSON_TRUE || type == JSON_FALSE)
21         return HB_VALUE_TYPE_BOOL;
22     return type;
23 }
24 
hb_value_is_number(const hb_value_t * value)25 int hb_value_is_number(const hb_value_t *value)
26 {
27     return json_is_number(value);
28 }
29 
hb_value_dup(const hb_value_t * value)30 hb_value_t * hb_value_dup(const hb_value_t *value)
31 {
32     if (value == NULL) return NULL;
33     return json_deep_copy(value);
34 }
35 
hb_value_incref(hb_value_t * value)36 hb_value_t* hb_value_incref(hb_value_t *value)
37 {
38     return json_incref(value);
39 }
40 
hb_value_decref(hb_value_t * value)41 void hb_value_decref(hb_value_t *value)
42 {
43     if (value == NULL) return;
44     json_decref(value);
45 }
46 
hb_value_free(hb_value_t ** _value)47 void hb_value_free(hb_value_t **_value)
48 {
49     hb_value_decref(*_value);
50     *_value = NULL;
51 }
52 
hb_value_null()53 hb_value_t * hb_value_null()
54 {
55     return json_null();
56 }
57 
hb_value_string(const char * value)58 hb_value_t * hb_value_string(const char * value)
59 {
60     // json_string does not create a value for NULL strings.
61     // So create JSON_NULL in this case
62     if (value == NULL)
63         return json_null();
64     return json_string(value);
65 }
66 
hb_value_int(json_int_t value)67 hb_value_t * hb_value_int(json_int_t value)
68 {
69     return json_integer(value);
70 }
71 
hb_value_double(double value)72 hb_value_t * hb_value_double(double value)
73 {
74     return json_real(value);
75 }
76 
hb_value_bool(int value)77 hb_value_t * hb_value_bool(int value)
78 {
79     return json_boolean(value);
80 }
81 
hb_value_json(const char * json)82 hb_value_t * hb_value_json(const char *json)
83 {
84     json_error_t error;
85     hb_value_t *val = json_loads(json, 0, &error);
86     if (val == NULL)
87     {
88         hb_error("hb_value_json: Failed, error %s", error.text);
89     }
90     return val;
91 }
92 
hb_value_read_json(const char * path)93 hb_value_t * hb_value_read_json(const char *path)
94 {
95     FILE * fp;
96     json_error_t error;
97 
98     fp = hb_fopen(path, "r");
99     if (fp == NULL)
100     {
101         return NULL;
102     }
103     hb_value_t *val = json_loadf(fp, 0, &error);
104     fclose(fp);
105     return val;
106 }
107 
xform_null(hb_value_type_t type)108 static hb_value_t* xform_null(hb_value_type_t type)
109 {
110     switch (type)
111     {
112         default:
113         case HB_VALUE_TYPE_NULL:
114             return json_null();
115         case HB_VALUE_TYPE_BOOL:
116             return json_false();
117         case HB_VALUE_TYPE_INT:
118             return json_integer(0);
119         case HB_VALUE_TYPE_DOUBLE:
120             return json_real(0.0);
121         case HB_VALUE_TYPE_STRING:
122             return json_string("");
123     }
124 }
125 
xform_bool(const hb_value_t * value,hb_value_type_t type)126 static hb_value_t* xform_bool(const hb_value_t *value, hb_value_type_t type)
127 {
128     json_int_t b = json_is_true(value);
129     switch (type)
130     {
131         default:
132         case HB_VALUE_TYPE_NULL:
133             return json_null();
134         case HB_VALUE_TYPE_BOOL:
135             return json_boolean(b);
136         case HB_VALUE_TYPE_INT:
137             return json_integer(b);
138         case HB_VALUE_TYPE_DOUBLE:
139             return json_real(b);
140         case HB_VALUE_TYPE_STRING:
141         {
142             char *s = hb_strdup_printf("%"JSON_INTEGER_FORMAT, b);
143             hb_value_t *v = json_string(s);
144             free(s);
145             return v;
146         }
147     }
148 }
149 
xform_int(const hb_value_t * value,hb_value_type_t type)150 static hb_value_t* xform_int(const hb_value_t *value, hb_value_type_t type)
151 {
152     json_int_t i = json_integer_value(value);
153     switch (type)
154     {
155         default:
156         case HB_VALUE_TYPE_NULL:
157             return json_null();
158         case HB_VALUE_TYPE_BOOL:
159             return json_boolean(i);
160         case HB_VALUE_TYPE_INT:
161             return json_integer(i);
162         case HB_VALUE_TYPE_DOUBLE:
163             return json_real(i);
164         case HB_VALUE_TYPE_STRING:
165         {
166             char *s = hb_strdup_printf("%"JSON_INTEGER_FORMAT, i);
167             hb_value_t *v = json_string(s);
168             free(s);
169             return v;
170         }
171     }
172 }
173 
xform_double(const hb_value_t * value,hb_value_type_t type)174 static hb_value_t* xform_double(const hb_value_t *value, hb_value_type_t type)
175 {
176     double d = json_real_value(value);
177     switch (type)
178     {
179         default:
180         case HB_VALUE_TYPE_NULL:
181             return json_null();
182         case HB_VALUE_TYPE_BOOL:
183             return json_boolean((int)d != 0);
184         case HB_VALUE_TYPE_INT:
185             return json_integer(d);
186         case HB_VALUE_TYPE_DOUBLE:
187             return json_real(d);
188         case HB_VALUE_TYPE_STRING:
189         {
190             char *s = hb_strdup_printf("%g", d);
191             hb_value_t *v = json_string(s);
192             free(s);
193             return v;
194         }
195     }
196 }
197 
xform_string(const hb_value_t * value,hb_value_type_t type)198 static hb_value_t* xform_string(const hb_value_t *value, hb_value_type_t type)
199 {
200     const char *s = json_string_value(value);
201     switch (type)
202     {
203         default:
204         case HB_VALUE_TYPE_NULL:
205         {
206             return json_null();
207         }
208         case HB_VALUE_TYPE_BOOL:
209         {
210             if (!strcasecmp(s, "true") ||
211                 !strcasecmp(s, "yes")  ||
212                 !strcasecmp(s, "1"))
213             {
214                 return json_true();
215             }
216             return json_false();
217         }
218         case HB_VALUE_TYPE_INT:
219         {
220             return json_integer(strtoll(s, NULL, 0));
221         }
222         case HB_VALUE_TYPE_DOUBLE:
223         {
224             return json_real(strtod(s, NULL));
225         }
226         case HB_VALUE_TYPE_STRING:
227         {
228             return json_string(s);
229         }
230     }
231 }
232 
xform_array(const hb_value_t * value,hb_value_type_t type)233 static hb_value_t* xform_array(const hb_value_t *value, hb_value_type_t type)
234 {
235     hb_value_t *first = NULL;
236     int count = hb_value_array_len(value);
237 
238     if (count > 0)
239         first = hb_value_array_get(value, 0);
240     switch (type)
241     {
242         default:
243         case HB_VALUE_TYPE_NULL:
244         case HB_VALUE_TYPE_BOOL:
245         case HB_VALUE_TYPE_INT:
246         case HB_VALUE_TYPE_DOUBLE:
247             return hb_value_xform(first, type);
248         case HB_VALUE_TYPE_STRING:
249         {
250             char *r = strdup("");
251             int ii;
252             for (ii = 0; ii < count; ii++)
253             {
254                 hb_value_t *v = hb_value_array_get(value, ii);
255                 hb_value_t *x = hb_value_xform(v, type);
256                 const char *s = hb_value_get_string(x);
257                 if (s != NULL)
258                 {
259                     char *tmp = r;
260                     r = hb_strdup_printf("%s%s,", tmp, s);
261                     free(tmp);
262                 }
263                 hb_value_free(&x);
264             }
265             int len = strlen(r);
266             hb_value_t *v;
267             if (len > 0)
268             {
269                 // Removing trailing ','
270                 r[len - 1] = 0;
271                 v = json_string(r);
272             }
273             else
274             {
275                 free(r);
276                 r = NULL;
277                 v = json_null();
278             }
279             free(r);
280             return v;
281         }
282     }
283 }
284 
xform_dict(const hb_value_t * dict,hb_value_type_t type)285 static hb_value_t* xform_dict(const hb_value_t *dict, hb_value_type_t type)
286 {
287     hb_value_t *first = NULL;
288     hb_dict_iter_t iter = hb_dict_iter_init(dict);
289 
290     if (iter != HB_DICT_ITER_DONE)
291         first = hb_dict_iter_value(iter);
292 
293     switch (type)
294     {
295         default:
296         case HB_VALUE_TYPE_NULL:
297         case HB_VALUE_TYPE_BOOL:
298         case HB_VALUE_TYPE_INT:
299         case HB_VALUE_TYPE_DOUBLE:
300             return hb_value_xform(first, type);
301         case HB_VALUE_TYPE_STRING:
302         {
303             char *r = strdup("");
304             hb_dict_iter_t iter;
305             for (iter  = hb_dict_iter_init(dict);
306                  iter != HB_DICT_ITER_DONE;
307                  iter  = hb_dict_iter_next(dict, iter))
308             {
309                 const char *k = hb_dict_iter_key(iter);
310                 hb_value_t *v = hb_dict_iter_value(iter);
311                 hb_value_t *x = hb_value_xform(v, type);
312                 const char *s = hb_value_get_string(x);
313 
314                 char *tmp = r;
315                 r = hb_strdup_printf("%s%s%s%s:",
316                                      r,
317                                      k,
318                                      s  ? "=" : "",
319                                      s  ? s   : "");
320                 free(tmp);
321                 hb_value_free(&x);
322             }
323             int len = strlen(r);
324             hb_value_t *v;
325             if (len > 0)
326             {
327                 // Removing trailing ':'
328                 r[len - 1] = 0;
329                 v = json_string(r);
330             }
331             else
332             {
333                 free(r);
334                 r = NULL;
335                 v = json_null();
336             }
337             free(r);
338             return v;
339         }
340     }
341 }
342 
hb_value_xform(const hb_value_t * value,hb_value_type_t type)343 hb_value_t* hb_value_xform(const hb_value_t *value, hb_value_type_t type)
344 {
345     hb_value_type_t src_type = hb_value_type(value);
346     if (src_type == type && value != NULL)
347     {
348         json_incref((hb_value_t*)value);
349         return (hb_value_t*)value;
350     }
351     switch (src_type)
352     {
353         default:
354         case HB_VALUE_TYPE_NULL:
355         {
356             return xform_null(type);
357         }
358         case HB_VALUE_TYPE_BOOL:
359         {
360             return xform_bool(value, type);
361         }
362         case HB_VALUE_TYPE_INT:
363         {
364             return xform_int(value, type);
365         }
366         case HB_VALUE_TYPE_DOUBLE:
367         {
368             return xform_double(value, type);
369         }
370         case HB_VALUE_TYPE_STRING:
371         {
372             return xform_string(value, type);
373         }
374         case HB_VALUE_TYPE_ARRAY:
375         {
376             return xform_array(value, type);
377         }
378         case HB_VALUE_TYPE_DICT:
379         {
380             return xform_dict(value, type);
381         }
382     }
383 }
384 
hb_value_get_string(const hb_value_t * value)385 const char * hb_value_get_string(const hb_value_t *value)
386 {
387     if (hb_value_type(value) != HB_VALUE_TYPE_STRING) return NULL;
388     return json_string_value(value);
389 }
390 
hb_value_get_int(const hb_value_t * value)391 json_int_t hb_value_get_int(const hb_value_t *value)
392 {
393     json_int_t result;
394     hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_INT);
395     result = json_integer_value(v);
396     json_decref(v);
397     return result;
398 }
399 
hb_value_get_double(const hb_value_t * value)400 double hb_value_get_double(const hb_value_t *value)
401 {
402     double result;
403     hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_DOUBLE);
404     result = json_real_value(v);
405     json_decref(v);
406     return result;
407 }
408 
hb_value_get_bool(const hb_value_t * value)409 int hb_value_get_bool(const hb_value_t *value)
410 {
411     int result;
412     hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_BOOL);
413     result = json_is_true(v);
414     json_decref(v);
415     return result;
416 }
417 
418 char*
hb_value_get_string_xform(const hb_value_t * value)419 hb_value_get_string_xform(const hb_value_t *value)
420 {
421     char *result;
422     if (hb_value_type(value) == HB_VALUE_TYPE_NULL)
423         return NULL;
424     hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_STRING);
425     if (hb_value_type(v) == HB_VALUE_TYPE_NULL)
426         return NULL;
427     result = strdup(json_string_value(v));
428     json_decref(v);
429     return result;
430 }
431 
hb_value_get_json(const hb_value_t * value)432 char * hb_value_get_json(const hb_value_t *value)
433 {
434     return json_dumps(value, JSON_INDENT(4) | JSON_SORT_KEYS);
435 }
436 
hb_value_write_file_json(hb_value_t * value,FILE * file)437 int  hb_value_write_file_json(hb_value_t *value, FILE *file)
438 {
439     return json_dumpf(value, file, JSON_INDENT(4) | JSON_SORT_KEYS);
440 }
441 
hb_value_write_json(hb_value_t * value,const char * path)442 int  hb_value_write_json(hb_value_t *value, const char *path)
443 {
444     return json_dump_file(value, path, JSON_INDENT(4) | JSON_SORT_KEYS);
445 }
446 
hb_dict_free(hb_dict_t ** _dict)447 void hb_dict_free(hb_dict_t **_dict)
448 {
449     hb_value_free(_dict);
450 }
451 
hb_dict_init()452 hb_dict_t * hb_dict_init()
453 {
454     return json_object();
455 }
456 
457 void
hb_dict_clear(hb_dict_t * dict)458 hb_dict_clear(hb_dict_t *dict)
459 {
460     json_object_clear(dict);
461 }
462 
hb_dict_elements(hb_dict_t * dict)463 int hb_dict_elements(hb_dict_t * dict)
464 {
465     return json_object_size(dict);
466 }
467 
makelower(const char * key)468 static char * makelower(const char *key)
469 {
470     int    ii, len = strlen(key);
471     char * lower = malloc(len + 1);
472 
473     for (ii = 0; ii < len; ii++)
474     {
475         lower[ii] = tolower(key[ii]);
476     }
477     lower[ii] = '\0';
478     return lower;
479 }
480 
hb_dict_set(hb_dict_t * dict,const char * key,hb_value_t * value)481 void hb_dict_set(hb_dict_t * dict, const char *key, hb_value_t *value)
482 {
483     json_object_set_new(dict, key, value);
484 }
485 
hb_dict_merge(hb_dict_t * dict,hb_dict_t * value)486 void hb_dict_merge(hb_dict_t * dict, hb_dict_t *value)
487 {
488     json_object_update(dict, value);
489 }
490 
hb_dict_case_set(hb_dict_t * dict,const char * key,hb_value_t * value)491 void hb_dict_case_set(hb_dict_t * dict, const char *key, hb_value_t *value)
492 {
493     char * lower = makelower(key);
494     json_object_set_new(dict, lower, value);
495     free(lower);
496 }
497 
hb_dict_remove(hb_dict_t * dict,const char * key)498 int hb_dict_remove(hb_dict_t * dict, const char * key)
499 {
500     int    result;
501 
502     // First try case sensitive lookup
503     result = json_object_del(dict, key) == 0;
504     if (!result)
505     {
506         // If not found, try case insensitive lookup
507         char * lower = makelower(key);
508         result = json_object_del(dict, lower) == 0;
509         free(lower);
510     }
511     return result;
512 }
513 
hb_dict_get(const hb_dict_t * dict,const char * key)514 hb_value_t * hb_dict_get(const hb_dict_t * dict, const char * key)
515 {
516     hb_value_t * result;
517 
518     // First try case sensitive lookup
519     result = json_object_get(dict, key);
520     if (result == NULL)
521     {
522         // If not found, try case insensitive lookup
523         char * lower = makelower(key);
524         result = json_object_get(dict, lower);
525         free(lower);
526     }
527     return result;
528 }
529 
530 //  Dictionary extraction helpers
531 //
532 // Extract the given key from the dict and assign to dst *only*
533 // if key is found in dict.  Values are converted to the requested
534 // data type.
535 //
536 // return: 1 - key is in dict
537 //         0 - key is not in dict
hb_dict_extract_int(int * dst,const hb_dict_t * dict,const char * key)538 int hb_dict_extract_int(int *dst, const hb_dict_t * dict, const char * key)
539 {
540     if (dict == NULL || key == NULL || dst == NULL)
541     {
542         return 0;
543     }
544 
545     hb_value_t *val = hb_dict_get(dict, key);
546     if (val == NULL)
547     {
548         return 0;
549     }
550 
551     *dst = hb_value_get_int(val);
552     return 1;
553 }
554 
hb_dict_extract_double(double * dst,const hb_dict_t * dict,const char * key)555 int hb_dict_extract_double(double *dst, const hb_dict_t * dict,
556                                         const char * key)
557 {
558     if (dict == NULL || key == NULL || dst == NULL)
559     {
560         return 0;
561     }
562 
563     hb_value_t *val = hb_dict_get(dict, key);
564     if (val == NULL)
565     {
566         return 0;
567     }
568 
569     *dst = hb_value_get_double(val);
570     return 1;
571 }
572 
hb_dict_extract_bool(int * dst,const hb_dict_t * dict,const char * key)573 int hb_dict_extract_bool(int *dst, const hb_dict_t * dict, const char * key)
574 {
575     if (dict == NULL || key == NULL || dst == NULL)
576     {
577         return 0;
578     }
579 
580     hb_value_t *val = hb_dict_get(dict, key);
581     if (val == NULL)
582     {
583         return 0;
584     }
585 
586     *dst = hb_value_get_bool(val);
587     return 1;
588 }
589 
hb_dict_extract_string(char ** dst,const hb_dict_t * dict,const char * key)590 int hb_dict_extract_string(char **dst, const hb_dict_t * dict, const char * key)
591 {
592     if (dict == NULL || key == NULL || dst == NULL)
593     {
594         return 0;
595     }
596 
597     hb_value_t *val = hb_dict_get(dict, key);
598     if (val == NULL)
599     {
600         return 0;
601     }
602 
603     *dst = hb_value_get_string_xform(val);
604     return 1;
605 }
606 
hb_dict_extract_rational(hb_rational_t * dst,const hb_dict_t * dict,const char * key)607 int hb_dict_extract_rational(hb_rational_t *dst, const hb_dict_t * dict,
608                                                  const char * key)
609 {
610     if (dict == NULL || key == NULL || dst == NULL)
611     {
612         return 0;
613     }
614 
615     hb_value_t *val = hb_dict_get(dict, key);
616     if (val == NULL)
617     {
618         return 0;
619     }
620 
621     if (hb_value_type(val) == HB_VALUE_TYPE_DICT)
622     {
623         hb_value_t * num_val = hb_dict_get(val, "Num");
624         if (num_val == NULL)
625         {
626             return 0;
627         }
628         hb_value_t * den_val = hb_dict_get(val, "Den");
629         if (den_val == NULL)
630         {
631             return 0;
632         }
633 
634         dst->num = hb_value_get_int(num_val);
635         dst->den = hb_value_get_int(den_val);
636         return 1;
637     }
638     else if (hb_value_type(val) == HB_VALUE_TYPE_STRING)
639     {
640         const char * str = hb_value_get_string(val);
641         char ** rational = hb_str_vsplit(str, '/');
642         if (rational[0] != NULL && rational[1] != NULL &&
643             isdigit(rational[0][0]) && isdigit(rational[1][0]))
644         {
645             char *num_end, *den_end;
646 
647             // found rational format value
648             int num = strtol(rational[0], &num_end, 0);
649             int den = strtol(rational[1], &den_end, 0);
650             // confirm that the 2 components were entirely numbers
651             if (num_end[0] == 0 && den_end[0] == 0)
652             {
653                 dst->num = num;
654                 dst->den = den;
655                 hb_str_vfree(rational);
656                 return 1;
657             }
658         }
659         hb_str_vfree(rational);
660     }
661 
662     return 0;
663 }
664 
hb_dict_extract_int_array(int * dst,int count,const hb_dict_t * dict,const char * key)665 int hb_dict_extract_int_array(int *dst, int count,
666                               const hb_dict_t * dict, const char * key)
667 {
668     if (dict == NULL || key == NULL || dst == NULL)
669     {
670         return 0;
671     }
672 
673     hb_value_t *val = hb_dict_get(dict, key);
674     if (hb_value_type(val) != HB_VALUE_TYPE_ARRAY)
675     {
676         return 0;
677     }
678 
679     int len = hb_value_array_len(val);
680     count = count < len ? count : len;
681 
682     int ii;
683     for (ii = 0; ii < count; ii++)
684     {
685         dst[ii] = hb_value_get_int(hb_value_array_get(val, ii));
686     }
687     return 1;
688 }
689 
hb_dict_iter_init(const hb_dict_t * dict)690 hb_dict_iter_t hb_dict_iter_init(const hb_dict_t *dict)
691 {
692     if (dict == NULL)
693         return HB_DICT_ITER_DONE;
694     return json_object_iter((hb_dict_t*)dict);
695 }
696 
hb_dict_iter_next(const hb_dict_t * dict,hb_dict_iter_t iter)697 hb_dict_iter_t hb_dict_iter_next(const hb_dict_t *dict, hb_dict_iter_t iter)
698 {
699     return json_object_iter_next((hb_dict_t*)dict, iter);
700 }
701 
hb_dict_iter_key(const hb_dict_iter_t iter)702 const char * hb_dict_iter_key(const hb_dict_iter_t iter)
703 {
704     return json_object_iter_key(iter);
705 }
706 
hb_dict_iter_value(const hb_dict_iter_t iter)707 hb_value_t * hb_dict_iter_value(const hb_dict_iter_t iter)
708 {
709     return json_object_iter_value(iter);
710 }
711 
712 int
hb_dict_iter_next_ex(const hb_dict_t * dict,hb_dict_iter_t * iter,const char ** key,hb_value_t ** val)713 hb_dict_iter_next_ex(const hb_dict_t *dict, hb_dict_iter_t *iter,
714                      const char **key, hb_value_t **val)
715 {
716     if (*iter == NULL)
717         return 0;
718     if (key != NULL)
719         *key = json_object_iter_key(*iter);
720     if (val != NULL)
721         *val = json_object_iter_value(*iter);
722     *iter = json_object_iter_next((hb_dict_t*)dict, *iter);
723     return 1;
724 }
725 
726 hb_value_array_t*
hb_value_array_init()727 hb_value_array_init()
728 {
729     return json_array();
730 }
731 
732 void
hb_value_array_clear(hb_value_array_t * array)733 hb_value_array_clear(hb_value_array_t *array)
734 {
735     json_array_clear(array);
736 }
737 
738 hb_value_t*
hb_value_array_get(const hb_value_array_t * array,int index)739 hb_value_array_get(const hb_value_array_t *array, int index)
740 {
741     return json_array_get(array, index);
742 }
743 
744 void
hb_value_array_set(hb_value_array_t * array,int index,hb_value_t * value)745 hb_value_array_set(hb_value_array_t *array, int index, hb_value_t *value)
746 {
747     if (index < 0 || index >= json_array_size(array))
748     {
749         hb_error("hb_value_array_set: invalid index %d size %zu",
750                  index, json_array_size(array));
751         return;
752     }
753     json_array_set_new(array, index, value);
754 }
755 
756 void
hb_value_array_insert(hb_value_array_t * array,int index,hb_value_t * value)757 hb_value_array_insert(hb_value_array_t *array, int index, hb_value_t *value)
758 {
759     json_array_insert_new(array, index, value);
760 }
761 
762 void
hb_value_array_append(hb_value_array_t * array,hb_value_t * value)763 hb_value_array_append(hb_value_array_t *array, hb_value_t *value)
764 {
765     json_array_append_new(array, value);
766 }
767 
768 void
hb_value_array_concat(hb_value_array_t * array,hb_value_t * value)769 hb_value_array_concat(hb_value_array_t *array, hb_value_t *value)
770 {
771     if (hb_value_type(value) == HB_VALUE_TYPE_ARRAY)
772     {
773         int ii;
774         int len = hb_value_array_len(value);
775 
776         for (ii = 0; ii < len; ii++)
777         {
778             hb_value_t * val = hb_value_array_get(value, ii);
779             json_array_append_new(array, hb_value_dup(val));
780         }
781     }
782     else
783     {
784         json_array_append_new(array, hb_value_dup(value));
785     }
786 }
787 
788 void
hb_value_array_remove(hb_value_array_t * array,int index)789 hb_value_array_remove(hb_value_array_t *array, int index)
790 {
791     json_array_remove(array, index);
792 }
793 
794 void
hb_value_array_copy(hb_value_array_t * dst,const hb_value_array_t * src,int count)795 hb_value_array_copy(hb_value_array_t *dst,
796                     const hb_value_array_t *src, int count)
797 {
798     size_t len;
799     int ii;
800 
801     // empty the first array if it is not already empty
802     json_array_clear(dst);
803 
804     len = hb_value_array_len(src);
805     count = MIN(count, len);
806     for (ii = 0; ii < count; ii++)
807         hb_value_array_append(dst, hb_value_dup(hb_value_array_get(src, ii)));
808 }
809 
810 size_t
hb_value_array_len(const hb_value_array_t * array)811 hb_value_array_len(const hb_value_array_t *array)
812 {
813     return json_array_size(array);
814 }
815 
hb_encopts_to_dict(const char * encopts,int encoder)816 hb_dict_t * hb_encopts_to_dict(const char * encopts, int encoder)
817 {
818     hb_dict_t * dict = NULL;
819 
820     if (encopts && *encopts)
821     {
822         char *cur_opt, *opts_start, *value;
823         const char *name;
824         dict = hb_dict_init();
825         if( !dict )
826             return NULL;
827         cur_opt = opts_start = strdup(encopts);
828         if (opts_start)
829         {
830             while (*cur_opt)
831             {
832                 name = cur_opt;
833                 cur_opt += strcspn(cur_opt, ":");
834                 if (*cur_opt)
835                 {
836                     *cur_opt = 0;
837                     cur_opt++;
838                 }
839                 value = strchr(name, '=');
840                 if (value)
841                 {
842                     *value = 0;
843                     value++;
844                 }
845                 // x264 has multiple names for some options
846                 if (encoder & HB_VCODEC_X264_MASK)
847                     name = hb_x264_encopt_name(name);
848 #if HB_PROJECT_FEATURE_X265
849                 // x265 has multiple names for some options
850                 if (encoder & HB_VCODEC_X265_MASK)
851                     name = hb_x265_encopt_name(name);
852 #endif
853                 if (name != NULL)
854                 {
855                     hb_dict_set(dict, name, hb_value_string(value));
856                 }
857             }
858         }
859         free(opts_start);
860     }
861     return dict;
862 }
863 
hb_dict_to_encopts(const hb_dict_t * dict)864 char * hb_dict_to_encopts(const hb_dict_t * dict)
865 {
866     return hb_value_get_string_xform(dict);
867 }
868 
869