~ubuntu-branches/ubuntu/intrepid/miro/intrepid

« back to all changes in this revision

Viewing changes to portable/libtorrent/include/libtorrent/bencode.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2008-02-09 13:37:10 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080209133710-9rs90q6gckvp1b6i
Tags: 1.1.2-0ubuntu1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright (c) 2003, Arvid Norberg
 
4
All rights reserved.
 
5
 
 
6
Redistribution and use in source and binary forms, with or without
 
7
modification, are permitted provided that the following conditions
 
8
are met:
 
9
 
 
10
    * Redistributions of source code must retain the above copyright
 
11
      notice, this list of conditions and the following disclaimer.
 
12
    * Redistributions in binary form must reproduce the above copyright
 
13
      notice, this list of conditions and the following disclaimer in
 
14
      the documentation and/or other materials provided with the distribution.
 
15
    * Neither the name of the author nor the names of its
 
16
      contributors may be used to endorse or promote products derived
 
17
      from this software without specific prior written permission.
 
18
 
 
19
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
20
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
21
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
22
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 
23
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
24
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
25
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
26
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
27
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
28
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
29
POSSIBILITY OF SUCH DAMAGE.
 
30
 
 
31
*/
 
32
 
 
33
 
 
34
#ifndef TORRENT_BENCODE_HPP_INCLUDED
 
35
#define TORRENT_BENCODE_HPP_INCLUDED
 
36
 
 
37
 
 
38
 
 
39
/*
 
40
 * This file declares the following functions:
 
41
 *
 
42
 *----------------------------------
 
43
 * template<class OutIt>
 
44
 * void libtorrent::bencode(OutIt out, const libtorrent::entry& e);
 
45
 *
 
46
 * Encodes a message entry with bencoding into the output
 
47
 * iterator given. The bencoding is described in the BitTorrent
 
48
 * protocol description document OutIt must be an OutputIterator
 
49
 * of type char. This may throw libtorrent::invalid_encoding if
 
50
 * the entry contains invalid nodes (undefined_t for example).
 
51
 *
 
52
 *----------------------------------
 
53
 * template<class InIt>
 
54
 * libtorrent::entry libtorrent::bdecode(InIt start, InIt end);
 
55
 *
 
56
 * Decodes the buffer given by the start and end iterators
 
57
 * and returns the decoded entry. InIt must be an InputIterator
 
58
 * of type char. May throw libtorrent::invalid_encoding if
 
59
 * the string is not correctly bencoded.
 
60
 *
 
61
 */
 
62
 
 
63
 
 
64
 
 
65
 
 
66
#include <cstdlib>
 
67
 
 
68
#ifdef _MSC_VER
 
69
#pragma warning(push, 1)
 
70
#endif
 
71
 
 
72
#include <boost/lexical_cast.hpp>
 
73
#include <boost/static_assert.hpp>
 
74
 
 
75
#ifdef _MSC_VER
 
76
#pragma warning(pop)
 
77
#endif
 
78
 
 
79
#include "libtorrent/entry.hpp"
 
80
#include "libtorrent/config.hpp"
 
81
 
 
82
#include "libtorrent/assert.hpp"
 
83
 
 
84
#if defined(_MSC_VER)
 
85
namespace std
 
86
{
 
87
        using ::isdigit;
 
88
        using ::atoi;
 
89
};
 
90
 
 
91
#define for if (false) {}  else for
 
92
#endif
 
93
 
 
94
 
 
95
namespace libtorrent
 
