gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UINT32) return FALSE; *val = header->v.u32; g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", *val); return TRUE; }
gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UNICODE) return FALSE; *str = header->v.string; g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", *str); return TRUE; }
gssize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) { guint8 *ptr = buf; guint16 u16; guint32 u32; gunichar2 *utf16; glong utf16_len; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (buf_len < header->hlen) return -1; ptr = put_bytes(ptr, &header->id, sizeof(header->id)); switch (G_OBEX_HDR_ENC(header->id)) { case G_OBEX_HDR_ENC_UNICODE: utf16_len = utf8_to_utf16(&utf16, header->v.string); if (utf16_len < 0 || (guint16) utf16_len > buf_len) return -1; g_assert_cmpuint(utf16_len + 3, ==, header->hlen); u16 = g_htons(utf16_len + 3); ptr = put_bytes(ptr, &u16, sizeof(u16)); ptr = put_bytes(ptr, utf16, utf16_len); g_free(utf16); break; case G_OBEX_HDR_ENC_BYTES: u16 = g_htons(header->hlen); ptr = put_bytes(ptr, &u16, sizeof(u16)); if (header->extdata) ptr = put_bytes(ptr, header->v.extdata, header->vlen); else ptr = put_bytes(ptr, header->v.data, header->vlen); break; case G_OBEX_HDR_ENC_UINT8: *ptr = header->v.u8; break; case G_OBEX_HDR_ENC_UINT32: u32 = g_htonl(header->v.u32); ptr = put_bytes(ptr, &u32, sizeof(u32)); break; default: g_assert_not_reached(); } return header->hlen; }
guint8 g_obex_header_get_id(GObexHeader *header) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x id 0x%02x", G_OBEX_HDR_ENC(header->id), header->id); return header->id; }
guint16 g_obex_header_get_length(GObexHeader *header) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x length %zu", G_OBEX_HDR_ENC(header->id), header->hlen); return header->hlen; }
gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val) { if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UINT32) return FALSE; *val = header->v.u32; return TRUE; }
gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val, gsize *len) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_BYTES) return FALSE; *len = header->vlen; if (header->extdata) *val = header->v.extdata; else *val = header->v.data; return TRUE; }
gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str) { if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UNICODE) return FALSE; *str = header->v.string; return TRUE; }
GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len) { GObexHeader *header; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_BYTES) return NULL; header = g_new0(GObexHeader, 1); header->id = id; header->vlen = len; header->hlen = len + 3; header->v.data = g_memdup(data, len); return header; }
GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val) { GObexHeader *header; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT32) return NULL; header = g_new0(GObexHeader, 1); header->id = id; header->vlen = 4; header->hlen = 5; header->v.u32 = val; g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", header->v.u32); return header; }
void g_obex_header_free(GObexHeader *header) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); switch (G_OBEX_HDR_ENC(header->id)) { case G_OBEX_HDR_ENC_UNICODE: g_free(header->v.string); break; case G_OBEX_HDR_ENC_BYTES: if (!header->extdata) g_free(header->v.data); break; case G_OBEX_HDR_ENC_UINT8: case G_OBEX_HDR_ENC_UINT32: break; default: g_assert_not_reached(); } g_free(header); }
GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str) { GObexHeader *header; gsize len; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UNICODE) return NULL; header = g_new0(GObexHeader, 1); header->id = id; len = g_utf8_strlen(str, -1); header->vlen = len; header->hlen = len == 0 ? 3 : 3 + ((len + 1) * 2); header->v.string = g_strdup(str); g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", header->v.string); return header; }
gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val, gsize *len) { if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_BYTES) return FALSE; *len = header->vlen; if (header->extdata) *val = header->v.extdata; else *val = header->v.data; return TRUE; }
GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val) { GObexHeader *header; if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT8) return NULL; header = g_new0(GObexHeader, 1); header->id = id; header->vlen = 1; header->hlen = 2; header->v.u8 = val; return header; }
GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val) { GObexHeader *header; if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT32) return NULL; header = g_new0(GObexHeader, 1); header->id = id; header->vlen = 4; header->hlen = 5; header->v.u32 = val; return header; }
GSList *g_obex_header_create_list(guint8 first_hdr_id, va_list args, gsize *total_len) { unsigned int id = first_hdr_id; GSList *l = NULL; g_obex_debug(G_OBEX_DEBUG_HEADER, ""); *total_len = 0; while (id != G_OBEX_HDR_INVALID) { GObexHeader *hdr; const char *str; const void *bytes; unsigned int val; gsize len; switch (G_OBEX_HDR_ENC(id)) { case G_OBEX_HDR_ENC_UNICODE: str = va_arg(args, const char *); hdr = g_obex_header_new_unicode(id, str); break; case G_OBEX_HDR_ENC_BYTES: bytes = va_arg(args, void *); len = va_arg(args, gsize); hdr = g_obex_header_new_bytes(id, bytes, len); break; case G_OBEX_HDR_ENC_UINT8: val = va_arg(args, unsigned int); hdr = g_obex_header_new_uint8(id, val); break; case G_OBEX_HDR_ENC_UINT32: val = va_arg(args, unsigned int); hdr = g_obex_header_new_uint32(id, val); break; default: g_assert_not_reached(); } l = g_slist_append(l, hdr); *total_len += hdr->hlen; id = va_arg(args, int); } return l; }
GObexHeader *g_obex_header_decode(const void *data, gsize len, GObexDataPolicy data_policy, gsize *parsed, GError **err) { GObexHeader *header; const guint8 *ptr = data; guint16 hdr_len; gsize str_len; GError *conv_err = NULL; if (len < 2) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Too short header in packet"); g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message); return NULL; } header = g_new0(GObexHeader, 1); ptr = get_bytes(&header->id, ptr, sizeof(header->id)); g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); switch (G_OBEX_HDR_ENC(header->id)) { case G_OBEX_HDR_ENC_UNICODE: if (len < 3) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Not enough data for unicode header (0x%02x)", header->id); goto failed; } ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len)); hdr_len = g_ntohs(hdr_len); if (hdr_len == 3) { header->v.string = g_strdup(""); header->vlen = 0; header->hlen = hdr_len; *parsed = hdr_len; break; } if (hdr_len > len || hdr_len < 5) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Invalid unicode header (0x%02x) length (%u)", header->id, hdr_len); goto failed; } header->v.string = g_convert((const char *) ptr, hdr_len - 5, "UTF8", "UTF16BE", NULL, &str_len, &conv_err); if (header->v.string == NULL) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Unicode conversion failed: %s", conv_err->message); g_error_free(conv_err); goto failed; } header->vlen = (gsize) str_len; header->hlen = hdr_len; *parsed = hdr_len; break; case G_OBEX_HDR_ENC_BYTES: if (len < 3) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Too short byte array header"); goto failed; } ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len)); hdr_len = g_ntohs(hdr_len); if (hdr_len > len) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Too long byte array header"); goto failed; } if (hdr_len < 3) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Too small byte array length"); goto failed; } header->vlen = hdr_len - 3; header->hlen = hdr_len; switch (data_policy) { case G_OBEX_DATA_COPY: header->v.data = g_memdup(ptr, header->vlen); break; case G_OBEX_DATA_REF: header->extdata = TRUE; header->v.extdata = ptr; break; default: g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS, "Invalid data policy"); goto failed; } *parsed = hdr_len; break; case G_OBEX_HDR_ENC_UINT8: header->vlen = 1; header->hlen = 2; header->v.u8 = *ptr; *parsed = 2; break; case G_OBEX_HDR_ENC_UINT32: if (len < 5) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Too short uint32 header"); goto failed; } header->vlen = 4; header->hlen = 5; ptr = get_bytes(&header->v.u32, ptr, sizeof(header->v.u32)); header->v.u32 = g_ntohl(header->v.u32); *parsed = 5; break; default: g_assert_not_reached(); } return header; failed: if (*err) g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message); g_obex_header_free(header); return NULL; }