summaryrefslogtreecommitdiffstats
path: root/libktorrent/torrent/bdecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libktorrent/torrent/bdecoder.cpp')
-rw-r--r--libktorrent/torrent/bdecoder.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/libktorrent/torrent/bdecoder.cpp b/libktorrent/torrent/bdecoder.cpp
new file mode 100644
index 0000000..6c5a179
--- /dev/null
+++ b/libktorrent/torrent/bdecoder.cpp
@@ -0,0 +1,224 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Joris Guisson *
+ * joris.guisson@gmail.com *
+ * *
+ * 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., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#include <util/log.h>
+#include <util/error.h>
+#include <klocale.h>
+#include "bdecoder.h"
+#include "bnode.h"
+#include "globals.h"
+
+namespace bt
+{
+
+ BDecoder::BDecoder(const QByteArray & data,bool verbose,Uint32 off)
+ : data(data),pos(off),verbose(verbose)
+ {
+ }
+
+
+ BDecoder::~BDecoder()
+ {}
+
+ BNode* BDecoder::decode()
+ {
+ if (pos >= data.size())
+ return 0;
+
+ if (data[pos] == 'd')
+ {
+ return parseDict();
+ }
+ else if (data[pos] == 'l')
+ {
+ return parseList();
+ }
+ else if (data[pos] == 'i')
+ {
+ return parseInt();
+ }
+ else if (data[pos] >= '0' && data[pos] <= '9')
+ {
+ return parseString();
+ }
+ else
+ {
+ throw Error(i18n("Illegal token: %1").arg(data[pos]));
+ }
+ }
+
+ BDictNode* BDecoder::parseDict()
+ {
+ Uint32 off = pos;
+ // we're now entering a dictionary
+ BDictNode* curr = new BDictNode(off);
+ pos++;
+ if (verbose) Out() << "DICT" << endl;
+ try
+ {
+ while (pos < data.size() && data[pos] != 'e')
+ {
+ if (verbose) Out() << "Key : " << endl;
+ BNode* kn = decode();
+ BValueNode* k = dynamic_cast<BValueNode*>(kn);
+ if (!k || k->data().getType() != Value::STRING)
+ {
+ delete kn;
+ throw Error(i18n("Decode error"));
+ }
+
+ QByteArray key = k->data().toByteArray();
+ delete kn;
+
+ BNode* data = decode();
+ curr->insert(key,data);
+ }
+ pos++;
+ }
+ catch (...)
+ {
+ delete curr;
+ throw;
+ }
+ if (verbose) Out() << "END" << endl;
+ curr->setLength(pos - off);
+ return curr;
+ }
+
+ BListNode* BDecoder::parseList()
+ {
+ Uint32 off = pos;
+ if (verbose) Out() << "LIST" << endl;
+ BListNode* curr = new BListNode(off);
+ pos++;
+ try
+ {
+ while (pos < data.size() && data[pos] != 'e')
+ {
+ BNode* n = decode();
+ curr->append(n);
+ }
+ pos++;
+ }
+ catch (...)
+ {
+ delete curr;
+ throw;
+ }
+ if (verbose) Out() << "END" << endl;
+ curr->setLength(pos - off);
+ return curr;
+ }
+
+ BValueNode* BDecoder::parseInt()
+ {
+ Uint32 off = pos;
+ pos++;
+ QString n;
+ // look for e and add everything between i and e to n
+ while (pos < data.size() && data[pos] != 'e')
+ {
+ n += data[pos];
+ pos++;
+ }
+
+ // check if we aren't at the end of the data
+ if (pos >= data.size())
+ {
+ throw Error(i18n("Unexpected end of input"));
+ }
+
+ // try to decode the int
+ bool ok = true;
+ int val = 0;
+ val = n.toInt(&ok);
+ if (ok)
+ {
+ pos++;
+ if (verbose) Out() << "INT = " << val << endl;
+ BValueNode* vn = new BValueNode(Value(val),off);
+ vn->setLength(pos - off);
+ return vn;
+ }
+ else
+ {
+ Int64 bi = 0LL;
+ bi = n.toLongLong(&ok);
+ if (!ok)
+ throw Error(i18n("Cannot convert %1 to an int").arg(n));
+
+ pos++;
+ if (verbose) Out() << "INT64 = " << n << endl;
+ BValueNode* vn = new BValueNode(Value(bi),off);
+ vn->setLength(pos - off);
+ return vn;
+ }
+ }
+
+ BValueNode* BDecoder::parseString()
+ {
+ Uint32 off = pos;
+ // string are encoded 4:spam (length:string)
+
+ // first get length by looking for the :
+ QString n;
+ while (pos < data.size() && data[pos] != ':')
+ {
+ n += data[pos];
+ pos++;
+ }
+ // check if we aren't at the end of the data
+ if (pos >= data.size())
+ {
+ throw Error(i18n("Unexpected end of input"));
+ }
+
+ // try to decode length
+ bool ok = true;
+ int len = 0;
+ len = n.toInt(&ok);
+ if (!ok)
+ {
+ throw Error(i18n("Cannot convert %1 to an int").arg(n));
+ }
+ // move pos to the first part of the string
+ pos++;
+ if (pos + len > data.size())
+ throw Error(i18n("Torrent is incomplete!"));
+
+ QByteArray arr(len);
+ for (unsigned int i = pos;i < pos + len;i++)
+ arr.at(i-pos) = data[i];
+ pos += len;
+ // read the string into n
+
+ // pos should be positioned right after the string
+ BValueNode* vn = new BValueNode(Value(arr),off);
+ vn->setLength(pos - off);
+ if (verbose)
+ {
+ if (arr.size() < 200)
+ Out() << "STRING " << QString(arr) << endl;
+ else
+ Out() << "STRING " << "really long string" << endl;
+ }
+ return vn;
+ }
+}
+