Send correct informations to a http tracker.
[tairent.git] / src / core / bencode.cpp
blob2b380d20cc9028bc6fc27fcd5c71bb4e3b53fef1
1 /***************************************************************************
2 * *
3 * Copyright (C) 2006 David Brodsky *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation and appearing *
8 * in the file LICENSE.GPL included in the packaging of this file. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * General Public License for more details. *
14 * *
15 ***************************************************************************/
17 #include <sstream>
19 #include <tairon/crypto/sha1.h>
21 #include "bencode.h"
23 namespace Tairent
26 namespace Core
29 /* {{{ BEncode::BEncode() */
30 BEncode::BEncode() : type(BEncode::NONE)
33 /* }}} */
35 /* {{{ BEncode::BEncode(const int64_t v) */
36 BEncode::BEncode(const int64_t v) : type(BEncode::VALUE), value(v)
39 /* }}} */
41 /* {{{ BEncode::BEncode(const String &s) */
42 BEncode::BEncode(const String &s) : type(BEncode::STRING), string(new String(s))
45 /* }}} */
47 /* {{{ BEncode::BEncode(const BEncode &b) */
48 BEncode::BEncode(const BEncode &b) : type(b.type)
50 switch (b.type) {
51 case BEncode::VALUE:
52 value = b.value;
53 break;
54 case BEncode::STRING:
55 string = new String(*(b.string));
56 break;
57 case BEncode::LIST:
58 list = new BEncode::List(*(b.list));
59 break;
60 case BEncode::MAP:
61 map = new BEncode::Map(*(b.map));
62 break;
63 default:
64 break;
67 /* }}} */
69 /* {{{ BEncode::BEncode(BEncode::Type t) */
70 BEncode::BEncode(BEncode::Type t) : type(t)
72 switch (t) {
73 case BEncode::VALUE:
74 value = 0;
75 break;
76 case BEncode::STRING:
77 string = new String();
78 break;
79 case BEncode::LIST:
80 list = new List();
81 break;
82 case BEncode::MAP:
83 map = new Map();
84 break;
85 default:
86 break;
89 /* }}} */
91 /* {{{ BEncode::~BEncode() */
92 BEncode::~BEncode()
94 clear();
96 /* }}} */
98 /* {{{ BEncode::asList() */
99 BEncode::List &BEncode::asList()
101 if (!isList())
102 throw BEncodeException("BEncode is not type list");
104 return *list;
106 /* }}} */
108 /* {{{ BEncode::asList() const */
109 const BEncode::List &BEncode::asList() const
111 if (!isList())
112 throw BEncodeException("BEncode is not type list");
114 return *list;
116 /* }}} */
118 /* {{{ BEncode::asMap() */
119 BEncode::Map &BEncode::asMap()
121 if (!isMap())
122 throw BEncodeException("BEncode is not type map");
124 return *map;
126 /* }}} */
128 /* {{{ BEncode::asMap() const */
129 const BEncode::Map &BEncode::asMap() const
131 if (!isMap())
132 throw BEncodeException("BEncode is not type map");
134 return *map;
136 /* }}} */
138 /* {{{ BEncode::asString() */
139 String &BEncode::asString()
141 if (!isString())
142 throw BEncodeException("BEncode is not type string");
144 return *string;
146 /* }}} */
148 /* {{{ BEncode::asString() const */
149 const String &BEncode::asString() const
151 if (!isString())
152 throw BEncodeException("BEncode is not type string");
154 return *string;
156 /* }}} */
158 /* {{{ BEncode::asValue() */
159 int64_t &BEncode::asValue()
161 if (!isValue())
162 throw BEncodeException("BEncode is not type value");
164 return value;
166 /* }}} */
168 /* {{{ BEncode::asValue() const */
169 const int64_t &BEncode::asValue() const
171 if (!isValue())
172 throw BEncodeException("BEncode is not type value");
174 return value;
176 /* }}} */
178 /* {{{ BEncode::clear */
179 void BEncode::clear()
181 switch (type) {
182 case BEncode::STRING:
183 delete string;
184 break;
185 case BEncode::LIST:
186 delete list;
187 break;
188 case BEncode::MAP:
189 delete map;
190 break;
191 default:
192 break;
195 type = BEncode::NONE;
197 /* }}} */
199 /* {{{ BEncode::computeSHA1() const */
200 String BEncode::computeSHA1() const
202 std::stringstream stream;
203 stream << *this;
205 if (stream.fail())
206 throw BEncodeException("Cannot write BEncode to stream");
208 return Tairon::Crypto::SHA1::hash(stream.str());
210 /* }}} */
212 /* {{{ BEncode::isList() const */
213 bool BEncode::isList() const
215 return (type == BEncode::LIST);
217 /* }}} */
219 /* {{{ BEncode::isMap() const */
220 bool BEncode::isMap() const
222 return (type == BEncode::MAP);
224 /* }}} */
226 /* {{{ BEncode::isString() const */
227 bool BEncode::isString() const
229 return (type == BEncode::STRING);
231 /* }}} */
233 /* {{{ BEncode::isValue() const */
234 bool BEncode::isValue() const
236 return (type == BEncode::VALUE);
238 /* }}} */
240 /* {{{ BEncode::getType() const */
241 BEncode::Type BEncode::getType() const
243 return type;
245 /* }}} */
247 /* {{{ BEncode::operator=(const BEncode &b) */
248 BEncode &BEncode::operator=(const BEncode &b)
250 clear();
252 type = b.type;
253 switch (type) {
254 case BEncode::VALUE:
255 value = b.value;
256 break;
257 case BEncode::STRING:
258 string = new String(*(b.string));
259 break;
260 case BEncode::LIST:
261 list = new BEncode::List(*(b.list));
262 break;
263 case BEncode::MAP:
264 map = new BEncode::Map(*(b.map));
265 break;
266 default:
267 break;
270 return *this;
272 /* }}} */
274 /* {{{ BEncode::operator[](const String &key) */
275 BEncode &BEncode::operator[](const String &key)
277 if (type != BEncode::MAP)
278 throw BEncodeException("Wrong type for BEncode operator [" + key + "]");
280 BEncode::Map::iterator it = map->find(key);
282 if (it == map->end())
283 throw BEncodeException("BEncode operator [] could not find element " + key);
285 return it->second;
287 /* }}} */
289 /* {{{ BEncode::operator[](const String &key) const */
290 const BEncode &BEncode::operator[](const String &key) const
292 if (type != BEncode::MAP)
293 throw BEncodeException("Wrong type for BEncode operator [" + key + "]");
295 BEncode::Map::const_iterator it = map->find(key);
297 if (it == map->end())
298 throw BEncodeException("BEncode operator [] could not find element " + key);
300 return it->second;
302 /* }}} */
304 /* {{{ BEncode::readString(std::istream &s, String &str) */
305 bool BEncode::readString(std::istream &s, String &str)
307 int size;
308 s >> size;
310 if (s.fail() || s.get() != ':')
311 return false;
313 str.resize(size);
315 size_t len = str.length();
316 for (size_t i = 0; i < len && s.good(); ++i)
317 str[i] = s.get();
319 return !s.fail();
321 /* }}} */
323 /* {{{ operator>>(std::istream &s, BEncode &b) */
324 std::istream &operator>>(std::istream &s, BEncode &b)
326 b.clear();
328 if (s.peek() < 0) {
329 s.setstate(std::istream::failbit);
330 return s;
333 char c;
335 const char *reason = 0;
337 switch (c = s.peek()) {
338 case 'i':
339 s.get();
340 s >> b.value;
342 if (s.fail() || s.get() != 'e') {
343 reason = "Failed to load integer";
344 break;
347 b.type = BEncode::VALUE;
349 return s;
351 case 'l':
352 s.get();
354 b.list = new BEncode::List;
355 b.type = BEncode::LIST;
357 while (s.good()) {
358 if (s.peek() == 'e') {
359 s.get();
360 return s;
363 BEncode::List::iterator it = b.list->insert(b.list->end(), BEncode());
365 s >> *it;
368 reason = "Failed to load list";
370 break;
372 case 'd':
373 s.get();
375 b.map = new BEncode::Map;
376 b.type = BEncode::MAP;
378 while (s.good()) {
379 if (s.peek() == 'e') {
380 s.get();
381 return s;
384 String str;
386 if (!BEncode::readString(s, str))
387 break;
389 s >> (*b.map)[str];
392 reason = "Failed to load dictionary";
394 break;
396 default:
397 if (c >= '0' && c <= '9') {
398 b.string = new String();
399 b.type = BEncode::STRING;
401 if (b.readString(s, *b.string))
402 return s;
405 reason = "Failed to load string";
407 break;
410 std::stringstream stream;
411 stream << reason << " at position " << s.tellg();
413 s.setstate(std::istream::failbit);
414 b.clear();
416 throw BEncodeException(stream.str());
418 return s;
420 /* }}} */
422 /* {{{ operator<<(std::ostream &s, const BEncode &b) */
423 std::ostream &operator<<(std::ostream &s, const BEncode &b)
425 switch (b.type) {
426 case BEncode::VALUE:
427 return s << 'i' << b.value << 'e';
428 case BEncode::STRING:
429 return s << b.string->size() << ':' << *(b.string);
430 case BEncode::LIST:
431 s << 'l';
433 for (BEncode::List::const_iterator it = b.list->begin(); it != b.list->end(); ++it)
434 s << *it;
436 return s << 'e';
437 case BEncode::MAP:
438 s << 'd';
440 for (BEncode::Map::const_iterator it = b.map->begin(); it != b.map->end(); ++it)
441 s << it->first.size() << ':' << it->first << it->second;
443 return s << 'e';
444 default:
445 break;
448 return s;
450 /* }}} */
452 }; // namespace Core
454 }; // namespace Tairent
456 // vim: ai sw=4 ts=4 noet fdm=marker