summaryrefslogtreecommitdiff
path: root/protocols/IcqOscarJ/tlv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/IcqOscarJ/tlv.cpp')
-rw-r--r--protocols/IcqOscarJ/tlv.cpp398
1 files changed, 398 insertions, 0 deletions
diff --git a/protocols/IcqOscarJ/tlv.cpp b/protocols/IcqOscarJ/tlv.cpp
new file mode 100644
index 0000000000..af6bde4fe7
--- /dev/null
+++ b/protocols/IcqOscarJ/tlv.cpp
@@ -0,0 +1,398 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede
+// Copyright 2001-2002 Jon Keating, Richard Hughes
+// Copyright 2002-2004 Martin berg, Sam Kothari, Robert Rainwater
+// Copyright 2004-2009 Joe Kucera
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $URL: http://miranda.googlecode.com/svn/trunk/miranda/protocols/IcqOscarJ/tlv.cpp $
+// Revision : $Revision: 13324 $
+// Last change on : $Date: 2011-01-23 17:58:59 +0200 (Вс, 23 янв 2011) $
+// Last change by : $Author: borkra $
+//
+// DESCRIPTION:
+//
+// Helper functions for Oscar TLV chains
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+
+
+/* set maxTlvs<=0 to get all TLVs in length, or a positive integer to get at most the first n */
+oscar_tlv_chain* readIntoTLVChain(BYTE **buf, WORD wLen, int maxTlvs)
+{
+ oscar_tlv_chain *now, *last, *chain = NULL;
+ WORD now_tlv_len;
+ int len = wLen;
+
+ if (!buf || !wLen) return NULL;
+
+ while (len > 0) /* don't use unsigned variable for this check */
+ {
+ now = (oscar_tlv_chain *)SAFE_MALLOC(sizeof(oscar_tlv_chain));
+
+ if (!now)
+ {
+ disposeChain(&chain);
+ return NULL;
+ }
+
+ unpackWord(buf, &(now->tlv.wType));
+ unpackWord(buf, &now_tlv_len);
+ now->tlv.wLen = now_tlv_len;
+ len -= 4;
+
+ if (now_tlv_len < 1)
+ {
+ now->tlv.pData = NULL;
+ }
+ else if (now_tlv_len <= len)
+ {
+ now->tlv.pData = (BYTE *)SAFE_MALLOC(now_tlv_len);
+ if (now->tlv.pData)
+ memcpy(now->tlv.pData, *buf, now_tlv_len);
+ }
+ else
+ { // the packet is shorter than it should be
+ SAFE_FREE((void**)&now);
+ return chain; // give at least the rest of chain
+ }
+
+ if (chain) // keep the original order
+ last->next = now;
+ else
+ chain = now;
+
+ last = now;
+
+ len -= now_tlv_len;
+ *buf += now_tlv_len;
+
+ if (--maxTlvs == 0)
+ break;
+ }
+
+ return chain;
+}
+
+// Returns a pointer to the TLV with type wType and number wIndex in the chain
+// If wIndex = 1, the first matching TLV will be returned, if wIndex = 2,
+// the second matching one will be returned.
+// wIndex must be > 0
+oscar_tlv* oscar_tlv_chain::getTLV(WORD wType, WORD wIndex)
+{
+ int i = 0;
+ oscar_tlv_chain *list = this;
+
+ while (list)
+ {
+ if (list->tlv.wType == wType)
+ i++;
+ if (i >= wIndex)
+ return &list->tlv;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+
+WORD oscar_tlv_chain::getChainLength()
+{
+ int len = 0;
+ oscar_tlv_chain *list = this;
+
+ while (list)
+ {
+ len += list->tlv.wLen + 4;
+ list = list->next;
+ }
+ return len;
+}
+
+
+oscar_tlv* oscar_tlv_chain::putTLV(WORD wType, WORD wLen, BYTE *pData, BOOL bReplace)
+{
+ oscar_tlv *tlv = getTLV(wType, 1);
+
+ if (tlv && bReplace)
+ {
+ SAFE_FREE((void**)&tlv->pData);
+ }
+ else
+ {
+ oscar_tlv_chain *last = this;
+
+ while (last && last->next)
+ last = last->next;
+
+ if (last)
+ {
+ last->next = (oscar_tlv_chain*)SAFE_MALLOC(sizeof(oscar_tlv_chain));
+ tlv = &last->next->tlv;
+ tlv->wType = wType;
+ }
+ }
+ if (tlv)
+ {
+ tlv->wLen = wLen;
+ tlv->pData = (PBYTE)SAFE_MALLOC(wLen);
+ memcpy(tlv->pData, pData, wLen);
+ }
+ return tlv;
+}
+
+
+oscar_tlv_chain* oscar_tlv_chain::removeTLV(oscar_tlv *tlv)
+{
+ oscar_tlv_chain *list = this, *prev = NULL, *chain = this;
+
+ while (list)
+ {
+ if (&list->tlv == tlv)
+ {
+ if (prev) // relink
+ prev->next = list->next;
+ else if (list->next)
+ { // move second item's tlv to the first item
+ list->tlv = list->next->tlv;
+ list = list->next;
+ }
+ else // result is an empty chain (NULL)
+ chain = NULL;
+ // release chain item memory
+ SAFE_FREE((void**)&list->tlv.pData);
+ SAFE_FREE((void**)&list);
+ }
+ prev = list;
+ list = list->next;
+ }
+
+ return chain;
+}
+
+
+WORD oscar_tlv_chain::getLength(WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv = getTLV(wType, wIndex);
+ if (tlv)
+ return tlv->wLen;
+
+ return 0;
+}
+
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+/* Values are returned in MSB format */
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+DWORD oscar_tlv_chain::getDWord(WORD wType, WORD wIndex)
+{
+ DWORD dw = 0;
+
+ oscar_tlv *tlv = getTLV(wType, wIndex);
+ if (tlv && tlv->wLen >= 4)
+ {
+ dw |= (*((tlv->pData)+0) << 24);
+ dw |= (*((tlv->pData)+1) << 16);
+ dw |= (*((tlv->pData)+2) << 8);
+ dw |= (*((tlv->pData)+3));
+ }
+
+ return dw;
+}
+
+
+WORD oscar_tlv_chain::getWord(WORD wType, WORD wIndex)
+{
+ WORD w = 0;
+
+ oscar_tlv *tlv = getTLV(wType, wIndex);
+ if (tlv && tlv->wLen >= 2)
+ {
+ w |= (*((tlv->pData)+0) << 8);
+ w |= (*((tlv->pData)+1));
+ }
+
+ return w;
+}
+
+
+BYTE oscar_tlv_chain::getByte(WORD wType, WORD wIndex)
+{
+ BYTE b = 0;
+
+ oscar_tlv *tlv = getTLV(wType, wIndex);
+ if (tlv && tlv->wLen)
+ {
+ b = *(tlv->pData);
+ }
+
+ return b;
+}
+
+
+int oscar_tlv_chain::getNumber(WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv = getTLV(wType, wIndex);
+
+ if (tlv)
+ {
+ if (tlv->wLen == 1)
+ return getByte(wType, wIndex);
+ else if (tlv->wLen == 2)
+ return getWord(wType, wIndex);
+ else if (tlv->wLen == 4)
+ return getDWord(wType, wIndex);
+ }
+ return 0;
+}
+
+
+double oscar_tlv_chain::getDouble(WORD wType, WORD wIndex)
+{
+ oscar_tlv *tlv = getTLV(wType, wIndex);
+
+ if (tlv && tlv->wLen == 8)
+ {
+ BYTE *buf = tlv->pData;
+ double d = 0;
+
+ unpackQWord(&buf, (DWORD64*)&d);
+
+ return d;
+ }
+ return 0;
+}
+
+
+char* oscar_tlv_chain::getString(WORD wType, WORD wIndex)
+{
+ char *str = NULL;
+
+ oscar_tlv *tlv = getTLV(wType, wIndex);
+ if (tlv)
+ {
+ str = (char*)SAFE_MALLOC(tlv->wLen + 1); /* For \0 */
+
+ if (!str) return NULL;
+
+ memcpy(str, tlv->pData, tlv->wLen);
+ str[tlv->wLen] = '\0';
+ }
+
+ return str;
+}
+
+
+void disposeChain(oscar_tlv_chain **chain)
+{
+ if (!chain || !*chain)
+ return;
+
+ oscar_tlv_chain *now = *chain;
+
+ while (now)
+ {
+ oscar_tlv_chain *next = now->next;
+
+ SAFE_FREE((void**)&now->tlv.pData);
+ SAFE_FREE((void**)&now);
+ now = next;
+ }
+
+ *chain = NULL;
+}
+
+
+oscar_tlv_record_list* readIntoTLVRecordList(BYTE **buf, WORD wLen, int nCount)
+{
+ oscar_tlv_record_list *list = NULL, *last;
+
+ while (wLen >= 2)
+ {
+ WORD wRecordSize;
+
+ unpackWord(buf, &wRecordSize);
+ wLen -= 2;
+ if (wRecordSize && wRecordSize <= wLen)
+ {
+ oscar_tlv_record_list *pRecord = (oscar_tlv_record_list*)SAFE_MALLOC(sizeof(oscar_tlv_record_list));
+ BYTE *pData = *buf;
+
+ *buf += wRecordSize;
+ wLen -= wRecordSize;
+
+ pRecord->item = readIntoTLVChain(&pData, wRecordSize, 0);
+ if (pRecord->item)
+ { // keep the order
+ if (list)
+ last->next = pRecord;
+ else
+ list = pRecord;
+
+ last = pRecord;
+ }
+ else
+ SAFE_FREE((void**)&pRecord);
+ }
+
+ if (--nCount == 0) break;
+ }
+ return list;
+}
+
+
+void disposeRecordList(oscar_tlv_record_list** list)
+{
+ if (!list || !*list)
+ return;
+
+ oscar_tlv_record_list *now = *list;
+
+ while (now)
+ {
+ oscar_tlv_record_list *next = now->next;
+
+ disposeChain(&now->item);
+ SAFE_FREE((void**)&now);
+ now = next;
+ }
+
+ *list = NULL;
+}
+
+
+oscar_tlv_chain* oscar_tlv_record_list::getRecordByTLV(WORD wType, int nValue)
+{
+ oscar_tlv_record_list *list = this;
+
+ while (list)
+ {
+ if (list->item && list->item->getTLV(wType, 1) && list->item->getNumber(wType, 1) == nValue)
+ return list->item;
+ list = list->next;
+ }
+
+ return NULL;
+}