Diff between f9e824c0e6495ee16903c0033f7cd4a2c7228dea and b105277b9726903f1eea33d6b0046e832406d539

Changed Files

File Additions Deletions Status
gobex/gobex-defs.h +31 -0 added
gobex/gobex-header.c +376 -0 added
gobex/gobex-header.h +78 -0 added
gobex/gobex-packet.c +261 -0 added
gobex/gobex-packet.h +59 -0 added
gobex/gobex.c +1 -576 modified
gobex/gobex.h +1 -74 modified
unit/test-gobex.c +1 -0 modified

Full Patch

diff --git a/gobex/gobex-defs.h b/gobex/gobex-defs.h
new file mode 100644
index 0000000..ad8b046
--- /dev/null
+++ b/gobex/gobex-defs.h
@@ -0,0 +1,31 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_DEFS_H
+#define __GOBEX_DEFS_H
+
+typedef enum {
+	G_OBEX_DATA_INHERIT,
+	G_OBEX_DATA_COPY,
+	G_OBEX_DATA_REF,
+} GObexDataPolicy;
+
+#endif /* __GOBEX_DEFS_H */
diff --git a/gobex/gobex-header.c b/gobex/gobex-header.c
new file mode 100644
index 0000000..5b0a502
--- /dev/null
+++ b/gobex/gobex-header.c
@@ -0,0 +1,376 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <string.h>
+
+#include "gobex-header.h"
+
+/* Header types */
+#define G_OBEX_HDR_TYPE_UNICODE	(0 << 6)
+#define G_OBEX_HDR_TYPE_BYTES	(1 << 6)
+#define G_OBEX_HDR_TYPE_UINT8	(2 << 6)
+#define G_OBEX_HDR_TYPE_UINT32	(3 << 6)
+
+#define G_OBEX_HDR_TYPE(id)	((id) & 0xc0)
+
+struct _GObexHeader {
+	guint8 id;
+	gboolean extdata;
+	size_t vlen;			/* Length of value */
+	size_t hlen;			/* Length of full encoded header */
+	union {
+		char *string;		/* UTF-8 converted from UTF-16 */
+		guint8 *data;		/* Own buffer */
+		const guint8 *extdata;	/* Reference to external buffer */
+		guint8 u8;
+		guint32 u32;
+	} v;
+};
+
+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] = g_htons((*utf16)[i]);
+
+	utf16_len = (utf16_len + 1) << 1;
+
+	return utf16_len;
+}
+
+static guint8 *put_bytes(guint8 *to, const void *from, size_t count)
+{
+	memcpy(to, from, count);
+	return (to + count);
+}
+
+static const guint8 *get_bytes(void *to, const guint8 *from, size_t count)
+{
+	memcpy(to, from, count);
+	return (from + count);
+}
+
+size_t g_obex_header_encode(GObexHeader *header, void *buf, size_t buf_len)
+{
+	guint8 *ptr = buf;
+	guint16 u16;
+	guint32 u32;
+	gunichar2 *utf16;
+	glong utf16_len;
+
+	if (buf_len < header->hlen)
+		return 0;
+
+	ptr = put_bytes(ptr, &header->id, sizeof(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 || (guint16) utf16_len > buf_len)
+			return 0;
+		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_TYPE_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_TYPE_UINT8:
+		*ptr = header->v.u8;
+		break;
+	case G_OBEX_HDR_TYPE_UINT32:
+		u32 = g_htonl(header->v.u32);
+		ptr = put_bytes(ptr, &u32, sizeof(u32));
+		break;
+	default:
+		g_assert_not_reached();
+	}
+
+	return header->hlen;
+}
+
+GObexHeader *g_obex_header_decode(const void *data, size_t len,
+				GObexDataPolicy data_policy, size_t *parsed)
+{
+	GObexHeader *header;
+	const guint8 *ptr = data;
+	guint16 hdr_len;
+	size_t str_len;
+
+	if (len < 2)
+		return NULL;
+
+	header = g_new0(GObexHeader, 1);
+
+	ptr = get_bytes(&header->id, ptr, sizeof(header->id));
+
+	switch (G_OBEX_HDR_TYPE(header->id)) {
+	case G_OBEX_HDR_TYPE_UNICODE:
+		if (len < 3)
+			goto failed;
+		ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
+		hdr_len = g_ntohs(hdr_len);
+		if (hdr_len > len || hdr_len < 5)
+			goto failed;
+
+		header->v.string = g_convert((const char *) ptr, hdr_len - 5,
+						"UTF8", "UTF16BE",
+						NULL, &str_len, NULL);
+		if (header->v.string == NULL)
+			goto failed;
+
+		header->vlen = (size_t) str_len;
+		header->hlen = hdr_len;
+
+		*parsed = hdr_len;
+
+		break;
+	case G_OBEX_HDR_TYPE_BYTES:
+		if (len < 3)
+			goto failed;
+		ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
+		hdr_len = g_ntohs(hdr_len);
+		if (hdr_len > len)
+			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:
+			goto failed;
+		}
+
+		*parsed = hdr_len;
+
+		break;
+	case G_OBEX_HDR_TYPE_UINT8:
+		header->vlen = 1;
+		header->hlen = 2;
+		header->v.u8 = *ptr;
+		*parsed = 2;
+		break;
+	case G_OBEX_HDR_TYPE_UINT32:
+		if (len < 5)
+			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:
+	g_obex_header_free(header);
+	return NULL;
+}
+
+void g_obex_header_free(GObexHeader *header)
+{
+	switch (G_OBEX_HDR_TYPE(header->id)) {
+	case G_OBEX_HDR_TYPE_UNICODE:
+		g_free(header->v.string);
+		break;
+	case G_OBEX_HDR_TYPE_BYTES:
+		if (!header->extdata)
+			g_free(header->v.data);
+		break;
+	case G_OBEX_HDR_TYPE_UINT8:
+	case G_OBEX_HDR_TYPE_UINT32:
+		break;
+	default:
+		g_assert_not_reached();
+	}
+
+	g_free(header);
+}
+
+gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str)
+{
+	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UNICODE)
+		return FALSE;
+
+	*str = header->v.string;
+
+	return TRUE;
+}
+
+gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
+								size_t *len)
+{
+	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_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_uint8(GObexHeader *header, guint8 *val)
+{
+	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT8)
+		return FALSE;
+
+	*val = header->v.u8;
+
+	return TRUE;
+}
+
+gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val)
+{
+	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT32)
+		return FALSE;
+
+	*val = header->v.u32;
+
+	return TRUE;
+}
+
+GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str)
+{
+	GObexHeader *header;
+	size_t len;
+
+	if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UNICODE)
+		return NULL;
+
+	header = g_new0(GObexHeader, 1);
+
+	header->id = id;
+
+	len = g_utf8_strlen(str, -1);
+
+	header->vlen = len;
+	header->hlen = 3 + ((len + 1) * 2);
+	header->v.string = g_strdup(str);
+
+	return header;
+}
+
+GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
+						GObexDataPolicy data_policy)
+{
+	GObexHeader *header;
+
+	if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_BYTES)
+		return NULL;
+
+	header = g_new0(GObexHeader, 1);
+
+	header->id = id;
+	header->vlen = len;
+	header->hlen = len + 3;
+
+	switch (data_policy) {
+	case G_OBEX_DATA_INHERIT:
+		header->v.data = data;
+		break;
+	case G_OBEX_DATA_COPY:
+		header->v.data = g_memdup(data, len);
+		break;
+	case G_OBEX_DATA_REF:
+		header->extdata = TRUE;
+		header->v.extdata = data;
+		break;
+	}
+
+	return header;
+}
+
+GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val)
+{
+	GObexHeader *header;
+
+	if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_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_TYPE(id) != G_OBEX_HDR_TYPE_UINT32)
+		return NULL;
+
+	header = g_new0(GObexHeader, 1);
+
+	header->id = id;
+	header->vlen = 4;
+	header->hlen = 5;
+	header->v.u32 = val;
+
+	return header;
+}
+
+guint8 g_obex_header_get_id(GObexHeader *header)
+{
+	return header->id;
+}
+
+guint16 g_obex_header_get_length(GObexHeader *header)
+{
+	return header->hlen;
+}
diff --git a/gobex/gobex-header.h b/gobex/gobex-header.h
new file mode 100644
index 0000000..3abe5c6
--- /dev/null
+++ b/gobex/gobex-header.h
@@ -0,0 +1,78 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_HEADER_H
+#define __GOBEX_HEADER_H
+
+#include <glib.h>
+
+#include <gobex/gobex-defs.h>
+
+/* Header ID's */
+#define G_OBEX_HDR_ID_COUNT		0xc0
+#define G_OBEX_HDR_ID_NAME		0x01
+#define G_OBEX_HDR_ID_TYPE		0x42
+#define G_OBEX_HDR_ID_LENGTH		0xc3
+#define G_OBEX_HDR_ID_TIME		0x44
+#define G_OBEX_HDR_ID_DESCRIPTION	0x05
+#define G_OBEX_HDR_ID_TARGET		0x46
+#define G_OBEX_HDR_ID_HTTP		0x47
+#define G_OBEX_HDR_ID_BODY		0x48
+#define G_OBEX_HDR_ID_BODY_END		0x49
+#define G_OBEX_HDR_ID_WHO		0x4a
+#define G_OBEX_HDR_ID_CONNECTION	0xcb
+#define G_OBEX_HDR_ID_APPARAM		0x4c
+#define G_OBEX_HDR_ID_AUTHCHAL		0x4d
+#define G_OBEX_HDR_ID_AUTHRESP		0x4e
+#define G_OBEX_HDR_ID_CREATOR		0xcf
+#define G_OBEX_HDR_ID_WANUUID		0x50
+#define G_OBEX_HDR_ID_OBJECTCLASS	0x51
+#define G_OBEX_HDR_ID_SESSIONPARAM	0x52
+#define G_OBEX_HDR_ID_SESSIONSEQ	0x93
+#define G_OBEX_HDR_ID_ACTION		0x94
+#define G_OBEX_HDR_ID_DESTNAME		0x15
+#define G_OBEX_HDR_ID_PERMISSIONS	0xd6
+#define G_OBEX_HDR_ID_SRM		0x97
+#define G_OBEX_HDR_ID_SRM_FLAGS		0x98
+
+typedef struct _GObexHeader GObexHeader;
+
+gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str);
+gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
+								size_t *len);
+gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val);
+gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val);
+
+GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str);
+GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
+						GObexDataPolicy data_policy);
+GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val);
+GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val);
+
+guint8 g_obex_header_get_id(GObexHeader *header);
+guint16 g_obex_header_get_length(GObexHeader *header);
+
+size_t g_obex_header_encode(GObexHeader *header, void *hdr_ptr, size_t buf_len);
+GObexHeader *g_obex_header_decode(const void *data, size_t len,
+				GObexDataPolicy data_policy, size_t *parsed);
+void g_obex_header_free(GObexHeader *header);
+
+#endif /* __GOBEX_HEADER_H */
diff --git a/gobex/gobex-packet.c b/gobex/gobex-packet.c
new file mode 100644
index 0000000..9b03ce1
--- /dev/null
+++ b/gobex/gobex-packet.c
@@ -0,0 +1,261 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include "gobex-packet.h"
+
+struct _GObexPacket {
+	guint8 opcode;
+	gboolean final;
+
+	GObexDataPolicy data_policy;
+
+	union {
+		void *buf;		/* Non-header data */
+		const void *buf_ref;	/* Reference to non-header data */
+	} data;
+	size_t data_len;
+
+	size_t hlen;		/* Length of all encoded headers */
+	GSList *headers;
+};
+
+GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
+{
+	GSList *l;
+
+	for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
+		GObexHeader *hdr = l->data;
+
+		if (g_obex_header_get_id(hdr) == id)
+			return hdr;
+	}
+
+	return NULL;
+}
+
+guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
+{
+	if (final)
+		*final = pkt->final;
+
+	return pkt->opcode;
+}
+
+gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
+{
+	pkt->headers = g_slist_append(pkt->headers, header);
+	pkt->hlen += g_obex_header_get_length(header);
+
+	return TRUE;
+}
+
+const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len)
+{
+	if (pkt->data_len == 0) {
+		*len = 0;
+		return NULL;
+	}
+
+	*len = pkt->data_len;
+
+	switch (pkt->data_policy) {
+	case G_OBEX_DATA_INHERIT:
+	case G_OBEX_DATA_COPY:
+		return pkt->data.buf;
+	case G_OBEX_DATA_REF:
+		return pkt->data.buf_ref;
+	}
+
+	g_assert_not_reached();
+}
+
+gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
+						GObexDataPolicy data_policy)
+{
+	if (pkt->data.buf || pkt->data.buf_ref)
+		return FALSE;
+
+	pkt->data_policy = data_policy;
+	pkt->data_len = len;
+
+	switch (data_policy) {
+	case G_OBEX_DATA_COPY:
+		pkt->data.buf = g_memdup(data, len);
+		break;
+	case G_OBEX_DATA_REF:
+		pkt->data.buf_ref = data;
+		break;
+	case G_OBEX_DATA_INHERIT:
+		pkt->data.buf = (void *) data;
+		break;
+	}
+
+	return TRUE;
+}
+
+GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final)
+{
+	GObexPacket *pkt;
+
+	pkt = g_new0(GObexPacket, 1);
+
+	pkt->opcode = opcode;
+	pkt->final = final;
+
+	pkt->data_policy = G_OBEX_DATA_COPY;
+
+	return pkt;
+}
+
+void g_obex_packet_free(GObexPacket *pkt)
+{
+	switch (pkt->data_policy) {
+	case G_OBEX_DATA_INHERIT:
+	case G_OBEX_DATA_COPY:
+		g_free(pkt->data.buf);
+		break;
+	case G_OBEX_DATA_REF:
+		break;
+	}
+
+	g_slist_foreach(pkt->headers, (GFunc) g_obex_header_free, NULL);
+	g_slist_free(pkt->headers);
+	g_free(pkt);
+}
+
+static gboolean parse_headers(GObexPacket *pkt, const void *data, size_t len,
+						GObexDataPolicy data_policy)
+{
+	const guint8 *buf = data;
+
+	while (len > 0) {
+		GObexHeader *header;
+		size_t parsed;
+
+		header = g_obex_header_decode(buf, len, data_policy, &parsed);
+		if (header == NULL)
+			return FALSE;
+
+		pkt->headers = g_slist_append(pkt->headers, header);
+
+		len -= parsed;
+		buf += parsed;
+	}
+
+	return TRUE;
+}
+
+static const guint8 *get_bytes(void *to, const guint8 *from, size_t count)
+{
+	memcpy(to, from, count);
+	return (from + count);
+}
+
+GObexPacket *g_obex_packet_decode(const void *data, size_t len,
+						size_t header_offset,
+						GObexDataPolicy data_policy)
+{
+	const guint8 *buf = data;
+	guint16 packet_len;
+	guint8 opcode;
+	GObexPacket *pkt;
+	gboolean final;
+
+	if (len < 3)
+		return NULL;
+
+	buf = get_bytes(&opcode, buf, sizeof(opcode));
+	buf = get_bytes(&packet_len, buf, sizeof(packet_len));
+
+	packet_len = g_ntohs(packet_len);
+	if (packet_len < len)
+		return NULL;
+
+	final = (opcode & G_OBEX_PACKET_FINAL) ? TRUE : FALSE;
+	opcode &= ~G_OBEX_PACKET_FINAL;
+
+	pkt = g_obex_packet_new(opcode, final);
+
+	if (header_offset == 0)
+		goto headers;
+
+	if (3 + header_offset < len)
+		goto failed;
+
+	if (data_policy == G_OBEX_DATA_INHERIT)
+		goto failed;
+
+	if (!g_obex_packet_set_data(pkt, buf, header_offset, data_policy))
+		goto failed;
+
+	buf += header_offset;
+
+headers:
+	if (!parse_headers(pkt, buf, len - (buf - (guint8 *) data),
+								data_policy))
+		goto failed;
+
+	return pkt;
+
+failed:
+	g_obex_packet_free(pkt);
+	return NULL;
+}
+
+ssize_t g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, size_t len)
+{
+	size_t count;
+	guint16 pkt_len, u16;
+	GSList *l;
+
+	pkt_len = 3 + pkt->data_len + pkt->hlen;
+
+	if (pkt_len > len)
+		return -ENOBUFS;
+
+	buf[0] = pkt->opcode;
+	if (pkt->final)
+		buf[0] |= G_OBEX_PACKET_FINAL;
+
+	u16 = g_htons(pkt_len);
+	memcpy(&buf[1], &u16, sizeof(u16));
+
+	if (pkt->data_len > 0) {
+		if (pkt->data_policy == G_OBEX_DATA_REF)
+			memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
+		else
+			memcpy(&buf[3], pkt->data.buf, pkt->data_len);
+	}
+
+	count = 3 + pkt->data_len;
+
+	for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
+		GObexHeader *hdr = l->data;
+		count += g_obex_header_encode(hdr, buf + count, len - count);
+	}
+
+	g_assert_cmpuint(count, ==, pkt_len);
+
+	return count;
+}
diff --git a/gobex/gobex-packet.h b/gobex/gobex-packet.h
new file mode 100644
index 0000000..ddce686
--- /dev/null
+++ b/gobex/gobex-packet.h
@@ -0,0 +1,59 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_PACKET_H
+#define __GOBEX_PACKET_H
+
+#include <unistd.h>
+
+#include <glib.h>
+
+#include <gobex/gobex-defs.h>
+#include <gobex/gobex-header.h>
+
+/* Opcodes */
+#define G_OBEX_OP_CONNECT	0x00
+#define G_OBEX_OP_DISCONNECT	0x01
+#define G_OBEX_OP_PUT		0x02
+#define G_OBEX_OP_GET		0x03
+#define G_OBEX_OP_SETPATH	0x05
+#define G_OBEX_OP_SESSION	0x07
+#define G_OBEX_OP_ABORT		0x7f
+
+#define G_OBEX_PACKET_FINAL	0x80
+
+typedef struct _GObexPacket GObexPacket;
+
+GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id);
+guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final);
+gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header);
+gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
+						GObexDataPolicy data_policy);
+const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len);
+GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final);
+void g_obex_packet_free(GObexPacket *pkt);
+
+GObexPacket *g_obex_packet_decode(const void *data, size_t len,
+						size_t header_offset,
+						GObexDataPolicy data_policy);
+ssize_t g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, size_t len);
+
+#endif /* __GOBEX_PACKET_H */
diff --git a/gobex/gobex.c b/gobex/gobex.c
index 75675cb..7c6e586 100644
--- a/gobex/gobex.c
+++ b/gobex/gobex.c
@@ -21,7 +21,6 @@
 
 #include <unistd.h>
 #include <string.h>
