]> Git Repo - VerusCoin.git/blob - src/streams.h
6fc8a93da3b04845ad875de894cb61569c1a3d6a
[VerusCoin.git] / src / streams.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #ifndef BITCOIN_STREAMS_H
7 #define BITCOIN_STREAMS_H
8
9 #include "support/allocators/zeroafterfree.h"
10 #include "serialize.h"
11
12 #include <algorithm>
13 #include <assert.h>
14 #include <ios>
15 #include <limits>
16 #include <map>
17 #include <set>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <string>
21 #include <string.h>
22 #include <utility>
23 #include <vector>
24
25 /** Double ended buffer combining vector and stream-like interfaces.
26  *
27  * >> and << read and write unformatted data using the above serialization templates.
28  * Fills with data in linear time; some stringstream implementations take N^2 time.
29  */
30 template<typename SerializeType>
31 class CBaseDataStream
32 {
33 protected:
34     typedef SerializeType vector_type;
35     vector_type vch;
36     unsigned int nReadPos;
37
38     int nType;
39     int nVersion;
40 public:
41
42     typedef typename vector_type::allocator_type   allocator_type;
43     typedef typename vector_type::size_type        size_type;
44     typedef typename vector_type::difference_type  difference_type;
45     typedef typename vector_type::reference        reference;
46     typedef typename vector_type::const_reference  const_reference;
47     typedef typename vector_type::value_type       value_type;
48     typedef typename vector_type::iterator         iterator;
49     typedef typename vector_type::const_iterator   const_iterator;
50     typedef typename vector_type::reverse_iterator reverse_iterator;
51
52     explicit CBaseDataStream(int nTypeIn, int nVersionIn)
53     {
54         Init(nTypeIn, nVersionIn);
55     }
56
57     CBaseDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
58     {
59         Init(nTypeIn, nVersionIn);
60     }
61
62 #if !defined(_MSC_VER) || _MSC_VER >= 1300
63     CBaseDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
64     {
65         Init(nTypeIn, nVersionIn);
66     }
67 #endif
68
69     CBaseDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
70     {
71         Init(nTypeIn, nVersionIn);
72     }
73
74     CBaseDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
75     {
76         Init(nTypeIn, nVersionIn);
77     }
78
79     CBaseDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
80     {
81         Init(nTypeIn, nVersionIn);
82     }
83
84     template <typename... Args>
85     CBaseDataStream(int nTypeIn, int nVersionIn, Args&&... args)
86     {
87         Init(nTypeIn, nVersionIn);
88         ::SerializeMany(*this, nType, nVersion, std::forward<Args>(args)...);
89     }
90
91     void Init(int nTypeIn, int nVersionIn)
92     {
93         nReadPos = 0;
94         nType = nTypeIn;
95         nVersion = nVersionIn;
96     }
97
98     CBaseDataStream& operator+=(const CBaseDataStream& b)
99     {
100         vch.insert(vch.end(), b.begin(), b.end());
101         return *this;
102     }
103
104     friend CBaseDataStream operator+(const CBaseDataStream& a, const CBaseDataStream& b)
105     {
106         CBaseDataStream ret = a;
107         ret += b;
108         return (ret);
109     }
110
111     std::string str() const
112     {
113         return (std::string(begin(), end()));
114     }
115
116
117     //
118     // Vector subset
119     //
120     const_iterator begin() const                     { return vch.begin() + nReadPos; }
121     iterator begin()                                 { return vch.begin() + nReadPos; }
122     const_iterator end() const                       { return vch.end(); }
123     iterator end()                                   { return vch.end(); }
124     size_type size() const                           { return vch.size() - nReadPos; }
125     bool empty() const                               { return vch.size() == nReadPos; }
126     void resize(size_type n, value_type c=0)         { vch.resize(n + nReadPos, c); }
127     void reserve(size_type n)                        { vch.reserve(n + nReadPos); }
128     const_reference operator[](size_type pos) const  { return vch[pos + nReadPos]; }
129     reference operator[](size_type pos)              { return vch[pos + nReadPos]; }
130     void clear()                                     { vch.clear(); nReadPos = 0; }
131     iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
132     void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
133
134     void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
135     {
136         assert(last - first >= 0);
137         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
138         {
139             // special case for inserting at the front when there's room
140             nReadPos -= (last - first);
141             memcpy(&vch[nReadPos], &first[0], last - first);
142         }
143         else
144             vch.insert(it, first, last);
145     }
146
147 #if !defined(_MSC_VER) || _MSC_VER >= 1300
148     void insert(iterator it, const char* first, const char* last)
149     {
150         assert(last - first >= 0);
151         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
152         {
153             // special case for inserting at the front when there's room
154             nReadPos -= (last - first);
155             memcpy(&vch[nReadPos], &first[0], last - first);
156         }
157         else
158             vch.insert(it, first, last);
159     }
160 #endif
161
162     iterator erase(iterator it)
163     {
164         if (it == vch.begin() + nReadPos)
165         {
166             // special case for erasing from the front
167             if (++nReadPos >= vch.size())
168             {
169                 // whenever we reach the end, we take the opportunity to clear the buffer
170                 nReadPos = 0;
171                 return vch.erase(vch.begin(), vch.end());
172             }
173             return vch.begin() + nReadPos;
174         }
175         else
176             return vch.erase(it);
177     }
178
179     iterator erase(iterator first, iterator last)
180     {
181         if (first == vch.begin() + nReadPos)
182         {
183             // special case for erasing from the front
184             if (last == vch.end())
185             {
186                 nReadPos = 0;
187                 return vch.erase(vch.begin(), vch.end());
188             }
189             else
190             {
191                 nReadPos = (last - vch.begin());
192                 return last;
193             }
194         }
195         else
196             return vch.erase(first, last);
197     }
198
199     inline void Compact()
200     {
201         vch.erase(vch.begin(), vch.begin() + nReadPos);
202         nReadPos = 0;
203     }
204
205     bool Rewind(size_type n)
206     {
207         // Rewind by n characters if the buffer hasn't been compacted yet
208         if (n > nReadPos)
209             return false;
210         nReadPos -= n;
211         return true;
212     }
213
214
215     //
216     // Stream subset
217     //
218     bool eof() const             { return size() == 0; }
219     CBaseDataStream* rdbuf()         { return this; }
220     int in_avail()               { return size(); }
221
222     void SetType(int n)          { nType = n; }
223     int GetType() const          { return nType; }
224     void SetVersion(int n)       { nVersion = n; }
225     int GetVersion() const       { return nVersion; }
226
227     void read(char* pch, size_t nSize)
228     {
229         // Read from the beginning of the buffer
230         unsigned int nReadPosNext = nReadPos + nSize;
231         if (nReadPosNext >= vch.size())
232         {
233             if (nReadPosNext > vch.size())
234             {
235                 throw std::ios_base::failure("CBaseDataStream::read(): end of data");
236             }
237             memcpy(pch, &vch[nReadPos], nSize);
238             nReadPos = 0;
239             vch.clear();
240             return;
241         }
242         memcpy(pch, &vch[nReadPos], nSize);
243         nReadPos = nReadPosNext;
244     }
245
246     void ignore(int nSize)
247     {
248         // Ignore from the beginning of the buffer
249         if (nSize < 0) {
250             throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
251         }
252         unsigned int nReadPosNext = nReadPos + nSize;
253         if (nReadPosNext >= vch.size())
254         {
255             if (nReadPosNext > vch.size())
256                 throw std::ios_base::failure("CBaseDataStream::ignore(): end of data");
257             nReadPos = 0;
258             vch.clear();
259             return;
260         }
261         nReadPos = nReadPosNext;
262     }
263
264     void write(const char* pch, size_t nSize)
265     {
266         // Write to the end of the buffer
267         vch.insert(vch.end(), pch, pch + nSize);
268     }
269
270     template<typename Stream>
271     void Serialize(Stream& s, int nType, int nVersion) const
272     {
273         // Special case: stream << stream concatenates like stream += stream
274         if (!vch.empty())
275             s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
276     }
277
278     template<typename T>
279     CBaseDataStream& operator<<(const T& obj)
280     {
281         // Serialize to this stream
282         ::Serialize(*this, obj, nType, nVersion);
283         return (*this);
284     }
285
286     template<typename T>
287     CBaseDataStream& operator>>(T& obj)
288     {
289         // Unserialize from this stream
290         ::Unserialize(*this, obj, nType, nVersion);
291         return (*this);
292     }
293
294     void GetAndClear(CSerializeData &d) {
295         d.insert(d.end(), begin(), end());
296         clear();
297     }
298 };
299
300 class CDataStream : public CBaseDataStream<CSerializeData>
301 {
302 public:
303     explicit CDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
304
305     CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
306             CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
307
308 #if !defined(_MSC_VER) || _MSC_VER >= 1300
309     CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) :
310             CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
311 #endif
312
313     CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
314             CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
315
316     CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) :
317             CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
318
319     CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) :
320             CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
321
322     template <typename... Args>
323     CDataStream(int nTypeIn, int nVersionIn, Args&&... args) :
324             CBaseDataStream(nTypeIn, nVersionIn, args...) { }
325
326 };
327
328
329
330
331
332
333
334
335
336
337 /** Non-refcounted RAII wrapper for FILE*
338  *
339  * Will automatically close the file when it goes out of scope if not null.
340  * If you're returning the file pointer, return file.release().
341  * If you need to close the file early, use file.fclose() instead of fclose(file).
342  */
343 class CAutoFile
344 {
345 private:
346     // Disallow copies
347     CAutoFile(const CAutoFile&);
348     CAutoFile& operator=(const CAutoFile&);
349
350     const int nType;
351     const int nVersion;
352
353     FILE* file; 
354
355 public:
356     CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
357     {
358         file = filenew;
359     }
360
361     ~CAutoFile()
362     {
363         fclose();
364     }
365
366     void fclose()
367     {
368         if (file) {
369             ::fclose(file);
370             file = NULL;
371         }
372     }
373
374     /** Get wrapped FILE* with transfer of ownership.
375      * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
376      * of this function to clean up the returned FILE*.
377      */
378     FILE* release()             { FILE* ret = file; file = NULL; return ret; }
379
380     /** Get wrapped FILE* without transfer of ownership.
381      * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
382      * CAutoFile outlives use of the passed pointer.
383      */
384     FILE* Get() const           { return file; }
385
386     /** Return true if the wrapped FILE* is NULL, false otherwise.
387      */
388     bool IsNull() const         { return (file == NULL); }
389
390     //
391     // Stream subset
392     //
393     int GetType() const          { return nType; }
394     int GetVersion() const       { return nVersion; }
395
396     void read(char* pch, size_t nSize)
397     {
398         if (!file)
399             throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
400         if (fread(pch, 1, nSize, file) != nSize)
401             throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
402     }
403
404     void ignore(size_t nSize)
405     {
406         if (!file)
407             throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL");
408         unsigned char data[4096];
409         while (nSize > 0) {
410             size_t nNow = std::min<size_t>(nSize, sizeof(data));
411             if (fread(data, 1, nNow, file) != nNow)
412                 throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
413             nSize -= nNow;
414         }
415     }
416
417     void write(const char* pch, size_t nSize)
418     {
419         if (!file)
420             throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
421         if (fwrite(pch, 1, nSize, file) != nSize)
422             throw std::ios_base::failure("CAutoFile::write: write failed");
423     }
424
425     template<typename T>
426     CAutoFile& operator<<(const T& obj)
427     {
428         // Serialize to this stream
429         if (!file)
430             throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
431         ::Serialize(*this, obj, nType, nVersion);
432         return (*this);
433     }
434
435     template<typename T>
436     CAutoFile& operator>>(T& obj)
437     {
438         // Unserialize from this stream
439         if (!file)
440             throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
441         ::Unserialize(*this, obj, nType, nVersion);
442         return (*this);
443     }
444 };
445
446 /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
447  *  deserialize from. It guarantees the ability to rewind a given number of bytes.
448  *
449  *  Will automatically close the file when it goes out of scope if not null.
450  *  If you need to close the file early, use file.fclose() instead of fclose(file).
451  */
452 class CBufferedFile
453 {
454 private:
455     // Disallow copies
456     CBufferedFile(const CBufferedFile&);
457     CBufferedFile& operator=(const CBufferedFile&);
458
459     const int nType;
460     const int nVersion;
461
462     FILE *src;            // source file
463     uint64_t nSrcPos;     // how many bytes have been read from source
464     uint64_t nReadPos;    // how many bytes have been read from this
465     uint64_t nReadLimit;  // up to which position we're allowed to read
466     uint64_t nRewind;     // how many bytes we guarantee to rewind
467     std::vector<char> vchBuf; // the buffer
468
469 protected:
470     // read data from the source to fill the buffer
471     bool Fill() {
472         unsigned int pos = nSrcPos % vchBuf.size();
473         unsigned int readNow = vchBuf.size() - pos;
474         unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
475         if (nAvail < readNow)
476             readNow = nAvail;
477         if (readNow == 0)
478             return false;
479         size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
480         if (read == 0) {
481             throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
482         } else {
483             nSrcPos += read;
484             return true;
485         }
486     }
487
488 public:
489     CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
490         nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
491     {
492         src = fileIn;
493     }
494
495     ~CBufferedFile()
496     {
497         fclose();
498     }
499
500     void fclose()
501     {
502         if (src) {
503             ::fclose(src);
504             src = NULL;
505         }
506     }
507
508     // check whether we're at the end of the source file
509     bool eof() const {
510         return nReadPos == nSrcPos && feof(src);
511     }
512
513     // read a number of bytes
514     void read(char *pch, size_t nSize) {
515         if (nSize + nReadPos > nReadLimit)
516             throw std::ios_base::failure("Read attempted past buffer limit");
517         if (nSize + nRewind > vchBuf.size())
518             throw std::ios_base::failure("Read larger than buffer size");
519         while (nSize > 0) {
520             if (nReadPos == nSrcPos)
521                 Fill();
522             unsigned int pos = nReadPos % vchBuf.size();
523             size_t nNow = nSize;
524             if (nNow + pos > vchBuf.size())
525                 nNow = vchBuf.size() - pos;
526             if (nNow + nReadPos > nSrcPos)
527                 nNow = nSrcPos - nReadPos;
528             memcpy(pch, &vchBuf[pos], nNow);
529             nReadPos += nNow;
530             pch += nNow;
531             nSize -= nNow;
532         }
533     }
534
535     // return the current reading position
536     uint64_t GetPos() {
537         return nReadPos;
538     }
539
540     // rewind to a given reading position
541     bool SetPos(uint64_t nPos) {
542         nReadPos = nPos;
543         if (nReadPos + nRewind < nSrcPos) {
544             nReadPos = nSrcPos - nRewind;
545             return false;
546         } else if (nReadPos > nSrcPos) {
547             nReadPos = nSrcPos;
548             return false;
549         } else {
550             return true;
551         }
552     }
553
554     bool Seek(uint64_t nPos) {
555         long nLongPos = nPos;
556         if (nPos != (uint64_t)nLongPos)
557             return false;
558         if (fseek(src, nLongPos, SEEK_SET))
559             return false;
560         nLongPos = ftell(src);
561         nSrcPos = nLongPos;
562         nReadPos = nLongPos;
563         return true;
564     }
565
566     // prevent reading beyond a certain position
567     // no argument removes the limit
568     bool SetLimit(uint64_t nPos = (uint64_t)(-1)) {
569         if (nPos < nReadPos)
570             return false;
571         nReadLimit = nPos;
572         return true;
573     }
574
575     template<typename T>
576     CBufferedFile& operator>>(T& obj) {
577         // Unserialize from this stream
578         ::Unserialize(*this, obj, nType, nVersion);
579         return (*this);
580     }
581
582     // search for a given byte in the stream, and remain positioned on it
583     void FindByte(char ch) {
584         while (true) {
585             if (nReadPos == nSrcPos)
586                 Fill();
587             if (vchBuf[nReadPos % vchBuf.size()] == ch)
588                 break;
589             nReadPos++;
590         }
591     }
592 };
593
594 #endif // BITCOIN_STREAMS_H
This page took 0.049359 seconds and 2 git commands to generate.