From 579f895300d2e599edde398f99f09f0bcdc7a10a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Jun 2011 13:51:45 +0300 Subject: [PATCH] gobex: Add header encoding support --- gobex/gobex.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ gobex/gobex.h | 1 + unit/test-gobex.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/gobex/gobex.c b/gobex/gobex.c index fcf662d0a..7e6cf52f7 100644 --- a/gobex/gobex.c +++ b/gobex/gobex.c @@ -58,6 +58,74 @@ struct _GObex { GQueue *req_queue; }; +static glong utf8_to_utf16(gunichar2 **utf16, const char *utf8) { + glong utf16_len; + int i; + + if (*utf8 == '\0') { + *utf16 = NULL; + return 0; + } + + *utf16 = g_utf8_to_utf16(utf8, -1, NULL, &utf16_len, NULL); + if (*utf16 == NULL) + return -1; + + /* g_utf8_to_utf16 produces host-byteorder UTF-16, + * but OBEX requires network byteorder (big endian) */ + for (i = 0; i < utf16_len; i++) + (*utf16)[i] = htobe16((*utf16)[i]); + + utf16_len = (utf16_len + 1) << 1; + + return utf16_len; +} + +size_t g_obex_header_encode(GObexHeader *header, void *hdr_ptr, size_t buf_len) +{ + uint8_t *buf = hdr_ptr; + uint16_t u16; + uint32_t u32; + gunichar2 *utf16; + glong utf16_len; + + if (buf_len < header->hlen) + return 0; + + buf[0] = header->id; + + switch (G_OBEX_HDR_TYPE(header->id)) { + case G_OBEX_HDR_TYPE_UNICODE: + utf16_len = utf8_to_utf16(&utf16, header->v.string); + if (utf16_len < 0 || (uint16_t) utf16_len > buf_len) + return 0; + u16 = htobe16(utf16_len + 3); + memcpy(&buf[1], &u16, sizeof(u16)); + memcpy(&buf[3], utf16, utf16_len); + g_free(utf16); + break; + case G_OBEX_HDR_TYPE_BYTES: + u16 = htobe16(header->hlen); + memcpy(&buf[1], &u16, sizeof(u16)); + if (header->extdata) + memcpy(&buf[3], header->v.extdata, header->vlen); + else + memcpy(&buf[3], header->v.data, header->vlen); + break; + case G_OBEX_HDR_TYPE_UINT8: + buf[1] = header->v.u8; + break; + case G_OBEX_HDR_TYPE_UINT32: + u32 = htobe32(header->v.u32); + memcpy(&buf[1], &u32, sizeof(u32)); + break; + default: + g_assert_not_reached(); + } + + return header->hlen; +} + GObexHeader *g_obex_header_parse(const void *data, size_t len, gboolean copy, size_t *parsed) { diff --git a/gobex/gobex.h b/gobex/gobex.h index b49adfeff..df95ede76 100644 --- a/gobex/gobex.h +++ b/gobex/gobex.h @@ -66,6 +66,7 @@ typedef struct _GObex GObex; typedef struct _GObexRequest GObexRequest; typedef struct _GObexHeader GObexHeader; +size_t g_obex_header_encode(GObexHeader *header, void *hdr_ptr, size_t buf_len); GObexHeader *g_obex_header_parse(const void *data, size_t len, gboolean copy, size_t *parsed); void g_obex_header_free(GObexHeader *header); diff --git a/unit/test-gobex.c b/unit/test-gobex.c index 480847db7..e7c56f2d1 100644 --- a/unit/test-gobex.c +++ b/unit/test-gobex.c @@ -20,6 +20,7 @@ */ #include +#include #include @@ -39,6 +40,66 @@ static GObex *create_gobex(int fd) return g_obex_new(io); } +static void dump_bytes(uint8_t *buf, size_t buf_len) +{ + size_t i; + + for (i = 0; i < buf_len; i++) + g_print("%02x ", buf[i]); + + g_print("\n"); +} + +static void parse_and_decode(uint8_t *buf, size_t buf_len) +{ + GObexHeader *header; + uint8_t encoded[1024]; + size_t len; + + header = g_obex_header_parse(buf, buf_len, FALSE, &len); + g_assert(header != NULL); + g_assert_cmpuint(len, ==, buf_len); + + len = g_obex_header_encode(header, encoded, sizeof(encoded)); + + g_obex_header_free(header); + + if (len != buf_len) + goto failed; + + if (memcmp(encoded, buf, len) != 0) + goto failed; + + return; + +failed: + g_print("\nIn: "); + dump_bytes(buf, buf_len); + g_print("Out: "); + dump_bytes(encoded, len); + g_assert(0); +} + +static void test_header_encode_connid(void) +{ + parse_and_decode(hdr_connid, sizeof(hdr_connid)); +} + +static void test_header_encode_name(void) +{ + parse_and_decode(hdr_name, sizeof(hdr_name)); +} + +static void test_header_encode_body(void) +{ + parse_and_decode(hdr_body, sizeof(hdr_body)); +} + +static void test_header_encode_actionid(void) +{ + parse_and_decode(hdr_actionid, sizeof(hdr_actionid)); +} + static void test_parse_header_connid(void) { GObexHeader *header; @@ -220,6 +281,14 @@ int main(int argc, char *argv[]) g_test_add_func("/gobex/test_parse_header_multi", test_parse_header_multi); + g_test_add_func("/gobex/test_header_encode_connid", + test_header_encode_connid); + g_test_add_func("/gobex/test_header_encode_name", + test_header_encode_name); + g_test_add_func("/gobex/test_header_encode_body", + test_header_encode_body); + g_test_add_func("/gobex/test_header_encode_connid", + test_header_encode_actionid); g_test_run(); return 0; -- 2.47.3