File indexing completed on 2025-01-05 04:37:08
0001 /* 0002 SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "bdecoder.h" 0007 #include "bnode.h" 0008 #include <klocalizedstring.h> 0009 #include <util/error.h> 0010 #include <util/log.h> 0011 0012 namespace bt 0013 { 0014 BDecoder::BDecoder(const Uint8 *ptr, Uint32 size, bool verbose, Uint32 off) 0015 : data(QByteArray::fromRawData((const char *)ptr, size)) 0016 , pos(off) 0017 , verbose(verbose) 0018 , level(0) 0019 { 0020 } 0021 0022 BDecoder::BDecoder(const QByteArray &data, bool verbose, Uint32 off) 0023 : data(data) 0024 , pos(off) 0025 , verbose(verbose) 0026 , level(0) 0027 { 0028 } 0029 0030 BDecoder::~BDecoder() 0031 { 0032 } 0033 0034 BNode *BDecoder::decode() 0035 { 0036 if (pos >= (Uint32)data.size()) 0037 return nullptr; 0038 0039 if (data[pos] == 'd') { 0040 return parseDict(); 0041 } else if (data[pos] == 'l') { 0042 return parseList(); 0043 } else if (data[pos] == 'i') { 0044 return parseInt(); 0045 } else if (data[pos] >= '0' && data[pos] <= '9') { 0046 return parseString(); 0047 } else { 0048 throw Error(i18n("Illegal token: %1", data[pos])); 0049 } 0050 } 0051 0052 BDictNode *BDecoder::decodeDict() 0053 { 0054 BNode *n = nullptr; 0055 try { 0056 n = decode(); 0057 if (n && n->getType() == BNode::DICT) 0058 return (BDictNode *)n; 0059 0060 delete n; 0061 } catch (...) { 0062 delete n; 0063 throw; 0064 } 0065 0066 return nullptr; 0067 } 0068 0069 BListNode *BDecoder::decodeList() 0070 { 0071 BNode *n = nullptr; 0072 try { 0073 n = decode(); 0074 if (n && n->getType() == BNode::LIST) 0075 return (BListNode *)n; 0076 0077 delete n; 0078 } catch (...) { 0079 delete n; 0080 throw; 0081 } 0082 0083 return nullptr; 0084 } 0085 0086 BDictNode *BDecoder::parseDict() 0087 { 0088 Uint32 off = pos; 0089 // we're now entering a dictionary 0090 BDictNode *curr = new BDictNode(off); 0091 pos++; 0092 debugMsg(QString("DICT")); 0093 level++; 0094 try { 0095 while (pos < (Uint32)data.size() && data[pos] != 'e') { 0096 debugMsg(QString("Key : ")); 0097 BNode *kn = decode(); 0098 BValueNode *k = dynamic_cast<BValueNode *>(kn); 0099 if (!k || k->data().getType() != Value::STRING) { 0100 delete kn; 0101 throw Error(i18n("Decode error")); 0102 } 0103 0104 QByteArray key = k->data().toByteArray(); 0105 delete kn; 0106 0107 BNode *value = decode(); 0108 if (!value) 0109 throw Error(i18n("Decode error")); 0110 0111 curr->insert(key, value); 0112 } 0113 pos++; 0114 } catch (...) { 0115 delete curr; 0116 throw; 0117 } 0118 level--; 0119 debugMsg(QString("END")); 0120 curr->setLength(pos - off); 0121 return curr; 0122 } 0123 0124 BListNode *BDecoder::parseList() 0125 { 0126 Uint32 off = pos; 0127 debugMsg(QString("LIST")); 0128 level++; 0129 BListNode *curr = new BListNode(off); 0130 pos++; 0131 try { 0132 while (pos < (Uint32)data.size() && data[pos] != 'e') { 0133 BNode *n = decode(); 0134 if (n) 0135 curr->append(n); 0136 } 0137 pos++; 0138 } catch (...) { 0139 delete curr; 0140 throw; 0141 } 0142 level--; 0143 debugMsg(QString("END")); 0144 curr->setLength(pos - off); 0145 return curr; 0146 } 0147 0148 BValueNode *BDecoder::parseInt() 0149 { 0150 Uint32 off = pos; 0151 pos++; 0152 QString n; 0153 // look for e and add everything between i and e to n 0154 while (pos < (Uint32)data.size() && data[pos] != 'e') { 0155 n += data[pos]; 0156 pos++; 0157 } 0158 0159 // check if we aren't at the end of the data 0160 if (pos >= (Uint32)data.size()) { 0161 throw Error(i18n("Unexpected end of input")); 0162 } 0163 0164 // try to decode the int 0165 bool ok = true; 0166 int val = 0; 0167 val = n.toInt(&ok); 0168 if (ok) { 0169 pos++; 0170 debugMsg(QStringLiteral("INT = %1").arg(val)); 0171 BValueNode *vn = new BValueNode(Value(val), off); 0172 vn->setLength(pos - off); 0173 return vn; 0174 } else { 0175 Int64 bi = 0LL; 0176 bi = n.toLongLong(&ok); 0177 if (!ok) 0178 throw Error(i18n("Cannot convert %1 to an int", n)); 0179 0180 pos++; 0181 debugMsg(QStringLiteral("INT64 = %1").arg(n)); 0182 BValueNode *vn = new BValueNode(Value(bi), off); 0183 vn->setLength(pos - off); 0184 return vn; 0185 } 0186 } 0187 0188 BValueNode *BDecoder::parseString() 0189 { 0190 const Uint32 off = pos; 0191 // string are encoded 4:spam (length:string) 0192 0193 // first get length by looking for the : 0194 while (pos < (Uint32)data.size() && data[pos] != ':') { 0195 pos++; 0196 } 0197 // check if we aren't at the end of the data 0198 if (pos >= (Uint32)data.size()) { 0199 throw Error(i18n("Unexpected end of input")); 0200 } 0201 0202 // try to decode length 0203 bool ok = true; 0204 int len = 0; 0205 // This is an optimized version of QByteArray::fromRawData(data.constData() + off, pos - off).toInt(&ok) 0206 const char *start = data.constData() + off; 0207 const char *end = start + pos - off; 0208 while (start < end) { 0209 int n = *start++ - '0'; 0210 if (n < 0 || n > 9) { 0211 ok = false; 0212 break; 0213 } 0214 len = (len << 3) + (len << 1) + n; 0215 } 0216 0217 if (!ok || len < 0) { 0218 throw Error(i18n("Cannot convert %1 to an int", QString::fromUtf8(data.constData() + off, pos - off))); 0219 } 0220 // move pos to the first part of the string 0221 pos++; 0222 if (pos + len > (Uint32)data.size()) 0223 throw Error(i18n("Torrent is incomplete.")); 0224 0225 const QByteArray arr(data.constData() + pos, len); 0226 pos += len; 0227 // read the string into n 0228 0229 // pos should be positioned right after the string 0230 BValueNode *vn = new BValueNode(Value(arr), off); 0231 vn->setLength(pos - off); 0232 if (verbose) { 0233 if (arr.size() < 200) 0234 debugMsg(QStringLiteral("STRING ") + QString::fromUtf8(arr)); 0235 else 0236 debugMsg(QStringLiteral("STRING really long string")); 0237 } 0238 return vn; 0239 } 0240 0241 void BDecoder::debugMsg(const QString &msg) 0242 { 0243 if (!verbose) 0244 return; 0245 0246 Log &log = Out(SYS_GEN | LOG_DEBUG); 0247 for (int i = 0; i < level; i++) 0248 log << "-"; 0249 0250 log << msg << endl; 0251 } 0252 0253 }