diff --git a/gobex/gobex.c b/gobex/gobex.c
index fcf662d..7e6cf52 100644
--- a/gobex/gobex.c
+++ b/gobex/gobex.c
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 b49adfe..df95ede 100644
--- a/gobex/gobex.h
+++ b/gobex/gobex.h
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 480847d..e7c56f2 100644
--- a/unit/test-gobex.c
+++ b/unit/test-gobex.c
*/
#include <unistd.h>
+#include <string.h>
#include <gobex/gobex.h>
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;
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;