-#include <errno.h>
 
 #include "gobex.h"
 
@@ -29,46 +28,6 @@
 #define G_OBEX_MINIMUM_MTU	255
 #define G_OBEX_MAXIMUM_MTU	65535
 
-/* Header types */
-#define G_OBEX_HDR_TYPE_UNICODE	(0 << 6)
-#define G_OBEX_HDR_TYPE_BYTES	(1 << 6)
-#define G_OBEX_HDR_TYPE_UINT8	(2 << 6)
-#define G_OBEX_HDR_TYPE_UINT32	(3 << 6)
-
-#define G_OBEX_HDR_TYPE(id)	((id) & 0xc0)
-
-#define G_OBEX_FINAL		0x80
-
-struct _GObexHeader {
-	guint8 id;
-	gboolean extdata;
-	size_t vlen;			/* Length of value */
-	size_t hlen;			/* Length of full encoded header */
-	union {
-		char *string;		/* UTF-8 converted from UTF-16 */
-		guint8 *data;		/* Own buffer */
-		const guint8 *extdata;	/* Reference to external buffer */
-		guint8 u8;
-		guint32 u32;
-	} v;
-};
-
-struct _GObexPacket {
-	guint8 opcode;
-	gboolean final;
-
-	GObexDataPolicy data_policy;
-
-	union {
-		void *buf;		/* Non-header data */
-		const void *buf_ref;	/* Reference to non-header data */
-	} data;
-	size_t data_len;
-
-	size_t hlen;		/* Length of all encoded headers */
-	GSList *headers;
-};
-
 struct _GObex {
 	gint ref_count;
 	GIOChannel *io;
@@ -116,430 +75,6 @@ struct setpath_data {
 	guint8 constants;
 } __attribute__ ((packed));
 
-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] = g_htons((*utf16)[i]);
-
-	utf16_len = (utf16_len + 1) << 1;
-
-	return utf16_len;
-}
-
-static guint8 *put_bytes(guint8 *to, const void *from, size_t count)
-{
-	memcpy(to, from, count);
-	return (to + count);
-}
-
-static const guint8 *get_bytes(void *to, const guint8 *from, size_t count)
-{
-	memcpy(to, from, count);
-	return (from + count);
-}
-
-size_t g_obex_header_encode(GObexHeader *header, void *buf, size_t buf_len)
-{
-	guint8 *ptr = buf;
-	guint16 u16;
-	guint32 u32;
-	gunichar2 *utf16;
-	glong utf16_len;
-
-	if (buf_len < header->hlen)
-		return 0;
-
-	ptr = put_bytes(ptr, &header->id, sizeof(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 || (guint16) utf16_len > buf_len)
-			return 0;
-		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_TYPE_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_TYPE_UINT8:
-		*ptr = header->v.u8;
-		break;
-	case G_OBEX_HDR_TYPE_UINT32:
-		u32 = g_htonl(header->v.u32);
-		ptr = put_bytes(ptr, &u32, sizeof(u32));
-		break;
-	default:
-		g_assert_not_reached();
-	}
-
-	return header->hlen;
-}
-
-GObexHeader *g_obex_header_decode(const void *data, size_t len,
-				GObexDataPolicy data_policy, size_t *parsed)
-{
-	GObexHeader *header;
-	const guint8 *ptr = data;
-	guint16 hdr_len;
-	size_t str_len;
-
-	if (len < 2)
-		return NULL;
-
-	header = g_new0(GObexHeader, 1);
-
-	ptr = get_bytes(&header->id, ptr, sizeof(header->id));
-
-	switch (G_OBEX_HDR_TYPE(header->id)) {
-	case G_OBEX_HDR_TYPE_UNICODE:
-		if (len < 3)
-			goto failed;
-		ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
-		hdr_len = g_ntohs(hdr_len);
-		if (hdr_len > len || hdr_len < 5)
-			goto failed;
-
-		header->v.string = g_convert((const char *) ptr, hdr_len - 5,
-						"UTF8", "UTF16BE",
-						NULL, &str_len, NULL);
-		if (header->v.string == NULL)
-			goto failed;
-
-		header->vlen = (size_t) str_len;
-		header->hlen = hdr_len;
-
-		*parsed = hdr_len;
-
-		break;
-	case G_OBEX_HDR_TYPE_BYTES:
-		if (len < 3)
-			goto failed;
-		ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
-		hdr_len = g_ntohs(hdr_len);
-		if (hdr_len > len)
-			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:
-			goto failed;
-		}
-
-		*parsed = hdr_len;
-
-		break;
-	case G_OBEX_HDR_TYPE_UINT8:
-		header->vlen = 1;
-		header->hlen = 2;
-		header->v.u8 = *ptr;
-		*parsed = 2;
-		break;
-	case G_OBEX_HDR_TYPE_UINT32:
-		if (len < 5)
-			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:
-	g_obex_header_free(header);
-	return NULL;
-}
-
-void g_obex_header_free(GObexHeader *header)
-{
-	switch (G_OBEX_HDR_TYPE(header->id)) {
-	case G_OBEX_HDR_TYPE_UNICODE:
-		g_free(header->v.string);
-		break;
-	case G_OBEX_HDR_TYPE_BYTES:
-		if (!header->extdata)
-			g_free(header->v.data);
-		break;
-	case G_OBEX_HDR_TYPE_UINT8:
-	case G_OBEX_HDR_TYPE_UINT32:
-		break;
-	default:
-		g_assert_not_reached();
-	}
-
-	g_free(header);
-}
-
-gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str)
-{
-	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UNICODE)
-		return FALSE;
-
-	*str = header->v.string;
-
-	return TRUE;
-}
-
-gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
-								size_t *len)
-{
-	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_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_uint8(GObexHeader *header, guint8 *val)
-{
-	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT8)
-		return FALSE;
-
-	*val = header->v.u8;
-
-	return TRUE;
-}
-
-gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val)
-{
-	if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT32)
-		return FALSE;
-
-	*val = header->v.u32;
-
-	return TRUE;
-}
-
-GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str)
-{
-	GObexHeader *header;
-	size_t len;
-
-	if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UNICODE)
-		return NULL;
-
-	header = g_new0(GObexHeader, 1);
-
-	header->id = id;
-
-	len = g_utf8_strlen(str, -1);
-
-	header->vlen = len;
-	header->hlen = 3 + ((len + 1) * 2);
-	header->v.string = g_strdup(str);
-
-	return header;
-}
-
-GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
-						GObexDataPolicy data_policy)
-{
-	GObexHeader *header;
-
-	if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_BYTES)
-		return NULL;
-
-	header = g_new0(GObexHeader, 1);
-
-	header->id = id;
-	header->vlen = len;
-	header->hlen = len + 3;
-
-	switch (data_policy) {
-	case G_OBEX_DATA_INHERIT:
-		header->v.data = data;
-		break;
-	case G_OBEX_DATA_COPY:
-		header->v.data = g_memdup(data, len);
-		break;
-	case G_OBEX_DATA_REF:
-		header->extdata = TRUE;
-		header->v.extdata = data;
-		break;
-	}
-
-	return header;
-}
-
-GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val)
-{
-	GObexHeader *header;
-
-	if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_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_TYPE(id) != G_OBEX_HDR_TYPE_UINT32)
-		return NULL;
-
-	header = g_new0(GObexHeader, 1);
-
-	header->id = id;
-	header->vlen = 4;
-	header->hlen = 5;
-	header->v.u32 = val;
-
-	return header;
-}
-
-GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
-{
-	GSList *l;
-
-	for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
-		GObexHeader *hdr = l->data;
-
-		if (hdr->id == id)
-			return hdr;
-	}
-
-	return NULL;
-}
-
-guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
-{
-	if (final)
-		*final = pkt->final;
-
-	return pkt->opcode;
-}
-
-gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
-{
-	pkt->headers = g_slist_append(pkt->headers, header);
-	pkt->hlen += header->hlen;
-
-	return TRUE;
-}
-
-const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len)
-{
-	if (pkt->data_len == 0) {
-		*len = 0;
-		return NULL;
-	}
-
-	*len = pkt->data_len;
-
-	switch (pkt->data_policy) {
-	case G_OBEX_DATA_INHERIT:
-	case G_OBEX_DATA_COPY:
-		return pkt->data.buf;
-	case G_OBEX_DATA_REF:
-		return pkt->data.buf_ref;
-	}
-
-	g_assert_not_reached();
-}
-
-gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
-						GObexDataPolicy data_policy)
-{
-	if (pkt->data.buf || pkt->data.buf_ref)
-		return FALSE;
-
-	pkt->data_policy = data_policy;
-	pkt->data_len = len;
-
-	switch (data_policy) {
-	case G_OBEX_DATA_COPY:
-		pkt->data.buf = g_memdup(data, len);
-		break;
-	case G_OBEX_DATA_REF:
-		pkt->data.buf_ref = data;
-		break;
-	case G_OBEX_DATA_INHERIT:
-		pkt->data.buf = (void *) data;
-		break;
-	}
-
-	return TRUE;
-}
-
-GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final)
-{
-	GObexPacket *pkt;
-
-	pkt = g_new0(GObexPacket, 1);
-
-	pkt->opcode = opcode;
-	pkt->final = final;
-
-	pkt->data_policy = G_OBEX_DATA_COPY;
-
-	return pkt;
-}
-
-void g_obex_packet_free(GObexPacket *pkt)
-{
-	switch (pkt->data_policy) {
-	case G_OBEX_DATA_INHERIT:
-	case G_OBEX_DATA_COPY:
-		g_free(pkt->data.buf);
-		break;
-	case G_OBEX_DATA_REF:
-		break;
-	}
-
-	g_slist_foreach(pkt->headers, (GFunc) g_obex_header_free, NULL);
-	g_slist_free(pkt->headers);
-	g_free(pkt);
-}
-
 static ssize_t req_header_offset(guint8 opcode)
 {
 	switch (opcode) {
@@ -575,116 +110,6 @@ static ssize_t rsp_header_offset(guint8 opcode)
 	}
 }
 
