Diff between f41a6a9a41748c31719c01b2e557000a8d0aa3ec and 579f895300d2e599edde398f99f09f0bcdc7a10a

Changed Files

File Additions Deletions Status
gobex/gobex.c +68 -0 modified
gobex/gobex.h +1 -0 modified
unit/test-gobex.c +69 -0 modified

Full Patch

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