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