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