changed: upgraded libhts (tvheadend message library) to latest version
[xbmc:xbmc-antiquated.git] / XBMC / xbmc / lib / libhts / htsmsg.c
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 "htsmsg.h"
27
28 static void htsmsg_clear(htsmsg_t *msg);
29
30 /*
31  *
32  */
33 static void
34 htsmsg_field_destroy(htsmsg_t *msg, htsmsg_field_t *f)
35 {
36   TAILQ_REMOVE(&msg->hm_fields, f, hmf_link);
37
38   switch(f->hmf_type) {
39   case HMF_MAP:
40   case HMF_LIST:
41     htsmsg_clear(&f->hmf_msg);
42     break;
43
44   case HMF_STR:
45     if(f->hmf_flags & HMF_ALLOCED)
46       free((void *)f->hmf_str);
47     break;
48
49   case HMF_BIN:
50     if(f->hmf_flags & HMF_ALLOCED)
51       free((void *)f->hmf_bin);
52     break;
53   default:
54     break;
55   }
56   if(f->hmf_flags & HMF_NAME_ALLOCED)
57     free((void *)f->hmf_name);
58   free(f);
59 }
60
61 /*
62  *
63  */
64 static void
65 htsmsg_clear(htsmsg_t *msg)
66 {
67   htsmsg_field_t *f;
68
69   while((f = TAILQ_FIRST(&msg->hm_fields)) != NULL)
70     htsmsg_field_destroy(msg, f);
71 }
72
73
74
75 /*
76  *
77  */
78 htsmsg_field_t *
79 htsmsg_field_add(htsmsg_t *msg, const char *name, int type, int flags)
80 {
81   htsmsg_field_t *f = malloc(sizeof(htsmsg_field_t));
82   
83   TAILQ_INSERT_TAIL(&msg->hm_fields, f, hmf_link);
84
85   if(msg->hm_islist) {
86     assert(name == NULL);
87   } else {
88     assert(name != NULL);
89   }
90
91   if(flags & HMF_NAME_ALLOCED)
92     f->hmf_name = name ? strdup(name) : NULL;
93   else
94     f->hmf_name = name;
95
96   f->hmf_type = type;
97   f->hmf_flags = flags;
98   return f;
99 }
100
101
102 /*
103  *
104  */
105 static htsmsg_field_t *
106 htsmsg_field_find(htsmsg_t *msg, const char *name)
107 {
108   htsmsg_field_t *f;
109
110   TAILQ_FOREACH(f, &msg->hm_fields, hmf_link) {
111     if(f->hmf_name != NULL && !strcmp(f->hmf_name, name))
112       return f;
113   }
114   return NULL;
115 }
116
117
118
119 /**
120  *
121  */
122 int
123 htsmsg_delete_field(htsmsg_t *msg, const char *name)
124 {
125   htsmsg_field_t *f;
126
127   if((f = htsmsg_field_find(msg, name)) == NULL)
128     return HTSMSG_ERR_FIELD_NOT_FOUND;
129   htsmsg_field_destroy(msg, f);
130   return 0;
131 }
132
133
134 /*
135  *
136  */
137 htsmsg_t *
138 htsmsg_create_map(void)
139 {
140   htsmsg_t *msg;
141
142   msg = malloc(sizeof(htsmsg_t));
143   TAILQ_INIT(&msg->hm_fields);
144   msg->hm_data = NULL;
145   msg->hm_islist = 0;
146   return msg;
147 }
148
149 /*
150  *
151  */
152 htsmsg_t *
153 htsmsg_create_list(void)
154 {
155   htsmsg_t *msg;
156
157   msg = malloc(sizeof(htsmsg_t));
158   TAILQ_INIT(&msg->hm_fields);
159   msg->hm_data = NULL;
160   msg->hm_islist = 1;
161   return msg;
162 }
163
164
165 /*
166  *
167  */
168 void
169 htsmsg_destroy(htsmsg_t *msg)
170 {
171   if(msg == NULL)
172     return;
173
174   htsmsg_clear(msg);
175   free((void *)msg->hm_data);
176   free(msg);
177 }
178
179 /*
180  *
181  */
182 void
183 htsmsg_add_u32(htsmsg_t *msg, const char *name, uint32_t u32)
184 {
185   htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_S64, HMF_NAME_ALLOCED);
186   f->hmf_s64 = u32;
187 }
188
189 /*
190  *
191  */
192 void
193 htsmsg_add_s64(htsmsg_t *msg, const char *name, int64_t s64)
194 {
195   htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_S64, HMF_NAME_ALLOCED);
196   f->hmf_s64 = s64;
197 }
198
199 /*
200  *
201  */
202 void
203 htsmsg_add_s32(htsmsg_t *msg, const char *name, int32_t s32)
204 {
205   htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_S64, HMF_NAME_ALLOCED);
206   f->hmf_s64 = s32;
207 }
208
209
210
211 /*
212  *
213  */
214 void
215 htsmsg_add_str(htsmsg_t *msg, const char *name, const char *str)
216 {
217   htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_STR, 
218                                         HMF_ALLOCED | HMF_NAME_ALLOCED);
219   f->hmf_str = strdup(str);
220 }
221
222 /*
223  *
224  */
225 void
226 htsmsg_add_bin(htsmsg_t *msg, const char *name, const void *bin, size_t len)
227 {
228   htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_BIN, 
229                                        HMF_ALLOCED | HMF_NAME_ALLOCED);
230   void *v;
231   f->hmf_bin = v = malloc(len);
232   f->hmf_binsize = len;
233   memcpy(v, bin, len);
234 }
235
236 /*
237  *
238  */
239 void
240 htsmsg_add_binptr(htsmsg_t *msg, const char *name, const void *bin, size_t len)
241 {
242   htsmsg_field_t *f = htsmsg_field_add(msg, name, HMF_BIN, HMF_NAME_ALLOCED);
243   f->hmf_bin = bin;
244   f->hmf_binsize = len;
245 }
246
247
248 /*
249  *
250  */
251 void
252 htsmsg_add_msg(htsmsg_t *msg, const char *name, htsmsg_t *sub)
253 {
254   htsmsg_field_t *f;
255
256   f = htsmsg_field_add(msg, name, sub->hm_islist ? HMF_LIST : HMF_MAP,
257                        HMF_NAME_ALLOCED);
258
259   assert(sub->hm_data == NULL);
260   TAILQ_MOVE(&f->hmf_msg.hm_fields, &sub->hm_fields, hmf_link);
261   free(sub);
262 }
263
264
265
266 /*
267  *
268  */
269 void
270 htsmsg_add_msg_extname(htsmsg_t *msg, const char *name, htsmsg_t *sub)
271 {
272   htsmsg_field_t *f;
273
274   f = htsmsg_field_add(msg, name, sub->hm_islist ? HMF_LIST : HMF_MAP, 0);
275
276   assert(sub->hm_data == NULL);
277   TAILQ_MOVE(&f->hmf_msg.hm_fields, &sub->hm_fields, hmf_link);
278   free(sub);
279 }
280
281
282
283 /**
284  *
285  */
286 int
287 htsmsg_get_s64(htsmsg_t *msg, const char *name, int64_t *s64p)
288 {
289   htsmsg_field_t *f;
290
291   if((f = htsmsg_field_find(msg, name)) == NULL)
292     return HTSMSG_ERR_FIELD_NOT_FOUND;
293
294   switch(f->hmf_type) {
295   default:
296     return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
297   case HMF_STR:
298     *s64p = strtoll(f->hmf_str, NULL, 0);
299     break;
300   case HMF_S64:
301     *s64p = f->hmf_s64;
302     break;
303   }
304   return 0;
305 }
306
307
308 /*
309  *
310  */
311 int
312 htsmsg_get_u32(htsmsg_t *msg, const char *name, uint32_t *u32p)
313 {
314   int r;
315   int64_t s64;
316
317   if((r = htsmsg_get_s64(msg, name, &s64)) != 0)
318     return r;
319
320   if(s64 < 0 || s64 > 0xffffffffLL)
321     return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
322   
323   *u32p = s64;
324   return 0;
325 }
326
327 /**
328  *
329  */
330 int
331 htsmsg_get_u32_or_default(htsmsg_t *msg, const char *name, uint32_t def)
332 {
333   uint32_t u32;
334     return htsmsg_get_u32(msg, name, &u32) ? def : u32;
335 }
336
337
338
339 /*
340  *
341  */
342 int
343 htsmsg_get_s32(htsmsg_t *msg, const char *name, int32_t *s32p)
344 {
345   int r;
346   int64_t s64;
347
348   if((r = htsmsg_get_s64(msg, name, &s64)) != 0)
349     return r;
350
351   if(s64 < -0x80000000LL || s64 > 0x7fffffffLL)
352     return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
353   
354   *s32p = s64;
355   return 0;
356 }
357
358
359 /*
360  *
361  */
362 int
363 htsmsg_get_bin(htsmsg_t *msg, const char *name, const void **binp,
364                size_t *lenp)
365 {
366   htsmsg_field_t *f;
367   
368   if((f = htsmsg_field_find(msg, name)) == NULL)
369     return HTSMSG_ERR_FIELD_NOT_FOUND;
370   
371   if(f->hmf_type != HMF_BIN)
372     return HTSMSG_ERR_CONVERSION_IMPOSSIBLE;
373
374   *binp = f->hmf_bin;
375   *lenp = f->hmf_binsize;
376   return 0;
377 }
378
379 /**
380  *
381  */
382 const char *
383 htsmsg_field_get_string(htsmsg_field_t *f)
384 {
385   char buf[40];
386   
387   switch(f->hmf_type) {
388   default:
389     return NULL;
390   case HMF_STR:
391     break;
392   case HMF_S64:
393     snprintf(buf, sizeof(buf), "%"PRId64, f->hmf_s64);
394     f->hmf_str = strdup(buf);
395     f->hmf_type = HMF_STR;
396     break;
397   }
398   return f->hmf_str;
399 }
400
401 /*
402  *
403  */
404 const char *
405 htsmsg_get_str(htsmsg_t *msg, const char *name)
406 {
407   htsmsg_field_t *f;
408
409   if((f = htsmsg_field_find(msg, name)) == NULL)
410     return NULL;
411   return htsmsg_field_get_string(f);
412
413 }
414
415 /*
416  *
417  */
418 htsmsg_t *
419 htsmsg_get_map(htsmsg_t *msg, const char *name)
420 {
421   htsmsg_field_t *f;
422
423   if((f = htsmsg_field_find(msg, name)) == NULL || f->hmf_type != HMF_MAP)
424     return NULL;
425
426   return &f->hmf_msg;
427 }
428
429 /**
430  *
431  */
432 htsmsg_t *
433 htsmsg_get_map_multi(htsmsg_t *msg, ...)
434 {
435   va_list ap;
436   const char *n;
437   va_start(ap, msg);
438
439   while(msg != NULL && (n = va_arg(ap, char *)) != NULL)
440     msg = htsmsg_get_map(msg, n);
441   return msg;
442 }
443
444 /*
445  *
446  */
447 htsmsg_t *
448 htsmsg_get_list(htsmsg_t *msg, const char *name)
449 {
450   htsmsg_field_t *f;
451
452   if((f = htsmsg_field_find(msg, name)) == NULL || f->hmf_type != HMF_LIST)
453     return NULL;
454
455   return &f->hmf_msg;
456 }
457
458 /**
459  *
460  */
461 htsmsg_t *
462 htsmsg_detach_submsg(htsmsg_field_t *f)
463 {
464   htsmsg_t *r = htsmsg_create_map();
465
466   TAILQ_MOVE(&r->hm_fields, &f->hmf_msg.hm_fields, hmf_link);
467   TAILQ_INIT(&f->hmf_msg.hm_fields);
468   r->hm_islist = f->hmf_type == HMF_LIST;
469   return r;
470 }
471
472
473 /*
474  *
475  */
476 static void
477 htsmsg_print0(htsmsg_t *msg, int indent)
478 {
479   htsmsg_field_t *f;
480   int i;
481
482   TAILQ_FOREACH(f, &msg->hm_fields, hmf_link) {
483
484     for(i = 0; i < indent; i++) printf("\t");
485     
486     printf("%s (", f->hmf_name ?: "");
487     
488     switch(f->hmf_type) {
489
490     case HMF_MAP:
491       printf("MAP) = {\n");
492       htsmsg_print0(&f->hmf_msg, indent + 1);
493       for(i = 0; i < indent; i++) printf("\t"); printf("}\n");
494       break;
495
496     case HMF_LIST:
497       printf("LIST) = {\n");
498       htsmsg_print0(&f->hmf_msg, indent + 1);
499       for(i = 0; i < indent; i++) printf("\t"); printf("}\n");
500       break;
501       
502     case HMF_STR:
503       printf("STR) = \"%s\"\n", f->hmf_str);
504       break;
505
506     case HMF_BIN:
507       printf("BIN) = [");
508       for(i = 0; i < f->hmf_binsize - 1; i++)
509         printf("%02x.", ((uint8_t *)f->hmf_bin)[i]);
510       printf("%02x]\n", ((uint8_t *)f->hmf_bin)[i]);
511       break;
512
513     case HMF_S64:
514       printf("S64) = %" PRId64 "\n", f->hmf_s64);
515       break;
516     }
517   }
518
519
520 /*
521  *
522  */
523 void
524 htsmsg_print(htsmsg_t *msg)
525 {
526   htsmsg_print0(msg, 0);
527
528
529
530 /**
531  *
532  */
533 static void
534 htsmsg_copy_i(htsmsg_t *src, htsmsg_t *dst)
535 {
536   htsmsg_field_t *f;
537   htsmsg_t *sub;
538
539   TAILQ_FOREACH(f, &src->hm_fields, hmf_link) {
540
541     switch(f->hmf_type) {
542
543     case HMF_MAP:
544     case HMF_LIST:
545       sub = f->hmf_type == HMF_LIST ? 
546         htsmsg_create_list() : htsmsg_create_map();
547       htsmsg_copy_i(&f->hmf_msg, sub);
548       htsmsg_add_msg(dst, f->hmf_name, sub);
549       break;
550       
551     case HMF_STR:
552       htsmsg_add_str(dst, f->hmf_name, f->hmf_str);
553       break;
554
555     case HMF_S64:
556       htsmsg_add_s64(dst, f->hmf_name, f->hmf_s64);
557       break;
558
559     case HMF_BIN:
560       htsmsg_add_bin(dst, f->hmf_name, f->hmf_bin, f->hmf_binsize);
561       break;
562     }
563   }
564 }
565
566 htsmsg_t *
567 htsmsg_copy(htsmsg_t *src)
568 {
569   htsmsg_t *dst = src->hm_islist ? htsmsg_create_list() : htsmsg_create_map();
570   htsmsg_copy_i(src, dst);
571   return dst;
572 }