added some precautionary checks in bdecoder
[libtorrent.git] / include / libtorrent / entry.hpp
blob473eb1ca8085f9ecf1453259d3720968818c910c
1 /*
3 Copyright (c) 2003, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
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:
46 * integer()
47 * string()
48 * list()
49 * dict()
50 * The actual type has to match the type you
51 * are asking for, otherwise you will get an
52 * assertion failure.
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.
62 #include <iosfwd>
63 #include <map>
64 #include <list>
65 #include <string>
66 #include <stdexcept>
68 #include "libtorrent/size_type.hpp"
69 #include "libtorrent/config.hpp"
70 #include "libtorrent/assert.hpp"
72 namespace libtorrent
75 struct TORRENT_EXPORT type_error: std::runtime_error
77 type_error(const char* error): std::runtime_error(error) {}
80 namespace detail
82 template<int v1, int v2>
83 struct max2 { enum { value = v1>v2?v1:v2 }; };
85 template<int v1, int v2, int v3>
86 struct max3
88 enum
90 temp = max2<v1,v2>::value,
91 value = temp>v3?temp:v3
95 template<int v1, int v2, int v3, int v4>
96 struct max4
98 enum
100 temp = max3<v1,v2, v3>::value,
101 value = temp>v4?temp:v4
106 class entry;
108 class TORRENT_EXPORT entry
110 public:
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;
120 enum data_type
122 int_t,
123 string_t,
124 list_t,
125 dictionary_t,
126 undefined_t
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&);
136 entry();
137 entry(data_type t);
138 entry(entry const& e);
139 ~entry();
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;
153 list_type& list();
154 const list_type& list() const;
155 dictionary_type& dict();
156 const dictionary_type& dict() const;
158 void swap(entry& e);
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;
167 #endif
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;
175 protected:
177 void construct(data_type t);
178 void copy(const entry& e);
179 void destruct();
181 private:
183 data_type m_type;
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>)
189 union
191 char data[
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;
198 #else
199 union
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;
207 #endif
209 #ifndef NDEBUG
210 public:
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;
218 #endif
221 inline std::ostream& operator<<(std::ostream& os, const entry& e)
223 e.print(os, 0);
224 return os;
227 inline entry::data_type entry::type() const
229 #ifndef NDEBUG
230 m_type_queried = true;
231 #endif
232 return m_type;
235 inline entry::~entry() { destruct(); }
237 inline void entry::operator=(const entry& e)
239 destruct();
240 copy(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);
250 #endif
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);
261 #endif
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);
273 #endif
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);
284 #endif
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);
296 #endif
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);
307 #endif
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);
319 #endif
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);
330 #endif
331 TORRENT_ASSERT(m_type == dictionary_t);
332 return *reinterpret_cast<const dictionary_type*>(data);
337 #endif // TORRENT_ENTRY_HPP_INCLUDED