upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

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