96
{
 
97
 
 
98
        struct TORRENT_EXPORT invalid_encoding: std::exception
 
99
        {
 
100
                virtual const char* what() const throw() { return "invalid bencoding"; }
 
101
        };
 
102
 
 
103
        namespace detail
 
104
        {
 
105
                template <class OutIt>
 
106
                void write_string(OutIt& out, const std::string& val)
 
107
                {
 
108
                        std::string::const_iterator end = val.begin() + val.length();
 
109
                        std::copy(val.begin(), end, out);
 
110
                }
 
111
 
 
112
                TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val);
 
113
 
 
114
                template <class OutIt>
 
115
                void write_integer(OutIt& out, entry::integer_type val)
 
116
                {
 
117
                        // the stack allocated buffer for keeping the
 
118
                        // decimal representation of the number can
 
119
                        // not hold number bigger than this:
 
120
                        BOOST_STATIC_ASSERT(sizeof(entry::integer_type) <= 8);
 
121
                        char buf[21];
 
122
                        for (char const* str = integer_to_str(buf, 21, val);
 
123
                                *str != 0; ++str)
 
124
                        {
 
125
                                *out = *str;
 
126
                                ++out;
 
127
                        }
 
128
                }       
 
129
                
 
130
                template <class OutIt>
 
131
                void write_char(OutIt& out, char c)
 
132
                {
 
133
                        *out = c;
 
134
                        ++out;
 
135
                }
 
136
 
 
137
                template <class InIt>
 
138
                std::string read_until(InIt& in, InIt end, char end_token)
 
139
                {
 
140
                        if (in == end) throw invalid_encoding();
 
141
                        std::string ret;
 
142
                        while (*in != end_token)
 
143
                        {
 
144
                                ret += *in;
 
145
                                ++in;
 
146
                                if (in == end) throw invalid_encoding();
 
147
                        }
 
148
                        return ret;
 
149
                }
 
150
 
 
151
                template<class InIt>
 
152
                void read_string(InIt& in, InIt end, int len, std::string& str)
 
153
                {
 
154
                        TORRENT_ASSERT(len >= 0);
 
155
                        for (int i = 0; i < len; ++i)
 
156
                        {
 
157
                                if (in == end) throw invalid_encoding();
 
158
                                str += *in;
 
159
                                ++in;
 
160
                        }
 
161
                }
 
162
 
 
163
                template<class OutIt>
 
164
                void bencode_recursive(OutIt& out, const entry& e)
 
165
                {
 
166
                        switch(e.type())
 
167
                        {
 
168
                        case entry::int_t:
 
169
                                write_char(out, 'i');
 
170
                                write_integer(out, e.integer());
 
171
                                write_char(out, 'e');
 
172
                                break;
 
173
                        case entry::string_t:
 
174
                                write_integer(out, e.string().length());
 
175
                                write_char(out, ':');
 
176
                                write_string(out, e.string());
 
177
                                break;
 
178
                        case entry::list_t:
 
179
                                write_char(out, 'l');
 
180
                                for (entry::list_type::const_iterator i = e.list().begin(); i != e.list().end(); ++i)
 
181
                                        bencode_recursive(out, *i);
 
182
                                write_char(out, 'e');
 
183
                                break;
 
184
                        case entry::dictionary_t:
 
185
                                write_char(out, 'd');
 
186
                                for (entry::dictionary_type::const_iterator i = e.dict().begin();
 
187
                                        i != e.dict().end(); ++i)
 
188
                                {
 
189
                                        // write key
 
190
                                        write_integer(out, i->first.length());
 
191
                                        write_char(out, ':');
 
192
                                        write_string(out, i->first);
 
193
                                        // write value
 
194
                                        bencode_recursive(out, i->second);
 
195
                                }
 
196
                                write_char(out, 'e');
 
197
                                break;
 
198
                        default:
 
199
                                // do nothing
 
200
                                break;
 
201
                        }
 
202
                }
 
203
 
 
204
                template<class InIt>
 
205
                void bdecode_recursive(InIt& in, InIt end, entry& ret)
 
206
                {
 
207
                        if (in == end) throw invalid_encoding();
 
208
                        switch (*in)
 
209
                        {
 
210
 
 
211
                        // ----------------------------------------------
 
212
                        // integer
 
213
                        case 'i':
 
214
                                {
 
215
                                ++in; // 'i' 
 
216
                                std::string val = read_until(in, end, 'e');
 
217
                                TORRENT_ASSERT(*in == 'e');
 
218
                                ++in; // 'e' 
 
219
                                ret = entry(entry::int_t);
 
220
                                ret.integer() = boost::lexical_cast<entry::integer_type>(val);
 
221
                                } break;
 
222
 
 
223
                        // ----------------------------------------------
 
224
                        // list
 
225
                        case 'l':
 
226
                                {
 
227
                                ret = entry(entry::list_t);
 
228
                                ++in; // 'l'
 
229
                                while (*in != 'e')
 
230
                                {
 
231
                                        ret.list().push_back(entry());
 
232
                                        entry& e = ret.list().back();
 
233
                                        bdecode_recursive(in, end, e);
 
234
                                        if (in == end) throw invalid_encoding();
 
235
                                }
 
236
                                TORRENT_ASSERT(*in == 'e');
 
237
                                ++in; // 'e'
 
238
                                } break;
 
239
 
 
240
                        // ----------------------------------------------
 
241
                        // dictionary
 
242
                        case 'd':
 
243
                                {
 
244
                                ret = entry(entry::dictionary_t);
 
245
                                ++in; // 'd'
 
246
                                while (*in != 'e')
 
247
                                {
 
248
                                        entry key;
 
249
                                        bdecode_recursive(in, end, key);
 
250
                                        entry& e = ret[key.string()];
 
251
                                        bdecode_recursive(in, end, e);
 
252
                                        if (in == end) throw invalid_encoding();
 
253
                                }
 
254
                                TORRENT_ASSERT(*in == 'e');
 
255
                                ++in; // 'e'
 
256
                                } break;
 
257
 
 
258
                        // ----------------------------------------------
 
259
                        // string
 
260
                        default:
 
261
                                if (isdigit((unsigned char)*in))
 
262
                                {
 
263
                                        std::string len_s = read_until(in, end, ':');
 
264
                                        TORRENT_ASSERT(*in == ':');
 
265
                                        ++in; // ':'
 
266
                                        int len = std::atoi(len_s.c_str());
 
267
                                        ret = entry(entry::string_t);
 
268
                                        read_string(in, end, len, ret.string());
 
269
                                }
 
270
                                else
 
271
                                {
 
272
                                        throw invalid_encoding();
 
273
                                }
 
274
                        }
 
275
                }
 
276
        }
 
277
 
 
278
        template<class OutIt>
 
279
        void bencode(OutIt out, const entry& e)
 
280
        {
 
281
                detail::bencode_recursive(out, e);
 
282
        }
 
283
 
 
284
        template<class InIt>
 
285
        entry bdecode(InIt start, InIt end)
 
286
        {
 
287
                try
 
288
                {
 
289
                        entry e;
 
290
                        detail::bdecode_recursive(start, end, e);
 
291
                        return e;
 
292
                }
 
293
                catch(type_error&)
 
294
                {
 
295
                        throw invalid_encoding();
 
296
                }
 
297
        }
 
298
 
 
299
}
 
300
 
 
301
#endif // TORRENT_BENCODE_HPP_INCLUDED