1 /******************************************************************************
2 Copyright (C) 2014 by Hugh Bailey <obs.jim@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18 #include "util/bmem.h"
19 #include "util/threading.h"
20 #include "util/dstr.h"
21 #include "util/darray.h"
22 #include "util/platform.h"
23 #include "graphics/vec2.h"
24 #include "graphics/vec3.h"
25 #include "graphics/vec4.h"
26 #include "graphics/quat.h"
27 #include "obs-data.h"
28
29 #include <jansson.h>
30
31 struct obs_data_item {
32 volatile long ref;
33 struct obs_data *parent;
34 struct obs_data_item *next;
35 enum obs_data_type type;
36 size_t name_len;
37 size_t data_len;
38 size_t data_size;
39 size_t default_len;
40 size_t default_size;
41 size_t autoselect_size;
42 size_t capacity;
43 };
44
45 struct obs_data {
46 volatile long ref;
47 char *json;
48 struct obs_data_item *first_item;
49 };
50
51 struct obs_data_array {
52 volatile long ref;
53 DARRAY(obs_data_t *) objects;
54 };
55
56 struct obs_data_number {
57 enum obs_data_number_type type;
58 union {
59 long long int_val;
60 double double_val;
61 };
62 };
63
64 /* ------------------------------------------------------------------------- */
65 /* Item structure, designed to be one allocation only */
66
get_align_size(size_t size)67 static inline size_t get_align_size(size_t size)
68 {
69 const size_t alignment = base_get_alignment();
70 return (size + alignment - 1) & ~(alignment - 1);
71 }
72
73 /* ensures data after the name has alignment (in case of SSE) */
get_name_align_size(const char * name)74 static inline size_t get_name_align_size(const char *name)
75 {
76 size_t name_size = strlen(name) + 1;
77 size_t alignment = base_get_alignment();
78 size_t total_size;
79
80 total_size = sizeof(struct obs_data_item) + (name_size + alignment - 1);
81 total_size &= ~(alignment - 1);
82
83 return total_size - sizeof(struct obs_data_item);
84 }
85
get_item_name(struct obs_data_item * item)86 static inline char *get_item_name(struct obs_data_item *item)
87 {
88 return (char *)item + sizeof(struct obs_data_item);
89 }
90
get_data_ptr(obs_data_item_t * item)91 static inline void *get_data_ptr(obs_data_item_t *item)
92 {
93 return (uint8_t *)get_item_name(item) + item->name_len;
94 }
95
get_item_data(struct obs_data_item * item)96 static inline void *get_item_data(struct obs_data_item *item)
97 {
98 if (!item->data_size && !item->default_size && !item->autoselect_size)
99 return NULL;
100 return get_data_ptr(item);
101 }
102
get_default_data_ptr(obs_data_item_t * item)103 static inline void *get_default_data_ptr(obs_data_item_t *item)
104 {
105 return (uint8_t *)get_data_ptr(item) + item->data_len;
106 }
107
get_item_default_data(struct obs_data_item * item)108 static inline void *get_item_default_data(struct obs_data_item *item)
109 {
110 return item->default_size ? get_default_data_ptr(item) : NULL;
111 }
112
get_autoselect_data_ptr(obs_data_item_t * item)113 static inline void *get_autoselect_data_ptr(obs_data_item_t *item)
114 {
115 return (uint8_t *)get_default_data_ptr(item) + item->default_len;
116 }
117
get_item_autoselect_data(struct obs_data_item * item)118 static inline void *get_item_autoselect_data(struct obs_data_item *item)
119 {
120 return item->autoselect_size ? get_autoselect_data_ptr(item) : NULL;
121 }
122
obs_data_item_total_size(struct obs_data_item * item)123 static inline size_t obs_data_item_total_size(struct obs_data_item *item)
124 {
125 return sizeof(struct obs_data_item) + item->name_len + item->data_len +
126 item->default_len + item->autoselect_size;
127 }
128
get_item_obj(struct obs_data_item * item)129 static inline obs_data_t *get_item_obj(struct obs_data_item *item)
130 {
131 if (!item)
132 return NULL;
133
134 obs_data_t **data = get_item_data(item);
135 if (!data)
136 return NULL;
137
138 return *data;
139 }
140
get_item_default_obj(struct obs_data_item * item)141 static inline obs_data_t *get_item_default_obj(struct obs_data_item *item)
142 {
143 if (!item || !item->default_size)
144 return NULL;
145
146 return *(obs_data_t **)get_default_data_ptr(item);
147 }
148
get_item_autoselect_obj(struct obs_data_item * item)149 static inline obs_data_t *get_item_autoselect_obj(struct obs_data_item *item)
150 {
151 if (!item || !item->autoselect_size)
152 return NULL;
153
154 return *(obs_data_t **)get_autoselect_data_ptr(item);
155 }
156
get_item_array(struct obs_data_item * item)157 static inline obs_data_array_t *get_item_array(struct obs_data_item *item)
158 {
159 obs_data_array_t **array;
160
161 if (!item)
162 return NULL;
163
164 array = (obs_data_array_t **)get_item_data(item);
165 return array ? *array : NULL;
166 }
167
168 static inline obs_data_array_t *
get_item_default_array(struct obs_data_item * item)169 get_item_default_array(struct obs_data_item *item)
170 {
171 if (!item || !item->default_size)
172 return NULL;
173
174 return *(obs_data_array_t **)get_default_data_ptr(item);
175 }
176
177 static inline obs_data_array_t *
get_item_autoselect_array(struct obs_data_item * item)178 get_item_autoselect_array(struct obs_data_item *item)
179 {
180 if (!item || !item->autoselect_size)
181 return NULL;
182
183 return *(obs_data_array_t **)get_autoselect_data_ptr(item);
184 }
185
item_data_release(struct obs_data_item * item)186 static inline void item_data_release(struct obs_data_item *item)
187 {
188 if (!obs_data_item_has_user_value(item))
189 return;
190
191 if (item->type == OBS_DATA_OBJECT) {
192 obs_data_t *obj = get_item_obj(item);
193 obs_data_release(obj);
194
195 } else if (item->type == OBS_DATA_ARRAY) {
196 obs_data_array_t *array = get_item_array(item);
197 obs_data_array_release(array);
198 }
199 }
200
item_default_data_release(struct obs_data_item * item)201 static inline void item_default_data_release(struct obs_data_item *item)
202 {
203 if (item->type == OBS_DATA_OBJECT) {
204 obs_data_t *obj = get_item_default_obj(item);
205 obs_data_release(obj);
206
207 } else if (item->type == OBS_DATA_ARRAY) {
208 obs_data_array_t *array = get_item_default_array(item);
209 obs_data_array_release(array);
210 }
211 }
212
item_autoselect_data_release(struct obs_data_item * item)213 static inline void item_autoselect_data_release(struct obs_data_item *item)
214 {
215 if (item->type == OBS_DATA_OBJECT) {
216 obs_data_t *obj = get_item_autoselect_obj(item);
217 obs_data_release(obj);
218
219 } else if (item->type == OBS_DATA_ARRAY) {
220 obs_data_array_t *array = get_item_autoselect_array(item);
221 obs_data_array_release(array);
222 }
223 }
224
item_data_addref(struct obs_data_item * item)225 static inline void item_data_addref(struct obs_data_item *item)
226 {
227 if (item->type == OBS_DATA_OBJECT) {
228 obs_data_t *obj = get_item_obj(item);
229 obs_data_addref(obj);
230
231 } else if (item->type == OBS_DATA_ARRAY) {
232 obs_data_array_t *array = get_item_array(item);
233 obs_data_array_addref(array);
234 }
235 }
236
item_default_data_addref(struct obs_data_item * item)237 static inline void item_default_data_addref(struct obs_data_item *item)
238 {
239 if (!item->data_size)
240 return;
241
242 if (item->type == OBS_DATA_OBJECT) {
243 obs_data_t *obj = get_item_default_obj(item);
244 obs_data_addref(obj);
245
246 } else if (item->type == OBS_DATA_ARRAY) {
247 obs_data_array_t *array = get_item_default_array(item);
248 obs_data_array_addref(array);
249 }
250 }
251
item_autoselect_data_addref(struct obs_data_item * item)252 static inline void item_autoselect_data_addref(struct obs_data_item *item)
253 {
254 if (item->type == OBS_DATA_OBJECT) {
255 obs_data_t *obj = get_item_autoselect_obj(item);
256 obs_data_addref(obj);
257
258 } else if (item->type == OBS_DATA_ARRAY) {
259 obs_data_array_t *array = get_item_autoselect_array(item);
260 obs_data_array_addref(array);
261 }
262 }
263
obs_data_item_create(const char * name,const void * data,size_t size,enum obs_data_type type,bool default_data,bool autoselect_data)264 static struct obs_data_item *obs_data_item_create(const char *name,
265 const void *data, size_t size,
266 enum obs_data_type type,
267 bool default_data,
268 bool autoselect_data)
269 {
270 struct obs_data_item *item;
271 size_t name_size, total_size;
272
273 if (!name || !data)
274 return NULL;
275
276 name_size = get_name_align_size(name);
277 total_size = name_size + sizeof(struct obs_data_item) + size;
278
279 item = bzalloc(total_size);
280
281 item->capacity = total_size;
282 item->type = type;
283 item->name_len = name_size;
284 item->ref = 1;
285
286 if (default_data) {
287 item->default_len = size;
288 item->default_size = size;
289
290 } else if (autoselect_data) {
291 item->autoselect_size = size;
292
293 } else {
294 item->data_len = size;
295 item->data_size = size;
296 }
297
298 strcpy(get_item_name(item), name);
299 memcpy(get_item_data(item), data, size);
300
301 item_data_addref(item);
302 return item;
303 }
304
get_item_prev_next(struct obs_data * data,struct obs_data_item * current)305 static struct obs_data_item **get_item_prev_next(struct obs_data *data,
306 struct obs_data_item *current)
307 {
308 if (!current || !data)
309 return NULL;
310
311 struct obs_data_item **prev_next = &data->first_item;
312 struct obs_data_item *item = data->first_item;
313
314 while (item) {
315 if (item == current)
316 return prev_next;
317
318 prev_next = &item->next;
319 item = item->next;
320 }
321
322 return NULL;
323 }
324
obs_data_item_detach(struct obs_data_item * item)325 static inline void obs_data_item_detach(struct obs_data_item *item)
326 {
327 struct obs_data_item **prev_next =
328 get_item_prev_next(item->parent, item);
329
330 if (prev_next) {
331 *prev_next = item->next;
332 item->next = NULL;
333 }
334 }
335
obs_data_item_reattach(struct obs_data_item * old_ptr,struct obs_data_item * new_ptr)336 static inline void obs_data_item_reattach(struct obs_data_item *old_ptr,
337 struct obs_data_item *new_ptr)
338 {
339 struct obs_data_item **prev_next =
340 get_item_prev_next(new_ptr->parent, old_ptr);
341
342 if (prev_next)
343 *prev_next = new_ptr;
344 }
345
346 static struct obs_data_item *
obs_data_item_ensure_capacity(struct obs_data_item * item)347 obs_data_item_ensure_capacity(struct obs_data_item *item)
348 {
349 size_t new_size = obs_data_item_total_size(item);
350 struct obs_data_item *new_item;
351
352 if (item->capacity >= new_size)
353 return item;
354
355 new_item = brealloc(item, new_size);
356 new_item->capacity = new_size;
357
358 obs_data_item_reattach(item, new_item);
359 return new_item;
360 }
361
obs_data_item_destroy(struct obs_data_item * item)362 static inline void obs_data_item_destroy(struct obs_data_item *item)
363 {
364 item_data_release(item);
365 item_default_data_release(item);
366 item_autoselect_data_release(item);
367 obs_data_item_detach(item);
368 bfree(item);
369 }
370
move_data(obs_data_item_t * old_item,void * old_data,obs_data_item_t * item,void * data,size_t len)371 static inline void move_data(obs_data_item_t *old_item, void *old_data,
372 obs_data_item_t *item, void *data, size_t len)
373 {
374 ptrdiff_t old_offset = (uint8_t *)old_data - (uint8_t *)old_item;
375 ptrdiff_t new_offset = (uint8_t *)data - (uint8_t *)item;
376
377 if (!old_data)
378 return;
379
380 memmove((uint8_t *)item + new_offset, (uint8_t *)item + old_offset,
381 len);
382 }
383
obs_data_item_setdata(struct obs_data_item ** p_item,const void * data,size_t size,enum obs_data_type type)384 static inline void obs_data_item_setdata(struct obs_data_item **p_item,
385 const void *data, size_t size,
386 enum obs_data_type type)
387 {
388 if (!p_item || !*p_item)
389 return;
390
391 struct obs_data_item *item = *p_item;
392 ptrdiff_t old_default_data_pos =
393 (uint8_t *)get_default_data_ptr(item) - (uint8_t *)item;
394 item_data_release(item);
395
396 item->data_size = size;
397 item->type = type;
398 item->data_len = (item->default_size || item->autoselect_size)
399 ? get_align_size(size)
400 : size;
401 item = obs_data_item_ensure_capacity(item);
402
403 if (item->default_size || item->autoselect_size)
404 memmove(get_default_data_ptr(item),
405 (uint8_t *)item + old_default_data_pos,
406 item->default_len + item->autoselect_size);
407
408 if (size) {
409 memcpy(get_item_data(item), data, size);
410 item_data_addref(item);
411 }
412
413 *p_item = item;
414 }
415
obs_data_item_set_default_data(struct obs_data_item ** p_item,const void * data,size_t size,enum obs_data_type type)416 static inline void obs_data_item_set_default_data(struct obs_data_item **p_item,
417 const void *data, size_t size,
418 enum obs_data_type type)
419 {
420 if (!p_item || !*p_item)
421 return;
422
423 struct obs_data_item *item = *p_item;
424 void *old_autoselect_data = get_autoselect_data_ptr(item);
425 item_default_data_release(item);
426
427 item->type = type;
428 item->default_size = size;
429 item->default_len = item->autoselect_size ? get_align_size(size) : size;
430 item->data_len = item->data_size ? get_align_size(item->data_size) : 0;
431 item = obs_data_item_ensure_capacity(item);
432
433 if (item->autoselect_size)
434 move_data(*p_item, old_autoselect_data, item,
435 get_autoselect_data_ptr(item), item->autoselect_size);
436
437 if (size) {
438 memcpy(get_item_default_data(item), data, size);
439 item_default_data_addref(item);
440 }
441
442 *p_item = item;
443 }
444
445 static inline void
obs_data_item_set_autoselect_data(struct obs_data_item ** p_item,const void * data,size_t size,enum obs_data_type type)446 obs_data_item_set_autoselect_data(struct obs_data_item **p_item,
447 const void *data, size_t size,
448 enum obs_data_type type)
449 {
450 if (!p_item || !*p_item)
451 return;
452
453 struct obs_data_item *item = *p_item;
454 item_autoselect_data_release(item);
455
456 item->autoselect_size = size;
457 item->type = type;
458 item->data_len = item->data_size ? get_align_size(item->data_size) : 0;
459 item->default_len =
460 item->default_size ? get_align_size(item->default_size) : 0;
461 item = obs_data_item_ensure_capacity(item);
462
463 if (size) {
464 memcpy(get_item_autoselect_data(item), data, size);
465 item_autoselect_data_addref(item);
466 }
467
468 *p_item = item;
469 }
470
471 /* ------------------------------------------------------------------------- */
472
473 static void obs_data_add_json_item(obs_data_t *data, const char *key,
474 json_t *json);
475
obs_data_add_json_object_data(obs_data_t * data,json_t * jobj)476 static inline void obs_data_add_json_object_data(obs_data_t *data, json_t *jobj)
477 {
478 const char *item_key;
479 json_t *jitem;
480
481 json_object_foreach (jobj, item_key, jitem) {
482 obs_data_add_json_item(data, item_key, jitem);
483 }
484 }
485
obs_data_add_json_object(obs_data_t * data,const char * key,json_t * jobj)486 static inline void obs_data_add_json_object(obs_data_t *data, const char *key,
487 json_t *jobj)
488 {
489 obs_data_t *sub_obj = obs_data_create();
490
491 obs_data_add_json_object_data(sub_obj, jobj);
492 obs_data_set_obj(data, key, sub_obj);
493 obs_data_release(sub_obj);
494 }
495
obs_data_add_json_array(obs_data_t * data,const char * key,json_t * jarray)496 static void obs_data_add_json_array(obs_data_t *data, const char *key,
497 json_t *jarray)
498 {
499 obs_data_array_t *array = obs_data_array_create();
500 size_t idx;
501 json_t *jitem;
502
503 json_array_foreach (jarray, idx, jitem) {
504 obs_data_t *item;
505
506 if (!json_is_object(jitem))
507 continue;
508
509 item = obs_data_create();
510 obs_data_add_json_object_data(item, jitem);
511 obs_data_array_push_back(array, item);
512 obs_data_release(item);
513 }
514
515 obs_data_set_array(data, key, array);
516 obs_data_array_release(array);
517 }
518
obs_data_add_json_item(obs_data_t * data,const char * key,json_t * json)519 static void obs_data_add_json_item(obs_data_t *data, const char *key,
520 json_t *json)
521 {
522 if (json_is_object(json))
523 obs_data_add_json_object(data, key, json);
524 else if (json_is_array(json))
525 obs_data_add_json_array(data, key, json);
526 else if (json_is_string(json))
527 obs_data_set_string(data, key, json_string_value(json));
528 else if (json_is_integer(json))
529 obs_data_set_int(data, key, json_integer_value(json));
530 else if (json_is_real(json))
531 obs_data_set_double(data, key, json_real_value(json));
532 else if (json_is_true(json))
533 obs_data_set_bool(data, key, true);
534 else if (json_is_false(json))
535 obs_data_set_bool(data, key, false);
536 }
537
538 /* ------------------------------------------------------------------------- */
539
set_json_string(json_t * json,const char * name,obs_data_item_t * item)540 static inline void set_json_string(json_t *json, const char *name,
541 obs_data_item_t *item)
542 {
543 const char *val = obs_data_item_get_string(item);
544 json_object_set_new(json, name, json_string(val));
545 }
546
set_json_number(json_t * json,const char * name,obs_data_item_t * item)547 static inline void set_json_number(json_t *json, const char *name,
548 obs_data_item_t *item)
549 {
550 enum obs_data_number_type type = obs_data_item_numtype(item);
551
552 if (type == OBS_DATA_NUM_INT) {
553 long long val = obs_data_item_get_int(item);
554 json_object_set_new(json, name, json_integer(val));
555 } else {
556 double val = obs_data_item_get_double(item);
557 json_object_set_new(json, name, json_real(val));
558 }
559 }
560
set_json_bool(json_t * json,const char * name,obs_data_item_t * item)561 static inline void set_json_bool(json_t *json, const char *name,
562 obs_data_item_t *item)
563 {
564 bool val = obs_data_item_get_bool(item);
565 json_object_set_new(json, name, val ? json_true() : json_false());
566 }
567
568 static json_t *obs_data_to_json(obs_data_t *data);
569
set_json_obj(json_t * json,const char * name,obs_data_item_t * item)570 static inline void set_json_obj(json_t *json, const char *name,
571 obs_data_item_t *item)
572 {
573 obs_data_t *obj = obs_data_item_get_obj(item);
574 json_object_set_new(json, name, obs_data_to_json(obj));
575 obs_data_release(obj);
576 }
577
set_json_array(json_t * json,const char * name,obs_data_item_t * item)578 static inline void set_json_array(json_t *json, const char *name,
579 obs_data_item_t *item)
580 {
581 json_t *jarray = json_array();
582 obs_data_array_t *array = obs_data_item_get_array(item);
583 size_t count = obs_data_array_count(array);
584
585 for (size_t idx = 0; idx < count; idx++) {
586 obs_data_t *sub_item = obs_data_array_item(array, idx);
587 json_t *jitem = obs_data_to_json(sub_item);
588 json_array_append_new(jarray, jitem);
589 obs_data_release(sub_item);
590 }
591
592 json_object_set_new(json, name, jarray);
593 obs_data_array_release(array);
594 }
595
obs_data_to_json(obs_data_t * data)596 static json_t *obs_data_to_json(obs_data_t *data)
597 {
598 json_t *json = json_object();
599 obs_data_item_t *item = NULL;
600
601 for (item = obs_data_first(data); item; obs_data_item_next(&item)) {
602 enum obs_data_type type = obs_data_item_gettype(item);
603 const char *name = get_item_name(item);
604
605 if (!obs_data_item_has_user_value(item))
606 continue;
607
608 if (type == OBS_DATA_STRING)
609 set_json_string(json, name, item);
610 else if (type == OBS_DATA_NUMBER)
611 set_json_number(json, name, item);
612 else if (type == OBS_DATA_BOOLEAN)
613 set_json_bool(json, name, item);
614 else if (type == OBS_DATA_OBJECT)
615 set_json_obj(json, name, item);
616 else if (type == OBS_DATA_ARRAY)
617 set_json_array(json, name, item);
618 }
619
620 return json;
621 }
622
623 /* ------------------------------------------------------------------------- */
624
obs_data_create()625 obs_data_t *obs_data_create()
626 {
627 struct obs_data *data = bzalloc(sizeof(struct obs_data));
628 data->ref = 1;
629
630 return data;
631 }
632
obs_data_create_from_json(const char * json_string)633 obs_data_t *obs_data_create_from_json(const char *json_string)
634 {
635 obs_data_t *data = obs_data_create();
636
637 json_error_t error;
638 json_t *root = json_loads(json_string, JSON_REJECT_DUPLICATES, &error);
639
640 if (root) {
641 obs_data_add_json_object_data(data, root);
642 json_decref(root);
643 } else {
644 blog(LOG_ERROR,
645 "obs-data.c: [obs_data_create_from_json] "
646 "Failed reading json string (%d): %s",
647 error.line, error.text);
648 obs_data_release(data);
649 data = NULL;
650 }
651
652 return data;
653 }
654
obs_data_create_from_json_file(const char * json_file)655 obs_data_t *obs_data_create_from_json_file(const char *json_file)
656 {
657 char *file_data = os_quick_read_utf8_file(json_file);
658 obs_data_t *data = NULL;
659
660 if (file_data) {
661 data = obs_data_create_from_json(file_data);
662 bfree(file_data);
663 }
664
665 return data;
666 }
667
obs_data_create_from_json_file_safe(const char * json_file,const char * backup_ext)668 obs_data_t *obs_data_create_from_json_file_safe(const char *json_file,
669 const char *backup_ext)
670 {
671 obs_data_t *file_data = obs_data_create_from_json_file(json_file);
672 if (!file_data && backup_ext && *backup_ext) {
673 struct dstr backup_file = {0};
674
675 dstr_copy(&backup_file, json_file);
676 if (*backup_ext != '.')
677 dstr_cat(&backup_file, ".");
678 dstr_cat(&backup_file, backup_ext);
679
680 if (os_file_exists(backup_file.array)) {
681 blog(LOG_WARNING,
682 "obs-data.c: "
683 "[obs_data_create_from_json_file_safe] "
684 "attempting backup file");
685
686 /* delete current file if corrupt to prevent it from
687 * being backed up again */
688 os_rename(backup_file.array, json_file);
689
690 file_data = obs_data_create_from_json_file(json_file);
691 }
692
693 dstr_free(&backup_file);
694 }
695
696 return file_data;
697 }
698
obs_data_addref(obs_data_t * data)699 void obs_data_addref(obs_data_t *data)
700 {
701 if (data)
702 os_atomic_inc_long(&data->ref);
703 }
704
obs_data_destroy(struct obs_data * data)705 static inline void obs_data_destroy(struct obs_data *data)
706 {
707 struct obs_data_item *item = data->first_item;
708
709 while (item) {
710 struct obs_data_item *next = item->next;
711 obs_data_item_release(&item);
712 item = next;
713 }
714
715 /* NOTE: don't use bfree for json text, allocated by json */
716 free(data->json);
717 bfree(data);
718 }
719
obs_data_release(obs_data_t * data)720 void obs_data_release(obs_data_t *data)
721 {
722 if (!data)
723 return;
724
725 if (os_atomic_dec_long(&data->ref) == 0)
726 obs_data_destroy(data);
727 }
728
obs_data_get_json(obs_data_t * data)729 const char *obs_data_get_json(obs_data_t *data)
730 {
731 if (!data)
732 return NULL;
733
734 /* NOTE: don't use libobs bfree for json text */
735 free(data->json);
736 data->json = NULL;
737
738 json_t *root = obs_data_to_json(data);
739 data->json = json_dumps(root, JSON_PRESERVE_ORDER | JSON_COMPACT);
740 json_decref(root);
741
742 return data->json;
743 }
744
obs_data_get_last_json(obs_data_t * data)745 const char *obs_data_get_last_json(obs_data_t *data)
746 {
747 return data ? data->json : NULL;
748 }
749
obs_data_save_json(obs_data_t * data,const char * file)750 bool obs_data_save_json(obs_data_t *data, const char *file)
751 {
752 const char *json = obs_data_get_json(data);
753
754 if (json && *json) {
755 return os_quick_write_utf8_file(file, json, strlen(json),
756 false);
757 }
758
759 return false;
760 }
761
obs_data_save_json_safe(obs_data_t * data,const char * file,const char * temp_ext,const char * backup_ext)762 bool obs_data_save_json_safe(obs_data_t *data, const char *file,
763 const char *temp_ext, const char *backup_ext)
764 {
765 const char *json = obs_data_get_json(data);
766
767 if (json && *json) {
768 return os_quick_write_utf8_file_safe(
769 file, json, strlen(json), false, temp_ext, backup_ext);
770 }
771
772 return false;
773 }
774
get_defaults_array_cb(obs_data_t * data,void * vp)775 static void get_defaults_array_cb(obs_data_t *data, void *vp)
776 {
777 obs_data_array_t *defs = (obs_data_array_t *)vp;
778 obs_data_t *obs_defaults = obs_data_get_defaults(data);
779
780 obs_data_array_push_back(defs, obs_defaults);
781
782 obs_data_release(obs_defaults);
783 }
784
obs_data_get_defaults(obs_data_t * data)785 obs_data_t *obs_data_get_defaults(obs_data_t *data)
786 {
787 obs_data_t *defaults = obs_data_create();
788
789 if (!data)
790 return defaults;
791
792 struct obs_data_item *item = data->first_item;
793
794 while (item) {
795 const char *name = get_item_name(item);
796 switch (item->type) {
797 case OBS_DATA_NULL:
798 break;
799
800 case OBS_DATA_STRING: {
801 const char *str =
802 obs_data_get_default_string(data, name);
803 obs_data_set_string(defaults, name, str);
804 break;
805 }
806
807 case OBS_DATA_NUMBER: {
808 switch (obs_data_item_numtype(item)) {
809 case OBS_DATA_NUM_DOUBLE: {
810 double val =
811 obs_data_get_default_double(data, name);
812 obs_data_set_double(defaults, name, val);
813 break;
814 }
815
816 case OBS_DATA_NUM_INT: {
817 long long val =
818 obs_data_get_default_int(data, name);
819 obs_data_set_int(defaults, name, val);
820 break;
821 }
822
823 case OBS_DATA_NUM_INVALID:
824 break;
825 }
826 break;
827 }
828
829 case OBS_DATA_BOOLEAN: {
830 bool val = obs_data_get_default_bool(data, name);
831 obs_data_set_bool(defaults, name, val);
832 break;
833 }
834
835 case OBS_DATA_OBJECT: {
836 obs_data_t *val = obs_data_get_default_obj(data, name);
837 obs_data_t *defs = obs_data_get_defaults(val);
838
839 obs_data_set_obj(defaults, name, defs);
840
841 obs_data_release(defs);
842 obs_data_release(val);
843 break;
844 }
845
846 case OBS_DATA_ARRAY: {
847 obs_data_array_t *arr =
848 obs_data_get_default_array(data, name);
849 obs_data_array_t *defs = obs_data_array_create();
850
851 obs_data_array_enum(arr, get_defaults_array_cb,
852 (void *)defs);
853 obs_data_set_array(defaults, name, defs);
854
855 obs_data_array_release(defs);
856 obs_data_array_release(arr);
857 break;
858 }
859 }
860
861 item = item->next;
862 }
863
864 return defaults;
865 }
866
get_item(struct obs_data * data,const char * name)867 static struct obs_data_item *get_item(struct obs_data *data, const char *name)
868 {
869 if (!data)
870 return NULL;
871
872 struct obs_data_item *item = data->first_item;
873
874 while (item) {
875 if (strcmp(get_item_name(item), name) == 0)
876 return item;
877
878 item = item->next;
879 }
880
881 return NULL;
882 }
883
set_item_data(struct obs_data * data,struct obs_data_item ** item,const char * name,const void * ptr,size_t size,enum obs_data_type type,bool default_data,bool autoselect_data)884 static void set_item_data(struct obs_data *data, struct obs_data_item **item,
885 const char *name, const void *ptr, size_t size,
886 enum obs_data_type type, bool default_data,
887 bool autoselect_data)
888 {
889 obs_data_item_t *new_item = NULL;
890
891 if ((!item || !*item) && data) {
892 new_item = obs_data_item_create(name, ptr, size, type,
893 default_data, autoselect_data);
894
895 obs_data_item_t *prev = obs_data_first(data);
896 obs_data_item_t *next = obs_data_first(data);
897 obs_data_item_next(&next);
898 for (; prev && next;
899 obs_data_item_next(&prev), obs_data_item_next(&next)) {
900 if (strcmp(get_item_name(next), name) > 0)
901 break;
902 }
903
904 new_item->parent = data;
905 if (prev && strcmp(get_item_name(prev), name) < 0) {
906 prev->next = new_item;
907 new_item->next = next;
908
909 } else {
910 data->first_item = new_item;
911 new_item->next = prev;
912 }
913
914 if (!prev)
915 data->first_item = new_item;
916
917 obs_data_item_release(&prev);
918 obs_data_item_release(&next);
919
920 } else if (default_data) {
921 obs_data_item_set_default_data(item, ptr, size, type);
922 } else if (autoselect_data) {
923 obs_data_item_set_autoselect_data(item, ptr, size, type);
924 } else {
925 obs_data_item_setdata(item, ptr, size, type);
926 }
927 }
928
set_item(struct obs_data * data,obs_data_item_t ** item,const char * name,const void * ptr,size_t size,enum obs_data_type type)929 static inline void set_item(struct obs_data *data, obs_data_item_t **item,
930 const char *name, const void *ptr, size_t size,
931 enum obs_data_type type)
932 {
933 obs_data_item_t *actual_item = NULL;
934
935 if (!data && !item)
936 return;
937
938 if (!item) {
939 actual_item = get_item(data, name);
940 item = &actual_item;
941 }
942
943 set_item_data(data, item, name, ptr, size, type, false, false);
944 }
945
set_item_def(struct obs_data * data,obs_data_item_t ** item,const char * name,const void * ptr,size_t size,enum obs_data_type type)946 static inline void set_item_def(struct obs_data *data, obs_data_item_t **item,
947 const char *name, const void *ptr, size_t size,
948 enum obs_data_type type)
949 {
950 obs_data_item_t *actual_item = NULL;
951
952 if (!data && !item)
953 return;
954
955 if (!item) {
956 actual_item = get_item(data, name);
957 item = &actual_item;
958 }
959
960 if (*item && (*item)->type != type)
961 return;
962
963 set_item_data(data, item, name, ptr, size, type, true, false);
964 }
965
set_item_auto(struct obs_data * data,obs_data_item_t ** item,const char * name,const void * ptr,size_t size,enum obs_data_type type)966 static inline void set_item_auto(struct obs_data *data, obs_data_item_t **item,
967 const char *name, const void *ptr, size_t size,
968 enum obs_data_type type)
969 {
970 obs_data_item_t *actual_item = NULL;
971
972 if (!data && !item)
973 return;
974
975 if (!item) {
976 actual_item = get_item(data, name);
977 item = &actual_item;
978 }
979
980 set_item_data(data, item, name, ptr, size, type, false, true);
981 }
982
copy_obj(struct obs_data * data,const char * name,struct obs_data * obj,void (* callback)(obs_data_t *,const char *,obs_data_t *))983 static void copy_obj(struct obs_data *data, const char *name,
984 struct obs_data *obj,
985 void (*callback)(obs_data_t *, const char *, obs_data_t *))
986 {
987 if (obj) {
988 obs_data_t *new_obj = obs_data_create();
989 obs_data_apply(new_obj, obj);
990 callback(data, name, new_obj);
991 obs_data_release(new_obj);
992 }
993 }
994
copy_array(struct obs_data * data,const char * name,struct obs_data_array * array,void (* callback)(obs_data_t *,const char *,obs_data_array_t *))995 static void copy_array(struct obs_data *data, const char *name,
996 struct obs_data_array *array,
997 void (*callback)(obs_data_t *, const char *,
998 obs_data_array_t *))
999 {
1000 if (array) {
1001 obs_data_array_t *new_array = obs_data_array_create();
1002 da_reserve(new_array->objects, array->objects.num);
1003
1004 for (size_t i = 0; i < array->objects.num; i++) {
1005 obs_data_t *new_obj = obs_data_create();
1006 obs_data_t *obj = array->objects.array[i];
1007
1008 obs_data_apply(new_obj, obj);
1009 obs_data_array_push_back(new_array, new_obj);
1010
1011 obs_data_release(new_obj);
1012 }
1013
1014 callback(data, name, new_array);
1015 obs_data_array_release(new_array);
1016 }
1017 }
1018
copy_item(struct obs_data * data,struct obs_data_item * item)1019 static inline void copy_item(struct obs_data *data, struct obs_data_item *item)
1020 {
1021 const char *name = get_item_name(item);
1022 void *ptr = get_item_data(item);
1023
1024 if (item->type == OBS_DATA_OBJECT) {
1025 obs_data_t **obj = item->data_size ? ptr : NULL;
1026
1027 if (obj)
1028 copy_obj(data, name, *obj, obs_data_set_obj);
1029
1030 } else if (item->type == OBS_DATA_ARRAY) {
1031 obs_data_array_t **array = item->data_size ? ptr : NULL;
1032
1033 if (array)
1034 copy_array(data, name, *array, obs_data_set_array);
1035
1036 } else {
1037 if (item->data_size)
1038 set_item(data, NULL, name, ptr, item->data_size,
1039 item->type);
1040 }
1041 }
1042
obs_data_apply(obs_data_t * target,obs_data_t * apply_data)1043 void obs_data_apply(obs_data_t *target, obs_data_t *apply_data)
1044 {
1045 struct obs_data_item *item;
1046
1047 if (!target || !apply_data || target == apply_data)
1048 return;
1049
1050 item = apply_data->first_item;
1051
1052 while (item) {
1053 copy_item(target, item);
1054 item = item->next;
1055 }
1056 }
1057
obs_data_erase(obs_data_t * data,const char * name)1058 void obs_data_erase(obs_data_t *data, const char *name)
1059 {
1060 struct obs_data_item *item = get_item(data, name);
1061
1062 if (item) {
1063 obs_data_item_detach(item);
1064 obs_data_item_release(&item);
1065 }
1066 }
1067
clear_item(struct obs_data_item * item)1068 static inline void clear_item(struct obs_data_item *item)
1069 {
1070 void *ptr = get_item_data(item);
1071 size_t size;
1072
1073 if (item->data_len) {
1074 if (item->type == OBS_DATA_OBJECT) {
1075 obs_data_t **obj = item->data_size ? ptr : NULL;
1076
1077 if (obj && *obj)
1078 obs_data_release(*obj);
1079
1080 } else if (item->type == OBS_DATA_ARRAY) {
1081 obs_data_array_t **array = item->data_size ? ptr : NULL;
1082
1083 if (array && *array)
1084 obs_data_array_release(*array);
1085 }
1086
1087 size = item->default_len + item->autoselect_size;
1088 if (size)
1089 memmove(ptr, (uint8_t *)ptr + item->data_len, size);
1090
1091 item->data_size = 0;
1092 item->data_len = 0;
1093 }
1094 }
1095
obs_data_clear(obs_data_t * target)1096 void obs_data_clear(obs_data_t *target)
1097 {
1098 struct obs_data_item *item;
1099
1100 if (!target)
1101 return;
1102
1103 item = target->first_item;
1104
1105 while (item) {
1106 clear_item(item);
1107 item = item->next;
1108 }
1109 }
1110
1111 typedef void (*set_item_t)(obs_data_t *, obs_data_item_t **, const char *,
1112 const void *, size_t, enum obs_data_type);
1113
obs_set_string(obs_data_t * data,obs_data_item_t ** item,const char * name,const char * val,set_item_t set_item_)1114 static inline void obs_set_string(obs_data_t *data, obs_data_item_t **item,
1115 const char *name, const char *val,
1116 set_item_t set_item_)
1117 {
1118 if (!val)
1119 val = "";
1120 set_item_(data, item, name, val, strlen(val) + 1, OBS_DATA_STRING);
1121 }
1122
obs_set_int(obs_data_t * data,obs_data_item_t ** item,const char * name,long long val,set_item_t set_item_)1123 static inline void obs_set_int(obs_data_t *data, obs_data_item_t **item,
1124 const char *name, long long val,
1125 set_item_t set_item_)
1126 {
1127 struct obs_data_number num;
1128 num.type = OBS_DATA_NUM_INT;
1129 num.int_val = val;
1130 set_item_(data, item, name, &num, sizeof(struct obs_data_number),
1131 OBS_DATA_NUMBER);
1132 }
1133
obs_set_double(obs_data_t * data,obs_data_item_t ** item,const char * name,double val,set_item_t set_item_)1134 static inline void obs_set_double(obs_data_t *data, obs_data_item_t **item,
1135 const char *name, double val,
1136 set_item_t set_item_)
1137 {
1138 struct obs_data_number num;
1139 num.type = OBS_DATA_NUM_DOUBLE;
1140 num.double_val = val;
1141 set_item_(data, item, name, &num, sizeof(struct obs_data_number),
1142 OBS_DATA_NUMBER);
1143 }
1144
obs_set_bool(obs_data_t * data,obs_data_item_t ** item,const char * name,bool val,set_item_t set_item_)1145 static inline void obs_set_bool(obs_data_t *data, obs_data_item_t **item,
1146 const char *name, bool val,
1147 set_item_t set_item_)
1148 {
1149 set_item_(data, item, name, &val, sizeof(bool), OBS_DATA_BOOLEAN);
1150 }
1151
obs_set_obj(obs_data_t * data,obs_data_item_t ** item,const char * name,obs_data_t * obj,set_item_t set_item_)1152 static inline void obs_set_obj(obs_data_t *data, obs_data_item_t **item,
1153 const char *name, obs_data_t *obj,
1154 set_item_t set_item_)
1155 {
1156 set_item_(data, item, name, &obj, sizeof(obs_data_t *),
1157 OBS_DATA_OBJECT);
1158 }
1159
obs_set_array(obs_data_t * data,obs_data_item_t ** item,const char * name,obs_data_array_t * array,set_item_t set_item_)1160 static inline void obs_set_array(obs_data_t *data, obs_data_item_t **item,
1161 const char *name, obs_data_array_t *array,
1162 set_item_t set_item_)
1163 {
1164 set_item_(data, item, name, &array, sizeof(obs_data_t *),
1165 OBS_DATA_ARRAY);
1166 }
1167
obs_take_obj(obs_data_t * data,obs_data_item_t ** item,const char * name,obs_data_t * obj,set_item_t set_item_)1168 static inline void obs_take_obj(obs_data_t *data, obs_data_item_t **item,
1169 const char *name, obs_data_t *obj,
1170 set_item_t set_item_)
1171 {
1172 obs_set_obj(data, item, name, obj, set_item_);
1173 obs_data_release(obj);
1174 }
1175
obs_data_set_string(obs_data_t * data,const char * name,const char * val)1176 void obs_data_set_string(obs_data_t *data, const char *name, const char *val)
1177 {
1178 obs_set_string(data, NULL, name, val, set_item);
1179 }
1180
obs_data_set_int(obs_data_t * data,const char * name,long long val)1181 void obs_data_set_int(obs_data_t *data, const char *name, long long val)
1182 {
1183 obs_set_int(data, NULL, name, val, set_item);
1184 }
1185
obs_data_set_double(obs_data_t * data,const char * name,double val)1186 void obs_data_set_double(obs_data_t *data, const char *name, double val)
1187 {
1188 obs_set_double(data, NULL, name, val, set_item);
1189 }
1190
obs_data_set_bool(obs_data_t * data,const char * name,bool val)1191 void obs_data_set_bool(obs_data_t *data, const char *name, bool val)
1192 {
1193 obs_set_bool(data, NULL, name, val, set_item);
1194 }
1195
obs_data_set_obj(obs_data_t * data,const char * name,obs_data_t * obj)1196 void obs_data_set_obj(obs_data_t *data, const char *name, obs_data_t *obj)
1197 {
1198 obs_set_obj(data, NULL, name, obj, set_item);
1199 }
1200
obs_data_set_array(obs_data_t * data,const char * name,obs_data_array_t * array)1201 void obs_data_set_array(obs_data_t *data, const char *name,
1202 obs_data_array_t *array)
1203 {
1204 obs_set_array(data, NULL, name, array, set_item);
1205 }
1206
obs_data_set_default_string(obs_data_t * data,const char * name,const char * val)1207 void obs_data_set_default_string(obs_data_t *data, const char *name,
1208 const char *val)
1209 {
1210 obs_set_string(data, NULL, name, val, set_item_def);
1211 }
1212
obs_data_set_default_int(obs_data_t * data,const char * name,long long val)1213 void obs_data_set_default_int(obs_data_t *data, const char *name, long long val)
1214 {
1215 obs_set_int(data, NULL, name, val, set_item_def);
1216 }
1217
obs_data_set_default_double(obs_data_t * data,const char * name,double val)1218 void obs_data_set_default_double(obs_data_t *data, const char *name, double val)
1219 {
1220 obs_set_double(data, NULL, name, val, set_item_def);
1221 }
1222
obs_data_set_default_bool(obs_data_t * data,const char * name,bool val)1223 void obs_data_set_default_bool(obs_data_t *data, const char *name, bool val)
1224 {
1225 obs_set_bool(data, NULL, name, val, set_item_def);
1226 }
1227
obs_data_set_default_obj(obs_data_t * data,const char * name,obs_data_t * obj)1228 void obs_data_set_default_obj(obs_data_t *data, const char *name,
1229 obs_data_t *obj)
1230 {
1231 obs_set_obj(data, NULL, name, obj, set_item_def);
1232 }
1233
obs_data_set_default_array(obs_data_t * data,const char * name,obs_data_array_t * arr)1234 void obs_data_set_default_array(obs_data_t *data, const char *name,
1235 obs_data_array_t *arr)
1236 {
1237 obs_set_array(data, NULL, name, arr, set_item_def);
1238 }
1239
obs_data_set_autoselect_string(obs_data_t * data,const char * name,const char * val)1240 void obs_data_set_autoselect_string(obs_data_t *data, const char *name,
1241 const char *val)
1242 {
1243 obs_set_string(data, NULL, name, val, set_item_auto);
1244 }
1245
obs_data_set_autoselect_int(obs_data_t * data,const char * name,long long val)1246 void obs_data_set_autoselect_int(obs_data_t *data, const char *name,
1247 long long val)
1248 {
1249 obs_set_int(data, NULL, name, val, set_item_auto);
1250 }
1251
obs_data_set_autoselect_double(obs_data_t * data,const char * name,double val)1252 void obs_data_set_autoselect_double(obs_data_t *data, const char *name,
1253 double val)
1254 {
1255 obs_set_double(data, NULL, name, val, set_item_auto);
1256 }
1257
obs_data_set_autoselect_bool(obs_data_t * data,const char * name,bool val)1258 void obs_data_set_autoselect_bool(obs_data_t *data, const char *name, bool val)
1259 {
1260 obs_set_bool(data, NULL, name, val, set_item_auto);
1261 }
1262
obs_data_set_autoselect_obj(obs_data_t * data,const char * name,obs_data_t * obj)1263 void obs_data_set_autoselect_obj(obs_data_t *data, const char *name,
1264 obs_data_t *obj)
1265 {
1266 obs_set_obj(data, NULL, name, obj, set_item_auto);
1267 }
1268
obs_data_set_autoselect_array(obs_data_t * data,const char * name,obs_data_array_t * arr)1269 void obs_data_set_autoselect_array(obs_data_t *data, const char *name,
1270 obs_data_array_t *arr)
1271 {
1272 obs_set_array(data, NULL, name, arr, set_item_auto);
1273 }
1274
obs_data_get_string(obs_data_t * data,const char * name)1275 const char *obs_data_get_string(obs_data_t *data, const char *name)
1276 {
1277 return obs_data_item_get_string(get_item(data, name));
1278 }
1279
obs_data_get_int(obs_data_t * data,const char * name)1280 long long obs_data_get_int(obs_data_t *data, const char *name)
1281 {
1282 return obs_data_item_get_int(get_item(data, name));
1283 }
1284
obs_data_get_double(obs_data_t * data,const char * name)1285 double obs_data_get_double(obs_data_t *data, const char *name)
1286 {
1287 return obs_data_item_get_double(get_item(data, name));
1288 }
1289
obs_data_get_bool(obs_data_t * data,const char * name)1290 bool obs_data_get_bool(obs_data_t *data, const char *name)
1291 {
1292 return obs_data_item_get_bool(get_item(data, name));
1293 }
1294
obs_data_get_obj(obs_data_t * data,const char * name)1295 obs_data_t *obs_data_get_obj(obs_data_t *data, const char *name)
1296 {
1297 return obs_data_item_get_obj(get_item(data, name));
1298 }
1299
obs_data_get_array(obs_data_t * data,const char * name)1300 obs_data_array_t *obs_data_get_array(obs_data_t *data, const char *name)
1301 {
1302 return obs_data_item_get_array(get_item(data, name));
1303 }
1304
obs_data_get_default_string(obs_data_t * data,const char * name)1305 const char *obs_data_get_default_string(obs_data_t *data, const char *name)
1306 {
1307 return obs_data_item_get_default_string(get_item(data, name));
1308 }
1309
obs_data_get_default_int(obs_data_t * data,const char * name)1310 long long obs_data_get_default_int(obs_data_t *data, const char *name)
1311 {
1312 return obs_data_item_get_default_int(get_item(data, name));
1313 }
1314
obs_data_get_default_double(obs_data_t * data,const char * name)1315 double obs_data_get_default_double(obs_data_t *data, const char *name)
1316 {
1317 return obs_data_item_get_default_double(get_item(data, name));
1318 }
1319
obs_data_get_default_bool(obs_data_t * data,const char * name)1320 bool obs_data_get_default_bool(obs_data_t *data, const char *name)
1321 {
1322 return obs_data_item_get_default_bool(get_item(data, name));
1323 }
1324
obs_data_get_default_obj(obs_data_t * data,const char * name)1325 obs_data_t *obs_data_get_default_obj(obs_data_t *data, const char *name)
1326 {
1327 return obs_data_item_get_default_obj(get_item(data, name));
1328 }
1329
obs_data_get_default_array(obs_data_t * data,const char * name)1330 obs_data_array_t *obs_data_get_default_array(obs_data_t *data, const char *name)
1331 {
1332 return obs_data_item_get_default_array(get_item(data, name));
1333 }
1334
obs_data_get_autoselect_string(obs_data_t * data,const char * name)1335 const char *obs_data_get_autoselect_string(obs_data_t *data, const char *name)
1336 {
1337 return obs_data_item_get_autoselect_string(get_item(data, name));
1338 }
1339
obs_data_get_autoselect_int(obs_data_t * data,const char * name)1340 long long obs_data_get_autoselect_int(obs_data_t *data, const char *name)
1341 {
1342 return obs_data_item_get_autoselect_int(get_item(data, name));
1343 }
1344
obs_data_get_autoselect_double(obs_data_t * data,const char * name)1345 double obs_data_get_autoselect_double(obs_data_t *data, const char *name)
1346 {
1347 return obs_data_item_get_autoselect_double(get_item(data, name));
1348 }
1349
obs_data_get_autoselect_bool(obs_data_t * data,const char * name)1350 bool obs_data_get_autoselect_bool(obs_data_t *data, const char *name)
1351 {
1352 return obs_data_item_get_autoselect_bool(get_item(data, name));
1353 }
1354
obs_data_get_autoselect_obj(obs_data_t * data,const char * name)1355 obs_data_t *obs_data_get_autoselect_obj(obs_data_t *data, const char *name)
1356 {
1357 return obs_data_item_get_autoselect_obj(get_item(data, name));
1358 }
1359
obs_data_get_autoselect_array(obs_data_t * data,const char * name)1360 obs_data_array_t *obs_data_get_autoselect_array(obs_data_t *data,
1361 const char *name)
1362 {
1363 return obs_data_item_get_autoselect_array(get_item(data, name));
1364 }
1365
obs_data_array_create()1366 obs_data_array_t *obs_data_array_create()
1367 {
1368 struct obs_data_array *array = bzalloc(sizeof(struct obs_data_array));
1369 array->ref = 1;
1370
1371 return array;
1372 }
1373
obs_data_array_addref(obs_data_array_t * array)1374 void obs_data_array_addref(obs_data_array_t *array)
1375 {
1376 if (array)
1377 os_atomic_inc_long(&array->ref);
1378 }
1379
obs_data_array_destroy(obs_data_array_t * array)1380 static inline void obs_data_array_destroy(obs_data_array_t *array)
1381 {
1382 if (array) {
1383 for (size_t i = 0; i < array->objects.num; i++)
1384 obs_data_release(array->objects.array[i]);
1385 da_free(array->objects);
1386 bfree(array);
1387 }
1388 }
1389
obs_data_array_release(obs_data_array_t * array)1390 void obs_data_array_release(obs_data_array_t *array)
1391 {
1392 if (!array)
1393 return;
1394
1395 if (os_atomic_dec_long(&array->ref) == 0)
1396 obs_data_array_destroy(array);
1397 }
1398
obs_data_array_count(obs_data_array_t * array)1399 size_t obs_data_array_count(obs_data_array_t *array)
1400 {
1401 return array ? array->objects.num : 0;
1402 }
1403
obs_data_array_item(obs_data_array_t * array,size_t idx)1404 obs_data_t *obs_data_array_item(obs_data_array_t *array, size_t idx)
1405 {
1406 obs_data_t *data;
1407
1408 if (!array)
1409 return NULL;
1410
1411 data = (idx < array->objects.num) ? array->objects.array[idx] : NULL;
1412
1413 if (data)
1414 os_atomic_inc_long(&data->ref);
1415 return data;
1416 }
1417
obs_data_array_push_back(obs_data_array_t * array,obs_data_t * obj)1418 size_t obs_data_array_push_back(obs_data_array_t *array, obs_data_t *obj)
1419 {
1420 if (!array || !obj)
1421 return 0;
1422
1423 os_atomic_inc_long(&obj->ref);
1424 return da_push_back(array->objects, &obj);
1425 }
1426
obs_data_array_insert(obs_data_array_t * array,size_t idx,obs_data_t * obj)1427 void obs_data_array_insert(obs_data_array_t *array, size_t idx, obs_data_t *obj)
1428 {
1429 if (!array || !obj)
1430 return;
1431
1432 os_atomic_inc_long(&obj->ref);
1433 da_insert(array->objects, idx, &obj);
1434 }
1435
obs_data_array_push_back_array(obs_data_array_t * array,obs_data_array_t * array2)1436 void obs_data_array_push_back_array(obs_data_array_t *array,
1437 obs_data_array_t *array2)
1438 {
1439 if (!array || !array2)
1440 return;
1441
1442 for (size_t i = 0; i < array2->objects.num; i++) {
1443 obs_data_t *obj = array2->objects.array[i];
1444 obs_data_addref(obj);
1445 }
1446 da_push_back_da(array->objects, array2->objects);
1447 }
1448
obs_data_array_erase(obs_data_array_t * array,size_t idx)1449 void obs_data_array_erase(obs_data_array_t *array, size_t idx)
1450 {
1451 if (array) {
1452 obs_data_release(array->objects.array[idx]);
1453 da_erase(array->objects, idx);
1454 }
1455 }
1456
obs_data_array_enum(obs_data_array_t * array,void (* cb)(obs_data_t * data,void * param),void * param)1457 void obs_data_array_enum(obs_data_array_t *array,
1458 void (*cb)(obs_data_t *data, void *param), void *param)
1459 {
1460 if (array && cb) {
1461 for (size_t i = 0; i < array->objects.num; i++) {
1462 cb(array->objects.array[i], param);
1463 }
1464 }
1465 }
1466
1467 /* ------------------------------------------------------------------------- */
1468 /* Item status inspection */
1469
obs_data_has_user_value(obs_data_t * data,const char * name)1470 bool obs_data_has_user_value(obs_data_t *data, const char *name)
1471 {
1472 return data && obs_data_item_has_user_value(get_item(data, name));
1473 }
1474
obs_data_has_default_value(obs_data_t * data,const char * name)1475 bool obs_data_has_default_value(obs_data_t *data, const char *name)
1476 {
1477 return data && obs_data_item_has_default_value(get_item(data, name));
1478 }
1479
obs_data_has_autoselect_value(obs_data_t * data,const char * name)1480 bool obs_data_has_autoselect_value(obs_data_t *data, const char *name)
1481 {
1482 return data && obs_data_item_has_autoselect_value(get_item(data, name));
1483 }
1484
obs_data_item_has_user_value(obs_data_item_t * item)1485 bool obs_data_item_has_user_value(obs_data_item_t *item)
1486 {
1487 return item && item->data_size;
1488 }
1489
obs_data_item_has_default_value(obs_data_item_t * item)1490 bool obs_data_item_has_default_value(obs_data_item_t *item)
1491 {
1492 return item && item->default_size;
1493 }
1494
obs_data_item_has_autoselect_value(obs_data_item_t * item)1495 bool obs_data_item_has_autoselect_value(obs_data_item_t *item)
1496 {
1497 return item && item->autoselect_size;
1498 }
1499
1500 /* ------------------------------------------------------------------------- */
1501 /* Clearing data values */
1502
obs_data_unset_user_value(obs_data_t * data,const char * name)1503 void obs_data_unset_user_value(obs_data_t *data, const char *name)
1504 {
1505 obs_data_item_unset_user_value(get_item(data, name));
1506 }
1507
obs_data_unset_default_value(obs_data_t * data,const char * name)1508 void obs_data_unset_default_value(obs_data_t *data, const char *name)
1509 {
1510 obs_data_item_unset_default_value(get_item(data, name));
1511 }
1512
obs_data_unset_autoselect_value(obs_data_t * data,const char * name)1513 void obs_data_unset_autoselect_value(obs_data_t *data, const char *name)
1514 {
1515 obs_data_item_unset_autoselect_value(get_item(data, name));
1516 }
1517
obs_data_item_unset_user_value(obs_data_item_t * item)1518 void obs_data_item_unset_user_value(obs_data_item_t *item)
1519 {
1520 if (!item || !item->data_size)
1521 return;
1522
1523 void *old_non_user_data = get_default_data_ptr(item);
1524
1525 item_data_release(item);
1526 item->data_size = 0;
1527 item->data_len = 0;
1528
1529 if (item->default_size || item->autoselect_size)
1530 move_data(item, old_non_user_data, item,
1531 get_default_data_ptr(item),
1532 item->default_len + item->autoselect_size);
1533 }
1534
obs_data_item_unset_default_value(obs_data_item_t * item)1535 void obs_data_item_unset_default_value(obs_data_item_t *item)
1536 {
1537 if (!item || !item->default_size)
1538 return;
1539
1540 void *old_autoselect_data = get_autoselect_data_ptr(item);
1541
1542 item_default_data_release(item);
1543 item->default_size = 0;
1544 item->default_len = 0;
1545
1546 if (item->autoselect_size)
1547 move_data(item, old_autoselect_data, item,
1548 get_autoselect_data_ptr(item), item->autoselect_size);
1549 }
1550
obs_data_item_unset_autoselect_value(obs_data_item_t * item)1551 void obs_data_item_unset_autoselect_value(obs_data_item_t *item)
1552 {
1553 if (!item || !item->autoselect_size)
1554 return;
1555
1556 item_autoselect_data_release(item);
1557 item->autoselect_size = 0;
1558 }
1559
1560 /* ------------------------------------------------------------------------- */
1561 /* Item iteration */
1562
obs_data_first(obs_data_t * data)1563 obs_data_item_t *obs_data_first(obs_data_t *data)
1564 {
1565 if (!data)
1566 return NULL;
1567
1568 if (data->first_item)
1569 os_atomic_inc_long(&data->first_item->ref);
1570 return data->first_item;
1571 }
1572
obs_data_item_byname(obs_data_t * data,const char * name)1573 obs_data_item_t *obs_data_item_byname(obs_data_t *data, const char *name)
1574 {
1575 if (!data)
1576 return NULL;
1577
1578 struct obs_data_item *item = get_item(data, name);
1579 if (item)
1580 os_atomic_inc_long(&item->ref);
1581 return item;
1582 }
1583
obs_data_item_next(obs_data_item_t ** item)1584 bool obs_data_item_next(obs_data_item_t **item)
1585 {
1586 if (item && *item) {
1587 obs_data_item_t *next = (*item)->next;
1588 obs_data_item_release(item);
1589
1590 *item = next;
1591
1592 if (next) {
1593 os_atomic_inc_long(&next->ref);
1594 return true;
1595 }
1596 }
1597
1598 return false;
1599 }
1600
obs_data_item_release(obs_data_item_t ** item)1601 void obs_data_item_release(obs_data_item_t **item)
1602 {
1603 if (item && *item) {
1604 long ref = os_atomic_dec_long(&(*item)->ref);
1605 if (!ref) {
1606 obs_data_item_destroy(*item);
1607 *item = NULL;
1608 }
1609 }
1610 }
1611
obs_data_item_remove(obs_data_item_t ** item)1612 void obs_data_item_remove(obs_data_item_t **item)
1613 {
1614 if (item && *item) {
1615 obs_data_item_detach(*item);
1616 obs_data_item_release(item);
1617 }
1618 }
1619
obs_data_item_gettype(obs_data_item_t * item)1620 enum obs_data_type obs_data_item_gettype(obs_data_item_t *item)
1621 {
1622 return item ? item->type : OBS_DATA_NULL;
1623 }
1624
obs_data_item_numtype(obs_data_item_t * item)1625 enum obs_data_number_type obs_data_item_numtype(obs_data_item_t *item)
1626 {
1627 struct obs_data_number *num;
1628
1629 if (!item || item->type != OBS_DATA_NUMBER)
1630 return OBS_DATA_NUM_INVALID;
1631
1632 num = get_item_data(item);
1633 if (!num)
1634 return OBS_DATA_NUM_INVALID;
1635
1636 return num->type;
1637 }
1638
obs_data_item_get_name(obs_data_item_t * item)1639 const char *obs_data_item_get_name(obs_data_item_t *item)
1640 {
1641 if (!item)
1642 return NULL;
1643
1644 return get_item_name(item);
1645 }
1646
obs_data_item_set_string(obs_data_item_t ** item,const char * val)1647 void obs_data_item_set_string(obs_data_item_t **item, const char *val)
1648 {
1649 obs_set_string(NULL, item, NULL, val, set_item);
1650 }
1651
obs_data_item_set_int(obs_data_item_t ** item,long long val)1652 void obs_data_item_set_int(obs_data_item_t **item, long long val)
1653 {
1654 obs_set_int(NULL, item, NULL, val, set_item);
1655 }
1656
obs_data_item_set_double(obs_data_item_t ** item,double val)1657 void obs_data_item_set_double(obs_data_item_t **item, double val)
1658 {
1659 obs_set_double(NULL, item, NULL, val, set_item);
1660 }
1661
obs_data_item_set_bool(obs_data_item_t ** item,bool val)1662 void obs_data_item_set_bool(obs_data_item_t **item, bool val)
1663 {
1664 obs_set_bool(NULL, item, NULL, val, set_item);
1665 }
1666
obs_data_item_set_obj(obs_data_item_t ** item,obs_data_t * val)1667 void obs_data_item_set_obj(obs_data_item_t **item, obs_data_t *val)
1668 {
1669 obs_set_obj(NULL, item, NULL, val, set_item);
1670 }
1671
obs_data_item_set_array(obs_data_item_t ** item,obs_data_array_t * val)1672 void obs_data_item_set_array(obs_data_item_t **item, obs_data_array_t *val)
1673 {
1674 obs_set_array(NULL, item, NULL, val, set_item);
1675 }
1676
obs_data_item_set_default_string(obs_data_item_t ** item,const char * val)1677 void obs_data_item_set_default_string(obs_data_item_t **item, const char *val)
1678 {
1679 obs_set_string(NULL, item, NULL, val, set_item_def);
1680 }
1681
obs_data_item_set_default_int(obs_data_item_t ** item,long long val)1682 void obs_data_item_set_default_int(obs_data_item_t **item, long long val)
1683 {
1684 obs_set_int(NULL, item, NULL, val, set_item_def);
1685 }
1686
obs_data_item_set_default_double(obs_data_item_t ** item,double val)1687 void obs_data_item_set_default_double(obs_data_item_t **item, double val)
1688 {
1689 obs_set_double(NULL, item, NULL, val, set_item_def);
1690 }
1691
obs_data_item_set_default_bool(obs_data_item_t ** item,bool val)1692 void obs_data_item_set_default_bool(obs_data_item_t **item, bool val)
1693 {
1694 obs_set_bool(NULL, item, NULL, val, set_item_def);
1695 }
1696
obs_data_item_set_default_obj(obs_data_item_t ** item,obs_data_t * val)1697 void obs_data_item_set_default_obj(obs_data_item_t **item, obs_data_t *val)
1698 {
1699 obs_set_obj(NULL, item, NULL, val, set_item_def);
1700 }
1701
obs_data_item_set_default_array(obs_data_item_t ** item,obs_data_array_t * val)1702 void obs_data_item_set_default_array(obs_data_item_t **item,
1703 obs_data_array_t *val)
1704 {
1705 obs_set_array(NULL, item, NULL, val, set_item_def);
1706 }
1707
obs_data_item_set_autoselect_string(obs_data_item_t ** item,const char * val)1708 void obs_data_item_set_autoselect_string(obs_data_item_t **item,
1709 const char *val)
1710 {
1711 obs_set_string(NULL, item, NULL, val, set_item_auto);
1712 }
1713
obs_data_item_set_autoselect_int(obs_data_item_t ** item,long long val)1714 void obs_data_item_set_autoselect_int(obs_data_item_t **item, long long val)
1715 {
1716 obs_set_int(NULL, item, NULL, val, set_item_auto);
1717 }
1718
obs_data_item_set_autoselect_double(obs_data_item_t ** item,double val)1719 void obs_data_item_set_autoselect_double(obs_data_item_t **item, double val)
1720 {
1721 obs_set_double(NULL, item, NULL, val, set_item_auto);
1722 }
1723
obs_data_item_set_autoselect_bool(obs_data_item_t ** item,bool val)1724 void obs_data_item_set_autoselect_bool(obs_data_item_t **item, bool val)
1725 {
1726 obs_set_bool(NULL, item, NULL, val, set_item_auto);
1727 }
1728
obs_data_item_set_autoselect_obj(obs_data_item_t ** item,obs_data_t * val)1729 void obs_data_item_set_autoselect_obj(obs_data_item_t **item, obs_data_t *val)
1730 {
1731 obs_set_obj(NULL, item, NULL, val, set_item_auto);
1732 }
1733
obs_data_item_set_autoselect_array(obs_data_item_t ** item,obs_data_array_t * val)1734 void obs_data_item_set_autoselect_array(obs_data_item_t **item,
1735 obs_data_array_t *val)
1736 {
1737 obs_set_array(NULL, item, NULL, val, set_item_auto);
1738 }
1739
item_valid(struct obs_data_item * item,enum obs_data_type type)1740 static inline bool item_valid(struct obs_data_item *item,
1741 enum obs_data_type type)
1742 {
1743 return item && item->type == type;
1744 }
1745
1746 typedef void *(*get_data_t)(obs_data_item_t *);
1747
data_item_get_string(obs_data_item_t * item,get_data_t get_data)1748 static inline const char *data_item_get_string(obs_data_item_t *item,
1749 get_data_t get_data)
1750 {
1751 return item_valid(item, OBS_DATA_STRING) && get_data(item)
1752 ? get_data(item)
1753 : "";
1754 }
1755
item_int(struct obs_data_item * item,get_data_t get_data)1756 static inline long long item_int(struct obs_data_item *item,
1757 get_data_t get_data)
1758 {
1759 if (item && get_data(item)) {
1760 struct obs_data_number *num = get_data(item);
1761 return (num->type == OBS_DATA_NUM_INT)
1762 ? num->int_val
1763 : (long long)num->double_val;
1764 }
1765
1766 return 0;
1767 }
1768
data_item_get_int(obs_data_item_t * item,get_data_t get_data)1769 static inline long long data_item_get_int(obs_data_item_t *item,
1770 get_data_t get_data)
1771 {
1772 return item_int(item_valid(item, OBS_DATA_NUMBER) ? item : NULL,
1773 get_data);
1774 }
1775
item_double(struct obs_data_item * item,get_data_t get_data)1776 static inline double item_double(struct obs_data_item *item,
1777 get_data_t get_data)
1778 {
1779 if (item && get_data(item)) {
1780 struct obs_data_number *num = get_data(item);
1781 return (num->type == OBS_DATA_NUM_INT) ? (double)num->int_val
1782 : num->double_val;
1783 }
1784
1785 return 0.0;
1786 }
1787
data_item_get_double(obs_data_item_t * item,get_data_t get_data)1788 static inline double data_item_get_double(obs_data_item_t *item,
1789 get_data_t get_data)
1790 {
1791 return item_double(item_valid(item, OBS_DATA_NUMBER) ? item : NULL,
1792 get_data);
1793 }
1794
data_item_get_bool(obs_data_item_t * item,get_data_t get_data)1795 static inline bool data_item_get_bool(obs_data_item_t *item,
1796 get_data_t get_data)
1797 {
1798 return item_valid(item, OBS_DATA_BOOLEAN) && get_data(item)
1799 ? *(bool *)get_data(item)
1800 : false;
1801 }
1802
1803 typedef obs_data_t *(*get_obj_t)(obs_data_item_t *);
1804
data_item_get_obj(obs_data_item_t * item,get_obj_t get_obj)1805 static inline obs_data_t *data_item_get_obj(obs_data_item_t *item,
1806 get_obj_t get_obj)
1807 {
1808 obs_data_t *obj = item_valid(item, OBS_DATA_OBJECT) ? get_obj(item)
1809 : NULL;
1810
1811 if (obj)
1812 os_atomic_inc_long(&obj->ref);
1813 return obj;
1814 }
1815
1816 typedef obs_data_array_t *(*get_array_t)(obs_data_item_t *);
1817
data_item_get_array(obs_data_item_t * item,get_array_t get_array)1818 static inline obs_data_array_t *data_item_get_array(obs_data_item_t *item,
1819 get_array_t get_array)
1820 {
1821 obs_data_array_t *array =
1822 item_valid(item, OBS_DATA_ARRAY) ? get_array(item) : NULL;
1823
1824 if (array)
1825 os_atomic_inc_long(&array->ref);
1826 return array;
1827 }
1828
obs_data_item_get_string(obs_data_item_t * item)1829 const char *obs_data_item_get_string(obs_data_item_t *item)
1830 {
1831 return data_item_get_string(item, get_item_data);
1832 }
1833
obs_data_item_get_int(obs_data_item_t * item)1834 long long obs_data_item_get_int(obs_data_item_t *item)
1835 {
1836 return data_item_get_int(item, get_item_data);
1837 }
1838
obs_data_item_get_double(obs_data_item_t * item)1839 double obs_data_item_get_double(obs_data_item_t *item)
1840 {
1841 return data_item_get_double(item, get_item_data);
1842 }
1843
obs_data_item_get_bool(obs_data_item_t * item)1844 bool obs_data_item_get_bool(obs_data_item_t *item)
1845 {
1846 return data_item_get_bool(item, get_item_data);
1847 }
1848
obs_data_item_get_obj(obs_data_item_t * item)1849 obs_data_t *obs_data_item_get_obj(obs_data_item_t *item)
1850 {
1851 return data_item_get_obj(item, get_item_obj);
1852 }
1853
obs_data_item_get_array(obs_data_item_t * item)1854 obs_data_array_t *obs_data_item_get_array(obs_data_item_t *item)
1855 {
1856 return data_item_get_array(item, get_item_array);
1857 }
1858
obs_data_item_get_default_string(obs_data_item_t * item)1859 const char *obs_data_item_get_default_string(obs_data_item_t *item)
1860 {
1861 return data_item_get_string(item, get_item_default_data);
1862 }
1863
obs_data_item_get_default_int(obs_data_item_t * item)1864 long long obs_data_item_get_default_int(obs_data_item_t *item)
1865 {
1866 return data_item_get_int(item, get_item_default_data);
1867 }
1868
obs_data_item_get_default_double(obs_data_item_t * item)1869 double obs_data_item_get_default_double(obs_data_item_t *item)
1870 {
1871 return data_item_get_double(item, get_item_default_data);
1872 }
1873
obs_data_item_get_default_bool(obs_data_item_t * item)1874 bool obs_data_item_get_default_bool(obs_data_item_t *item)
1875 {
1876 return data_item_get_bool(item, get_item_default_data);
1877 }
1878
obs_data_item_get_default_obj(obs_data_item_t * item)1879 obs_data_t *obs_data_item_get_default_obj(obs_data_item_t *item)
1880 {
1881 return data_item_get_obj(item, get_item_default_obj);
1882 }
1883
obs_data_item_get_default_array(obs_data_item_t * item)1884 obs_data_array_t *obs_data_item_get_default_array(obs_data_item_t *item)
1885 {
1886 return data_item_get_array(item, get_item_default_array);
1887 }
1888
obs_data_item_get_autoselect_string(obs_data_item_t * item)1889 const char *obs_data_item_get_autoselect_string(obs_data_item_t *item)
1890 {
1891 return data_item_get_string(item, get_item_autoselect_data);
1892 }
1893
obs_data_item_get_autoselect_int(obs_data_item_t * item)1894 long long obs_data_item_get_autoselect_int(obs_data_item_t *item)
1895 {
1896 return data_item_get_int(item, get_item_autoselect_data);
1897 }
1898
obs_data_item_get_autoselect_double(obs_data_item_t * item)1899 double obs_data_item_get_autoselect_double(obs_data_item_t *item)
1900 {
1901 return data_item_get_double(item, get_item_autoselect_data);
1902 }
1903
obs_data_item_get_autoselect_bool(obs_data_item_t * item)1904 bool obs_data_item_get_autoselect_bool(obs_data_item_t *item)
1905 {
1906 return data_item_get_bool(item, get_item_autoselect_data);
1907 }
1908
obs_data_item_get_autoselect_obj(obs_data_item_t * item)1909 obs_data_t *obs_data_item_get_autoselect_obj(obs_data_item_t *item)
1910 {
1911 return data_item_get_obj(item, get_item_autoselect_obj);
1912 }
1913
obs_data_item_get_autoselect_array(obs_data_item_t * item)1914 obs_data_array_t *obs_data_item_get_autoselect_array(obs_data_item_t *item)
1915 {
1916 return data_item_get_array(item, get_item_autoselect_array);
1917 }
1918
1919 /* ------------------------------------------------------------------------- */
1920 /* Helper functions for certain structures */
1921
1922 typedef void (*set_obj_t)(obs_data_t *, const char *, obs_data_t *);
1923
set_vec2(obs_data_t * data,const char * name,const struct vec2 * val,set_obj_t set_obj)1924 static inline void set_vec2(obs_data_t *data, const char *name,
1925 const struct vec2 *val, set_obj_t set_obj)
1926 {
1927 obs_data_t *obj = obs_data_create();
1928 obs_data_set_double(obj, "x", val->x);
1929 obs_data_set_double(obj, "y", val->y);
1930 set_obj(data, name, obj);
1931 obs_data_release(obj);
1932 }
1933
set_vec3(obs_data_t * data,const char * name,const struct vec3 * val,set_obj_t set_obj)1934 static inline void set_vec3(obs_data_t *data, const char *name,
1935 const struct vec3 *val, set_obj_t set_obj)
1936 {
1937 obs_data_t *obj = obs_data_create();
1938 obs_data_set_double(obj, "x", val->x);
1939 obs_data_set_double(obj, "y", val->y);
1940 obs_data_set_double(obj, "z", val->z);
1941 set_obj(data, name, obj);
1942 obs_data_release(obj);
1943 }
1944
set_vec4(obs_data_t * data,const char * name,const struct vec4 * val,set_obj_t set_obj)1945 static inline void set_vec4(obs_data_t *data, const char *name,
1946 const struct vec4 *val, set_obj_t set_obj)
1947 {
1948 obs_data_t *obj = obs_data_create();
1949 obs_data_set_double(obj, "x", val->x);
1950 obs_data_set_double(obj, "y", val->y);
1951 obs_data_set_double(obj, "z", val->z);
1952 obs_data_set_double(obj, "w", val->w);
1953 set_obj(data, name, obj);
1954 obs_data_release(obj);
1955 }
1956
set_quat(obs_data_t * data,const char * name,const struct quat * val,set_obj_t set_obj)1957 static inline void set_quat(obs_data_t *data, const char *name,
1958 const struct quat *val, set_obj_t set_obj)
1959 {
1960 obs_data_t *obj = obs_data_create();
1961 obs_data_set_double(obj, "x", val->x);
1962 obs_data_set_double(obj, "y", val->y);
1963 obs_data_set_double(obj, "z", val->z);
1964 obs_data_set_double(obj, "w", val->w);
1965 set_obj(data, name, obj);
1966 obs_data_release(obj);
1967 }
1968
obs_data_set_vec2(obs_data_t * data,const char * name,const struct vec2 * val)1969 void obs_data_set_vec2(obs_data_t *data, const char *name,
1970 const struct vec2 *val)
1971 {
1972 set_vec2(data, name, val, obs_data_set_obj);
1973 }
1974
obs_data_set_vec3(obs_data_t * data,const char * name,const struct vec3 * val)1975 void obs_data_set_vec3(obs_data_t *data, const char *name,
1976 const struct vec3 *val)
1977 {
1978 set_vec3(data, name, val, obs_data_set_obj);
1979 }
1980
obs_data_set_vec4(obs_data_t * data,const char * name,const struct vec4 * val)1981 void obs_data_set_vec4(obs_data_t *data, const char *name,
1982 const struct vec4 *val)
1983 {
1984 set_vec4(data, name, val, obs_data_set_obj);
1985 }
1986
obs_data_set_quat(obs_data_t * data,const char * name,const struct quat * val)1987 void obs_data_set_quat(obs_data_t *data, const char *name,
1988 const struct quat *val)
1989 {
1990 set_quat(data, name, val, obs_data_set_obj);
1991 }
1992
obs_data_set_default_vec2(obs_data_t * data,const char * name,const struct vec2 * val)1993 void obs_data_set_default_vec2(obs_data_t *data, const char *name,
1994 const struct vec2 *val)
1995 {
1996 set_vec2(data, name, val, obs_data_set_default_obj);
1997 }
1998
obs_data_set_default_vec3(obs_data_t * data,const char * name,const struct vec3 * val)1999 void obs_data_set_default_vec3(obs_data_t *data, const char *name,
2000 const struct vec3 *val)
2001 {
2002 set_vec3(data, name, val, obs_data_set_default_obj);
2003 }
2004
obs_data_set_default_vec4(obs_data_t * data,const char * name,const struct vec4 * val)2005 void obs_data_set_default_vec4(obs_data_t *data, const char *name,
2006 const struct vec4 *val)
2007 {
2008 set_vec4(data, name, val, obs_data_set_default_obj);
2009 }
2010
obs_data_set_default_quat(obs_data_t * data,const char * name,const struct quat * val)2011 void obs_data_set_default_quat(obs_data_t *data, const char *name,
2012 const struct quat *val)
2013 {
2014 set_quat(data, name, val, obs_data_set_default_obj);
2015 }
2016
obs_data_set_autoselect_vec2(obs_data_t * data,const char * name,const struct vec2 * val)2017 void obs_data_set_autoselect_vec2(obs_data_t *data, const char *name,
2018 const struct vec2 *val)
2019 {
2020 set_vec2(data, name, val, obs_data_set_autoselect_obj);
2021 }
2022
obs_data_set_autoselect_vec3(obs_data_t * data,const char * name,const struct vec3 * val)2023 void obs_data_set_autoselect_vec3(obs_data_t *data, const char *name,
2024 const struct vec3 *val)
2025 {
2026 set_vec3(data, name, val, obs_data_set_autoselect_obj);
2027 }
2028
obs_data_set_autoselect_vec4(obs_data_t * data,const char * name,const struct vec4 * val)2029 void obs_data_set_autoselect_vec4(obs_data_t *data, const char *name,
2030 const struct vec4 *val)
2031 {
2032 set_vec4(data, name, val, obs_data_set_autoselect_obj);
2033 }
2034
obs_data_set_autoselect_quat(obs_data_t * data,const char * name,const struct quat * val)2035 void obs_data_set_autoselect_quat(obs_data_t *data, const char *name,
2036 const struct quat *val)
2037 {
2038 set_quat(data, name, val, obs_data_set_autoselect_obj);
2039 }
2040
get_vec2(obs_data_t * obj,struct vec2 * val)2041 static inline void get_vec2(obs_data_t *obj, struct vec2 *val)
2042 {
2043 if (!obj)
2044 return;
2045
2046 val->x = (float)obs_data_get_double(obj, "x");
2047 val->y = (float)obs_data_get_double(obj, "y");
2048 obs_data_release(obj);
2049 }
2050
get_vec3(obs_data_t * obj,struct vec3 * val)2051 static inline void get_vec3(obs_data_t *obj, struct vec3 *val)
2052 {
2053 if (!obj)
2054 return;
2055
2056 val->x = (float)obs_data_get_double(obj, "x");
2057 val->y = (float)obs_data_get_double(obj, "y");
2058 val->z = (float)obs_data_get_double(obj, "z");
2059 obs_data_release(obj);
2060 }
2061
get_vec4(obs_data_t * obj,struct vec4 * val)2062 static inline void get_vec4(obs_data_t *obj, struct vec4 *val)
2063 {
2064 if (!obj)
2065 return;
2066
2067 val->x = (float)obs_data_get_double(obj, "x");
2068 val->y = (float)obs_data_get_double(obj, "y");
2069 val->z = (float)obs_data_get_double(obj, "z");
2070 val->w = (float)obs_data_get_double(obj, "w");
2071 obs_data_release(obj);
2072 }
2073
get_quat(obs_data_t * obj,struct quat * val)2074 static inline void get_quat(obs_data_t *obj, struct quat *val)
2075 {
2076 if (!obj)
2077 return;
2078
2079 val->x = (float)obs_data_get_double(obj, "x");
2080 val->y = (float)obs_data_get_double(obj, "y");
2081 val->z = (float)obs_data_get_double(obj, "z");
2082 val->w = (float)obs_data_get_double(obj, "w");
2083 obs_data_release(obj);
2084 }
2085
obs_data_get_vec2(obs_data_t * data,const char * name,struct vec2 * val)2086 void obs_data_get_vec2(obs_data_t *data, const char *name, struct vec2 *val)
2087 {
2088 get_vec2(obs_data_get_obj(data, name), val);
2089 }
2090
obs_data_get_vec3(obs_data_t * data,const char * name,struct vec3 * val)2091 void obs_data_get_vec3(obs_data_t *data, const char *name, struct vec3 *val)
2092 {
2093 get_vec3(obs_data_get_obj(data, name), val);
2094 }
2095
obs_data_get_vec4(obs_data_t * data,const char * name,struct vec4 * val)2096 void obs_data_get_vec4(obs_data_t *data, const char *name, struct vec4 *val)
2097 {
2098 get_vec4(obs_data_get_obj(data, name), val);
2099 }
2100
obs_data_get_quat(obs_data_t * data,const char * name,struct quat * val)2101 void obs_data_get_quat(obs_data_t *data, const char *name, struct quat *val)
2102 {
2103 get_quat(obs_data_get_obj(data, name), val);
2104 }
2105
obs_data_get_default_vec2(obs_data_t * data,const char * name,struct vec2 * val)2106 void obs_data_get_default_vec2(obs_data_t *data, const char *name,
2107 struct vec2 *val)
2108 {
2109 get_vec2(obs_data_get_default_obj(data, name), val);
2110 }
2111
obs_data_get_default_vec3(obs_data_t * data,const char * name,struct vec3 * val)2112 void obs_data_get_default_vec3(obs_data_t *data, const char *name,
2113 struct vec3 *val)
2114 {
2115 get_vec3(obs_data_get_default_obj(data, name), val);
2116 }
2117
obs_data_get_default_vec4(obs_data_t * data,const char * name,struct vec4 * val)2118 void obs_data_get_default_vec4(obs_data_t *data, const char *name,
2119 struct vec4 *val)
2120 {
2121 get_vec4(obs_data_get_default_obj(data, name), val);
2122 }
2123
obs_data_get_default_quat(obs_data_t * data,const char * name,struct quat * val)2124 void obs_data_get_default_quat(obs_data_t *data, const char *name,
2125 struct quat *val)
2126 {
2127 get_quat(obs_data_get_default_obj(data, name), val);
2128 }
2129
obs_data_get_autoselect_vec2(obs_data_t * data,const char * name,struct vec2 * val)2130 void obs_data_get_autoselect_vec2(obs_data_t *data, const char *name,
2131 struct vec2 *val)
2132 {
2133 get_vec2(obs_data_get_autoselect_obj(data, name), val);
2134 }
2135
obs_data_get_autoselect_vec3(obs_data_t * data,const char * name,struct vec3 * val)2136 void obs_data_get_autoselect_vec3(obs_data_t *data, const char *name,
2137 struct vec3 *val)
2138 {
2139 get_vec3(obs_data_get_autoselect_obj(data, name), val);
2140 }
2141
obs_data_get_autoselect_vec4(obs_data_t * data,const char * name,struct vec4 * val)2142 void obs_data_get_autoselect_vec4(obs_data_t *data, const char *name,
2143 struct vec4 *val)
2144 {
2145 get_vec4(obs_data_get_autoselect_obj(data, name), val);
2146 }
2147
obs_data_get_autoselect_quat(obs_data_t * data,const char * name,struct quat * val)2148 void obs_data_get_autoselect_quat(obs_data_t *data, const char *name,
2149 struct quat *val)
2150 {
2151 get_quat(obs_data_get_autoselect_obj(data, name), val);
2152 }
2153
2154 /* ------------------------------------------------------------------------- */
2155 /* Helper functions for media_frames_per_seconds */
2156
2157 static inline obs_data_t *
make_frames_per_second(struct media_frames_per_second fps,const char * option)2158 make_frames_per_second(struct media_frames_per_second fps, const char *option)
2159 {
2160 obs_data_t *obj = obs_data_create();
2161
2162 if (!option) {
2163 obs_data_set_double(obj, "numerator", fps.numerator);
2164 obs_data_set_double(obj, "denominator", fps.denominator);
2165
2166 } else {
2167 obs_data_set_string(obj, "option", option);
2168 }
2169
2170 return obj;
2171 }
2172
obs_data_set_frames_per_second(obs_data_t * data,const char * name,struct media_frames_per_second fps,const char * option)2173 void obs_data_set_frames_per_second(obs_data_t *data, const char *name,
2174 struct media_frames_per_second fps,
2175 const char *option)
2176 {
2177 obs_take_obj(data, NULL, name, make_frames_per_second(fps, option),
2178 set_item);
2179 }
2180
obs_data_set_default_frames_per_second(obs_data_t * data,const char * name,struct media_frames_per_second fps,const char * option)2181 void obs_data_set_default_frames_per_second(obs_data_t *data, const char *name,
2182 struct media_frames_per_second fps,
2183 const char *option)
2184 {
2185 obs_take_obj(data, NULL, name, make_frames_per_second(fps, option),
2186 set_item_def);
2187 }
2188
obs_data_set_autoselect_frames_per_second(obs_data_t * data,const char * name,struct media_frames_per_second fps,const char * option)2189 void obs_data_set_autoselect_frames_per_second(
2190 obs_data_t *data, const char *name, struct media_frames_per_second fps,
2191 const char *option)
2192 {
2193 obs_take_obj(data, NULL, name, make_frames_per_second(fps, option),
2194 set_item_auto);
2195 }
2196
get_option(obs_data_t * data,const char ** option)2197 static inline bool get_option(obs_data_t *data, const char **option)
2198 {
2199 if (!option)
2200 return false;
2201
2202 struct obs_data_item *opt = obs_data_item_byname(data, "option");
2203 if (!opt)
2204 return false;
2205
2206 *option = obs_data_item_get_string(opt);
2207 obs_data_item_release(&opt);
2208
2209 obs_data_release(data);
2210
2211 return true;
2212 }
2213
2214 #define CLAMP(x, min, max) ((x) < min ? min : ((x) > max ? max : (x)))
2215
get_frames_per_second(obs_data_t * data,struct media_frames_per_second * fps,const char ** option)2216 static inline bool get_frames_per_second(obs_data_t *data,
2217 struct media_frames_per_second *fps,
2218 const char **option)
2219 {
2220 if (!data)
2221 return false;
2222
2223 if (get_option(data, option))
2224 return true;
2225
2226 if (!fps)
2227 goto free;
2228
2229 struct obs_data_item *num = obs_data_item_byname(data, "numerator");
2230 struct obs_data_item *den = obs_data_item_byname(data, "denominator");
2231 if (!num || !den) {
2232 obs_data_item_release(&num);
2233 obs_data_item_release(&den);
2234 goto free;
2235 }
2236
2237 long long num_ll = obs_data_item_get_int(num);
2238 long long den_ll = obs_data_item_get_int(den);
2239
2240 fps->numerator = (uint32_t)CLAMP(num_ll, 0, (long long)UINT32_MAX);
2241 fps->denominator = (uint32_t)CLAMP(den_ll, 0, (long long)UINT32_MAX);
2242
2243 obs_data_item_release(&num);
2244 obs_data_item_release(&den);
2245
2246 obs_data_release(data);
2247
2248 return media_frames_per_second_is_valid(*fps);
2249
2250 free:
2251 obs_data_release(data);
2252 return false;
2253 }
2254
obs_data_get_frames_per_second(obs_data_t * data,const char * name,struct media_frames_per_second * fps,const char ** option)2255 bool obs_data_get_frames_per_second(obs_data_t *data, const char *name,
2256 struct media_frames_per_second *fps,
2257 const char **option)
2258 {
2259 return get_frames_per_second(obs_data_get_obj(data, name), fps, option);
2260 }
2261
obs_data_get_default_frames_per_second(obs_data_t * data,const char * name,struct media_frames_per_second * fps,const char ** option)2262 bool obs_data_get_default_frames_per_second(obs_data_t *data, const char *name,
2263 struct media_frames_per_second *fps,
2264 const char **option)
2265 {
2266 return get_frames_per_second(obs_data_get_default_obj(data, name), fps,
2267 option);
2268 }
2269
obs_data_get_autoselect_frames_per_second(obs_data_t * data,const char * name,struct media_frames_per_second * fps,const char ** option)2270 bool obs_data_get_autoselect_frames_per_second(
2271 obs_data_t *data, const char *name, struct media_frames_per_second *fps,
2272 const char **option)
2273 {
2274 return get_frames_per_second(obs_data_get_autoselect_obj(data, name),
2275 fps, option);
2276 }
2277
obs_data_item_set_frames_per_second(obs_data_item_t ** item,struct media_frames_per_second fps,const char * option)2278 void obs_data_item_set_frames_per_second(obs_data_item_t **item,
2279 struct media_frames_per_second fps,
2280 const char *option)
2281 {
2282 obs_take_obj(NULL, item, NULL, make_frames_per_second(fps, option),
2283 set_item);
2284 }
2285
obs_data_item_set_default_frames_per_second(obs_data_item_t ** item,struct media_frames_per_second fps,const char * option)2286 void obs_data_item_set_default_frames_per_second(
2287 obs_data_item_t **item, struct media_frames_per_second fps,
2288 const char *option)
2289 {
2290 obs_take_obj(NULL, item, NULL, make_frames_per_second(fps, option),
2291 set_item_def);
2292 }
2293
obs_data_item_set_autoselect_frames_per_second(obs_data_item_t ** item,struct media_frames_per_second fps,const char * option)2294 void obs_data_item_set_autoselect_frames_per_second(
2295 obs_data_item_t **item, struct media_frames_per_second fps,
2296 const char *option)
2297 {
2298 obs_take_obj(NULL, item, NULL, make_frames_per_second(fps, option),
2299 set_item_auto);
2300 }
2301
obs_data_item_get_frames_per_second(obs_data_item_t * item,struct media_frames_per_second * fps,const char ** option)2302 bool obs_data_item_get_frames_per_second(obs_data_item_t *item,
2303 struct media_frames_per_second *fps,
2304 const char **option)
2305 {
2306 return get_frames_per_second(obs_data_item_get_obj(item), fps, option);
2307 }
2308
obs_data_item_get_default_frames_per_second(obs_data_item_t * item,struct media_frames_per_second * fps,const char ** option)2309 bool obs_data_item_get_default_frames_per_second(
2310 obs_data_item_t *item, struct media_frames_per_second *fps,
2311 const char **option)
2312 {
2313 return get_frames_per_second(obs_data_item_get_default_obj(item), fps,
2314 option);
2315 }
2316
obs_data_item_get_autoselect_frames_per_second(obs_data_item_t * item,struct media_frames_per_second * fps,const char ** option)2317 bool obs_data_item_get_autoselect_frames_per_second(
2318 obs_data_item_t *item, struct media_frames_per_second *fps,
2319 const char **option)
2320 {
2321 return get_frames_per_second(obs_data_item_get_autoselect_obj(item),
2322 fps, option);
2323 }
2324