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