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