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