Wip: more compact serialize.h
[novacoin.git] / src / serialize.cpp
1 #include "serialize.h"
2 #include "hash.h"
3
4 template<typename Stream>
5 void WriteCompactSize(Stream& os, uint64_t nSize)
6 {
7     if (nSize < 253)
8     {
9         unsigned char chSize = (unsigned char)nSize;
10         WRITEDATA(os, chSize);
11     }
12     else if (nSize <= std::numeric_limits<unsigned short>::max())
13     {
14         unsigned char chSize = 253;
15         unsigned short xSize = (unsigned short)nSize;
16         WRITEDATA(os, chSize);
17         WRITEDATA(os, xSize);
18     }
19     else if (nSize <= std::numeric_limits<unsigned int>::max())
20     {
21         unsigned char chSize = 254;
22         unsigned int xSize = (unsigned int)nSize;
23         WRITEDATA(os, chSize);
24         WRITEDATA(os, xSize);
25     }
26     else
27     {
28         unsigned char chSize = 255;
29         uint64_t xSize = nSize;
30         WRITEDATA(os, chSize);
31         WRITEDATA(os, xSize);
32     }
33     return;
34 }
35
36
37 template<typename Stream>
38 uint64_t ReadCompactSize(Stream& is)
39 {
40     unsigned char chSize;
41     READDATA(is, chSize);
42     uint64_t nSizeRet = 0;
43     if (chSize < 253)
44     {
45         nSizeRet = chSize;
46     }
47     else if (chSize == 253)
48     {
49         unsigned short xSize;
50         READDATA(is, xSize);
51         nSizeRet = xSize;
52     }
53     else if (chSize == 254)
54     {
55         unsigned int xSize;
56         READDATA(is, xSize);
57         nSizeRet = xSize;
58     }
59     else
60     {
61         uint64_t xSize;
62         READDATA(is, xSize);
63         nSizeRet = xSize;
64     }
65     if (nSizeRet > (uint64_t)MAX_SIZE)
66         throw std::ios_base::failure("ReadCompactSize() : size too large");
67     return nSizeRet;
68 }
69
70
71
72 // Template instantiation
73
74 template void WriteCompactSize<CAutoFile>(CAutoFile&, uint64_t);
75 template void WriteCompactSize<CDataStream>(CDataStream&, uint64_t);
76 template void WriteCompactSize<CHashWriter>(CHashWriter&, uint64_t);
77
78 template uint64_t ReadCompactSize<CAutoFile>(CAutoFile&);
79 template uint64_t ReadCompactSize<CDataStream>(CDataStream&);
80
81 //
82 //CBufferedFile
83 //
84
85 void CBufferedFile::setstate(short bits, const char *psz)
86 {
87     state |= bits;
88     if (state & exceptmask)
89         throw std::ios_base::failure(psz);
90 }
91
92 bool CBufferedFile::Fill()
93 {
94     unsigned int pos = (unsigned int)(nSrcPos % vchBuf.size());
95     unsigned int readNow = (unsigned int)(vchBuf.size() - pos);
96     unsigned int nAvail = (unsigned int)(vchBuf.size() - (nSrcPos - nReadPos) - nRewind);
97     if (nAvail < readNow)
98         readNow = nAvail;
99     if (readNow == 0)
100         return false;
101     size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
102     if (read == 0) {
103         setstate(std::ios_base::failbit, feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed");
104         return false;
105     } else {
106         nSrcPos += read;
107         return true;
108     }
109 }
110
111 CBufferedFile::CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
112     src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, 0),
113     state(0), exceptmask(std::ios_base::badbit | std::ios_base::failbit), nType(nTypeIn), nVersion(nVersionIn) { }
114
115 bool CBufferedFile::good() const
116 {
117     return state == 0;
118 }
119
120 bool CBufferedFile::eof() const
121 {
122     return nReadPos == nSrcPos && feof(src);
123 }
124
125 CBufferedFile& CBufferedFile::read(char *pch, size_t nSize)
126 {
127     if (nSize + nReadPos > nReadLimit)
128         throw std::ios_base::failure("Read attempted past buffer limit");
129     if (nSize + nRewind > vchBuf.size())
130         throw std::ios_base::failure("Read larger than buffer size");
131     while (nSize > 0) {
132         if (nReadPos == nSrcPos)
133             Fill();
134         unsigned int pos = (unsigned int)(nReadPos % vchBuf.size());
135         size_t nNow = nSize;
136         if (nNow + pos > vchBuf.size())
137             nNow = vchBuf.size() - pos;
138         if (nNow + nReadPos > nSrcPos)
139             nNow = (size_t)(nSrcPos - nReadPos);
140         memcpy(pch, &vchBuf[pos], nNow);
141         nReadPos += nNow;
142         pch += nNow;
143         nSize -= nNow;
144     }
145     return (*this);
146 }
147
148 uint64_t CBufferedFile::GetPos()
149 {
150     return nReadPos;
151 }
152
153 bool CBufferedFile::SetPos(uint64_t nPos)
154 {
155     nReadPos = nPos;
156     if (nReadPos + nRewind < nSrcPos) {
157         nReadPos = nSrcPos - nRewind;
158         return false;
159     } else if (nReadPos > nSrcPos) {
160         nReadPos = nSrcPos;
161         return false;
162     } else {
163         return true;
164     }
165 }
166
167 bool CBufferedFile::Seek(uint64_t nPos)
168 {
169     long nLongPos = (long)nPos;
170     if (nPos != (uint64_t)nLongPos)
171         return false;
172     if (fseek(src, nLongPos, SEEK_SET))
173         return false;
174     nLongPos = ftell(src);
175     nSrcPos = nLongPos;
176     nReadPos = nLongPos;
177     state = 0;
178     return true;
179 }
180
181 bool CBufferedFile::SetLimit(uint64_t nPos)
182 {
183     if (nPos < nReadPos)
184         return false;
185     nReadLimit = nPos;
186     return true;
187 }
188
189 void CBufferedFile::FindByte(char ch)
190 {
191     for ( ; ; ) {
192         if (nReadPos == nSrcPos)
193             Fill();
194         if (vchBuf[nReadPos % vchBuf.size()] == ch)
195             break;
196         nReadPos++;
197     }
198 }