Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
88216419 | 2 | // Copyright (c) 2009-2012 The Bitcoin developers |
0a61b0df | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. | |
223b6f1b WL |
5 | #ifndef BITCOIN_SERIALIZE_H |
6 | #define BITCOIN_SERIALIZE_H | |
0a61b0df | 7 | |
d743f035 | 8 | #include <string> |
0a61b0df | 9 | #include <vector> |
10 | #include <map> | |
d743f035 | 11 | #include <set> |
223b6f1b | 12 | #include <cassert> |
0e87f34b | 13 | #include <limits> |
223b6f1b WL |
14 | #include <cstring> |
15 | #include <cstdio> | |
16 | ||
0a61b0df | 17 | #include <boost/type_traits/is_fundamental.hpp> |
84d7c981 | 18 | #include <boost/tuple/tuple.hpp> |
19 | #include <boost/tuple/tuple_comparison.hpp> | |
20 | #include <boost/tuple/tuple_io.hpp> | |
223b6f1b | 21 | |
bde280b9 WL |
22 | typedef long long int64; |
23 | typedef unsigned long long uint64; | |
24 | ||
6853e627 | 25 | #ifdef WIN32 |
db1a5609 | 26 | #define _WIN32_WINNT 0x0501 |
52d3a481 WL |
27 | #define WIN32_LEAN_AND_MEAN 1 |
28 | #ifndef NOMINMAX | |
29 | #define NOMINMAX | |
30 | #endif | |
24c835b0 | 31 | #include <windows.h> |
c1aacf0b DN |
32 | // This is used to attempt to keep keying material out of swap |
33 | // Note that VirtualLock does not provide this as a guarantee on Windows, | |
34 | // but, in practice, memory that has been VirtualLock'd almost never gets written to | |
35 | // the pagefile except in rare circumstances where memory is extremely low. | |
36 | #define mlock(p, n) VirtualLock((p), (n)); | |
37 | #define munlock(p, n) VirtualUnlock((p), (n)); | |
38 | #else | |
39 | #include <sys/mman.h> | |
a48c6719 DH |
40 | #include <limits.h> |
41 | /* This comes from limits.h if it's not defined there set a sane default */ | |
42 | #ifndef PAGESIZE | |
43 | #include <unistd.h> | |
44 | #define PAGESIZE sysconf(_SC_PAGESIZE) | |
45 | #endif | |
46 | #define mlock(a,b) \ | |
47 | mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ | |
48 | (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) | |
49 | #define munlock(a,b) \ | |
50 | munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ | |
51 | (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) | |
c1aacf0b DN |
52 | #endif |
53 | ||
0a61b0df | 54 | class CScript; |
55 | class CDataStream; | |
56 | class CAutoFile; | |
0a61b0df | 57 | static const unsigned int MAX_SIZE = 0x02000000; |
58 | ||
f8ded588 | 59 | static const int PROTOCOL_VERSION = 60000; |
0a61b0df | 60 | |
82dc6426 GS |
61 | // Used to bypass the rule against non-const reference to temporary |
62 | // where it makes sense with wrappers such as CFlatData or CTxDB | |
63 | template<typename T> | |
64 | inline T& REF(const T& val) | |
65 | { | |
66 | return const_cast<T&>(val); | |
67 | } | |
0a61b0df | 68 | |
69 | ///////////////////////////////////////////////////////////////// | |
70 | // | |
71 | // Templates for serializing to anything that looks like a stream, | |
72 | // i.e. anything that supports .read(char*, int) and .write(char*, int) | |
73 | // | |
74 | ||
75 | enum | |
76 | { | |
77 | // primary actions | |
78 | SER_NETWORK = (1 << 0), | |
79 | SER_DISK = (1 << 1), | |
80 | SER_GETHASH = (1 << 2), | |
81 | ||
82 | // modifiers | |
83 | SER_SKIPSIG = (1 << 16), | |
84 | SER_BLOCKHEADERONLY = (1 << 17), | |
85 | }; | |
86 | ||
87 | #define IMPLEMENT_SERIALIZE(statements) \ | |
f8ded588 | 88 | unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const \ |
0a61b0df | 89 | { \ |
90 | CSerActionGetSerializeSize ser_action; \ | |
91 | const bool fGetSize = true; \ | |
92 | const bool fWrite = false; \ | |
93 | const bool fRead = false; \ | |
94 | unsigned int nSerSize = 0; \ | |
95 | ser_streamplaceholder s; \ | |
a1de57a0 | 96 | assert(fGetSize||fWrite||fRead); /* suppress warning */ \ |
0a61b0df | 97 | s.nType = nType; \ |
98 | s.nVersion = nVersion; \ | |
99 | {statements} \ | |
100 | return nSerSize; \ | |
101 | } \ | |
102 | template<typename Stream> \ | |
f8ded588 | 103 | void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const \ |
0a61b0df | 104 | { \ |
105 | CSerActionSerialize ser_action; \ | |
106 | const bool fGetSize = false; \ | |
107 | const bool fWrite = true; \ | |
108 | const bool fRead = false; \ | |
109 | unsigned int nSerSize = 0; \ | |
a1de57a0 | 110 | assert(fGetSize||fWrite||fRead); /* suppress warning */ \ |
0a61b0df | 111 | {statements} \ |
112 | } \ | |
113 | template<typename Stream> \ | |
f8ded588 | 114 | void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) \ |
0a61b0df | 115 | { \ |
116 | CSerActionUnserialize ser_action; \ | |
117 | const bool fGetSize = false; \ | |
118 | const bool fWrite = false; \ | |
119 | const bool fRead = true; \ | |
120 | unsigned int nSerSize = 0; \ | |
a1de57a0 | 121 | assert(fGetSize||fWrite||fRead); /* suppress warning */ \ |
0a61b0df | 122 | {statements} \ |
123 | } | |
124 | ||
125 | #define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) | |
126 | ||
0a61b0df | 127 | |
128 | ||
129 | ||
130 | ||
131 | ||
132 | // | |
133 | // Basic types | |
134 | // | |
135 | #define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) | |
136 | #define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) | |
137 | ||
138 | inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } | |
139 | inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } | |
140 | inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } | |
141 | inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } | |
142 | inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } | |
143 | inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } | |
144 | inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } | |
145 | inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } | |
146 | inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); } | |
bde280b9 WL |
147 | inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); } |
148 | inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); } | |
0a61b0df | 149 | inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } |
150 | inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } | |
151 | ||
152 | template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } | |
153 | template<typename Stream> inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } | |
154 | template<typename Stream> inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } | |
155 | template<typename Stream> inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } | |
156 | template<typename Stream> inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } | |
157 | template<typename Stream> inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } | |
158 | template<typename Stream> inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); } | |
159 | template<typename Stream> inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } | |
160 | template<typename Stream> inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } | |
bde280b9 WL |
161 | template<typename Stream> inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); } |
162 | template<typename Stream> inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); } | |
0a61b0df | 163 | template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } |
164 | template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } | |
165 | ||
166 | template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } | |
167 | template<typename Stream> inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } | |
168 | template<typename Stream> inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } | |
169 | template<typename Stream> inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } | |
170 | template<typename Stream> inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); } | |
171 | template<typename Stream> inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); } | |
172 | template<typename Stream> inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); } | |
173 | template<typename Stream> inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); } | |
174 | template<typename Stream> inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); } | |
bde280b9 WL |
175 | template<typename Stream> inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); } |
176 | template<typename Stream> inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); } | |
0a61b0df | 177 | template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); } |
178 | template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); } | |
179 | ||
180 | inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } | |
181 | template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } | |
182 | template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } | |
183 | ||
184 | ||
185 | ||
186 | ||
187 | ||
188 | ||
189 | // | |
190 | // Compact size | |
191 | // size < 253 -- 1 byte | |
192 | // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) | |
193 | // size <= UINT_MAX -- 5 bytes (254 + 4 bytes) | |
194 | // size > UINT_MAX -- 9 bytes (255 + 8 bytes) | |
195 | // | |
bde280b9 | 196 | inline unsigned int GetSizeOfCompactSize(uint64 nSize) |
0a61b0df | 197 | { |
a790fa46 | 198 | if (nSize < 253) return sizeof(unsigned char); |
26ce92b3 GA |
199 | else if (nSize <= std::numeric_limits<unsigned short>::max()) return sizeof(unsigned char) + sizeof(unsigned short); |
200 | else if (nSize <= std::numeric_limits<unsigned int>::max()) return sizeof(unsigned char) + sizeof(unsigned int); | |
bde280b9 | 201 | else return sizeof(unsigned char) + sizeof(uint64); |
0a61b0df | 202 | } |
203 | ||
204 | template<typename Stream> | |
bde280b9 | 205 | void WriteCompactSize(Stream& os, uint64 nSize) |
0a61b0df | 206 | { |
a790fa46 | 207 | if (nSize < 253) |
0a61b0df | 208 | { |
209 | unsigned char chSize = nSize; | |
210 | WRITEDATA(os, chSize); | |
211 | } | |
26ce92b3 | 212 | else if (nSize <= std::numeric_limits<unsigned short>::max()) |
0a61b0df | 213 | { |
a790fa46 | 214 | unsigned char chSize = 253; |
0a61b0df | 215 | unsigned short xSize = nSize; |
216 | WRITEDATA(os, chSize); | |
217 | WRITEDATA(os, xSize); | |
218 | } | |
26ce92b3 | 219 | else if (nSize <= std::numeric_limits<unsigned int>::max()) |
0a61b0df | 220 | { |
a790fa46 | 221 | unsigned char chSize = 254; |
0a61b0df | 222 | unsigned int xSize = nSize; |
223 | WRITEDATA(os, chSize); | |
224 | WRITEDATA(os, xSize); | |
225 | } | |
226 | else | |
227 | { | |
a790fa46 | 228 | unsigned char chSize = 255; |
bde280b9 | 229 | uint64 xSize = nSize; |
0a61b0df | 230 | WRITEDATA(os, chSize); |
a790fa46 | 231 | WRITEDATA(os, xSize); |
0a61b0df | 232 | } |
233 | return; | |
234 | } | |
235 | ||
236 | template<typename Stream> | |
bde280b9 | 237 | uint64 ReadCompactSize(Stream& is) |
0a61b0df | 238 | { |
239 | unsigned char chSize; | |
240 | READDATA(is, chSize); | |
bde280b9 | 241 | uint64 nSizeRet = 0; |
a790fa46 | 242 | if (chSize < 253) |
0a61b0df | 243 | { |
244 | nSizeRet = chSize; | |
245 | } | |
a790fa46 | 246 | else if (chSize == 253) |
0a61b0df | 247 | { |
a790fa46 | 248 | unsigned short xSize; |
249 | READDATA(is, xSize); | |
250 | nSizeRet = xSize; | |
0a61b0df | 251 | } |
a790fa46 | 252 | else if (chSize == 254) |
0a61b0df | 253 | { |
a790fa46 | 254 | unsigned int xSize; |
255 | READDATA(is, xSize); | |
256 | nSizeRet = xSize; | |
0a61b0df | 257 | } |
258 | else | |
259 | { | |
bde280b9 | 260 | uint64 xSize; |
a790fa46 | 261 | READDATA(is, xSize); |
262 | nSizeRet = xSize; | |
0a61b0df | 263 | } |
bde280b9 | 264 | if (nSizeRet > (uint64)MAX_SIZE) |
0a61b0df | 265 | throw std::ios_base::failure("ReadCompactSize() : size too large"); |
266 | return nSizeRet; | |
267 | } | |
268 | ||
269 | ||
270 | ||
0a61b0df | 271 | #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) |
6b8de05d PW |
272 | |
273 | /** Wrapper for serializing arrays and POD. | |
274 | * There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it. | |
275 | */ | |
0a61b0df | 276 | class CFlatData |
277 | { | |
278 | protected: | |
279 | char* pbegin; | |
280 | char* pend; | |
281 | public: | |
282 | CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } | |
283 | char* begin() { return pbegin; } | |
284 | const char* begin() const { return pbegin; } | |
285 | char* end() { return pend; } | |
286 | const char* end() const { return pend; } | |
287 | ||
288 | unsigned int GetSerializeSize(int, int=0) const | |
289 | { | |
290 | return pend - pbegin; | |
291 | } | |
292 | ||
293 | template<typename Stream> | |
294 | void Serialize(Stream& s, int, int=0) const | |
295 | { | |
296 | s.write(pbegin, pend - pbegin); | |
297 | } | |
298 | ||
299 | template<typename Stream> | |
300 | void Unserialize(Stream& s, int, int=0) | |
301 | { | |
302 | s.read(pbegin, pend - pbegin); | |
303 | } | |
304 | }; | |
305 | ||
306 | ||
307 | ||
6b8de05d | 308 | /** string stored as a fixed length field */ |
0a61b0df | 309 | template<std::size_t LEN> |
310 | class CFixedFieldString | |
311 | { | |
312 | protected: | |
223b6f1b WL |
313 | const std::string* pcstr; |
314 | std::string* pstr; | |
0a61b0df | 315 | public: |
223b6f1b WL |
316 | explicit CFixedFieldString(const std::string& str) : pcstr(&str), pstr(NULL) { } |
317 | explicit CFixedFieldString(std::string& str) : pcstr(&str), pstr(&str) { } | |
0a61b0df | 318 | |
319 | unsigned int GetSerializeSize(int, int=0) const | |
320 | { | |
321 | return LEN; | |
322 | } | |
323 | ||
324 | template<typename Stream> | |
325 | void Serialize(Stream& s, int, int=0) const | |
326 | { | |
327 | char pszBuf[LEN]; | |
328 | strncpy(pszBuf, pcstr->c_str(), LEN); | |
329 | s.write(pszBuf, LEN); | |
330 | } | |
331 | ||
332 | template<typename Stream> | |
333 | void Unserialize(Stream& s, int, int=0) | |
334 | { | |
335 | if (pstr == NULL) | |
336 | throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string"); | |
337 | char pszBuf[LEN+1]; | |
338 | s.read(pszBuf, LEN); | |
339 | pszBuf[LEN] = '\0'; | |
340 | *pstr = pszBuf; | |
341 | } | |
342 | }; | |
343 | ||
344 | ||
345 | ||
346 | ||
347 | ||
348 | // | |
349 | // Forward declarations | |
350 | // | |
351 | ||
352 | // string | |
223b6f1b WL |
353 | template<typename C> unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int=0); |
354 | template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str, int, int=0); | |
355 | template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0); | |
0a61b0df | 356 | |
357 | // vector | |
358 | template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); | |
359 | template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); | |
f8ded588 | 360 | template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION); |
0a61b0df | 361 | template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); |
362 | template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); | |
f8ded588 | 363 | template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION); |
0a61b0df | 364 | template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); |
365 | template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); | |
f8ded588 | 366 | template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION); |
0a61b0df | 367 | |
368 | // others derived from vector | |
f8ded588 GA |
369 | extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=PROTOCOL_VERSION); |
370 | template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion=PROTOCOL_VERSION); | |
371 | template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion=PROTOCOL_VERSION); | |
0a61b0df | 372 | |
373 | // pair | |
f8ded588 GA |
374 | template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION); |
375 | template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION); | |
376 | template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION); | |
0a61b0df | 377 | |
84d7c981 | 378 | // 3 tuple |
f8ded588 GA |
379 | template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION); |
380 | template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION); | |
381 | template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION); | |
84d7c981 | 382 | |
383 | // 4 tuple | |
f8ded588 GA |
384 | template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION); |
385 | template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION); | |
386 | template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION); | |
84d7c981 | 387 | |
0a61b0df | 388 | // map |
f8ded588 GA |
389 | template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); |
390 | template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); | |
391 | template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); | |
0a61b0df | 392 | |
393 | // set | |
f8ded588 GA |
394 | template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); |
395 | template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); | |
396 | template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); | |
0a61b0df | 397 | |
398 | ||
399 | ||
400 | ||
401 | ||
402 | // | |
403 | // If none of the specialized versions above matched, default to calling member function. | |
404 | // "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. | |
405 | // The compiler will only cast int to long if none of the other templates matched. | |
406 | // Thanks to Boost serialization for this idea. | |
407 | // | |
408 | template<typename T> | |
f8ded588 | 409 | inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=PROTOCOL_VERSION) |
0a61b0df | 410 | { |
411 | return a.GetSerializeSize((int)nType, nVersion); | |
412 | } | |
413 | ||
414 | template<typename Stream, typename T> | |
f8ded588 | 415 | inline void Serialize(Stream& os, const T& a, long nType, int nVersion=PROTOCOL_VERSION) |
0a61b0df | 416 | { |
417 | a.Serialize(os, (int)nType, nVersion); | |
418 | } | |
419 | ||
420 | template<typename Stream, typename T> | |
f8ded588 | 421 | inline void Unserialize(Stream& is, T& a, long nType, int nVersion=PROTOCOL_VERSION) |
0a61b0df | 422 | { |
423 | a.Unserialize(is, (int)nType, nVersion); | |
424 | } | |
425 | ||
426 | ||
427 | ||
428 | ||
429 | ||
430 | // | |
431 | // string | |
432 | // | |
433 | template<typename C> | |
223b6f1b | 434 | unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int) |
0a61b0df | 435 | { |
436 | return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); | |
437 | } | |
438 | ||
439 | template<typename Stream, typename C> | |
223b6f1b | 440 | void Serialize(Stream& os, const std::basic_string<C>& str, int, int) |
0a61b0df | 441 | { |
442 | WriteCompactSize(os, str.size()); | |
443 | if (!str.empty()) | |
444 | os.write((char*)&str[0], str.size() * sizeof(str[0])); | |
445 | } | |
446 | ||
447 | template<typename Stream, typename C> | |
223b6f1b | 448 | void Unserialize(Stream& is, std::basic_string<C>& str, int, int) |
0a61b0df | 449 | { |
450 | unsigned int nSize = ReadCompactSize(is); | |
451 | str.resize(nSize); | |
452 | if (nSize != 0) | |
453 | is.read((char*)&str[0], nSize * sizeof(str[0])); | |
454 | } | |
455 | ||
456 | ||
457 | ||
458 | // | |
459 | // vector | |
460 | // | |
461 | template<typename T, typename A> | |
462 | unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) | |
463 | { | |
464 | return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); | |
465 | } | |
466 | ||
467 | template<typename T, typename A> | |
468 | unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) | |
469 | { | |
470 | unsigned int nSize = GetSizeOfCompactSize(v.size()); | |
471 | for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi) | |
472 | nSize += GetSerializeSize((*vi), nType, nVersion); | |
473 | return nSize; | |
474 | } | |
475 | ||
476 | template<typename T, typename A> | |
477 | inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion) | |
478 | { | |
479 | return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental<T>()); | |
480 | } | |
481 | ||
482 | ||
483 | template<typename Stream, typename T, typename A> | |
484 | void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) | |
485 | { | |
486 | WriteCompactSize(os, v.size()); | |
487 | if (!v.empty()) | |
488 | os.write((char*)&v[0], v.size() * sizeof(T)); | |
489 | } | |
490 | ||
491 | template<typename Stream, typename T, typename A> | |
492 | void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) | |
493 | { | |
494 | WriteCompactSize(os, v.size()); | |
495 | for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi) | |
496 | ::Serialize(os, (*vi), nType, nVersion); | |
497 | } | |
498 | ||
499 | template<typename Stream, typename T, typename A> | |
500 | inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion) | |
501 | { | |
502 | Serialize_impl(os, v, nType, nVersion, boost::is_fundamental<T>()); | |
503 | } | |
504 | ||
505 | ||
506 | template<typename Stream, typename T, typename A> | |
507 | void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) | |
508 | { | |
509 | //unsigned int nSize = ReadCompactSize(is); | |
510 | //v.resize(nSize); | |
511 | //is.read((char*)&v[0], nSize * sizeof(T)); | |
512 | ||
513 | // Limit size per read so bogus size value won't cause out of memory | |
514 | v.clear(); | |
515 | unsigned int nSize = ReadCompactSize(is); | |
516 | unsigned int i = 0; | |
517 | while (i < nSize) | |
518 | { | |
223b6f1b | 519 | unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); |
0a61b0df | 520 | v.resize(i + blk); |
521 | is.read((char*)&v[i], blk * sizeof(T)); | |
522 | i += blk; | |
523 | } | |
524 | } | |
525 | ||
526 | template<typename Stream, typename T, typename A> | |
527 | void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) | |
528 | { | |
529 | //unsigned int nSize = ReadCompactSize(is); | |
530 | //v.resize(nSize); | |
531 | //for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi) | |
532 | // Unserialize(is, (*vi), nType, nVersion); | |
533 | ||
534 | v.clear(); | |
535 | unsigned int nSize = ReadCompactSize(is); | |
536 | unsigned int i = 0; | |
537 | unsigned int nMid = 0; | |
538 | while (nMid < nSize) | |
539 | { | |
540 | nMid += 5000000 / sizeof(T); | |
541 | if (nMid > nSize) | |
542 | nMid = nSize; | |
543 | v.resize(nMid); | |
544 | for (; i < nMid; i++) | |
545 | Unserialize(is, v[i], nType, nVersion); | |
546 | } | |
547 | } | |
548 | ||
549 | template<typename Stream, typename T, typename A> | |
550 | inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion) | |
551 | { | |
552 | Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental<T>()); | |
553 | } | |
554 | ||
555 | ||
556 | ||
557 | // | |
558 | // others derived from vector | |
559 | // | |
560 | inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) | |
561 | { | |
223b6f1b | 562 | return GetSerializeSize((const std::vector<unsigned char>&)v, nType, nVersion); |
0a61b0df | 563 | } |
564 | ||
565 | template<typename Stream> | |
566 | void Serialize(Stream& os, const CScript& v, int nType, int nVersion) | |
567 | { | |
223b6f1b | 568 | Serialize(os, (const std::vector<unsigned char>&)v, nType, nVersion); |
0a61b0df | 569 | } |
570 | ||
571 | template<typename Stream> | |
572 | void Unserialize(Stream& is, CScript& v, int nType, int nVersion) | |
573 | { | |
223b6f1b | 574 | Unserialize(is, (std::vector<unsigned char>&)v, nType, nVersion); |
0a61b0df | 575 | } |
576 | ||
577 | ||
578 | ||
579 | // | |
580 | // pair | |
581 | // | |
582 | template<typename K, typename T> | |
583 | unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion) | |
584 | { | |
585 | return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); | |
586 | } | |
587 | ||
588 | template<typename Stream, typename K, typename T> | |
589 | void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion) | |
590 | { | |
591 | Serialize(os, item.first, nType, nVersion); | |
592 | Serialize(os, item.second, nType, nVersion); | |
593 | } | |
594 | ||
595 | template<typename Stream, typename K, typename T> | |
596 | void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion) | |
597 | { | |
598 | Unserialize(is, item.first, nType, nVersion); | |
599 | Unserialize(is, item.second, nType, nVersion); | |
600 | } | |
601 | ||
602 | ||
603 | ||
84d7c981 | 604 | // |
605 | // 3 tuple | |
606 | // | |
607 | template<typename T0, typename T1, typename T2> | |
608 | unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion) | |
609 | { | |
610 | unsigned int nSize = 0; | |
223b6f1b WL |
611 | nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); |
612 | nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); | |
613 | nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); | |
84d7c981 | 614 | return nSize; |
615 | } | |
616 | ||
617 | template<typename Stream, typename T0, typename T1, typename T2> | |
618 | void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion) | |
619 | { | |
223b6f1b WL |
620 | Serialize(os, boost::get<0>(item), nType, nVersion); |
621 | Serialize(os, boost::get<1>(item), nType, nVersion); | |
622 | Serialize(os, boost::get<2>(item), nType, nVersion); | |
84d7c981 | 623 | } |
624 | ||
625 | template<typename Stream, typename T0, typename T1, typename T2> | |
626 | void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion) | |
627 | { | |
223b6f1b WL |
628 | Unserialize(is, boost::get<0>(item), nType, nVersion); |
629 | Unserialize(is, boost::get<1>(item), nType, nVersion); | |
630 | Unserialize(is, boost::get<2>(item), nType, nVersion); | |
84d7c981 | 631 | } |
632 | ||
633 | ||
634 | ||
635 | // | |
636 | // 4 tuple | |
637 | // | |
638 | template<typename T0, typename T1, typename T2, typename T3> | |
639 | unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) | |
640 | { | |
641 | unsigned int nSize = 0; | |
223b6f1b WL |
642 | nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); |
643 | nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); | |
644 | nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); | |
645 | nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion); | |
84d7c981 | 646 | return nSize; |
647 | } | |
648 | ||
649 | template<typename Stream, typename T0, typename T1, typename T2, typename T3> | |
650 | void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) | |
651 | { | |
223b6f1b WL |
652 | Serialize(os, boost::get<0>(item), nType, nVersion); |
653 | Serialize(os, boost::get<1>(item), nType, nVersion); | |
654 | Serialize(os, boost::get<2>(item), nType, nVersion); | |
655 | Serialize(os, boost::get<3>(item), nType, nVersion); | |
84d7c981 | 656 | } |
657 | ||
658 | template<typename Stream, typename T0, typename T1, typename T2, typename T3> | |
659 | void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) | |
660 | { | |
223b6f1b WL |
661 | Unserialize(is, boost::get<0>(item), nType, nVersion); |
662 | Unserialize(is, boost::get<1>(item), nType, nVersion); | |
663 | Unserialize(is, boost::get<2>(item), nType, nVersion); | |
664 | Unserialize(is, boost::get<3>(item), nType, nVersion); | |
84d7c981 | 665 | } |
666 | ||
667 | ||
668 | ||
0a61b0df | 669 | // |
670 | // map | |
671 | // | |
672 | template<typename K, typename T, typename Pred, typename A> | |
673 | unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion) | |
674 | { | |
675 | unsigned int nSize = GetSizeOfCompactSize(m.size()); | |
676 | for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi) | |
677 | nSize += GetSerializeSize((*mi), nType, nVersion); | |
678 | return nSize; | |
679 | } | |
680 | ||
681 | template<typename Stream, typename K, typename T, typename Pred, typename A> | |
682 | void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion) | |
683 | { | |
684 | WriteCompactSize(os, m.size()); | |
685 | for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi) | |
686 | Serialize(os, (*mi), nType, nVersion); | |
687 | } | |
688 | ||
689 | template<typename Stream, typename K, typename T, typename Pred, typename A> | |
690 | void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion) | |
691 | { | |
692 | m.clear(); | |
693 | unsigned int nSize = ReadCompactSize(is); | |
694 | typename std::map<K, T, Pred, A>::iterator mi = m.begin(); | |
695 | for (unsigned int i = 0; i < nSize; i++) | |
696 | { | |
223b6f1b | 697 | std::pair<K, T> item; |
0a61b0df | 698 | Unserialize(is, item, nType, nVersion); |
699 | mi = m.insert(mi, item); | |
700 | } | |
701 | } | |
702 | ||
703 | ||
704 | ||
705 | // | |
706 | // set | |
707 | // | |
708 | template<typename K, typename Pred, typename A> | |
709 | unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion) | |
710 | { | |
711 | unsigned int nSize = GetSizeOfCompactSize(m.size()); | |
712 | for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it) | |
713 | nSize += GetSerializeSize((*it), nType, nVersion); | |
714 | return nSize; | |
715 | } | |
716 | ||
717 | template<typename Stream, typename K, typename Pred, typename A> | |
718 | void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion) | |
719 | { | |
720 | WriteCompactSize(os, m.size()); | |
721 | for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it) | |
722 | Serialize(os, (*it), nType, nVersion); | |
723 | } | |
724 | ||
725 | template<typename Stream, typename K, typename Pred, typename A> | |
726 | void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion) | |
727 | { | |
728 | m.clear(); | |
729 | unsigned int nSize = ReadCompactSize(is); | |
730 | typename std::set<K, Pred, A>::iterator it = m.begin(); | |
731 | for (unsigned int i = 0; i < nSize; i++) | |
732 | { | |
733 | K key; | |
734 | Unserialize(is, key, nType, nVersion); | |
735 | it = m.insert(it, key); | |
736 | } | |
737 | } | |
738 | ||
739 | ||
740 | ||
741 | // | |
742 | // Support for IMPLEMENT_SERIALIZE and READWRITE macro | |
743 | // | |
744 | class CSerActionGetSerializeSize { }; | |
745 | class CSerActionSerialize { }; | |
746 | class CSerActionUnserialize { }; | |
747 | ||
748 | template<typename Stream, typename T> | |
749 | inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) | |
750 | { | |
751 | return ::GetSerializeSize(obj, nType, nVersion); | |
752 | } | |
753 | ||
754 | template<typename Stream, typename T> | |
755 | inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) | |
756 | { | |
757 | ::Serialize(s, obj, nType, nVersion); | |
758 | return 0; | |
759 | } | |
760 | ||
761 | template<typename Stream, typename T> | |
762 | inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) | |
763 | { | |
764 | ::Unserialize(s, obj, nType, nVersion); | |
765 | return 0; | |
766 | } | |
767 | ||
768 | struct ser_streamplaceholder | |
769 | { | |
770 | int nType; | |
771 | int nVersion; | |
772 | }; | |
773 | ||
774 | ||
775 | ||
776 | ||
777 | ||
778 | ||
779 | ||
780 | ||
781 | ||
782 | // | |
c1aacf0b DN |
783 | // Allocator that locks its contents from being paged |
784 | // out of memory and clears its contents before deletion. | |
0a61b0df | 785 | // |
786 | template<typename T> | |
787 | struct secure_allocator : public std::allocator<T> | |
788 | { | |
789 | // MSVC8 default copy constructor is broken | |
790 | typedef std::allocator<T> base; | |
791 | typedef typename base::size_type size_type; | |
792 | typedef typename base::difference_type difference_type; | |
793 | typedef typename base::pointer pointer; | |
794 | typedef typename base::const_pointer const_pointer; | |
795 | typedef typename base::reference reference; | |
796 | typedef typename base::const_reference const_reference; | |
797 | typedef typename base::value_type value_type; | |
798 | secure_allocator() throw() {} | |
799 | secure_allocator(const secure_allocator& a) throw() : base(a) {} | |
47908a89 GA |
800 | template <typename U> |
801 | secure_allocator(const secure_allocator<U>& a) throw() : base(a) {} | |
0a61b0df | 802 | ~secure_allocator() throw() {} |
803 | template<typename _Other> struct rebind | |
804 | { typedef secure_allocator<_Other> other; }; | |
805 | ||
c1aacf0b DN |
806 | T* allocate(std::size_t n, const void *hint = 0) |
807 | { | |
808 | T *p; | |
809 | p = std::allocator<T>::allocate(n, hint); | |
810 | if (p != NULL) | |
811 | mlock(p, sizeof(T) * n); | |
812 | return p; | |
813 | } | |
814 | ||
0a61b0df | 815 | void deallocate(T* p, std::size_t n) |
816 | { | |
817 | if (p != NULL) | |
c1aacf0b | 818 | { |
0a61b0df | 819 | memset(p, 0, sizeof(T) * n); |
c1aacf0b DN |
820 | munlock(p, sizeof(T) * n); |
821 | } | |
223b6f1b | 822 | std::allocator<T>::deallocate(p, n); |
0a61b0df | 823 | } |
824 | }; | |
825 | ||
826 | ||
f7a9a113 MC |
827 | // |
828 | // Allocator that clears its contents before deletion. | |
829 | // | |
830 | template<typename T> | |
831 | struct zero_after_free_allocator : public std::allocator<T> | |
832 | { | |
833 | // MSVC8 default copy constructor is broken | |
834 | typedef std::allocator<T> base; | |
835 | typedef typename base::size_type size_type; | |
836 | typedef typename base::difference_type difference_type; | |
837 | typedef typename base::pointer pointer; | |
838 | typedef typename base::const_pointer const_pointer; | |
839 | typedef typename base::reference reference; | |
840 | typedef typename base::const_reference const_reference; | |
841 | typedef typename base::value_type value_type; | |
842 | zero_after_free_allocator() throw() {} | |
843 | zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {} | |
844 | template <typename U> | |
845 | zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a) {} | |
846 | ~zero_after_free_allocator() throw() {} | |
847 | template<typename _Other> struct rebind | |
848 | { typedef zero_after_free_allocator<_Other> other; }; | |
849 | ||
850 | void deallocate(T* p, std::size_t n) | |
851 | { | |
852 | if (p != NULL) | |
853 | memset(p, 0, sizeof(T) * n); | |
854 | std::allocator<T>::deallocate(p, n); | |
855 | } | |
856 | }; | |
857 | ||
858 | ||
0a61b0df | 859 | |
6b8de05d PW |
860 | /** Double ended buffer combining vector and stream-like interfaces. |
861 | * | |
862 | * >> and << read and write unformatted data using the above serialization templates. | |
863 | * Fills with data in linear time; some stringstream implementations take N^2 time. | |
864 | */ | |
0a61b0df | 865 | class CDataStream |
866 | { | |
867 | protected: | |
f7a9a113 | 868 | typedef std::vector<char, zero_after_free_allocator<char> > vector_type; |
0a61b0df | 869 | vector_type vch; |
870 | unsigned int nReadPos; | |
871 | short state; | |
872 | short exceptmask; | |
873 | public: | |
874 | int nType; | |
875 | int nVersion; | |
876 | ||
877 | typedef vector_type::allocator_type allocator_type; | |
878 | typedef vector_type::size_type size_type; | |
879 | typedef vector_type::difference_type difference_type; | |
880 | typedef vector_type::reference reference; | |
881 | typedef vector_type::const_reference const_reference; | |
882 | typedef vector_type::value_type value_type; | |
883 | typedef vector_type::iterator iterator; | |
884 | typedef vector_type::const_iterator const_iterator; | |
885 | typedef vector_type::reverse_iterator reverse_iterator; | |
886 | ||
f8ded588 | 887 | explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) |
0a61b0df | 888 | { |
889 | Init(nTypeIn, nVersionIn); | |
890 | } | |
891 | ||
f8ded588 | 892 | CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend) |
0a61b0df | 893 | { |
894 | Init(nTypeIn, nVersionIn); | |
895 | } | |
896 | ||
897 | #if !defined(_MSC_VER) || _MSC_VER >= 1300 | |
f8ded588 | 898 | CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend) |
0a61b0df | 899 | { |
900 | Init(nTypeIn, nVersionIn); | |
901 | } | |
902 | #endif | |
903 | ||
f8ded588 | 904 | CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) |
0a61b0df | 905 | { |
906 | Init(nTypeIn, nVersionIn); | |
907 | } | |
908 | ||
f8ded588 | 909 | CDataStream(const std::vector<char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) |
0a61b0df | 910 | { |
911 | Init(nTypeIn, nVersionIn); | |
912 | } | |
913 | ||
f8ded588 | 914 | CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) |
0a61b0df | 915 | { |
916 | Init(nTypeIn, nVersionIn); | |
917 | } | |
918 | ||
f8ded588 | 919 | void Init(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) |
0a61b0df | 920 | { |
921 | nReadPos = 0; | |
922 | nType = nTypeIn; | |
923 | nVersion = nVersionIn; | |
924 | state = 0; | |
223b6f1b | 925 | exceptmask = std::ios::badbit | std::ios::failbit; |
0a61b0df | 926 | } |
927 | ||
928 | CDataStream& operator+=(const CDataStream& b) | |
929 | { | |
930 | vch.insert(vch.end(), b.begin(), b.end()); | |
931 | return *this; | |
932 | } | |
933 | ||
934 | friend CDataStream operator+(const CDataStream& a, const CDataStream& b) | |
935 | { | |
936 | CDataStream ret = a; | |
937 | ret += b; | |
938 | return (ret); | |
939 | } | |
940 | ||
223b6f1b | 941 | std::string str() const |
0a61b0df | 942 | { |
223b6f1b | 943 | return (std::string(begin(), end())); |
0a61b0df | 944 | } |
945 | ||
946 | ||
947 | // | |
948 | // Vector subset | |
949 | // | |
950 | const_iterator begin() const { return vch.begin() + nReadPos; } | |
951 | iterator begin() { return vch.begin() + nReadPos; } | |
952 | const_iterator end() const { return vch.end(); } | |
953 | iterator end() { return vch.end(); } | |
954 | size_type size() const { return vch.size() - nReadPos; } | |
955 | bool empty() const { return vch.size() == nReadPos; } | |
956 | void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } | |
957 | void reserve(size_type n) { vch.reserve(n + nReadPos); } | |
958 | const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } | |
959 | reference operator[](size_type pos) { return vch[pos + nReadPos]; } | |
960 | void clear() { vch.clear(); nReadPos = 0; } | |
961 | iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } | |
962 | void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } | |
963 | ||
964 | void insert(iterator it, const_iterator first, const_iterator last) | |
965 | { | |
966 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) | |
967 | { | |
968 | // special case for inserting at the front when there's room | |
969 | nReadPos -= (last - first); | |
970 | memcpy(&vch[nReadPos], &first[0], last - first); | |
971 | } | |
972 | else | |
973 | vch.insert(it, first, last); | |
974 | } | |
975 | ||
223b6f1b | 976 | void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last) |
0a61b0df | 977 | { |
978 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) | |
979 | { | |
980 | // special case for inserting at the front when there's room | |
981 | nReadPos -= (last - first); | |
982 | memcpy(&vch[nReadPos], &first[0], last - first); | |
983 | } | |
984 | else | |
985 | vch.insert(it, first, last); | |
986 | } | |
987 | ||
988 | #if !defined(_MSC_VER) || _MSC_VER >= 1300 | |
989 | void insert(iterator it, const char* first, const char* last) | |
990 | { | |
991 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) | |
992 | { | |
993 | // special case for inserting at the front when there's room | |
994 | nReadPos -= (last - first); | |
995 | memcpy(&vch[nReadPos], &first[0], last - first); | |
996 | } | |
997 | else | |
998 | vch.insert(it, first, last); | |
999 | } | |
1000 | #endif | |
1001 | ||
1002 | iterator erase(iterator it) | |
1003 | { | |
1004 | if (it == vch.begin() + nReadPos) | |
1005 | { | |
1006 | // special case for erasing from the front | |
1007 | if (++nReadPos >= vch.size()) | |
1008 | { | |
1009 | // whenever we reach the end, we take the opportunity to clear the buffer | |
1010 | nReadPos = 0; | |
1011 | return vch.erase(vch.begin(), vch.end()); | |
1012 | } | |
1013 | return vch.begin() + nReadPos; | |
1014 | } | |
1015 | else | |
1016 | return vch.erase(it); | |
1017 | } | |
1018 | ||
1019 | iterator erase(iterator first, iterator last) | |
1020 | { | |
1021 | if (first == vch.begin() + nReadPos) | |
1022 | { | |
1023 | // special case for erasing from the front | |
1024 | if (last == vch.end()) | |
1025 | { | |
1026 | nReadPos = 0; | |
1027 | return vch.erase(vch.begin(), vch.end()); | |
1028 | } | |
1029 | else | |
1030 | { | |
1031 | nReadPos = (last - vch.begin()); | |
1032 | return last; | |
1033 | } | |
1034 | } | |
1035 | else | |
1036 | return vch.erase(first, last); | |
1037 | } | |
1038 | ||
1039 | inline void Compact() | |
1040 | { | |
1041 | vch.erase(vch.begin(), vch.begin() + nReadPos); | |
1042 | nReadPos = 0; | |
1043 | } | |
1044 | ||
1045 | bool Rewind(size_type n) | |
1046 | { | |
1047 | // Rewind by n characters if the buffer hasn't been compacted yet | |
1048 | if (n > nReadPos) | |
1049 | return false; | |
1050 | nReadPos -= n; | |
1051 | return true; | |
1052 | } | |
1053 | ||
1054 | ||
1055 | // | |
1056 | // Stream subset | |
1057 | // | |
1058 | void setstate(short bits, const char* psz) | |
1059 | { | |
1060 | state |= bits; | |
1061 | if (state & exceptmask) | |
1062 | throw std::ios_base::failure(psz); | |
1063 | } | |
1064 | ||
1065 | bool eof() const { return size() == 0; } | |
223b6f1b | 1066 | bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } |
0a61b0df | 1067 | bool good() const { return !eof() && (state == 0); } |
1068 | void clear(short n) { state = n; } // name conflict with vector clear() | |
1069 | short exceptions() { return exceptmask; } | |
1070 | short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } | |
1071 | CDataStream* rdbuf() { return this; } | |
1072 | int in_avail() { return size(); } | |
1073 | ||
1074 | void SetType(int n) { nType = n; } | |
1075 | int GetType() { return nType; } | |
1076 | void SetVersion(int n) { nVersion = n; } | |
1077 | int GetVersion() { return nVersion; } | |
1078 | void ReadVersion() { *this >> nVersion; } | |
1079 | void WriteVersion() { *this << nVersion; } | |
1080 | ||
1081 | CDataStream& read(char* pch, int nSize) | |
1082 | { | |
1083 | // Read from the beginning of the buffer | |
1084 | assert(nSize >= 0); | |
1085 | unsigned int nReadPosNext = nReadPos + nSize; | |
1086 | if (nReadPosNext >= vch.size()) | |
1087 | { | |
1088 | if (nReadPosNext > vch.size()) | |
1089 | { | |
223b6f1b | 1090 | setstate(std::ios::failbit, "CDataStream::read() : end of data"); |
0a61b0df | 1091 | memset(pch, 0, nSize); |
1092 | nSize = vch.size() - nReadPos; | |
1093 | } | |
1094 | memcpy(pch, &vch[nReadPos], nSize); | |
1095 | nReadPos = 0; | |
1096 | vch.clear(); | |
1097 | return (*this); | |
1098 | } | |
1099 | memcpy(pch, &vch[nReadPos], nSize); | |
1100 | nReadPos = nReadPosNext; | |
1101 | return (*this); | |
1102 | } | |
1103 | ||
1104 | CDataStream& ignore(int nSize) | |
1105 | { | |
1106 | // Ignore from the beginning of the buffer | |
1107 | assert(nSize >= 0); | |
1108 | unsigned int nReadPosNext = nReadPos + nSize; | |
1109 | if (nReadPosNext >= vch.size()) | |
1110 | { | |
1111 | if (nReadPosNext > vch.size()) | |
1112 | { | |
223b6f1b | 1113 | setstate(std::ios::failbit, "CDataStream::ignore() : end of data"); |
0a61b0df | 1114 | nSize = vch.size() - nReadPos; |
1115 | } | |
1116 | nReadPos = 0; | |
1117 | vch.clear(); | |
1118 | return (*this); | |
1119 | } | |
1120 | nReadPos = nReadPosNext; | |
1121 | return (*this); | |
1122 | } | |
1123 | ||
1124 | CDataStream& write(const char* pch, int nSize) | |
1125 | { | |
1126 | // Write to the end of the buffer | |
1127 | assert(nSize >= 0); | |
1128 | vch.insert(vch.end(), pch, pch + nSize); | |
1129 | return (*this); | |
1130 | } | |
1131 | ||
1132 | template<typename Stream> | |
f8ded588 | 1133 | void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const |
0a61b0df | 1134 | { |
1135 | // Special case: stream << stream concatenates like stream += stream | |
1136 | if (!vch.empty()) | |
1137 | s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); | |
1138 | } | |
1139 | ||
1140 | template<typename T> | |
1141 | unsigned int GetSerializeSize(const T& obj) | |
1142 | { | |
1143 | // Tells the size of the object if serialized to this stream | |
1144 | return ::GetSerializeSize(obj, nType, nVersion); | |
1145 | } | |
1146 | ||
1147 | template<typename T> | |
1148 | CDataStream& operator<<(const T& obj) | |
1149 | { | |
1150 | // Serialize to this stream | |
1151 | ::Serialize(*this, obj, nType, nVersion); | |
1152 | return (*this); | |
1153 | } | |
1154 | ||
1155 | template<typename T> | |
1156 | CDataStream& operator>>(T& obj) | |
1157 | { | |
1158 | // Unserialize from this stream | |
1159 | ::Unserialize(*this, obj, nType, nVersion); | |
1160 | return (*this); | |
1161 | } | |
1162 | }; | |
1163 | ||
1164 | #ifdef TESTCDATASTREAM | |
1165 | // VC6sp6 | |
1166 | // CDataStream: | |
1167 | // n=1000 0 seconds | |
1168 | // n=2000 0 seconds | |
1169 | // n=4000 0 seconds | |
1170 | // n=8000 0 seconds | |
1171 | // n=16000 0 seconds | |
1172 | // n=32000 0 seconds | |
1173 | // n=64000 1 seconds | |
1174 | // n=128000 1 seconds | |
1175 | // n=256000 2 seconds | |
1176 | // n=512000 4 seconds | |
1177 | // n=1024000 8 seconds | |
1178 | // n=2048000 16 seconds | |
1179 | // n=4096000 32 seconds | |
1180 | // stringstream: | |
1181 | // n=1000 1 seconds | |
1182 | // n=2000 1 seconds | |
1183 | // n=4000 13 seconds | |
1184 | // n=8000 87 seconds | |
1185 | // n=16000 400 seconds | |
1186 | // n=32000 1660 seconds | |
1187 | // n=64000 6749 seconds | |
1188 | // n=128000 27241 seconds | |
1189 | // n=256000 109804 seconds | |
1190 | #include <iostream> | |
1191 | int main(int argc, char *argv[]) | |
1192 | { | |
1193 | vector<unsigned char> vch(0xcc, 250); | |
1194 | printf("CDataStream:\n"); | |
1195 | for (int n = 1000; n <= 4500000; n *= 2) | |
1196 | { | |
1197 | CDataStream ss; | |
1198 | time_t nStart = time(NULL); | |
1199 | for (int i = 0; i < n; i++) | |
1200 | ss.write((char*)&vch[0], vch.size()); | |
1201 | printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); | |
1202 | } | |
1203 | printf("stringstream:\n"); | |
1204 | for (int n = 1000; n <= 4500000; n *= 2) | |
1205 | { | |
1206 | stringstream ss; | |
1207 | time_t nStart = time(NULL); | |
1208 | for (int i = 0; i < n; i++) | |
1209 | ss.write((char*)&vch[0], vch.size()); | |
1210 | printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); | |
1211 | } | |
1212 | } | |
1213 | #endif | |
1214 | ||
1215 | ||
1216 | ||
1217 | ||
1218 | ||
1219 | ||
1220 | ||
1221 | ||
1222 | ||
1223 | ||
6b8de05d PW |
1224 | /** RAII wrapper for FILE*. |
1225 | * | |
1226 | * Will automatically close the file when it goes out of scope if not null. | |
1227 | * If you're returning the file pointer, return file.release(). | |
1228 | * If you need to close the file early, use file.fclose() instead of fclose(file). | |
1229 | */ | |
0a61b0df | 1230 | class CAutoFile |
1231 | { | |
1232 | protected: | |
1233 | FILE* file; | |
1234 | short state; | |
1235 | short exceptmask; | |
1236 | public: | |
1237 | int nType; | |
1238 | int nVersion; | |
1239 | ||
1240 | typedef FILE element_type; | |
1241 | ||
f8ded588 | 1242 | CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=PROTOCOL_VERSION) |
0a61b0df | 1243 | { |
1244 | file = filenew; | |
1245 | nType = nTypeIn; | |
1246 | nVersion = nVersionIn; | |
1247 | state = 0; | |
223b6f1b | 1248 | exceptmask = std::ios::badbit | std::ios::failbit; |
0a61b0df | 1249 | } |
1250 | ||
1251 | ~CAutoFile() | |
1252 | { | |
1253 | fclose(); | |
1254 | } | |
1255 | ||
1256 | void fclose() | |
1257 | { | |
1258 | if (file != NULL && file != stdin && file != stdout && file != stderr) | |
1259 | ::fclose(file); | |
1260 | file = NULL; | |
1261 | } | |
1262 | ||
1263 | FILE* release() { FILE* ret = file; file = NULL; return ret; } | |
1264 | operator FILE*() { return file; } | |
1265 | FILE* operator->() { return file; } | |
1266 | FILE& operator*() { return *file; } | |
1267 | FILE** operator&() { return &file; } | |
1268 | FILE* operator=(FILE* pnew) { return file = pnew; } | |
1269 | bool operator!() { return (file == NULL); } | |
1270 | ||
1271 | ||
1272 | // | |
1273 | // Stream subset | |
1274 | // | |
1275 | void setstate(short bits, const char* psz) | |
1276 | { | |
1277 | state |= bits; | |
1278 | if (state & exceptmask) | |
1279 | throw std::ios_base::failure(psz); | |
1280 | } | |
1281 | ||
223b6f1b | 1282 | bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } |
0a61b0df | 1283 | bool good() const { return state == 0; } |
1284 | void clear(short n = 0) { state = n; } | |
1285 | short exceptions() { return exceptmask; } | |
1286 | short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } | |
1287 | ||
1288 | void SetType(int n) { nType = n; } | |
1289 | int GetType() { return nType; } | |
1290 | void SetVersion(int n) { nVersion = n; } | |
1291 | int GetVersion() { return nVersion; } | |
1292 | void ReadVersion() { *this >> nVersion; } | |
1293 | void WriteVersion() { *this << nVersion; } | |
1294 | ||
1295 | CAutoFile& read(char* pch, int nSize) | |
1296 | { | |
1297 | if (!file) | |
1298 | throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); | |
1299 | if (fread(pch, 1, nSize, file) != nSize) | |
223b6f1b | 1300 | setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); |
0a61b0df | 1301 | return (*this); |
1302 | } | |
1303 | ||
1304 | CAutoFile& write(const char* pch, int nSize) | |
1305 | { | |
1306 | if (!file) | |
1307 | throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); | |
1308 | if (fwrite(pch, 1, nSize, file) != nSize) | |
223b6f1b | 1309 | setstate(std::ios::failbit, "CAutoFile::write : write failed"); |
0a61b0df | 1310 | return (*this); |
1311 | } | |
1312 | ||
1313 | template<typename T> | |
1314 | unsigned int GetSerializeSize(const T& obj) | |
1315 | { | |
1316 | // Tells the size of the object if serialized to this stream | |
1317 | return ::GetSerializeSize(obj, nType, nVersion); | |
1318 | } | |
1319 | ||
1320 | template<typename T> | |
1321 | CAutoFile& operator<<(const T& obj) | |
1322 | { | |
1323 | // Serialize to this stream | |
1324 | if (!file) | |
1325 | throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); | |
1326 | ::Serialize(*this, obj, nType, nVersion); | |
1327 | return (*this); | |
1328 | } | |
1329 | ||
1330 | template<typename T> | |
1331 | CAutoFile& operator>>(T& obj) | |
1332 | { | |
1333 | // Unserialize from this stream | |
1334 | if (!file) | |
1335 | throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); | |
1336 | ::Unserialize(*this, obj, nType, nVersion); | |
1337 | return (*this); | |
1338 | } | |
1339 | }; | |
223b6f1b WL |
1340 | |
1341 | #endif |