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