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 NDEBUG
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 NDEBUG
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 NDEBUG
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 NDEBUG
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 NDEBUG
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 NDEBUG
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 NDEBUG
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 NDEBUG
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