Mercurial > pidgin
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)