3
Copyright (c) 2003, Arvid Norberg
6
Redistribution and use in source and binary forms, with or without
7
modification, are permitted provided that the following conditions
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.
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.
33
#ifndef TORRENT_ENTRY_HPP_INCLUDED
34
#define TORRENT_ENTRY_HPP_INCLUDED
38
* This file declares the entry class. It is a
39
* variant-type that can be an integer, list,
40
* dictionary (map) or a string. This type is
41
* used to hold bdecoded data (which is the
42
* encoding BitTorrent messages uses).
44
* it has 4 accessors to access the actual
45
* type of the object. They are:
50
* The actual type has to match the type you
51
* are asking for, otherwise you will get an
53
* When you default construct an entry, it is
54
* uninitialized. You can initialize it through the
55
* assignment operator, copy-constructor or
56
* the constructor that takes a data_type enum.
68
#include "libtorrent/size_type.hpp"
69
#include "libtorrent/config.hpp"
70
#include "libtorrent/assert.hpp"
75
struct TORRENT_EXPORT type_error: std::runtime_error
77
type_error(const char* error): std::runtime_error(error) {}
82
template<int v1, int v2>
83
struct max2 { enum { value = v1>v2?v1:v2 }; };
85
template<int v1, int v2, int v3>
90
temp = max2<v1,v2>::value,
91
value = temp>v3?temp:v3
95
template<int v1, int v2, int v3, int v4>
100
temp = max3<v1,v2, v3>::value,
101
value = temp>v4?temp:v4
108
class TORRENT_EXPORT entry
112
// the key is always a string. If a generic entry would be allowed
113
// as a key, sorting would become a problem (e.g. to compare a string
114
// to a list). The definition doesn't mention such a limit though.
115
typedef std::map<std::string, entry> dictionary_type;
116
typedef std::string string_type;
117
typedef std::list<entry> list_type;
118
typedef size_type integer_type;
129
data_type type() const;
131
entry(dictionary_type const&);
132
entry(string_type const&);
133
entry(list_type const&);
134
entry(integer_type const&);
138
entry(entry const& e);
141
bool operator==(entry const& e) const;
143
void operator=(entry const&);
144
void operator=(dictionary_type const&);
145
void operator=(string_type const&);
146
void operator=(list_type const&);
147
void operator=(integer_type const&);
149
integer_type& integer();
150
const integer_type& integer() const;
151
string_type& string();
152
const string_type& string() const;
154
const list_type& list() const;
155
dictionary_type& dict();
156
const dictionary_type& dict() const;
160
// these functions requires that the entry
161
// is a dictionary, otherwise they will throw
162
entry& operator[](char const* key);
163
entry& operator[](std::string const& key);
164
#ifndef BOOST_NO_EXCEPTIONS
165
const entry& operator[](char const* key) const;
166
const entry& operator[](std::string const& key) const;
168
entry* find_key(char const* key);
169
entry const* find_key(char const* key) const;
170
entry* find_key(std::string const& key);
171
entry const* find_key(std::string const& key) const;
173
void print(std::ostream& os, int indent = 0) const;
177
void construct(data_type t);
178
void copy(const entry& e);
185
#if defined(_MSC_VER) && _MSC_VER < 1310
186
// workaround for msvc-bug.
187
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
188
// and sizeof(list<char>) == sizeof(list<entry>)
192
detail::max4<sizeof(std::list<char>)
193
, sizeof(std::map<std::string, char>)
194
, sizeof(string_type)
195
, sizeof(integer_type)>::value];
196
integer_type dummy_aligner;
201
char data[detail::max4<sizeof(list_type)
202
, sizeof(dictionary_type)
203
, sizeof(string_type)
204
, sizeof(integer_type)>::value];
205
integer_type dummy_aligner;
211
// in debug mode this is set to false by bdecode
212
// to indicate that the program has not yet queried
213
// the type of this entry, and sould not assume
214
// that it has a certain type. This is asserted in
215
// the accessor functions. This does not apply if
216
// exceptions are used.
217
mutable bool m_type_queried;
221
inline std::ostream& operator<<(std::ostream& os, const entry& e)
227
inline entry::data_type entry::type() const
230
m_type_queried = true;
235
inline entry::~entry() { destruct(); }
237
inline void entry::operator=(const entry& e)
243
inline entry::integer_type& entry::integer()
245
if (m_type == undefined_t) construct(int_t);
246
#ifndef BOOST_NO_EXCEPTIONS
247
if (m_type != int_t) throw type_error("invalid type requested from entry");
248
#elif defined TORRENT_DEBUG
249
TORRENT_ASSERT(m_type_queried);
251
TORRENT_ASSERT(m_type == int_t);
252
return *reinterpret_cast<integer_type*>(data);
255
inline entry::integer_type const& entry::integer() const
257
#ifndef BOOST_NO_EXCEPTIONS
258
if (m_type != int_t) throw type_error("invalid type requested from entry");
259
#elif defined TORRENT_DEBUG
260
TORRENT_ASSERT(m_type_queried);
262
TORRENT_ASSERT(m_type == int_t);
263
return *reinterpret_cast<const integer_type*>(data);
266
inline entry::string_type& entry::string()
268
if (m_type == undefined_t) construct(string_t);
269
#ifndef BOOST_NO_EXCEPTIONS
270
if (m_type != string_t) throw type_error("invalid type requested from entry");
271
#elif defined TORRENT_DEBUG
272
TORRENT_ASSERT(m_type_queried);
274
TORRENT_ASSERT(m_type == string_t);
275
return *reinterpret_cast<string_type*>(data);
278
inline entry::string_type const& entry::string() const
280
#ifndef BOOST_NO_EXCEPTIONS
281
if (m_type != string_t) throw type_error("invalid type requested from entry");
282
#elif defined TORRENT_DEBUG
283
TORRENT_ASSERT(m_type_queried);
285
TORRENT_ASSERT(m_type == string_t);
286
return *reinterpret_cast<const string_type*>(data);
289
inline entry::list_type& entry::list()
291
if (m_type == undefined_t) construct(list_t);
292
#ifndef BOOST_NO_EXCEPTIONS
293
if (m_type != list_t) throw type_error("invalid type requested from entry");
294
#elif defined TORRENT_DEBUG
295
TORRENT_ASSERT(m_type_queried);
297
TORRENT_ASSERT(m_type == list_t);
298
return *reinterpret_cast<list_type*>(data);
301
inline entry::list_type const& entry::list() const
303
#ifndef BOOST_NO_EXCEPTIONS
304
if (m_type != list_t) throw type_error("invalid type requested from entry");
305
#elif defined TORRENT_DEBUG
306
TORRENT_ASSERT(m_type_queried);
308
TORRENT_ASSERT(m_type == list_t);
309
return *reinterpret_cast<const list_type*>(data);
312
inline entry::dictionary_type& entry::dict()
314
if (m_type == undefined_t) construct(dictionary_t);
315
#ifndef BOOST_NO_EXCEPTIONS
316
if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
317
#elif defined TORRENT_DEBUG
318
TORRENT_ASSERT(m_type_queried);
320
TORRENT_ASSERT(m_type == dictionary_t);
321
return *reinterpret_cast<dictionary_type*>(data);
324
inline entry::dictionary_type const& entry::dict() const
326
#ifndef BOOST_NO_EXCEPTIONS
327
if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
328
#elif defined TORRENT_DEBUG
329
TORRENT_ASSERT(m_type_queried);
331
TORRENT_ASSERT(m_type == dictionary_t);
332
return *reinterpret_cast<const dictionary_type*>(data);
337
#endif // TORRENT_ENTRY_HPP_INCLUDED