LCOV - code coverage report
Current view: top level - src - streams.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 146 185 78.9 %
Date: 2015-10-12 22:39:14 Functions: 43 86 50.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11