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