Add missing #include to src/main/torrentclient.h.
[tairent.git] / src / core / bencode.cpp
blobb651b9593d963b112e4f98f03b221d2f8db00589
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 return (*map)[key];
282 /* }}} */
284 /* {{{ BEncode::operator[](const String &key) const */
285 const BEncode &BEncode::operator[](const String &key) const
287 if (type != BEncode::MAP)
288 throw BEncodeException("Wrong type for BEncode operator [" + key + "]");
290 BEncode::Map::const_iterator it = map->find(key);
292 if (it == map->end())
293 throw BEncodeException("BEncode operator [] could not find element " + key);
295 return it->second;
297 /* }}} */
299 /* {{{ BEncode::readString(std::istream &s, String &str) */
300 bool BEncode::readString(std::istream &s, String &str)
302 int size;
303 s >> size;
305 if (s.fail() || s.get() != ':')
306 return false;
308 str.resize(size);
310 size_t len = str.length();
311 for (size_t i = 0; i < len && s.good(); ++i)
312 str[i] = s.get();
314 return !s.fail();
316 /* }}} */
318 /* {{{ operator>>(std::istream &s, BEncode &b) */
319 std::istream &operator>>(std::istream &s, BEncode &b)
321 b.clear();
323 if (s.peek() < 0) {
324 s.setstate(std::istream::failbit);
325 return s;
328 char c;
330 const char *reason = 0;
332 switch (c = s.peek()) {
333 case 'i':
334 s.get();
335 s >> b.value;
337 if (s.fail() || s.get() != 'e') {
338 reason = "Failed to load integer";
339 break;
342 b.type = BEncode::VALUE;
344 return s;
346 case 'l':
347 s.get();
349 b.list = new BEncode::List;
350 b.type = BEncode::LIST;
352 while (s.good()) {
353 if (s.peek() == 'e') {
354 s.get();
355 return s;
358 BEncode::List::iterator it = b.list->insert(b.list->end(), BEncode());
360 s >> *it;
363 reason = "Failed to load list";
365 break;
367 case 'd':
368 s.get();
370 b.map = new BEncode::Map;
371 b.type = BEncode::MAP;
373 while (s.good()) {
374 if (s.peek() == 'e') {
375 s.get();
376 return s;
379 String str;
381 if (!BEncode::readString(s, str))
382 break;
384 s >> (*b.map)[str];
387 reason = "Failed to load dictionary";
389 break;
391 default:
392 if (c >= '0' && c <= '9') {
393 b.string = new String();
394 b.type = BEncode::STRING;
396 if (b.readString(s, *b.string))
397 return s;
400 reason = "Failed to load string";
402 break;
405 std::stringstream stream;
406 stream << reason << " at position " << s.tellg();
408 s.setstate(std::istream::failbit);
409 b.clear();
411 throw BEncodeException(stream.str());
413 return s;
415 /* }}} */
417 /* {{{ operator<<(std::ostream &s, const BEncode &b) */
418 std::ostream &operator<<(std::ostream &s, const BEncode &b)
420 switch (b.type) {
421 case BEncode::VALUE:
422 return s << 'i' << b.value << 'e';
423 case BEncode::STRING:
424 return s << b.string->size() << ':' << *(b.string);
425 case BEncode::LIST:
426 s << 'l';
428 for (BEncode::List::const_iterator it = b.list->begin(); it != b.list->end(); ++it)
429 s << *it;
431 return s << 'e';
432 case BEncode::MAP:
433 s << 'd';
435 for (BEncode::Map::const_iterator it = b.map->begin(); it != b.map->end(); ++it)
436 s << it->first.size() << ':' << it->first << it->second;
438 return s << 'e';
439 default:
440 break;
443 return s;
445 /* }}} */
447 }; // namespace Core
449 }; // namespace Tairent
451 // vim: ai sw=4 ts=4 noet fdm=marker