Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / gobex / gobex-apparam.c
1 /*
2  *
3  *  OBEX library with GLib integration
4  *
5  *  Copyright (C) 2012  Intel Corporation.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include "gobex-apparam.h"
32 #include "gobex-debug.h"
33
34 struct _GObexApparam {
35         GHashTable *tags;
36 };
37
38 struct apparam_tag {
39         guint8 id;
40         guint8 len;
41         union {
42                 /* Data is stored in network order */
43                 char string[0];
44                 guint8 data[0];
45                 guint8 u8;
46                 guint16 u16;
47                 guint32 u32;
48                 guint64 u64;
49         } value;
50 } __attribute__ ((packed));
51
52 static struct apparam_tag *tag_new(guint8 id, guint8 len, const void *data)
53 {
54         struct apparam_tag *tag;
55
56         tag = g_malloc0(2 + len);
57         tag->id = id;
58         tag->len = len;
59         memcpy(tag->value.data, data, len);
60
61         return tag;
62 }
63
64 static GObexApparam *g_obex_apparam_new(void)
65 {
66         GObexApparam *apparam;
67
68         apparam = g_new0(GObexApparam, 1);
69         apparam->tags = g_hash_table_new_full(g_direct_hash, g_direct_equal,
70                                                         NULL, g_free);
71
72         return apparam;
73 }
74
75 static struct apparam_tag *apparam_tag_decode(const void *data, gsize size,
76                                                         gsize *parsed)
77 {
78         struct apparam_tag *tag;
79         const guint8 *ptr = data;
80         guint8 id;
81         guint8 len;
82
83         if (size < 2)
84                 return NULL;
85
86         id = ptr[0];
87         len = ptr[1];
88
89         if (len > size - 2)
90                 return NULL;
91
92         tag = tag_new(id, len, ptr + 2);
93         if (tag == NULL)
94                 return NULL;
95
96         *parsed = 2 + tag->len;
97
98         return tag;
99 }
100
101 GObexApparam *g_obex_apparam_decode(const void *data, gsize size)
102 {
103         GObexApparam *apparam;
104         GHashTable *tags;
105         gsize count = 0;
106
107 #ifndef __TIZEN_PATCH__
108         if (size < 2)
109                 return NULL;
110 #endif /* __TIZEN_PATCH__ */
111
112         apparam = g_obex_apparam_new();
113
114         tags = apparam->tags;
115         while (count < size) {
116                 struct apparam_tag *tag;
117                 gsize parsed;
118                 guint id;
119
120                 tag = apparam_tag_decode(data + count, size - count, &parsed);
121                 if (tag == NULL)
122                         break;
123
124                 id = tag->id;
125                 g_hash_table_insert(tags, GUINT_TO_POINTER(id), tag);
126
127                 count += parsed;
128         }
129
130         if (count != size) {
131                 g_obex_apparam_free(apparam);
132                 return NULL;
133         }
134
135         return apparam;
136 }
137
138 static gssize tag_encode(struct apparam_tag *tag, void *buf, gsize len)
139 {
140         gsize count = 2 + tag->len;
141
142         if (len < count)
143                 return -ENOBUFS;
144
145         memcpy(buf, tag, count);
146
147         return count;
148 }
149
150 gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
151 {
152         gsize count = 0;
153         gssize ret;
154         GHashTableIter iter;
155         gpointer key, value;
156
157         g_hash_table_iter_init(&iter, apparam->tags);
158         while (g_hash_table_iter_next(&iter, &key, &value)) {
159                 struct apparam_tag *tag = value;
160
161                 ret = tag_encode(tag, buf + count, len - count);
162                 if (ret < 0)
163                         return ret;
164
165                 count += ret;
166         }
167
168         return count;
169 }
170
171 #ifdef __TIZEN_PATCH__
172 void g_obex_apparam_remove_all(GObexApparam *apparam)
173 {
174         g_hash_table_remove_all(apparam->tags);
175 }
176 #endif
177
178 GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
179                                                 const void *value, gsize len)
180 {
181         struct apparam_tag *tag;
182         guint uid = id;
183
184         if (apparam == NULL)
185                 apparam = g_obex_apparam_new();
186
187         tag = tag_new(id, len, value);
188         g_hash_table_replace(apparam->tags, GUINT_TO_POINTER(uid), tag);
189
190         return apparam;
191 }
192
193 GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
194                                                         guint8 value)
195 {
196         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
197
198         return g_obex_apparam_set_bytes(apparam, id, &value, 1);
199 }
200
201 GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
202                                                         guint16 value)
203 {
204         guint16 num = g_htons(value);
205
206         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
207
208         return g_obex_apparam_set_bytes(apparam, id, &num, 2);
209 }
210
211 GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
212                                                         guint32 value)
213 {
214         guint32 num = g_htonl(value);
215
216         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
217
218         return g_obex_apparam_set_bytes(apparam, id, &num, 4);
219 }
220
221 GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
222                                                         guint64 value)
223 {
224         guint64 num = GUINT64_TO_BE(value);
225
226         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %"
227                                                 G_GUINT64_FORMAT, id, value);
228
229         return g_obex_apparam_set_bytes(apparam, id, &num, 8);
230 }
231
232 GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
233                                                         const char *value)
234 {
235         gsize len;
236
237         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %s", id, value);
238
239         len = strlen(value) + 1;
240         if (len > G_MAXUINT8) {
241                 ((char *) value)[G_MAXUINT8 - 1] = '\0';
242                 len = G_MAXUINT8;
243         }
244
245         return g_obex_apparam_set_bytes(apparam, id, value, len);
246 }
247
248 static struct apparam_tag *g_obex_apparam_find_tag(GObexApparam *apparam,
249                                                                 guint id)
250 {
251         return g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
252 }
253
254 gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
255                                                         guint8 *dest)
256 {
257         struct apparam_tag *tag;
258
259         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
260
261         tag = g_obex_apparam_find_tag(apparam, id);
262         if (tag == NULL)
263                 return FALSE;
264
265         *dest = tag->value.u8;
266
267         g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
268
269         return TRUE;
270 }
271
272 gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
273                                                         guint16 *dest)
274 {
275         struct apparam_tag *tag;
276
277         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
278
279         tag = g_obex_apparam_find_tag(apparam, id);
280         if (tag == NULL)
281                 return FALSE;
282
283         if (tag->len < sizeof(*dest))
284                 return FALSE;
285
286         *dest = g_ntohs(tag->value.u16);
287
288         g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
289
290         return TRUE;
291 }
292
293 gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
294                                                         guint32 *dest)
295 {
296         struct apparam_tag *tag;
297
298         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
299
300         tag = g_obex_apparam_find_tag(apparam, id);
301         if (tag == NULL)
302                 return FALSE;
303
304         if (tag->len < sizeof(*dest))
305                 return FALSE;
306
307         *dest = g_ntohl(tag->value.u32);
308
309         g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
310
311         return TRUE;
312 }
313
314 gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
315                                                         guint64 *dest)
316 {
317         struct apparam_tag *tag;
318
319         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
320
321         tag = g_obex_apparam_find_tag(apparam, id);
322         if (tag == NULL)
323                 return FALSE;
324
325         if (tag->len < sizeof(*dest))
326                 return FALSE;
327
328         *dest = GUINT64_FROM_BE(tag->value.u64);
329
330         g_obex_debug(G_OBEX_DEBUG_APPARAM, "%" G_GUINT64_FORMAT, *dest);
331
332         return TRUE;
333 }
334
335 char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id)
336 {
337         struct apparam_tag *tag;
338         char *string;
339
340         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
341
342         tag = g_obex_apparam_find_tag(apparam, id);
343         if (tag == NULL)
344                 return NULL;
345
346         string = g_strndup(tag->value.string, tag->len);
347
348         g_obex_debug(G_OBEX_DEBUG_APPARAM, "%s", string);
349
350         return string;
351 }
352
353 gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
354                                         const guint8 **val, gsize *len)
355 {
356         struct apparam_tag *tag;
357
358         g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
359
360         tag = g_obex_apparam_find_tag(apparam, id);
361         if (tag == NULL)
362                 return FALSE;
363
364         *len = tag->len;
365         *val = tag->value.data;
366
367         return TRUE;
368 }
369
370 void g_obex_apparam_free(GObexApparam *apparam)
371 {
372         g_hash_table_unref(apparam->tags);
373         g_free(apparam);
374 }