/src/bluez/gobex/gobex-header.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * |
4 | | * OBEX library with GLib integration |
5 | | * |
6 | | * Copyright (C) 2011 Intel Corporation. All rights reserved. |
7 | | * |
8 | | */ |
9 | | |
10 | | #ifdef HAVE_CONFIG_H |
11 | | #include <config.h> |
12 | | #endif |
13 | | |
14 | | #include <string.h> |
15 | | |
16 | | #include "gobex-header.h" |
17 | | #include "gobex-debug.h" |
18 | | #include "src/shared/util.h" |
19 | | |
20 | | /* Header types */ |
21 | 4.68k | #define G_OBEX_HDR_ENC_UNICODE (0 << 6) |
22 | 1.25k | #define G_OBEX_HDR_ENC_BYTES (1 << 6) |
23 | 3.04k | #define G_OBEX_HDR_ENC_UINT8 (2 << 6) |
24 | 4.87k | #define G_OBEX_HDR_ENC_UINT32 (3 << 6) |
25 | | |
26 | 12.4k | #define G_OBEX_HDR_ENC(id) ((id) & 0xc0) |
27 | | |
28 | | struct _GObexHeader { |
29 | | guint8 id; |
30 | | gboolean extdata; |
31 | | gsize vlen; /* Length of value */ |
32 | | gsize hlen; /* Length of full encoded header */ |
33 | | union { |
34 | | char *string; /* UTF-8 converted from UTF-16 */ |
35 | | guint8 *data; /* Own buffer */ |
36 | | const guint8 *extdata; /* Reference to external buffer */ |
37 | | guint8 u8; |
38 | | guint32 u32; |
39 | | } v; |
40 | | }; |
41 | | |
42 | 159 | static glong utf8_to_utf16(gunichar2 **utf16, const char *utf8) { |
43 | 159 | glong utf16_len; |
44 | 159 | int i; |
45 | | |
46 | 159 | if (*utf8 == '\0') { |
47 | 93 | *utf16 = NULL; |
48 | 93 | return 0; |
49 | 93 | } |
50 | | |
51 | 66 | *utf16 = g_utf8_to_utf16(utf8, -1, NULL, &utf16_len, NULL); |
52 | 66 | if (*utf16 == NULL) |
53 | 0 | return -1; |
54 | | |
55 | | /* g_utf8_to_utf16 produces host-byteorder UTF-16, |
56 | | * but OBEX requires network byteorder (big endian) */ |
57 | 705 | for (i = 0; i < utf16_len; i++) |
58 | 639 | (*utf16)[i] = g_htons((*utf16)[i]); |
59 | | |
60 | 66 | utf16_len = (utf16_len + 1) << 1; |
61 | | |
62 | 66 | return utf16_len; |
63 | 66 | } |
64 | | |
65 | | static glong utf16_to_utf8(char **utf8, const gunichar2 *utf16, guint16 len, |
66 | | GError **err) |
67 | 1.69k | { |
68 | 1.69k | glong utf8_len; |
69 | 1.69k | guint16 utf16_len, i; |
70 | 1.69k | gunichar2 *buf; |
71 | | |
72 | 1.69k | if (*utf16 == '\0') { |
73 | 172 | *utf8 = NULL; |
74 | 172 | return 0; |
75 | 172 | } |
76 | | |
77 | | /* OBEX requires network byteorder (big endian) UTF-16 |
78 | | * but g_utf16_to_utf8 expects host-byteorder UTF-8 |
79 | | */ |
80 | 1.51k | utf16_len = len / sizeof(gunichar2); |
81 | 1.51k | buf = alloca(sizeof(gunichar2) * (utf16_len + 1)); |
82 | 267k | for (i = 0; i < utf16_len; i++) |
83 | 266k | (buf)[i] = g_ntohs(utf16[i]); |
84 | 1.51k | buf[utf16_len] = '\0'; |
85 | | |
86 | 1.51k | *utf8 = g_utf16_to_utf8(buf, -1, NULL, &utf8_len, err); |
87 | 1.51k | if (*utf8 == NULL) |
88 | 5 | utf8_len = -1; |
89 | | |
90 | 1.51k | return utf8_len; |
91 | 1.69k | } |
92 | | |
93 | | static guint8 *put_bytes(guint8 *to, const void *from, gsize count) |
94 | 1.17k | { |
95 | 1.17k | memcpy(to, from, count); |
96 | 1.17k | return (to + count); |
97 | 1.17k | } |
98 | | |
99 | | static const guint8 *get_bytes(void *to, const guint8 *from, gsize count) |
100 | 10.4k | { |
101 | 10.4k | memcpy(to, from, count); |
102 | 10.4k | return (from + count); |
103 | 10.4k | } |
104 | | |
105 | | gssize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) |
106 | 540 | { |
107 | 540 | guint8 *ptr = buf; |
108 | 540 | guint16 u16; |
109 | 540 | guint32 u32; |
110 | 540 | gunichar2 *utf16; |
111 | 540 | glong utf16_len; |
112 | | |
113 | 540 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", |
114 | 540 | G_OBEX_HDR_ENC(header->id)); |
115 | | |
116 | 540 | if (buf_len < header->hlen) |
117 | 0 | return -1; |
118 | | |
119 | 540 | ptr = put_bytes(ptr, &header->id, sizeof(header->id)); |
120 | | |
121 | 540 | switch (G_OBEX_HDR_ENC(header->id)) { |
122 | 159 | case G_OBEX_HDR_ENC_UNICODE: |
123 | 159 | utf16_len = utf8_to_utf16(&utf16, header->v.string); |
124 | 159 | if (utf16_len < 0 || (guint16) utf16_len > buf_len) |
125 | 0 | return -1; |
126 | 159 | g_assert_cmpuint(utf16_len + 3, ==, header->hlen); |
127 | 159 | u16 = g_htons(utf16_len + 3); |
128 | 159 | ptr = put_bytes(ptr, &u16, sizeof(u16)); |
129 | 159 | put_bytes(ptr, utf16, utf16_len); |
130 | 159 | g_free(utf16); |
131 | 159 | break; |
132 | 75 | case G_OBEX_HDR_ENC_BYTES: |
133 | 75 | u16 = g_htons(header->hlen); |
134 | 75 | ptr = put_bytes(ptr, &u16, sizeof(u16)); |
135 | 75 | if (header->extdata) |
136 | 75 | put_bytes(ptr, header->v.extdata, header->vlen); |
137 | 0 | else |
138 | 0 | put_bytes(ptr, header->v.data, header->vlen); |
139 | 75 | break; |
140 | 143 | case G_OBEX_HDR_ENC_UINT8: |
141 | 143 | *ptr = header->v.u8; |
142 | 143 | break; |
143 | 163 | case G_OBEX_HDR_ENC_UINT32: |
144 | 163 | u32 = g_htonl(header->v.u32); |
145 | 163 | put_bytes(ptr, &u32, sizeof(u32)); |
146 | 163 | break; |
147 | 0 | default: |
148 | 0 | g_assert_not_reached(); |
149 | 540 | } |
150 | | |
151 | 540 | return header->hlen; |
152 | 540 | } |
153 | | |
154 | | GObexHeader *g_obex_header_decode(const void *data, gsize len, |
155 | | GObexDataPolicy data_policy, gsize *parsed, |
156 | | GError **err) |
157 | 5.94k | { |
158 | 5.94k | GObexHeader *header; |
159 | 5.94k | const guint8 *ptr = data; |
160 | 5.94k | guint16 hdr_len; |
161 | 5.94k | glong str_len; |
162 | 5.94k | GError *conv_err = NULL; |
163 | | |
164 | 5.94k | if (len < 2) { |
165 | 5 | if (!err) |
166 | 0 | return NULL; |
167 | 5 | g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, |
168 | 5 | "Too short header in packet"); |
169 | 5 | g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message); |
170 | 5 | return NULL; |
171 | 5 | } |
172 | | |
173 | 5.93k | header = g_new0(GObexHeader, 1); |
174 | | |
175 | 5.93k | ptr = get_bytes(&header->id, ptr, sizeof(header->id)); |
176 | | |
177 | 5.93k | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", |
178 | 5.93k | G_OBEX_HDR_ENC(header->id)); |
179 | | |
180 | 5.93k | switch (G_OBEX_HDR_ENC(header->id)) { |
181 | 2.26k | case G_OBEX_HDR_ENC_UNICODE: |
182 | 2.26k | if (len < 3) { |
183 | 1 | g_set_error(err, G_OBEX_ERROR, |
184 | 1 | G_OBEX_ERROR_PARSE_ERROR, |
185 | 1 | "Not enough data for unicode header (0x%02x)", |
186 | 1 | header->id); |
187 | 1 | goto failed; |
188 | 1 | } |
189 | 2.26k | ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len)); |
190 | 2.26k | hdr_len = g_ntohs(hdr_len); |
191 | | |
192 | 2.26k | if (hdr_len == 3) { |
193 | 534 | header->v.string = g_strdup(""); |
194 | 534 | header->vlen = 0; |
195 | 534 | header->hlen = hdr_len; |
196 | 534 | *parsed = hdr_len; |
197 | 534 | break; |
198 | 534 | } |
199 | | |
200 | 1.72k | if (hdr_len > len || hdr_len < 5) { |
201 | 37 | g_set_error(err, G_OBEX_ERROR, |
202 | 37 | G_OBEX_ERROR_PARSE_ERROR, |
203 | 37 | "Invalid unicode header (0x%02x) length (%u)", |
204 | 37 | header->id, hdr_len); |
205 | 37 | goto failed; |
206 | 37 | } |
207 | | |
208 | 1.69k | str_len = utf16_to_utf8(&header->v.string, |
209 | 1.69k | (const gunichar2 *) ptr, |
210 | 1.69k | hdr_len - 5, |
211 | 1.69k | &conv_err); |
212 | 1.69k | if (str_len < 0) { |
213 | 5 | g_set_error(err, G_OBEX_ERROR, |
214 | 5 | G_OBEX_ERROR_PARSE_ERROR, |
215 | 5 | "UTF16 to UTF8 conversion failed: %s", |
216 | 5 | conv_err->message); |
217 | 5 | g_error_free(conv_err); |
218 | 5 | goto failed; |
219 | 5 | } |
220 | | |
221 | 1.68k | header->vlen = (gsize) str_len; |
222 | 1.68k | header->hlen = hdr_len; |
223 | | |
224 | 1.68k | *parsed = hdr_len; |
225 | | |
226 | 1.68k | break; |
227 | 591 | case G_OBEX_HDR_ENC_BYTES: |
228 | 591 | if (len < 3) { |
229 | 2 | g_set_error(err, G_OBEX_ERROR, |
230 | 2 | G_OBEX_ERROR_PARSE_ERROR, |
231 | 2 | "Too short byte array header"); |
232 | 2 | goto failed; |
233 | 2 | } |
234 | 589 | ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len)); |
235 | 589 | hdr_len = g_ntohs(hdr_len); |
236 | 589 | if (hdr_len > len) { |
237 | 17 | g_set_error(err, G_OBEX_ERROR, |
238 | 17 | G_OBEX_ERROR_PARSE_ERROR, |
239 | 17 | "Too long byte array header"); |
240 | 17 | goto failed; |
241 | 17 | } |
242 | | |
243 | 572 | if (hdr_len < 3) { |
244 | 9 | g_set_error(err, G_OBEX_ERROR, |
245 | 9 | G_OBEX_ERROR_PARSE_ERROR, |
246 | 9 | "Too small byte array length"); |
247 | 9 | goto failed; |
248 | 9 | } |
249 | | |
250 | 563 | header->vlen = hdr_len - 3; |
251 | 563 | header->hlen = hdr_len; |
252 | | |
253 | 563 | switch (data_policy) { |
254 | 0 | case G_OBEX_DATA_COPY: |
255 | 0 | header->v.data = util_memdup(ptr, header->vlen); |
256 | 0 | break; |
257 | 563 | case G_OBEX_DATA_REF: |
258 | 563 | header->extdata = TRUE; |
259 | 563 | header->v.extdata = ptr; |
260 | 563 | break; |
261 | 0 | case G_OBEX_DATA_INHERIT: |
262 | 0 | default: |
263 | 0 | g_set_error(err, G_OBEX_ERROR, |
264 | 0 | G_OBEX_ERROR_INVALID_ARGS, |
265 | 0 | "Invalid data policy"); |
266 | 0 | goto failed; |
267 | 563 | } |
268 | | |
269 | 563 | *parsed = hdr_len; |
270 | | |
271 | 563 | break; |
272 | 1.45k | case G_OBEX_HDR_ENC_UINT8: |
273 | 1.45k | header->vlen = 1; |
274 | 1.45k | header->hlen = 2; |
275 | 1.45k | header->v.u8 = *ptr; |
276 | 1.45k | *parsed = 2; |
277 | 1.45k | break; |
278 | 1.63k | case G_OBEX_HDR_ENC_UINT32: |
279 | 1.63k | if (len < 5) { |
280 | 3 | g_set_error(err, G_OBEX_ERROR, |
281 | 3 | G_OBEX_ERROR_PARSE_ERROR, |
282 | 3 | "Too short uint32 header"); |
283 | 3 | goto failed; |
284 | 3 | } |
285 | 1.62k | header->vlen = 4; |
286 | 1.62k | header->hlen = 5; |
287 | 1.62k | get_bytes(&header->v.u32, ptr, sizeof(header->v.u32)); |
288 | 1.62k | header->v.u32 = g_ntohl(header->v.u32); |
289 | 1.62k | *parsed = 5; |
290 | 1.62k | break; |
291 | 0 | default: |
292 | 0 | g_assert_not_reached(); |
293 | 5.93k | } |
294 | | |
295 | 5.86k | return header; |
296 | | |
297 | 74 | failed: |
298 | 74 | if (*err) |
299 | 74 | g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message); |
300 | 74 | g_obex_header_free(header); |
301 | 74 | return NULL; |
302 | 5.93k | } |
303 | | |
304 | | void g_obex_header_free(GObexHeader *header) |
305 | 5.93k | { |
306 | 5.93k | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", |
307 | 5.93k | G_OBEX_HDR_ENC(header->id)); |
308 | | |
309 | 5.93k | switch (G_OBEX_HDR_ENC(header->id)) { |
310 | 2.26k | case G_OBEX_HDR_ENC_UNICODE: |
311 | 2.26k | g_free(header->v.string); |
312 | 2.26k | break; |
313 | 591 | case G_OBEX_HDR_ENC_BYTES: |
314 | 591 | if (!header->extdata) |
315 | 28 | free(header->v.data); |
316 | 591 | break; |
317 | 1.45k | case G_OBEX_HDR_ENC_UINT8: |
318 | 3.08k | case G_OBEX_HDR_ENC_UINT32: |
319 | 3.08k | break; |
320 | 0 | default: |
321 | 0 | g_assert_not_reached(); |
322 | 5.93k | } |
323 | | |
324 | 5.93k | g_free(header); |
325 | 5.93k | } |
326 | | |
327 | | gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str) |
328 | 0 | { |
329 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", |
330 | 0 | G_OBEX_HDR_ENC(header->id)); |
331 | |
|
332 | 0 | if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UNICODE) |
333 | 0 | return FALSE; |
334 | | |
335 | 0 | *str = header->v.string; |
336 | |
|
337 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", *str); |
338 | |
|
339 | 0 | return TRUE; |
340 | 0 | } |
341 | | |
342 | | gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val, |
343 | | gsize *len) |
344 | 0 | { |
345 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", |
346 | 0 | G_OBEX_HDR_ENC(header->id)); |
347 | |
|
348 | 0 | if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_BYTES) |
349 | 0 | return FALSE; |
350 | | |
351 | 0 | *len = header->vlen; |
352 | |
|
353 | 0 | if (header->extdata) |
354 | 0 | *val = header->v.extdata; |
355 | 0 | else |
356 | 0 | *val = header->v.data; |
357 | |
|
358 | 0 | return TRUE; |
359 | 0 | } |
360 | | |
361 | | GObexApparam *g_obex_header_get_apparam(GObexHeader *header) |
362 | 0 | { |
363 | 0 | gboolean ret; |
364 | 0 | const guint8 *val; |
365 | 0 | gsize len; |
366 | |
|
367 | 0 | ret = g_obex_header_get_bytes(header, &val, &len); |
368 | 0 | if (!ret) |
369 | 0 | return NULL; |
370 | | |
371 | 0 | return g_obex_apparam_decode(val, len); |
372 | 0 | } |
373 | | |
374 | | gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val) |
375 | 0 | { |
376 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", |
377 | 0 | G_OBEX_HDR_ENC(header->id)); |
378 | |
|
379 | 0 | if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UINT8) |
380 | 0 | return FALSE; |
381 | | |
382 | 0 | *val = header->v.u8; |
383 | |
|
384 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", *val); |
385 | |
|
386 | 0 | return TRUE; |
387 | 0 | } |
388 | | |
389 | | gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val) |
390 | 0 | { |
391 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", |
392 | 0 | G_OBEX_HDR_ENC(header->id)); |
393 | |
|
394 | 0 | if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UINT32) |
395 | 0 | return FALSE; |
396 | | |
397 | 0 | *val = header->v.u32; |
398 | |
|
399 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", *val); |
400 | |
|
401 | 0 | return TRUE; |
402 | 0 | } |
403 | | |
404 | | GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str) |
405 | 0 | { |
406 | 0 | GObexHeader *header; |
407 | 0 | gsize len; |
408 | |
|
409 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); |
410 | |
|
411 | 0 | if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UNICODE) |
412 | 0 | return NULL; |
413 | | |
414 | 0 | header = g_new0(GObexHeader, 1); |
415 | |
|
416 | 0 | header->id = id; |
417 | |
|
418 | 0 | len = g_utf8_strlen(str, -1); |
419 | |
|
420 | 0 | header->vlen = len; |
421 | 0 | header->hlen = len == 0 ? 3 : 3 + ((len + 1) * 2); |
422 | 0 | header->v.string = g_strdup(str); |
423 | |
|
424 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", header->v.string); |
425 | |
|
426 | 0 | return header; |
427 | 0 | } |
428 | | |
429 | | GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len) |
430 | 0 | { |
431 | 0 | GObexHeader *header; |
432 | |
|
433 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); |
434 | |
|
435 | 0 | if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_BYTES) |
436 | 0 | return NULL; |
437 | | |
438 | 0 | header = g_new0(GObexHeader, 1); |
439 | |
|
440 | 0 | header->id = id; |
441 | 0 | header->vlen = len; |
442 | 0 | header->hlen = len + 3; |
443 | 0 | header->v.data = util_memdup(data, len); |
444 | |
|
445 | 0 | return header; |
446 | 0 | } |
447 | | |
448 | | GObexHeader *g_obex_header_new_tag(guint8 id, GObexApparam *apparam) |
449 | 0 | { |
450 | 0 | guint8 buf[1024]; |
451 | 0 | gssize len; |
452 | |
|
453 | 0 | len = g_obex_apparam_encode(apparam, buf, sizeof(buf)); |
454 | 0 | if (len < 0) |
455 | 0 | return NULL; |
456 | | |
457 | 0 | return g_obex_header_new_bytes(id, buf, len); |
458 | 0 | } |
459 | | |
460 | | GObexHeader *g_obex_header_new_apparam(GObexApparam *apparam) |
461 | 0 | { |
462 | 0 | return g_obex_header_new_tag(G_OBEX_HDR_APPARAM, apparam); |
463 | 0 | } |
464 | | |
465 | | GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val) |
466 | 0 | { |
467 | 0 | GObexHeader *header; |
468 | |
|
469 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); |
470 | |
|
471 | 0 | if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT8) |
472 | 0 | return NULL; |
473 | | |
474 | 0 | header = g_new0(GObexHeader, 1); |
475 | |
|
476 | 0 | header->id = id; |
477 | 0 | header->vlen = 1; |
478 | 0 | header->hlen = 2; |
479 | 0 | header->v.u8 = val; |
480 | |
|
481 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", header->v.u8); |
482 | |
|
483 | 0 | return header; |
484 | 0 | } |
485 | | |
486 | | GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val) |
487 | 0 | { |
488 | 0 | GObexHeader *header; |
489 | |
|
490 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); |
491 | |
|
492 | 0 | if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT32) |
493 | 0 | return NULL; |
494 | | |
495 | 0 | header = g_new0(GObexHeader, 1); |
496 | |
|
497 | 0 | header->id = id; |
498 | 0 | header->vlen = 4; |
499 | 0 | header->hlen = 5; |
500 | 0 | header->v.u32 = val; |
501 | |
|
502 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", header->v.u32); |
503 | |
|
504 | 0 | return header; |
505 | 0 | } |
506 | | |
507 | | guint8 g_obex_header_get_id(GObexHeader *header) |
508 | 0 | { |
509 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x id 0x%02x", |
510 | 0 | G_OBEX_HDR_ENC(header->id), header->id); |
511 | |
|
512 | 0 | return header->id; |
513 | 0 | } |
514 | | |
515 | | guint16 g_obex_header_get_length(GObexHeader *header) |
516 | 0 | { |
517 | 0 | g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x length %zu", |
518 | 0 | G_OBEX_HDR_ENC(header->id), header->hlen); |
519 | |
|
520 | 0 | return header->hlen; |
521 | 0 | } |
522 | | |
523 | | GSList *g_obex_header_create_list(guint8 first_hdr_id, va_list args, |
524 | | gsize *total_len) |
525 | 142 | { |
526 | 142 | unsigned int id = first_hdr_id; |
527 | 142 | GSList *l = NULL; |
528 | | |
529 | 142 | g_obex_debug(G_OBEX_DEBUG_HEADER, ""); |
530 | | |
531 | 142 | *total_len = 0; |
532 | | |
533 | 142 | while (id != G_OBEX_HDR_INVALID) { |
534 | 0 | GObexHeader *hdr; |
535 | 0 | const char *str; |
536 | 0 | const void *bytes; |
537 | 0 | unsigned int val; |
538 | 0 | gsize len; |
539 | |
|
540 | 0 | switch (G_OBEX_HDR_ENC(id)) { |
541 | 0 | case G_OBEX_HDR_ENC_UNICODE: |
542 | 0 | str = va_arg(args, const char *); |
543 | 0 | hdr = g_obex_header_new_unicode(id, str); |
544 | 0 | break; |
545 | 0 | case G_OBEX_HDR_ENC_BYTES: |
546 | 0 | bytes = va_arg(args, void *); |
547 | 0 | len = va_arg(args, gsize); |
548 | 0 | hdr = g_obex_header_new_bytes(id, bytes, len); |
549 | 0 | break; |
550 | 0 | case G_OBEX_HDR_ENC_UINT8: |
551 | 0 | val = va_arg(args, unsigned int); |
552 | 0 | hdr = g_obex_header_new_uint8(id, val); |
553 | 0 | break; |
554 | 0 | case G_OBEX_HDR_ENC_UINT32: |
555 | 0 | val = va_arg(args, unsigned int); |
556 | 0 | hdr = g_obex_header_new_uint32(id, val); |
557 | 0 | break; |
558 | 0 | default: |
559 | 0 | g_assert_not_reached(); |
560 | 0 | } |
561 | | |
562 | 0 | l = g_slist_append(l, hdr); |
563 | 0 | *total_len += hdr->hlen; |
564 | 0 | id = va_arg(args, int); |
565 | 0 | } |
566 | | |
567 | 142 | return l; |
568 | 142 | } |