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