diff libpurple/protocols/msn/tlv.c @ 31558:ce968e115c95

propagate from branch 'im.pidgin.cpw.masca.p2p' (head 33ca865dacb9e5bcf763d06f6a42cbaca337cc64) to branch 'im.pidgin.pidgin' (head 92f47f4e8b0cbb107fd97e1ab814d1cedbf109ad)
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Fri, 06 May 2011 06:25:14 +0000
parents dfc2a8e98430
children bd59044a9100
line wrap: on
line diff
--- a/libpurple/protocols/msn/tlv.c	Tue Jan 04 05:05:06 2011 +0000
+++ b/libpurple/protocols/msn/tlv.c	Fri May 06 06:25:14 2011 +0000
@@ -45,51 +45,62 @@
 	g_free(oldtlv);
 }
 
-static GSList *
-msn_tlv_read(GSList *list, char *bs, size_t *bs_len)
-{
-	guint8 type, length;
-	msn_tlv_t *tlv;
-
-	type = msn_read8(bs);
-	length = msn_read8(bs);
-	*bs_len -= 2;
-
-	if (length > *bs_len) {
-		msn_tlvlist_free(list);
-		return NULL;
-	}
-
-	tlv = createtlv(type, length, NULL);
-	if (length > 0) {
-		tlv->value = g_memdup(bs, length);
-		if (!tlv->value) {
-			freetlv(tlv);
-			msn_tlvlist_free(list);
-			return NULL;
-		}
-	}
-
-	*bs_len -= length;
-
-	return g_slist_prepend(list, tlv);
-}
-
 GSList *
-msn_tlvlist_read(char *bs, size_t bs_len)
+msn_tlvlist_read(const char *bs, size_t bs_len)
 {
 	GSList *list = NULL;
 
 	while (bs_len > 0) {
-		list = msn_tlv_read(list, bs, &bs_len);
-		if (list == NULL)
+		guint8 type, length;
+		msn_tlv_t *tlv;
+
+		if (bs_len == 3 && *bs == 0) {
+			/* Padding to multiple of 4 */
+			break;
+		} else if (bs_len == 2 && *bs == 0) {
+			/* Padding to multiple of 4 */
+			break;
+		} else if (bs_len == 1) {
+			if (*bs == 0) {
+				/* Padding to multiple of 4 */
+				break;
+			} else {
+				/* TLV is not small enough to fit here */
+				msn_tlvlist_free(list);
+				return NULL;
+			}
+		}
+
+		type = msn_pop8(bs);
+		length = msn_pop8(bs);
+		bs_len -= 2;
+
+		if (length > bs_len) {
+			msn_tlvlist_free(list);
 			return NULL;
+		}
+
+		tlv = createtlv(type, length, NULL);
+		if (length > 0) {
+			tlv->value = g_memdup(bs, length);
+			if (!tlv->value) {
+				freetlv(tlv);
+				msn_tlvlist_free(list);
+				return NULL;
+			}
+		}
+
+		bs_len -= length;
+		bs += length;
+
+		list = g_slist_prepend(list, tlv);
 	}
 
 	return g_slist_reverse(list);
 }
 
-GSList *msn_tlvlist_copy(GSList *orig)
+GSList *
+msn_tlvlist_copy(GSList *orig)
 {
 	GSList *new = NULL;
 	msn_tlv_t *tlv;
@@ -267,7 +278,7 @@
 	return msn_tlvlist_replace_raw(list, type, 1, v8);
 }
 
-int 
+int
 msn_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value)
 {
 	char v32[4];
@@ -302,32 +313,47 @@
 	}
 }
 
-#if 0
-int
-msn_tlvlist_write(ByteStream *bs, GSList **list)
+char *
+msn_tlvlist_write(GSList *list, size_t *out_len)
 {
-	int goodbuflen;
-	GSList *cur;
-	msn_tlv_t *tlv;
+	char *buf;
+	char *tmp;
+	size_t bytes_left;
+	size_t total_len;
 
-	/* do an initial run to test total length */
-	goodbuflen = msn_tlvlist_size(*list);
+	tmp = buf = g_malloc(256);
+	bytes_left = total_len = 256;
+
+	for (; list; list = g_slist_next(list)) {
+		msn_tlv_t *tlv = (msn_tlv_t *)list->data;
 
-	if (goodbuflen > byte_stream_bytes_left(bs))
-		return 0; /* not enough buffer */
+		if (G_UNLIKELY(tlv->length + 2 > bytes_left)) {
+			buf = g_realloc(buf, total_len + 256);
+			bytes_left += 256;
+			total_len += 256;
+			tmp = buf + (total_len - bytes_left);
+		}
 
-	/* do the real write-out */
-	for (cur = *list; cur; cur = cur->next) {
-		tlv = cur->data;
-		byte_stream_put16(bs, tlv->type);
-		byte_stream_put16(bs, tlv->length);
-		if (tlv->length > 0)
-			byte_stream_putraw(bs, tlv->value, tlv->length);
+		msn_push8(tmp, tlv->type);
+		msn_push8(tmp, tlv->length);
+		memcpy(tmp, tlv->value, tlv->length);
+		tmp += tlv->length;
+
+		bytes_left -= (tlv->length + 2);
 	}
 
-	return 1; /* TODO: This is a nonsensical return */
+	/* Align length to multiple of 4 */
+	total_len = total_len - bytes_left;
+	bytes_left = 4 - total_len % 4;
+	if (bytes_left != 4)
+		memset(tmp, 0, bytes_left);
+	else
+		bytes_left = 0;
+
+	*out_len = total_len + bytes_left;
+
+	return buf;
 }
-#endif
 
 msn_tlv_t *
 msn_tlv_gettlv(GSList *list, const guint16 type, const int nth)