-static gboolean parse_headers(GObexPacket *pkt, const void *data, size_t len,
-						GObexDataPolicy data_policy)
-{
-	const guint8 *buf = data;
-
-	while (len > 0) {
-		GObexHeader *header;
-		size_t parsed;
-
-		header = g_obex_header_decode(buf, len, data_policy, &parsed);
-		if (header == NULL)
-			return FALSE;
-
-		pkt->headers = g_slist_append(pkt->headers, header);
-
-		len -= parsed;
-		buf += parsed;
-	}
-
-	return TRUE;
-}
-
-GObexPacket *g_obex_packet_decode(const void *data, size_t len,
-						size_t header_offset,
-						GObexDataPolicy data_policy)
-{
-	const guint8 *buf = data;
-	guint16 packet_len;
-	guint8 opcode;
-	GObexPacket *pkt;
-	gboolean final;
-
-	if (len < 3)
-		return NULL;
-
-	buf = get_bytes(&opcode, buf, sizeof(opcode));
-	buf = get_bytes(&packet_len, buf, sizeof(packet_len));
-
-	packet_len = g_ntohs(packet_len);
-	if (packet_len < len)
-		return NULL;
-
-	final = (opcode & G_OBEX_FINAL) ? TRUE : FALSE;
-	opcode &= ~G_OBEX_FINAL;
-
-	pkt = g_obex_packet_new(opcode, final);
-
-	if (header_offset == 0)
-		goto headers;
-
-	if (3 + header_offset < len)
-		goto failed;
-
-	if (data_policy == G_OBEX_DATA_INHERIT)
-		goto failed;
-
-	if (!g_obex_packet_set_data(pkt, buf, header_offset, data_policy))
-		goto failed;
-
-	buf += header_offset;
-
-headers:
-	if (!parse_headers(pkt, buf, len - (buf - (guint8 *) data),
-								data_policy))
-		goto failed;
-
-	return pkt;
-
-failed:
-	g_obex_packet_free(pkt);
-	return NULL;
-}
-
-static ssize_t g_obex_packet_encode(GObexPacket *pkt, uint8_t *buf, size_t len)
-{
-	size_t count;
-	guint16 pkt_len, u16;
-	GSList *l;
-
-	pkt_len = 3 + pkt->data_len + pkt->hlen;
-
-	if (pkt_len > len)
-		return -ENOBUFS;
-
-	buf[0] = pkt->opcode;
-	if (pkt->final)
-		buf[0] |= G_OBEX_FINAL;
-
-	u16 = g_htons(pkt_len);
-	memcpy(&buf[1], &u16, sizeof(u16));
-
-	if (pkt->data_len > 0) {
-		if (pkt->data_policy == G_OBEX_DATA_REF)
-			memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
-		else
-			memcpy(&buf[3], pkt->data.buf, pkt->data_len);
-	}
-
-	count = 3 + pkt->data_len;
-
-	for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
-		GObexHeader *hdr = l->data;
-		count += g_obex_header_encode(hdr, buf + count, len - count);
-	}
-
-	g_assert_cmpuint(count, ==, pkt_len);
-
-	return count;
-}
-
 static void pending_pkt_free(struct pending_pkt *p)
 {
 	g_obex_packet_free(p->pkt);
@@ -944,7 +369,7 @@ static gboolean incoming_data(GIOChannel *io, GIOCondition cond,
 		guint8 opcode = g_obex_packet_get_operation(p->pkt, NULL);
 		header_offset = req_header_offset(opcode);
 	} else {
-		guint8 opcode = obex->rx_buf[0] & ~G_OBEX_FINAL;
+		guint8 opcode = obex->rx_buf[0] & ~G_OBEX_PACKET_FINAL;
 		header_offset = rsp_header_offset(opcode);
 	}
 
diff --git a/gobex/gobex.h b/gobex/gobex.h
index 1d91fe7..5823eac 100644
--- a/gobex/gobex.h
+++ b/gobex/gobex.h
@@ -22,50 +22,9 @@
 #ifndef __GOBEX_H
 #define __GOBEX_H
 
-#include <stdint.h>
 #include <glib.h>
 
-/* Opcodes */
-#define G_OBEX_OP_CONNECT		0x00
-#define G_OBEX_OP_DISCONNECT		0x01
-#define G_OBEX_OP_PUT			0x02
-#define G_OBEX_OP_GET			0x03
-#define G_OBEX_OP_SETPATH		0x05
-#define G_OBEX_OP_SESSION		0x07
-#define G_OBEX_OP_ABORT			0x7f
-
-/* Header ID's */
-#define G_OBEX_HDR_ID_COUNT		0xc0
-#define G_OBEX_HDR_ID_NAME		0x01
-#define G_OBEX_HDR_ID_TYPE		0x42
-#define G_OBEX_HDR_ID_LENGTH		0xc3
-#define G_OBEX_HDR_ID_TIME		0x44
-#define G_OBEX_HDR_ID_DESCRIPTION	0x05
-#define G_OBEX_HDR_ID_TARGET		0x46
-#define G_OBEX_HDR_ID_HTTP		0x47
-#define G_OBEX_HDR_ID_BODY		0x48
-#define G_OBEX_HDR_ID_BODY_END		0x49
-#define G_OBEX_HDR_ID_WHO		0x4a
-#define G_OBEX_HDR_ID_CONNECTION	0xcb
-#define G_OBEX_HDR_ID_APPARAM		0x4c
-#define G_OBEX_HDR_ID_AUTHCHAL		0x4d
-#define G_OBEX_HDR_ID_AUTHRESP		0x4e
-#define G_OBEX_HDR_ID_CREATOR		0xcf
-#define G_OBEX_HDR_ID_WANUUID		0x50
-#define G_OBEX_HDR_ID_OBJECTCLASS	0x51
-#define G_OBEX_HDR_ID_SESSIONPARAM	0x52
-#define G_OBEX_HDR_ID_SESSIONSEQ	0x93
-#define G_OBEX_HDR_ID_ACTION		0x94
-#define G_OBEX_HDR_ID_DESTNAME		0x15
-#define G_OBEX_HDR_ID_PERMISSIONS	0xd6
-#define G_OBEX_HDR_ID_SRM		0x97
-#define G_OBEX_HDR_ID_SRM_FLAGS		0x98
-
-typedef enum {
-	G_OBEX_DATA_INHERIT,
-	G_OBEX_DATA_COPY,
-	G_OBEX_DATA_REF,
-} GObexDataPolicy;
+#include <gobex/gobex-packet.h>
 
 typedef enum {
 	G_OBEX_TRANSPORT_STREAM,
@@ -73,44 +32,12 @@ typedef enum {
 } GObexTransportType;
 
 typedef struct _GObex GObex;
-typedef struct _GObexPacket GObexPacket;
-typedef struct _GObexHeader GObexHeader;
 
 typedef void (*GObexRequestFunc) (GObex *obex, GObexPacket *req,
 							gpointer user_data);
 typedef void (*GObexResponseFunc) (GObex *obex, GError *err, GObexPacket *rsp,
 							gpointer user_data);
 
-gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str);
-gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
-								size_t *len);
-gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val);
-gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val);
-
-GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str);
-GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
-						GObexDataPolicy data_policy);
-GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val);
-GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val);
-
-size_t g_obex_header_encode(GObexHeader *header, void *hdr_ptr, size_t buf_len);
-GObexHeader *g_obex_header_decode(const void *data, size_t len,
-				GObexDataPolicy data_policy, size_t *parsed);
-void g_obex_header_free(GObexHeader *header);
-
-GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id);
-guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final);
-gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header);
-gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
-						GObexDataPolicy data_policy);
-const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len);
-GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final);
-void g_obex_packet_free(GObexPacket *pkt);
-
-GObexPacket *g_obex_packet_decode(const void *data, size_t len,
-						size_t header_offset,
-						GObexDataPolicy data_policy);
-
 gboolean g_obex_send(GObex *obex, GObexPacket *pkt);
 
 guint g_obex_send_req(GObex *obex, GObexPacket *req, GObexResponseFunc func,
diff --git a/unit/test-gobex.c b/unit/test-gobex.c
index 3d99c56..2d7734a 100644
--- a/unit/test-gobex.c
+++ b/unit/test-gobex.c
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
+#include <stdint.h>
 
 #include <gobex/gobex.h>