Merge pull request #4791 from jmarshallnz/playlist_settings
[vuplus_xbmc] / lib / libhts / htsmsg_binary.c
1 /*
2  *  Functions converting HTSMSGs to/from a simple binary format
3  *  Copyright (C) 2007 Andreas Ă–man
4  *
5  *  This program is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU General Public License
7  *  as published by the Free Software Foundation; either version 2
8  *  of the License, or (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, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #include <assert.h>
21 #include <sys/types.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "htsmsg_binary.h"
28
29 /*
30  *
31  */
32 static int
33 htsmsg_binary_des0(htsmsg_t *msg, const uint8_t *buf, size_t len)
34 {
35   unsigned type, namelen, datalen;
36   htsmsg_field_t *f;
37   htsmsg_t *sub;
38   char *n;
39   uint64_t u64;
40   int i;
41
42   while(len > 5) {
43
44     type    =  buf[0];
45     namelen =  buf[1];
46     datalen = (buf[2] << 24) |
47               (buf[3] << 16) |
48               (buf[4] << 8 ) |
49               (buf[5]      );
50     
51     buf += 6;
52     len -= 6;
53     
54     if(len < namelen + datalen)
55       return -1;
56
57     f = malloc(sizeof(htsmsg_field_t));
58     f->hmf_type  = type;
59
60     if(namelen > 0) {
61       n = malloc(namelen + 1);
62       memcpy(n, buf, namelen);
63       n[namelen] = 0;
64
65       buf += namelen;
66       len -= namelen;
67       f->hmf_flags = HMF_NAME_ALLOCED;
68
69     } else {
70       n = NULL;
71       f->hmf_flags = 0;
72     }
73
74     f->hmf_name  = n;
75
76     switch(type) {
77     case HMF_STR:
78       f->hmf_str = n = malloc(datalen + 1);
79       memcpy(n, buf, datalen);
80       n[datalen] = 0;
81       f->hmf_flags |= HMF_ALLOCED;
82       break;
83
84     case HMF_BIN:
85       f->hmf_bin = (const void *)buf;
86       f->hmf_binsize = datalen;
87       break;
88
89     case HMF_S64:
90       u64 = 0;
91       for(i = datalen - 1; i >= 0; i--)
92           u64 = (u64 << 8) | buf[i];
93       f->hmf_s64 = u64;
94       break;
95
96     case HMF_MAP:
97     case HMF_LIST:
98       sub = &f->hmf_msg;
99       TAILQ_INIT(&sub->hm_fields);
100       sub->hm_data = NULL;
101       if(htsmsg_binary_des0(sub, buf, datalen) < 0)
102         return -1;
103       break;
104
105     default:
106       free(n);
107       free(f);
108       return -1;
109     }
110
111     TAILQ_INSERT_TAIL(&msg->hm_fields, f, hmf_link);
112     buf += datalen;
113     len -= datalen;
114   }
115   return 0;
116 }
117
118
119
120 /*
121  *
122  */
123 htsmsg_t *
124 htsmsg_binary_deserialize(const void *data, size_t len, const void *buf)
125 {
126   htsmsg_t *msg = htsmsg_create_map();
127   msg->hm_data = buf;
128
129   if(htsmsg_binary_des0(msg, data, len) < 0) {
130     htsmsg_destroy(msg);
131     return NULL;
132   }
133   return msg;
134 }
135
136
137
138 /*
139  *
140  */
141 static size_t
142 htsmsg_binary_count(htsmsg_t *msg)
143 {
144   htsmsg_field_t *f;
145   size_t len = 0;
146   uint64_t u64;
147
148   TAILQ_FOREACH(f, &msg->hm_fields, hmf_link) {
149
150     len += 6;
151     len += f->hmf_name ? strlen(f->hmf_name) : 0;
152
153     switch(f->hmf_type) {
154     case HMF_MAP:
155     case HMF_LIST:
156       len += htsmsg_binary_count(&f->hmf_msg);
157       break;
158
159     case HMF_STR:
160       len += strlen(f->hmf_str);
161       break;
162
163     case HMF_BIN:
164       len += f->hmf_binsize;
165       break;
166
167     case HMF_S64:
168       u64 = f->hmf_s64;
169       while(u64 != 0) {
170         len++;
171         u64 = u64 >> 8;
172       }
173       break;
174     }
175   }
176   return len;
177 }
178
179
180 /*
181  *
182  */
183 static void
184 htsmsg_binary_write(htsmsg_t *msg, uint8_t *ptr)
185 {
186   htsmsg_field_t *f;
187   uint64_t u64;
188   int l, i, namelen;
189
190   TAILQ_FOREACH(f, &msg->hm_fields, hmf_link) {
191     namelen = f->hmf_name ? strlen(f->hmf_name) : 0;
192     *ptr++ = f->hmf_type;
193     *ptr++ = namelen;
194
195     switch(f->hmf_type) {
196     case HMF_MAP:
197     case HMF_LIST:
198       l = htsmsg_binary_count(&f->hmf_msg);
199       break;
200
201     case HMF_STR:
202       l = strlen(f->hmf_str);
203       break;
204
205     case HMF_BIN:
206       l = f->hmf_binsize;
207       break;
208
209     case HMF_S64:
210       u64 = f->hmf_s64;
211       l = 0;
212       while(u64 != 0) {
213         l++;
214         u64 = u64 >> 8;
215       }
216       break;
217     default:
218       abort();
219     }
220
221
222     *ptr++ = l >> 24;
223     *ptr++ = l >> 16;
224     *ptr++ = l >> 8;
225     *ptr++ = l;
226
227     if(namelen > 0) {
228       memcpy(ptr, f->hmf_name, namelen);
229       ptr += namelen;
230     }
231
232     switch(f->hmf_type) {
233     case HMF_MAP:
234     case HMF_LIST:
235       htsmsg_binary_write(&f->hmf_msg, ptr);
236       break;
237
238     case HMF_STR:
239       memcpy(ptr, f->hmf_str, l);
240       break;
241
242     case HMF_BIN:
243       memcpy(ptr, f->hmf_bin, l);
244       break;
245
246     case HMF_S64:
247       u64 = f->hmf_s64;
248       for(i = 0; i < l; i++) {
249         ptr[i] = (uint8_t)(u64 & 0xFF);
250         u64 = u64 >> 8;
251       }
252       break;
253     }
254     ptr += l;
255   }
256 }
257
258
259 /*
260  *
261  */
262 int
263 htsmsg_binary_serialize(htsmsg_t *msg, void **datap, size_t *lenp, int maxlen)
264 {
265   size_t len;
266   uint8_t *data;
267
268   len = htsmsg_binary_count(msg);
269   if(len + 4 > (size_t)maxlen)
270     return -1;
271
272   data = malloc(len + 4);
273
274   data[0] = len >> 24;
275   data[1] = len >> 16;
276   data[2] = len >> 8;
277   data[3] = len;
278
279   htsmsg_binary_write(msg, data + 4);
280   *datap = data;
281   *lenp  = len + 4;
282   return 0;
283 }