forked from zatserkl/DataFormat-v44
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBitBuffer.h
More file actions
297 lines (278 loc) · 10.2 KB
/
BitBuffer.h
File metadata and controls
297 lines (278 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
// Andriy Zatserklyaniy, April 17, 2014
#ifndef BitBuffer_h
#define BitBuffer_h
//
// Created by Andriy Zatserklyaniy on 1/19/14.
// Copyright (c) 2014 Andriy Zatserklyaniy. All rights reserved.
//
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cassert>
#include <cstdlib>
#include <exception>
#include <string>
#include <cstdlib> // for exit
using std::cout; using std::endl;
#define ACRed "\e[0;31m"
#define ACPlain "\e[0m"
class BitBuffer;
class BitBufferException: public std::exception {
std::string message; // adding of this field requires virtual destructor with qualifier throw()
const BitBuffer* bitBuffer;
public:
BitBufferException(const BitBuffer* the_bitBuffer, std::string the_message): message(the_message) {
bitBuffer = the_bitBuffer;
}
virtual ~BitBufferException() throw() {} // throw() avoids error message: overriden virtual ~exception() _NOEXCEPT;
virtual const char* what() const throw() {
return message.c_str();
}
inline void Print() const;
};
class BitBuffer {
friend class BitBufferException;
private:
std::ifstream file;
//--g++ size_t file_last_byte;
long file_last_byte;
char* buffer;
long buffer_size;
long buffer_first_byte; // abs position of the first byte of the buffer
long buffer_last_byte; // abs position of the last byte of the buffer
long current_byte; // last used byte in the buffer, 0 before the first read.
int current_bit; // bit in the current_byte to be returned
public:
BitBuffer(const char* filename, unsigned buffer_size_=32)
: file_last_byte(0)
, buffer_size(buffer_size_)
, current_byte(0)
, current_bit(0)
{
file.open(filename, std::ios::binary);
if (!file) {
cout<< "Could not open file " << filename <<endl;
exit(0);
}
// get length of file:
file.seekg (0, std::ios::end);
//--g++ file_last_byte = file.tellg() - 1LL;
file_last_byte = file.tellg();
--file_last_byte;
cout<< "BitBuffer: file_size = " << file_last_byte + 1 <<endl;
buffer = new char[buffer_size];
Rewind();
}
~BitBuffer() {
file.close();
delete[] buffer;
}
void Rewind() {
current_bit = 0;
current_byte = 0;
file.seekg(0, std::ios::beg);
// fill the buffer initially
buffer_first_byte = 0;
buffer_last_byte = buffer_size - 1;
if (buffer_last_byte > file_last_byte) buffer_last_byte = file_last_byte;
file.seekg (0, std::ios::beg);
file.read(buffer, buffer_last_byte - buffer_first_byte + 1);
}
// methods which return next bit/byte and increament the bit/byte pointer
inline bool getbit() {return nextbit();} // version with exception
inline bool getbit(bool& bit) {return nextbit(bit);} // version with condition
inline unsigned char loadbyte() {return nextbyte();} // version with exception
inline unsigned char loadbyte(unsigned char& byte) {return nextbyte(byte);} // version with condition
// methods to fill byte from the stream of bits
inline unsigned char fillbyte() // version with exception (through getbit)
{
// fills byte from the stream of bits
unsigned char byte = 0;
for (int i=0; i<8; ++i) {
unsigned char digit = getbit()? 1 << (7-i): 0;
byte = byte | digit;
}
return byte;
}
inline unsigned char fillbyte(unsigned char& byte) // version with condition
{
// fills byte from the stream of bits
byte = 0;
for (int i=0; i<8; ++i) {
bool bit;
if (!getbit(bit)) return 0;
unsigned digit = bit? 1 << (7-i): 0;
byte = byte | digit;
}
return 1;
}
inline unsigned char fillpart(unsigned char ndigits) // version with exception (through getbit)
{
// fills part of byte from the stream of bits
// user is responsible that ndigits <= 8
unsigned char byte = 0;
unsigned char max_digit = ndigits - 1;
for (int i=0; i<ndigits; ++i) {
unsigned char digit = getbit()? 1 << (max_digit-i): 0;
byte = byte | digit;
}
return byte;
}
inline unsigned char fillpart(unsigned char& byte, unsigned char ndigits) // version with condition
{
// fills part of byte from the stream of bits
// user is responsible that ndigits <= 8
byte = 0;
unsigned char max_digit = ndigits - 1;
for (int i=0; i<ndigits; ++i) {
bool bit;
if (!getbit(bit)) return 0;
unsigned char digit = bit? 1 << (max_digit-i): 0;
byte = byte | digit;
}
return 1;
}
// method which returns byte currently in use. No increament of the byte pointer
inline unsigned char get_current_byte() const {return buffer[current_byte];}
// actual low level methods
inline unsigned char nextbyte()
{
// version with exception
++current_byte;
if (buffer_first_byte + current_byte > buffer_last_byte) {
if (buffer_last_byte == file_last_byte) {
--current_byte; // restore last current_byte
throw BitBufferException(this, "*** EOF ***");
}
// read the next buffer
buffer_first_byte = buffer_last_byte + 1;
buffer_last_byte = buffer_first_byte + buffer_size - 1;
if (buffer_last_byte > file_last_byte) buffer_last_byte = file_last_byte;
file.read(buffer, buffer_last_byte - buffer_first_byte + 1);
current_byte = 0;
}
current_bit = 0;
return buffer[current_byte];
}
inline unsigned char nextbyte(unsigned char& byte)
{
// version with condition
++current_byte;
if (buffer_first_byte + current_byte > buffer_last_byte) {
if (buffer_last_byte == file_last_byte) {
--current_byte; // restore last current_byte
return 0;
}
// read the next buffer
buffer_first_byte = buffer_last_byte + 1;
buffer_last_byte = buffer_first_byte + buffer_size - 1;
if (buffer_last_byte > file_last_byte) buffer_last_byte = file_last_byte;
file.read(buffer, buffer_last_byte - buffer_first_byte + 1);
current_byte = 0;
}
byte = buffer[current_byte];
current_bit = 0;
return 1;
}
inline bool nextbit() {
// version with exception
if (current_bit > 7) nextbyte();
return buffer[current_byte] & (1 << (7-current_bit++)); // returns current_bit from current_byte
}
inline bool nextbit(bool& bit) {
// version with condition
if (buffer_first_byte + current_byte == file_last_byte && current_bit > 7) return false;
bit = getbit();
return true;
}
// unget bit/byte
bool ungetbyte() {
if (current_byte > 0) {
current_byte--;
return true;
}
else {
// this is the first byte of the new buffer
// read previous block
//cout<< "// read previous block. Currently: buffer_first_byte = " << buffer_first_byte << " buffer_last_byte = " << buffer_last_byte << " current_byte = " << current_byte <<endl;
if (buffer_first_byte == 0) return false; // ignore unget before the first get
buffer_last_byte = buffer_first_byte - 1;
buffer_first_byte = buffer_last_byte - buffer_size + 1;
if (buffer_first_byte < 0) buffer_first_byte = 0;
file.seekg(buffer_first_byte, std::ios::beg);
file.read(buffer, buffer_last_byte - buffer_first_byte + 1);
current_byte = buffer_last_byte - buffer_first_byte;
//cout<< "after read: buffer_first_byte = " << buffer_first_byte << " buffer_last_byte = " << buffer_last_byte << " current_byte = " << current_byte <<endl;
return true;
}
}
bool ungetbit() {
if (current_bit > 0) {
current_bit--;
return true;
}
else {
// look in the previous byte
if (ungetbyte()) {
current_bit = 7;
return true;
}
else {
// special case of unget before the first get
current_bit = 0;
return false;
}
}
}
bool Inside() const {
if (current_byte < file_last_byte) return true;
if (current_byte == file_last_byte && current_bit < 8) return true;
return false;
}
// debug methods
unsigned long FileSize() const {return file_last_byte + 1;}
void Print() const {
cout<< "BitBuffer::Print: current_byte = " << current_byte << " current_bit = " << current_bit
<< " buffer_first_byte = " << buffer_first_byte << " buffer_last_byte = " << buffer_last_byte
<< " file_last_byte = " << file_last_byte
<< " get_current_byte() = " << std::hex << std::setfill('0') << std::setw(2) << (unsigned) get_current_byte() << std::dec
<<endl;
}
unsigned Current_byte() const {return current_byte;}
int Current_bit() const {return current_bit;}
void PrintBuffer() const {
cout<< "0\t";
for (int ibyte=0; ibyte<=buffer_last_byte-buffer_first_byte; ++ibyte) {
if (ibyte > 0 && ibyte%10 == 0) cout<< "\n" << ibyte << "\t";
cout<< std::hex << std::setfill('0') << std::setw(2) << (unsigned) (unsigned char) buffer[ibyte] << std::dec << " ";
}
cout<<endl;
}
// declare a global operator << as a friend to let it access the private data
friend std::ostream& operator <<(std::ostream&, const BitBuffer&);
};
//
// global operator << is a friend of the class BitBuffer
//
std::ostream& operator <<(std::ostream& os, const BitBuffer& bitBuffer)
{
os<< "current_byte = " << bitBuffer.current_byte << " current_bit = " << bitBuffer.current_bit
<< " buffer_first_byte = " << bitBuffer.buffer_first_byte << " buffer_last_byte = " << bitBuffer.buffer_last_byte
<< " file_last_byte = " << bitBuffer.file_last_byte
<< " get_current_byte() = " << std::hex << std::setw(2) << std::setfill('0') << (unsigned) bitBuffer.get_current_byte() << std::setfill(' ') << std::dec
;
return os;
}
//
// method BitBufferException::Print() is a friend of the class BitBuffer (need to be after BitBuffer code to know its contents)
//
inline void BitBufferException::Print() const {
cout<< "BitBufferException::Print:"
<< " current_byte = " << bitBuffer->current_byte
<< " current_bit = " << bitBuffer->current_bit
<< " buffer_first_byte = " << bitBuffer->buffer_first_byte
<< " buffer_last_byte = " << bitBuffer->buffer_last_byte
<< " file_last_byte = " << bitBuffer->file_last_byte
<<endl;
}
#endif // BitBuffer_h