From ab7e0b08fa8c31cf1d468ab4b3c660e2b1836811 Mon Sep 17 00:00:00 2001 From: Fishbone Date: Sun, 2 Jun 2013 16:19:21 +0000 Subject: Added WhatsApp-protocol git-svn-id: http://svn.miranda-ng.org/main/trunk@4861 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- .../WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp | 349 +++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp (limited to 'protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp') diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp new file mode 100644 index 0000000000..7155334c7f --- /dev/null +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp @@ -0,0 +1,349 @@ +/* + * BinTreeNodeReader.cpp + * + * Created on: 26/06/2012 + * Author: Antonio + */ +#include "stdafx.h" +#include "BinTreeNodeReader.h" +#include "WAException.h" +#include "ProtocolTreeNode.h" +#include "utilities.h" +#include + + + +BinTreeNodeReader::BinTreeNodeReader(WAConnection* conn, ISocketConnection* connection, const char** dictionary, const int dictionarysize) { + this->conn = conn; + this->rawIn = connection; + this->tokenMap = dictionary; + this->tokenmapsize = dictionarysize; + this->readSize = 1; + this->in = NULL; + this->buf = new std::vector(BUFFER_SIZE); +} + +BinTreeNodeReader::~BinTreeNodeReader() { + if (this->buf != NULL) + delete this->buf; + if (this->in != NULL) + delete this->in; +} + +ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() { + int b = this->in->read(); + int size = readListSize(b); + b = this->in->read(); + if (b == 2) + return NULL; + + std::string* tag = this->readStringAsString(b); + + if ((size == 0) || (tag == NULL)) + throw WAException("nextTree sees 0 list or null tag", WAException::CORRUPT_STREAM_EX, -1); + int attribCount = (size - 2 + size % 2) / 2; + std::map* attribs = readAttributes(attribCount); + if (size % 2 == 1) { + ProtocolTreeNode* ret = new ProtocolTreeNode(*tag, attribs); + delete tag; + return ret; + } + b = this->in->read(); + if (isListTag(b)) { + ProtocolTreeNode* ret = new ProtocolTreeNode(*tag, attribs, NULL, readList(b)); + delete tag; + return ret; + } + + ReadData* obj = this->readString(b); + std::vector* data; + if (obj->type == STRING) { + std::string* s = (std::string*) obj->data; + data = new std::vector(s->begin(), s->end()); + delete s; + } else { + data = (std::vector*) obj->data; + } + + ProtocolTreeNode* ret = new ProtocolTreeNode(*tag, attribs, data); + delete obj; + delete tag; + return ret; +} + +bool BinTreeNodeReader::isListTag(int b) { + return (b == 248) || (b == 0) || (b == 249); +} + +void BinTreeNodeReader::decodeStream(int flags, int offset, int length) { + if ((flags & 8) != 0) { + if (length < 4) { + throw WAException("invalid length" + length, WAException::CORRUPT_STREAM_EX, 0); + } + offset += 4; + length -= 4; + this->conn->inputKey->decodeMessage(&(*this->buf)[0], offset - 4, offset, length); + } + if (this->in != NULL) + delete this->in; + this->in = new ByteArrayInputStream(this->buf, offset, length); +} + +std::map* BinTreeNodeReader::readAttributes(int attribCount) { + std::map* attribs = new std::map(); + for (int i = 0; i < attribCount; i++) { + std::string* key = readStringAsString(); + std::string* value = readStringAsString(); + (*attribs)[*key] = *value; + delete key; + delete value; + } + return attribs; +} + +std::vector* BinTreeNodeReader::readList(int token) { + int size = readListSize(token); + std::vector* list = new std::vector(size); + for (int i = 0; i < size; i++) { + (*list)[i] = nextTreeInternal(); + } + + return list; +} + +int BinTreeNodeReader::readListSize(int token) { + int size; + if (token == 0) { + size = 0; + } + else { + size = 0; + if (token == 248) { + size = readInt8(this->in); + } + else + { + size = 0; + if (token == 249) + size = readInt16(this->in); + else + throw new WAException("invalid list size in readListSize: token " + token, WAException::CORRUPT_STREAM_EX, 0); + } + } + + return size; +} + +std::vector* BinTreeNodeReader::readList() { + return readList(this->in->read()); +} + +ReadData* BinTreeNodeReader::readString() { + return readString(this->in->read()); +} + +ReadData* BinTreeNodeReader::readString(int token) { + if (token == -1) { + throw WAException("-1 token in readString", WAException::CORRUPT_STREAM_EX, -1); + } + + ReadData* ret = new ReadData(); + + if ((token > 4) && (token < 245)) { + ret->type = STRING; + ret->data = new std::string(getToken(token)); + return ret; + } + + switch(token) { + case 0: + return NULL; + case 252: { + int size8 = readInt8(this->in); + std::vector* buf8 = new std::vector(size8); + fillArray(*buf8, size8, this->in); + // std::string* ret = new std::string(buf8->begin(), buf8->end()); + // delete buf8; + ret->type = ARRAY; + ret->data = buf8; + return ret; + } + case 253: { + int size24 = readInt24(this->in); + std::vector* buf24 = new std::vector(size24); + fillArray(*buf24, size24, this->in); + // std::string* ret = new std::string(buf24->begin(), buf24->end()); + // delete buf24; + ret->type = ARRAY; + ret->data = buf24; + + return ret; + } + case 254: { + token = (unsigned char) this->in->read(); + ret->type = STRING; + ret->data = new std::string(getToken(245 + token)); + return ret; + } + case 250: { + std::string* user = readStringAsString(); + std::string* server = readStringAsString(); + if ((user != NULL) && (server != NULL)) { + std::string* result = new std::string(*user + "@" + *server); + delete user; + delete server; + ret->type = STRING; + ret->data = result; + return ret; + } + if (server != NULL) { + ret->type = STRING; + ret->data = server; + return ret; + } + throw WAException("readString couldn't reconstruct jid", WAException::CORRUPT_STREAM_EX, -1); + } + } + throw WAException("readString couldn't match token" + (int) token, WAException::CORRUPT_STREAM_EX, -1); +} + +std::string* BinTreeNodeReader::objectAsString(ReadData* o) { + if (o->type == STRING) { + return (std::string*) o->data; + } + + if (o->type == ARRAY) { + std::vector* v = (std::vector*) o->data; + std::string* ret = new std::string(v->begin(), v->end()); + delete v; + return ret; + } + + return NULL; +} + +std::string* BinTreeNodeReader::readStringAsString() { + ReadData* o = this->readString(); + std::string* ret = this->objectAsString(o); + delete o; + return ret; +} + +std::string* BinTreeNodeReader::readStringAsString(int token) { + ReadData* o = this->readString(token); + std::string* ret = this->objectAsString(o); + delete o; + return ret; +} + + +void BinTreeNodeReader::fillArray(std::vector& buff, int len, ByteArrayInputStream* in) { + int count = 0; + while (count < len) { + count += in->read(buff, count, len - count); + } +} + +void BinTreeNodeReader::fillArray(std::vector& buff, int len, ISocketConnection* in) { + int count = 0; + while (count < len) { + count += in->read(buff, count, len - count); + } +} + + +std::string BinTreeNodeReader::getToken(int token) { + std::string ret; + + if ((token >= 0) && (token < this->tokenmapsize)) + ret = std::string(this->tokenMap[token]); + if (ret.empty()) { + throw WAException("invalid token/length in getToken", WAException::CORRUPT_STREAM_EX, 0); + } + return ret; +} + + +void BinTreeNodeReader::getTopLevelStream() { + int stanzaSize; + int flags; + int byte = readInt8(this->rawIn); + flags = byte >> 4; + int size0 = byte & 15; + int size1 = readInt8(this->rawIn); + int size2 = readInt8(this->rawIn); + + stanzaSize = (size0 << 16) + (size1 << 8) + size2; + + if (this->buf->size() < (size_t) stanzaSize) { + int newsize = std::max((int) (this->buf->size() * 3 / 2), stanzaSize); + delete this->buf; + this->buf = new std::vector(newsize); + } + fillArray(*this->buf, stanzaSize, this->rawIn); + + this->decodeStream(flags, 0, stanzaSize); +} + +int BinTreeNodeReader::readInt8(ByteArrayInputStream* in) { + return in->read(); +} + +int BinTreeNodeReader::readInt16(ByteArrayInputStream* in) { + int intTop = in->read(); + int intBot = in->read(); + int value = (intTop << 8) + intBot; + return value; +} + +int BinTreeNodeReader::readInt24(ByteArrayInputStream* in) { + int int1 = in->read(); + int int2 = in->read(); + int int3 = in->read(); + int value = (int1 << 16) + (int2 << 8) + int3; + + return value; +} + +ProtocolTreeNode* BinTreeNodeReader::nextTree() { + this->getTopLevelStream(); + return nextTreeInternal(); +} + +void BinTreeNodeReader::streamStart() { + this->getTopLevelStream(); + + int tag = this->in->read(); + int size = readListSize(tag); + tag = this->in->read(); + if (tag != 1) { + throw WAException("expecting STREAM_START in streamStart", WAException::CORRUPT_STREAM_EX, 0); + } + int attribCount = (size - 2 + size % 2) / 2; + + std::map* attributes = readAttributes(attribCount); + delete attributes; +} + +int BinTreeNodeReader::readInt8(ISocketConnection* in) { + return in->read(); +} + +int BinTreeNodeReader::readInt16(ISocketConnection* in) { + int intTop = in->read(); + int intBot = in->read(); + int value = (intTop << 8) + intBot; + return value; +} + +int BinTreeNodeReader::readInt24(ISocketConnection* in) { + int int1 = in->read(); + int int2 = in->read(); + int int3 = in->read(); + int value = (int1 << 16) + (int2 << 8) + int3; + + return value; +} + + + -- cgit v1.2.3