1 /*
2 * Functions for manipulating HTS messages
3 * Copyright (C) 2007 Andreas Öman
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <assert.h>
20 #include <sys/types.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include "build.h"
27 #include "htsmsg.h"
28 #include "misc/dbl.h"
29 #include "htsmsg_json.h"
30 #include "memoryinfo.h"
31
32 #if ENABLE_SLOW_MEMORYINFO
33 memoryinfo_t htsmsg_memoryinfo = { .my_name = "htsmsg" };
34 memoryinfo_t htsmsg_field_memoryinfo = { .my_name = "htsmsg field" };
35 #endif
36
37 static void htsmsg_clear(htsmsg_t *msg);
38 static htsmsg_t *htsmsg_field_get_msg ( htsmsg_field_t *f, int islist );
39
40 /**
41 *
42 */
43 static void
htsmsg_field_data_destroy(htsmsg_field_t * f)44 htsmsg_field_data_destroy(htsmsg_field_t *f)
45 {
46 switch(f->hmf_type) {
47 case HMF_MAP:
48 case HMF_LIST:
49 htsmsg_clear(&f->hmf_msg);
50 break;
51
52 case HMF_STR:
53 if(f->hmf_flags & HMF_ALLOCED) {
54 #if ENABLE_SLOW_MEMORYINFO
55 memoryinfo_remove(&htsmsg_field_memoryinfo, strlen(f->hmf_str) + 1);
56 #endif
57 free((void *)f->hmf_str);
58 }
59 break;
60
61 case HMF_BIN:
62 if(f->hmf_flags & HMF_ALLOCED) {
63 #if ENABLE_SLOW_MEMORYINFO
64 memoryinfo_remove(&htsmsg_field_memoryinfo, f->hmf_binsize);
65 #endif
66 free((void *)f->hmf_bin);
67 }
68 break;
69 default:
70 break;
71 }
72 f->hmf_flags &= ~HMF_ALLOCED;
73 }
74
75 /**
76 *
77 */
78 void
htsmsg_field_destroy(htsmsg_t * msg,htsmsg_field_t * f)79 htsmsg_field_destroy(htsmsg_t *msg, htsmsg_field_t *f)
80 {
81 #if ENABLE_SLOW_MEMORYINFO
82 size_t asize = 0;
83 #endif
84
85 TAILQ_REMOVE(&msg->hm_fields, f, hmf_link);
86
87 htsmsg_field_data_destroy(f);
88
89 if (f->hmf_flags & HMF_NAME_ALLOCED) {
90 #if ENABLE_SLOW_MEMORYINFO
91 asize += strlen(f->hmf_name);
92 #endif
93 free((void *)f->hmf_name);
94 }
95 #if ENABLE_SLOW_MEMORYINFO
96 memoryinfo_free(&htsmsg_field_memoryinfo,
97 sizeof(*f) + f->hmf_edata_size + asize);
98 #endif
99 free(f);
100 }
101
102 /*
103 *
104 */
105 static void
htsmsg_clear(htsmsg_t * msg)106 htsmsg_clear(htsmsg_t *msg)
107 {
108 htsmsg_field_t *f;
109
110 while((f = TAILQ_FIRST(&msg->hm_fields)) != NULL)
111 htsmsg_field_destroy(msg, f);
112 }
113
114
115 /*
116 *
117 */
118 htsmsg_field_t *
htsmsg_field_add(htsmsg_t * msg,const char * name,int type,int flags,size_t esize)119 htsmsg_field_add(htsmsg_t *msg, const char *name, int type, int flags, size_t esize)
120 {
121 size_t nsize = 0;
122 htsmsg_field_t *f;
123 #if ENABLE_SLOW_MEMORYINFO
124 size_t asize = 0;
125 #endif
126
127 if((flags & HMF_NAME_INALLOCED) && name)
128 nsize = strlen(name) + 1;
129 f = malloc(sizeof(htsmsg_field_t) + nsize + esize);
130 if(f == NULL)
131 return NULL;
132 TAILQ_INSERT_TAIL(&msg->hm_fields, f, hmf_link);
133
134 if(msg->hm_islist) {
135 assert(name == NULL);
136 } else {
137 assert(name != NULL);
138 }
139
140 if(flags & HMF_NAME_INALLOCED) {
141 if (name) {
142 f->hmf_name = f->hmf_edata;
143 strcpy(f->hmf_edata, name);
144 } else {
145 f->hmf_name = NULL;
146 }
147 } else if(flags & HMF_NAME_ALLOCED) {
148 f->hmf_name = name ? strdup(name) : NULL;
149 #if ENABLE_SLOW_MEMORYINFO
150 asize = name ? strlen(name) + 1 : 0;
151 #endif
152 } else {
153 f->hmf_name = name;
154 }
155
156 if(esize) {
157 if(type == HMF_STR)
158 f->hmf_str = f->hmf_edata + nsize;
159 else if(type == HMF_BIN)
160 f->hmf_bin = f->hmf_edata + nsize;
161 }
162
163 f->hmf_type = type;
164 f->hmf_flags = flags;
165 #if ENABLE_SLOW_MEMORYINFO
166 f->hmf_edata_size = nsize + esize;
167 memoryinfo_alloc(&htsmsg_field_memoryinfo,
168 sizeof(htsmsg_field_t) + f->hmf_edata_size + asize);
169 #endif
170 return f;
171 }
172
173
174 /*
175 *
176 */
177 htsmsg_field_t *
htsmsg_field_find(htsmsg_t * msg,const char * name)178 htsmsg_field_find(htsmsg_t *msg, const char *name)
179 {
180 htsmsg_field_t *f;
181
182 if (msg == NULL || name == NULL)
183 return NULL;
184 TAILQ_FOREACH(f, &msg->hm_fields, hmf_link) {
185 if(f->hmf_name != NULL && !strcmp(f->hmf_name, name))
186 return f;
187 }
188 return NULL;
189 }
190
191
192 /*
193 *
194 */
195 htsmsg_field_t *
htsmsg_field_last(htsmsg_t * msg)196 htsmsg_field_last(htsmsg_t *msg)
197 {
198 if (msg == NULL)
199 return NULL;
200 return TAILQ_LAST(&msg->hm_fields, htsmsg_field_queue);
201 }
202
203
204 /**
205 *
206 */
207 int
htsmsg_delete_field(htsmsg_t * msg,const char * name)208 htsmsg_delete_field(htsmsg_t *msg, const char *name)
209 {
210 htsmsg_field_t *f;
211
212 if((f = htsmsg_field_find(msg, name)) == NULL)
213 return HTSMSG_ERR_FIELD_NOT_FOUND;
214 htsmsg_field_destroy(msg, f);
215 return 0;
216 }
217
218
219 /**
220 *
221 */
222 int
htsmsg_is_empty(htsmsg_t * msg)223 htsmsg_is_empty(htsmsg_t *msg)
224 {
225 if (msg == NULL)
226 return 1;
227
228 assert(msg->hm_data == NULL);
229 return TAILQ_EMPTY(&msg->hm_fields);
230 }
231
232
233 /*
234 *
235 */
236 htsmsg_t *
htsmsg_create_map(void)237 htsmsg_create_map(void)
238 {
239 htsmsg_t *msg;
240
241 msg = malloc(sizeof(htsmsg_t));
242 if (msg) {
243 TAILQ_INIT(&msg->hm_fields);
244 msg->hm_data = NULL;
245 msg->hm_data_size = 0;
246 msg->hm_islist = 0;
247 #if ENABLE_SLOW_MEMORYINFO
248 memoryinfo_alloc(&htsmsg_memoryinfo, sizeof(htsmsg_t));
249 #endif
250 }
251 return msg;
252 }
253
254 /*
255 *
256 */
257 htsmsg_t *
htsmsg_create_list(void)258 htsmsg_create_list(void)
259 {
260 htsmsg_t *msg;
261
262 msg = malloc(sizeof(htsmsg_t));
263 if (msg) {
264 TAILQ_INIT(&msg->hm_fields);
265 msg->hm_data = NULL;
266 msg->hm_data_size = 0;
267 msg->hm_islist = 1;
268 #if ENABLE_SLOW_MEMORYINFO
269 memoryinfo_alloc(&htsmsg_memoryinfo, sizeof(htsmsg_t));
270 #endif
271 }
272 return msg;
273 }
274
275
276 /*
277 *
278 */
279 void
htsmsg_destroy(htsmsg_t * msg)280 htsmsg_destroy(htsmsg_t *msg)
281 {
282 #if ENABLE_SLOW_MEMORYINFO
283 size_t size = 0;
284 #endif
285
286 if(msg == NULL)
287 return;
288
289 htsmsg_clear(msg);
290 if (msg->hm_data) {
291 free((void *)msg->hm_data);
292 #if ENABLE_SLOW_MEMORYINFO
293 size += msg->hm_data_size;
294 #endif
295 }
296 #if ENABLE_SLOW_MEMORYINFO
297 memoryinfo_free(&htsmsg_memoryinfo, sizeof(htsmsg_t) + size);
298 #endif
299 free(msg);
300 }
301
302 /*
303 *
304 */
305 void
htsmsg_add_bool(htsmsg_t * msg,const char * name,int b)306 htsmsg_add_bool(htsmsg_t *msg, const char *name, int b)
307 {
308 htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_BOOL, HMF_NAME_INALLOCED, 0);
309 f->hmf_bool = !!b;
310 }
311
312 /*
313 *
314 */
315 void
htsmsg_set_bool(htsmsg_t * msg,const char * name,int b)316 htsmsg_set_bool(htsmsg_t *msg, const char *name, int b)
317 {
318 htsmsg_field_t *f = htsmsg_field_find(msg, name);
319 if (!f)
320 f = htsmsg_field_add(msg, name, HMF_BOOL, HMF_NAME_INALLOCED, 0);
321 f->hmf_bool = !!b;
322 }
323
324 /*
325 *
326 */
327 void
htsmsg_add_s64(htsmsg_t * msg,const char * name,int64_t s64)328 htsmsg_add_s64(htsmsg_t *msg, const char *name, int64_t s64)
329 {
330 htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_S64, HMF_NAME_INALLOCED, 0);
331 f->hmf_s64 = s64;
332 }
333
334 /*
335 *
336 */
337 int
htsmsg_set_s64(htsmsg_t * msg,const char * name,int64_t s64)338 htsmsg_set_s64(htsmsg_t *msg, const char *name, int64_t s64)
339 {
340 htsmsg_field_t *f = htsmsg_field_find(msg, name);
341 if (!f)
342 f = htsmsg_field_add(msg, name, HMF_S64, HMF_NAME_INALLOCED, 0);
343 if (f->hmf_type != HMF_S64)
344 return 1;
345 f->hmf_s64 = s64;
346 return 0;
347 }
348
349
350 /*
351 *
352 */
353 void
htsmsg_add_dbl(htsmsg_t * msg,const char * name,double dbl)354 htsmsg_add_dbl(htsmsg_t *msg, const char *name, double dbl)
355 {
356 htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_DBL, HMF_NAME_INALLOCED, 0);
357 f->hmf_dbl = dbl;
358 }
359
360
361
362 /*
363 *
364 */
365 void
htsmsg_add_str(htsmsg_t * msg,const char * name,const char * str)366 htsmsg_add_str(htsmsg_t *msg, const char *name, const char *str)
367 {
368 htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_STR, HMF_NAME_INALLOCED,
369 strlen(str) + 1);
370 strcpy((char *)f->hmf_str, str);
371 f->hmf_flags |= HMF_INALLOCED;
372 }
373
374 /*
375 *
376 */
377 void
htsmsg_add_str2(htsmsg_t * msg,const char * name,const char * str)378 htsmsg_add_str2(htsmsg_t *msg, const char *name, const char *str)
379 {
380 if (msg && name && str)
381 htsmsg_add_str(msg, name, str);
382 }
383
384 /*
385 *
386 */
387 void
htsmsg_add_str_exclusive(htsmsg_t * msg,const char * str)388 htsmsg_add_str_exclusive(htsmsg_t *msg, const char *str)
389 {
390 htsmsg_field_t *f;
391
392 assert(msg->hm_islist);
393
394 TAILQ_FOREACH(f, &msg->hm_fields, hmf_link) {
395 assert(f->hmf_type == HMF_STR);
396 if (strcmp(f->hmf_str, str) == 0)
397 return;
398 }
399
400 htsmsg_add_str(msg, NULL, str);
401 }
402
403 /*
404 *
405 */
406 int
htsmsg_field_set_str(htsmsg_field_t * f,const char * str)407 htsmsg_field_set_str(htsmsg_field_t *f, const char *str)
408 {
409 if (f->hmf_type != HMF_STR)
410 return 1;
411 if (f->hmf_flags & HMF_ALLOCED) {
412 #if ENABLE_SLOW_MEMORYINFO
413 memoryinfo_remove(&htsmsg_field_memoryinfo, strlen(f->hmf_str) + 1);
414 #endif
415 free((void *)f->hmf_str);
416 }
417 else if (f->hmf_flags & HMF_INALLOCED) {
418 if (strlen(f->hmf_str) >= strlen(str)) {
419 strcpy((char *)f->hmf_str, str);
420 return 0;
421 }
422 f->hmf_flags &= ~HMF_INALLOCED;
423 }
424 f->hmf_flags |= HMF_ALLOCED;
425 f->hmf_str = strdup(str);
426 #if ENABLE_SLOW_MEMORYINFO
427 memoryinfo_alloc(&htsmsg_field_memoryinfo, strlen(str) + 1);
428 #endif
429 return 0;
430 }
431
432 /*
433 *
434 */
435 int
htsmsg_field_set_str_force(htsmsg_field_t * f,const char * str)436 htsmsg_field_set_str_force(htsmsg_field_t *f, const char *str)
437 {
438 if (f->hmf_type != HMF_STR) {
439 htsmsg_field_data_destroy(f);
440 f->hmf_type = HMF_STR;
441 f->hmf_str = "";
442 }
443 return htsmsg_field_set_str(f, str);
444 }
445
446 /*
447 *
448 */
449 int
htsmsg_set_str(htsmsg_t * msg,const char * name,const char * str)450 htsmsg_set_str(htsmsg_t *msg, const char *name, const char *str)
451 {
452 htsmsg_field_t *f = htsmsg_field_find(msg, name);
453 if (!f) {
454 htsmsg_add_str(msg, name, str);
455 return 0;
456 }
457 return htsmsg_field_set_str(f, str);
458 }
459
460 /*
461 *
462 */
463 void
htsmsg_add_bin(htsmsg_t * msg,const char * name,const void * bin,size_t len)464 htsmsg_add_bin(htsmsg_t *msg, const char *name, const void *bin, size_t len)
465 {
466 htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_BIN, HMF_NAME_INALLOCED, len);
467 f->hmf_bin = f->hmf_str;
468 f->hmf_binsize = len;
469 f->hmf_flags |= HMF_INALLOCED;
470 memcpy((void *)f->hmf_bin, bin, len);
471 }
472
473 /*
474 *
475 */
476 void
htsmsg_add_binptr(htsmsg_t * msg,const char * name,const void * bin,size_t len)477 htsmsg_add_binptr(htsmsg_t *msg, const char *name, const void *bin, size_t len)
478 {
479 htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_BIN, HMF_NAME_INALLOCED, 0);
480 f->hmf_bin = bin;
481 f->hmf_binsize = len;
482 }
483
484
485 /*
486 *
487 */
488 static htsmsg_t *
htsmsg_field_set_msg(htsmsg_field_t * f,htsmsg_t * sub)489 htsmsg_field_set_msg(htsmsg_field_t *f, htsmsg_t *sub)
490 {
491 assert(sub->hm_data == NULL);
492 f->hmf_msg.hm_data = NULL;
493 f->hmf_msg.hm_data_size = 0;
494 f->hmf_msg.hm_islist = sub->hm_islist;
495 TAILQ_MOVE(&f->hmf_msg.hm_fields, &sub->hm_fields, hmf_link);
496 #if ENABLE_SLOW_MEMORYINFO
497 memoryinfo_free(&htsmsg_memoryinfo, sizeof(htsmsg_t));
498 #endif
499 free(sub);
500
501 if (f->hmf_type == (f->hmf_msg.hm_islist ? HMF_LIST : HMF_MAP))
502 return &f->hmf_msg;
503
504 return NULL;
505 }
506
507 /*
508 *
509 */
510 htsmsg_t *
htsmsg_add_msg(htsmsg_t * msg,const char * name,htsmsg_t * sub)511 htsmsg_add_msg(htsmsg_t *msg, const char *name, htsmsg_t *sub)
512 {
513 htsmsg_field_t *f;
514
515 f = htsmsg_field_add(msg, name, sub->hm_islist ? HMF_LIST : HMF_MAP,
516 HMF_NAME_INALLOCED, 0);
517 return htsmsg_field_set_msg(f, sub);
518 }
519
520 /*
521 *
522 */
523 htsmsg_t *
htsmsg_set_msg(htsmsg_t * msg,const char * name,htsmsg_t * sub)524 htsmsg_set_msg(htsmsg_t *msg, const char *name, htsmsg_t *sub)
525 {
526 htsmsg_field_t *f = htsmsg_field_find(msg, name);
527 if (!f)
528 return htsmsg_add_msg(msg, name, sub);
529 htsmsg_field_data_destroy(f);
530 return htsmsg_field_set_msg(f, sub);
531 }
532
533
534
535 /*
536 *
537 */
538 void
htsmsg_add_msg_extname(htsmsg_t * msg,const char * name,htsmsg_t * sub)539 htsmsg_add_msg_extname(htsmsg_t *msg, const char *name, htsmsg_t *sub)
540 {
541 htsmsg_field_t *f;
542
543 f = htsmsg_field_add(msg, name, sub->hm_islist ? HMF_LIST : HMF_MAP, 0, 0);
544
545 assert(sub->hm_data == NULL);
546 f->hmf_msg.hm_data = NULL;
547 f->hmf_msg.hm_data_size = 0;
548 TAILQ_MOVE(&f->hmf_msg.hm_fields, &sub->hm_fields, hmf_link);
549 f->hmf_msg.hm_islist = sub->hm_islist;
550 #if ENABLE_SLOW_MEMORYINFO
551 memoryinfo_free(&htsmsg_memoryinfo, sizeof(htsmsg_t));
552 #endif
553 free(sub);
554 }
555
556
557
558 /**
559 *
560 */
561 int
htsmsg_get_s64(htsmsg_t * msg,const char * name,int64_t * s64p)562 htsmsg_get_s64(htsmsg_t *msg, const char *name, int64_t *s64p)
563 {
564 htsmsg_field_t *f;
565
566 if((f = htsmsg_field_find(msg, name)) == NULL)
567 return HTSMSG_ERR_FIELD_NOT_FOUND;
568
569 return htsmsg_field_get_s64(f, s64p);
570 }
571
572 int
htsmsg_field_get_s64(htsmsg_field_t * f,int64_t * s64p)573 htsmsg_field_get_s64
574 (htsmsg_field_t *f, int64_t *s64p)
575 {
576 switch(f->hmf_type) {
577 default:
578 return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
579 case HMF_STR:
580 *s64p = strtoll(f->hmf_str, NULL, 0);
581 break;
582 case HMF_S64:
583 *s64p = f->hmf_s64;
584 break;
585 case HMF_BOOL:
586 *s64p = f->hmf_bool;
587 break;
588 case HMF_DBL:
589 *s64p = f->hmf_dbl;
590 break;
591 }
592 return 0;
593 }
594
595
596 /**
597 *
598 */
599
600 int
bool_check(const char * str)601 bool_check(const char *str)
602 {
603 if (str &&
604 (!strcmp(str, "yes") ||
605 !strcmp(str, "true") ||
606 !strcmp(str, "on") ||
607 !strcmp(str, "1")))
608 return 1;
609 return 0;
610 }
611
612 int
htsmsg_field_get_bool(htsmsg_field_t * f,int * boolp)613 htsmsg_field_get_bool
614 ( htsmsg_field_t *f, int *boolp )
615 {
616 switch(f->hmf_type) {
617 default:
618 return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
619 case HMF_STR:
620 *boolp = bool_check(f->hmf_str);
621 break;
622 case HMF_S64:
623 *boolp = f->hmf_s64 ? 1 : 0;
624 break;
625 case HMF_BOOL:
626 *boolp = f->hmf_bool;
627 break;
628 }
629 return 0;
630 }
631
632 int
htsmsg_get_bool(htsmsg_t * msg,const char * name,int * boolp)633 htsmsg_get_bool
634 (htsmsg_t *msg, const char *name, int *boolp)
635 {
636 htsmsg_field_t *f;
637
638 if((f = htsmsg_field_find(msg, name)) == NULL)
639 return HTSMSG_ERR_FIELD_NOT_FOUND;
640
641 return htsmsg_field_get_bool(f, boolp);
642 }
643
644 int
htsmsg_get_bool_or_default(htsmsg_t * msg,const char * name,int def)645 htsmsg_get_bool_or_default(htsmsg_t *msg, const char *name, int def)
646 {
647 int ret;
648 return htsmsg_get_bool(msg, name, &ret) ? def : ret;
649 }
650
651
652 /**
653 *
654 */
655 int64_t
htsmsg_get_s64_or_default(htsmsg_t * msg,const char * name,int64_t def)656 htsmsg_get_s64_or_default(htsmsg_t *msg, const char *name, int64_t def)
657 {
658 int64_t s64;
659 return htsmsg_get_s64(msg, name, &s64) ? def : s64;
660 }
661
662
663 /*
664 *
665 */
666 int
htsmsg_get_u32(htsmsg_t * msg,const char * name,uint32_t * u32p)667 htsmsg_get_u32(htsmsg_t *msg, const char *name, uint32_t *u32p)
668 {
669 int r;
670 int64_t s64;
671
672 if((r = htsmsg_get_s64(msg, name, &s64)) != 0)
673 return r;
674
675 if(s64 < 0 || s64 > 0xffffffffLL)
676 return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
677
678 *u32p = s64;
679 return 0;
680 }
681
682 int
htsmsg_field_get_u32(htsmsg_field_t * f,uint32_t * u32p)683 htsmsg_field_get_u32(htsmsg_field_t *f, uint32_t *u32p)
684 {
685 int r;
686 int64_t s64;
687
688 if ((r = htsmsg_field_get_s64(f, &s64)))
689 return r;
690
691 if (s64 < 0 || s64 > 0xffffffffL)
692 return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
693
694 *u32p = s64;
695 return 0;
696 }
697
698 /**
699 *
700 */
701 int
htsmsg_get_u32_or_default(htsmsg_t * msg,const char * name,uint32_t def)702 htsmsg_get_u32_or_default(htsmsg_t *msg, const char *name, uint32_t def)
703 {
704 uint32_t u32;
705 return htsmsg_get_u32(msg, name, &u32) ? def : u32;
706 }
707
708
709 /**
710 *
711 */
712 int32_t
htsmsg_get_s32_or_default(htsmsg_t * msg,const char * name,int32_t def)713 htsmsg_get_s32_or_default(htsmsg_t *msg, const char *name, int32_t def)
714 {
715 int32_t s32;
716 return htsmsg_get_s32(msg, name, &s32) ? def : s32;
717 }
718
719
720
721 /*
722 *
723 */
724 int
htsmsg_get_s32(htsmsg_t * msg,const char * name,int32_t * s32p)725 htsmsg_get_s32(htsmsg_t *msg, const char *name, int32_t *s32p)
726 {
727 int r;
728 int64_t s64;
729
730 if((r = htsmsg_get_s64(msg, name, &s64)) != 0)
731 return r;
732
733 if(s64 < -0x80000000LL || s64 > 0x7fffffffLL)
734 return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
735
736 *s32p = s64;
737 return 0;
738 }
739
740
741 /*
742 *
743 */
744 int
htsmsg_get_dbl(htsmsg_t * msg,const char * name,double * dblp)745 htsmsg_get_dbl(htsmsg_t *msg, const char *name, double *dblp)
746 {
747 htsmsg_field_t *f;
748
749 if((f = htsmsg_field_find(msg, name)) == NULL)
750 return HTSMSG_ERR_FIELD_NOT_FOUND;
751
752 return htsmsg_field_get_dbl(f, dblp);
753 }
754
755 int
htsmsg_field_get_dbl(htsmsg_field_t * f,double * dblp)756 htsmsg_field_get_dbl
757 ( htsmsg_field_t *f, double *dblp )
758 {
759 switch (f->hmf_type) {
760 case HMF_S64:
761 *dblp = (double)f->hmf_s64;
762 break;
763 case HMF_DBL:
764 *dblp = f->hmf_dbl;
765 break;
766 case HMF_STR:
767 *dblp = my_str2double(f->hmf_str, NULL);
768 // TODO: better safety checks?
769 break;
770 default:
771 return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
772 }
773 return 0;
774 }
775
776 /*
777 *
778 */
779 int
htsmsg_get_bin(htsmsg_t * msg,const char * name,const void ** binp,size_t * lenp)780 htsmsg_get_bin(htsmsg_t *msg, const char *name, const void **binp,
781 size_t *lenp)
782 {
783 htsmsg_field_t *f;
784
785 if((f = htsmsg_field_find(msg, name)) == NULL)
786 return HTSMSG_ERR_FIELD_NOT_FOUND;
787
788 if(f->hmf_type != HMF_BIN)
789 return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
790
791 *binp = f->hmf_bin;
792 *lenp = f->hmf_binsize;
793 return 0;
794 }
795
796 /**
797 *
798 */
799 const char *
htsmsg_field_get_string(htsmsg_field_t * f)800 htsmsg_field_get_string(htsmsg_field_t *f)
801 {
802 char buf[128];
803
804 switch(f->hmf_type) {
805 default:
806 return NULL;
807 case HMF_STR:
808 break;
809 case HMF_BOOL:
810 htsmsg_field_set_str_force(f, f->hmf_bool ? "true" : "false");
811 break;
812 case HMF_S64:
813 snprintf(buf, sizeof(buf), "%"PRId64, f->hmf_s64);
814 htsmsg_field_set_str_force(f, buf);
815 break;
816 case HMF_DBL:
817 snprintf(buf, sizeof(buf), "%lf", f->hmf_dbl);
818 htsmsg_field_set_str_force(f, buf);
819 break;
820 }
821 return f->hmf_str;
822 }
823
824 /*
825 *
826 */
827 const char *
htsmsg_get_str(htsmsg_t * msg,const char * name)828 htsmsg_get_str(htsmsg_t *msg, const char *name)
829 {
830 htsmsg_field_t *f;
831
832 if((f = htsmsg_field_find(msg, name)) == NULL)
833 return NULL;
834 return htsmsg_field_get_string(f);
835
836 }
837
838 /*
839 *
840 */
841 htsmsg_t *
htsmsg_get_map(htsmsg_t * msg,const char * name)842 htsmsg_get_map(htsmsg_t *msg, const char *name)
843 {
844 htsmsg_field_t *f;
845
846 if((f = htsmsg_field_find(msg, name)) == NULL)
847 return NULL;
848
849 return htsmsg_field_get_map(f);
850 }
851
852 htsmsg_t *
htsmsg_field_get_map(htsmsg_field_t * f)853 htsmsg_field_get_map(htsmsg_field_t *f)
854 {
855 return htsmsg_field_get_msg(f, 0);
856 }
857
858 /**
859 *
860 */
861 htsmsg_t *
htsmsg_get_map_multi(htsmsg_t * msg,...)862 htsmsg_get_map_multi(htsmsg_t *msg, ...)
863 {
864 va_list ap;
865 const char *n;
866
867 va_start(ap, msg);
868 while(msg != NULL && (n = va_arg(ap, char *)) != NULL)
869 msg = htsmsg_get_map(msg, n);
870 va_end(ap);
871
872 return msg;
873 }
874
875 /**
876 *
877 */
878 const char *
htsmsg_get_str_multi(htsmsg_t * msg,...)879 htsmsg_get_str_multi(htsmsg_t *msg, ...)
880 {
881 va_list ap;
882 const char *n, *r = NULL;
883 htsmsg_field_t *f;
884
885 va_start(ap, msg);
886 while((n = va_arg(ap, char *)) != NULL) {
887 if((f = htsmsg_field_find(msg, n)) == NULL)
888 break;
889 else if(f->hmf_type == HMF_STR) {
890 r = f->hmf_str;
891 break;
892 } else if(f->hmf_type == HMF_MAP)
893 msg = &f->hmf_msg;
894 else
895 break;
896 }
897 va_end(ap);
898
899 return r;
900 }
901
902
903
904 /*
905 *
906 */
907 htsmsg_t *
htsmsg_get_list(htsmsg_t * msg,const char * name)908 htsmsg_get_list(htsmsg_t *msg, const char *name)
909 {
910 htsmsg_field_t *f;
911
912 if((f = htsmsg_field_find(msg, name)) == NULL)
913 return NULL;
914
915 return htsmsg_field_get_list(f);
916 }
917
918 htsmsg_t *
htsmsg_field_get_list(htsmsg_field_t * f)919 htsmsg_field_get_list ( htsmsg_field_t *f )
920 {
921 return htsmsg_field_get_msg(f, 1);
922 }
923
924 static htsmsg_t *
htsmsg_field_get_msg(htsmsg_field_t * f,int islist)925 htsmsg_field_get_msg ( htsmsg_field_t *f, int islist )
926 {
927 htsmsg_t *m;
928
929 /* Deserialize JSON (will keep either list or map) */
930 if (f->hmf_type == HMF_STR) {
931 if ((m = htsmsg_json_deserialize(f->hmf_str))) {
932 if (f->hmf_flags & HMF_ALLOCED) {
933 #if ENABLE_SLOW_MEMORYINFO
934 memoryinfo_free(&htsmsg_field_memoryinfo, strlen(f->hmf_str) + 1);
935 #endif
936 free((void*)f->hmf_str);
937 }
938 f->hmf_type = m->hm_islist ? HMF_LIST : HMF_MAP;
939 f->hmf_msg.hm_islist = m->hm_islist;
940 f->hmf_msg.hm_data = NULL;
941 f->hmf_msg.hm_data_size = 0;
942 TAILQ_MOVE(&f->hmf_msg.hm_fields, &m->hm_fields, hmf_link);
943 #if ENABLE_SLOW_MEMORYINFO
944 memoryinfo_free(&htsmsg_memoryinfo, sizeof(htsmsg_t));
945 #endif
946 free(m);
947 }
948 }
949
950 if (f->hmf_type == (islist ? HMF_LIST : HMF_MAP))
951 return &f->hmf_msg;
952
953 return NULL;
954 }
955
956 /**
957 *
958 */
959 htsmsg_t *
htsmsg_detach_submsg(htsmsg_field_t * f)960 htsmsg_detach_submsg(htsmsg_field_t *f)
961 {
962 htsmsg_t *r = htsmsg_create_map();
963
964 TAILQ_MOVE(&r->hm_fields, &f->hmf_msg.hm_fields, hmf_link);
965 TAILQ_INIT(&f->hmf_msg.hm_fields);
966 r->hm_islist = f->hmf_type == HMF_LIST;
967 return r;
968 }
969
970
971 /*
972 *
973 */
974 static void
htsmsg_print0(htsmsg_t * msg,int indent)975 htsmsg_print0(htsmsg_t *msg, int indent)
976 {
977 htsmsg_field_t *f;
978 int i;
979
980 TAILQ_FOREACH(f, &msg->hm_fields, hmf_link) {
981
982 for(i = 0; i < indent; i++) printf("\t");
983
984 printf("%s (", f->hmf_name ?: "");
985
986 switch(f->hmf_type) {
987
988 case HMF_MAP:
989 printf("MAP) = {\n");
990 htsmsg_print0(&f->hmf_msg, indent + 1);
991 for(i = 0; i < indent; i++) printf("\t");
992 printf("}\n");
993 break;
994
995 case HMF_LIST:
996 printf("LIST) = {\n");
997 htsmsg_print0(&f->hmf_msg, indent + 1);
998 for(i = 0; i < indent; i++) printf("\t");
999 printf("}\n");
1000 break;
1001
1002 case HMF_STR:
1003 printf("STR) = \"%s\"\n", f->hmf_str);
1004 break;
1005
1006 case HMF_BIN:
1007 printf("BIN) = [");
1008 for(i = 0; i < f->hmf_binsize - 1; i++)
1009 printf("%02x.", ((uint8_t *)f->hmf_bin)[i]);
1010 printf("%02x]\n", ((uint8_t *)f->hmf_bin)[i]);
1011 break;
1012
1013 case HMF_S64:
1014 printf("S64) = %" PRId64 "\n", f->hmf_s64);
1015 break;
1016
1017 case HMF_BOOL:
1018 printf("BOOL) = %s\n", f->hmf_bool ? "true" : "false");
1019 break;
1020
1021 case HMF_DBL:
1022 printf("DBL) = %f\n", f->hmf_dbl);
1023 break;
1024 }
1025 }
1026 }
1027
1028 /*
1029 *
1030 */
1031 void
htsmsg_print(htsmsg_t * msg)1032 htsmsg_print(htsmsg_t *msg)
1033 {
1034 htsmsg_print0(msg, 0);
1035 }
1036
1037
1038 /**
1039 *
1040 */
1041 static void
htsmsg_copy_i(htsmsg_t * src,htsmsg_t * dst)1042 htsmsg_copy_i(htsmsg_t *src, htsmsg_t *dst)
1043 {
1044 htsmsg_field_t *f;
1045 htsmsg_t *sub;
1046
1047 TAILQ_FOREACH(f, &src->hm_fields, hmf_link) {
1048
1049 switch(f->hmf_type) {
1050
1051 case HMF_MAP:
1052 case HMF_LIST:
1053 sub = f->hmf_type == HMF_LIST ?
1054 htsmsg_create_list() : htsmsg_create_map();
1055 htsmsg_copy_i(&f->hmf_msg, sub);
1056 htsmsg_add_msg(dst, f->hmf_name, sub);
1057 break;
1058
1059 case HMF_STR:
1060 htsmsg_add_str(dst, f->hmf_name, f->hmf_str);
1061 break;
1062
1063 case HMF_S64:
1064 htsmsg_add_s64(dst, f->hmf_name, f->hmf_s64);
1065 break;
1066
1067 case HMF_BOOL:
1068 htsmsg_add_bool(dst, f->hmf_name, f->hmf_bool);
1069 break;
1070
1071 case HMF_BIN:
1072 htsmsg_add_bin(dst, f->hmf_name, f->hmf_bin, f->hmf_binsize);
1073 break;
1074
1075 case HMF_DBL:
1076 htsmsg_add_dbl(dst, f->hmf_name, f->hmf_dbl);
1077 break;
1078 }
1079 }
1080 }
1081
1082 htsmsg_t *
htsmsg_copy(htsmsg_t * src)1083 htsmsg_copy(htsmsg_t *src)
1084 {
1085 htsmsg_t *dst;
1086 if (src == NULL) return NULL;
1087 dst = src->hm_islist ? htsmsg_create_list() : htsmsg_create_map();
1088 htsmsg_copy_i(src, dst);
1089 return dst;
1090 }
1091
1092 /**
1093 *
1094 */
1095 int
htsmsg_cmp(htsmsg_t * m1,htsmsg_t * m2)1096 htsmsg_cmp(htsmsg_t *m1, htsmsg_t *m2)
1097 {
1098 htsmsg_field_t *f1, *f2;
1099
1100 if (m1 == NULL && m2 == NULL)
1101 return 0;
1102 if (m1 == NULL || m2 == NULL)
1103 return 1;
1104
1105 f2 = TAILQ_FIRST(&m2->hm_fields);
1106 TAILQ_FOREACH(f1, &m1->hm_fields, hmf_link) {
1107
1108 if (f2 == NULL)
1109 return 1;
1110
1111 if (f1->hmf_type != f2->hmf_type)
1112 return 1;
1113 if (strcmp(f1->hmf_name ?: "", f2->hmf_name ?: ""))
1114 return 1;
1115
1116 switch(f1->hmf_type) {
1117
1118 case HMF_MAP:
1119 case HMF_LIST:
1120 if (htsmsg_cmp(&f1->hmf_msg, &f2->hmf_msg))
1121 return 1;
1122 break;
1123
1124 case HMF_STR:
1125 if (strcmp(f1->hmf_str, f2->hmf_str))
1126 return 1;
1127 break;
1128
1129 case HMF_S64:
1130 if (f1->hmf_s64 != f2->hmf_s64)
1131 return 1;
1132 break;
1133
1134 case HMF_BOOL:
1135 if (f1->hmf_bool != f2->hmf_bool)
1136 return 1;
1137 break;
1138
1139 case HMF_BIN:
1140 if (f1->hmf_binsize != f2->hmf_binsize)
1141 return 1;
1142 if (memcmp(f1->hmf_bin, f2->hmf_bin, f1->hmf_binsize))
1143 return 1;
1144 break;
1145
1146 case HMF_DBL:
1147 if (f1->hmf_dbl != f2->hmf_dbl)
1148 return 1;
1149 break;
1150 }
1151
1152 f2 = TAILQ_NEXT(f2, hmf_link);
1153 }
1154
1155 if (f2)
1156 return 1;
1157 return 0;
1158 }
1159
1160 /**
1161 *
1162 */
1163 htsmsg_t *
htsmsg_get_map_in_list(htsmsg_t * m,int num)1164 htsmsg_get_map_in_list(htsmsg_t *m, int num)
1165 {
1166 htsmsg_field_t *f;
1167
1168 HTSMSG_FOREACH(f, m) {
1169 if(!--num)
1170 return htsmsg_get_map_by_field(f);
1171 }
1172 return NULL;
1173 }
1174
1175
1176 /**
1177 *
1178 */
1179 htsmsg_t *
htsmsg_get_map_by_field_if_name(htsmsg_field_t * f,const char * name)1180 htsmsg_get_map_by_field_if_name(htsmsg_field_t *f, const char *name)
1181 {
1182 if(f->hmf_type != HMF_MAP)
1183 return NULL;
1184 if(strcmp(f->hmf_name, name))
1185 return NULL;
1186 return &f->hmf_msg;
1187 }
1188
1189
1190 /**
1191 *
1192 */
1193 const char *
htsmsg_get_cdata(htsmsg_t * m,const char * field)1194 htsmsg_get_cdata(htsmsg_t *m, const char *field)
1195 {
1196 return htsmsg_get_str_multi(m, field, "cdata", NULL);
1197 }
1198
1199 /**
1200 * Convert list to CSV string
1201 *
1202 * Note: this will NOT work for lists of complex types
1203 */
1204 char *
htsmsg_list_2_csv(htsmsg_t * m,char delim,int human)1205 htsmsg_list_2_csv(htsmsg_t *m, char delim, int human)
1206 {
1207 int alloc, used, first = 1;
1208 char *ret;
1209 htsmsg_field_t *f;
1210 char sep[3];
1211 const char *ssep;
1212 if (!m->hm_islist) return NULL;
1213
1214 #define REALLOC(l)\
1215 if ((alloc - used) < l) {\
1216 alloc = MAX((l)*2, alloc*2);\
1217 ret = realloc(ret, alloc);\
1218 }\
1219
1220 ret = malloc(alloc = 512);
1221 *ret = 0;
1222 used = 0;
1223 if (human) {
1224 sep[0] = delim;
1225 if (human & 2) {
1226 sep[1] = '\0';
1227 } else {
1228 sep[1] = ' ';
1229 sep[2] = '\0';
1230 }
1231 ssep = "";
1232 } else {
1233 sep[0] = delim;
1234 sep[1] = '\0';
1235 ssep = "\"";
1236 }
1237 HTSMSG_FOREACH(f, m) {
1238 if (f->hmf_type == HMF_STR) {
1239 REALLOC(4 + strlen(f->hmf_str));
1240 used += sprintf(ret+used, "%s%s%s%s", !first ? sep : "", ssep, f->hmf_str, ssep);
1241 } else if (f->hmf_type == HMF_S64) {
1242 REALLOC(34); // max length is actually 20 chars + 2
1243 used += sprintf(ret+used, "%s%"PRId64, !first ? sep : "", f->hmf_s64);
1244 } else if (f->hmf_type == HMF_BOOL) {
1245 REALLOC(12); // max length is actually 10 chars + 2
1246 used += sprintf(ret+used, "%s%d", !first ? sep : "", f->hmf_bool);
1247 } else {
1248 // TODO: handle doubles
1249 free(ret);
1250 return NULL;
1251 }
1252 first = 0;
1253 }
1254
1255 return ret;
1256 }
1257
1258 htsmsg_t *
htsmsg_csv_2_list(const char * str,char delim)1259 htsmsg_csv_2_list(const char *str, char delim)
1260 {
1261 char *tokbuf, *tok, *saveptr = NULL, *p;
1262 const char d[2] = { delim, '\0' };
1263 htsmsg_t *m = htsmsg_create_list();
1264
1265 if (str) {
1266 tokbuf = strdup(str);
1267 tok = strtok_r(tokbuf, d, &saveptr);
1268 while (tok) {
1269 if (tok[0] == '"') {
1270 p = ++tok;
1271 while (*p && *p != '"') {
1272 if (*p == '\\') {
1273 p++;
1274 if (*p)
1275 p++;
1276 continue;
1277 }
1278 p++;
1279 }
1280 *p = '\0';
1281 }
1282 htsmsg_add_str(m, NULL, tok);
1283 tok = strtok_r(NULL, ",", &saveptr);
1284 }
1285 free(tokbuf);
1286 }
1287 return m;
1288 }
1289
1290 /*
1291 *
1292 */
1293 htsmsg_t *
htsmsg_create_key_val(const char * key,const char * val)1294 htsmsg_create_key_val(const char *key, const char *val)
1295 {
1296 htsmsg_t *r = htsmsg_create_map();
1297 if (r) {
1298 htsmsg_add_str(r, "key", key);
1299 htsmsg_add_str(r, "val", val);
1300 }
1301 return r;
1302 }
1303