xoreos  0.0.5
bitstreamwriter.h
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #ifndef COMMON_BITSTREAMWRITER_H
26 #define COMMON_BITSTREAMWRITER_H
27 
28 #include <cassert>
29 
30 #include <boost/noncopyable.hpp>
31 
32 #include "src/common/types.h"
34 #include "src/common/error.h"
35 #include "src/common/writestream.h"
36 
37 namespace Common {
38 
41 public:
42  virtual ~BitStreamWriter() {
43  }
44 
46  virtual void putBit(bool bit) = 0;
47 
49  virtual void putBits(uint32 bits, size_t n) = 0;
50 
52  virtual void flush() = 0;
53 
54 protected:
56  }
57 };
58 
69 template<int valueBits, bool isLE, bool isMSB2LSB>
70 class BitStreamWriterImpl : boost::noncopyable, public BitStreamWriter {
71 private:
73 
76 
78  inline void writeData(uint64 data) {
79  if (isLE) {
80  if (valueBits == 8)
81  _stream->writeByte(data);
82  if (valueBits == 16)
83  _stream->writeUint16LE(data);
84  if (valueBits == 32)
85  _stream->writeUint32LE(data);
86  if (valueBits == 64)
87  _stream->writeUint64LE(data);
88  } else {
89  if (valueBits == 8)
90  _stream->writeByte(data);
91  if (valueBits == 16)
92  _stream->writeUint16BE(data);
93  if (valueBits == 32)
94  _stream->writeUint32BE(data);
95  if (valueBits == 64)
96  _stream->writeUint64BE(data);
97  }
98  }
99 
101  inline void writeValue() {
102  /* If we're writing the bits LSB first, they accumulate at the upper parts of the value data.
103  * We need to shift them down before writing it to the byte stream. */
104  if (!isMSB2LSB)
105  _value >>= 64 - valueBits;
106 
107  writeData(_value);
108  _value = 0;
109  }
110 
111 public:
113  BitStreamWriterImpl(WriteStream *stream, bool disposeAfterUse = false) :
114  _stream(stream, disposeAfterUse), _value(0), _inValue(0) {
115 
116  assert(_stream);
117 
118  if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32) && (valueBits != 64))
119  throw Exception("BitStreamWriter: Invalid memory layout %d, %d, %d", valueBits, isLE, isMSB2LSB);
120  }
121 
124  _stream(&stream, false), _value(0), _inValue(0) {
125 
126  if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32) && (valueBits != 64))
127  throw Exception("BitStreamWriter: Invalid memory layout %d, %d, %d", valueBits, isLE, isMSB2LSB);
128  }
129 
131  }
132 
134  void putBit(bool bit) {
135  // Put the bit, according to the writing direction
136  if (isMSB2LSB)
137  _value = (_value << 1) | (bit ? 1 : 0);
138  else
139  _value = (_value >> 1) | (static_cast<uint64>(bit ? 1 : 0) << 63);
140 
141  // Increase the position within the current value
142  _inValue = (_inValue + 1) % valueBits;
143 
144  // Check if we have a full value to write
145  if (_inValue == 0)
146  writeValue();
147  }
148 
150  void putBits(uint32 bits, size_t n) {
151  if (n == 0)
152  return;
153 
154  if (n > 32)
155  throw Exception("Too many bits requested to be written");
156 
157  if (isMSB2LSB)
158  bits <<= 32 - n;
159 
160  while (n-- > 0) {
161  if (isMSB2LSB) {
162  putBit(bits & 0x80000000);
163  bits <<= 1;
164  } else {
165  putBit(bits & 1);
166  bits >>= 1;
167  }
168  }
169  }
170 
175  void flush() {
176  if (_inValue > 0) {
177  const size_t padding = valueBits - _inValue;
178  if (isMSB2LSB)
179  _value <<= padding;
180  else
181  _value >>= padding;
182 
183  writeValue();
184  _inValue = 0;
185  }
186 
187  _stream->flush();
188  }
189 };
190 
191 // typedefs for various memory layouts.
192 
197 
206 
215 
224 
225 } // End of namespace Common
226 
227 #endif // COMMON_BITSTREAMWRITER_H
void writeValue()
Write the full data value.
A template implementing a bit stream writer for different data memory layouts.
void writeData(uint64 data)
Write a data value.
Definition: 2dafile.h:39
BitStreamWriterImpl< 16, true, false > BitStreamWriter16LELSB
16-bit little-endian data, LSB to MSB.
void putBit(bool bit)
Write a bit to the bit stream.
BitStreamWriterImpl< 64, false, false > BitStreamWriter64BELSB
64-bit big-endian data, LSB to MSB.
BitStreamWriterImpl< 16, true, true > BitStreamWriter16LEMSB
16-bit little-endian data, MSB to LSB.
uint64_t uint64
Definition: types.h:206
uint8_t uint8
Definition: types.h:200
BitStreamWriterImpl< 32, true, true > BitStreamWriter32LEMSB
32-bit little-endian data, MSB to LSB.
BitStreamWriterImpl< 64, true, false > BitStreamWriter64LELSB
64-bit little-endian data, LSB to MSB.
BitStreamWriterImpl< 16, false, true > BitStreamWriter16BEMSB
16-bit big-endian data, MSB to LSB.
uint8 _inValue
Position within the current value.
BitStreamWriterImpl< 64, false, true > BitStreamWriter64BEMSB
64-bit big-endian data, MSB to LSB.
BitStreamWriterImpl(WriteStream &stream)
Create a bit stream using this input data stream.
Basic exceptions to throw.
BitStreamWriterImpl< 8, false, true > BitStreamWriter8MSB
8-bit data, MSB to LSB.
Basic writing stream interfaces.
Low-level type definitions to handle fixed width types portably.
StackException Exception
Definition: error.h:59
Generic interface for a writable data stream.
Definition: writestream.h:64
void flush()
Flush the stream, forcing all cached bits to the written.
A disposable plain pointer, allowing pointer-y access and normal deletion.
A bit stream writer.
virtual void putBits(uint32 bits, size_t n)=0
Write a multi-bit value to the bit stream.
A smart pointer with a deletion flag.
uint32_t uint32
Definition: types.h:204
virtual void putBit(bool bit)=0
Write a bit to the bit stream.
BitStreamWriterImpl< 32, true, false > BitStreamWriter32LELSB
32-bit little-endian data, LSB to MSB.
BitStreamWriterImpl< 64, true, true > BitStreamWriter64LEMSB
64-bit little-endian data, MSB to LSB.
BitStreamWriterImpl< 8, false, false > BitStreamWriter8LSB
8-bit data, LSB to MSB.
BitStreamWriterImpl< 32, false, false > BitStreamWriter32BELSB
32-bit big-endian data, LSB to MSB.
virtual void flush()=0
Flush the stream, forcing all cached bits to the written.
uint64 _value
Current value.
DisposablePtr< WriteStream > _stream
The output stream.
BitStreamWriterImpl(WriteStream *stream, bool disposeAfterUse=false)
Create a bit stream using this input data stream and optionally delete it on destruction.
void putBits(uint32 bits, size_t n)
Write a multi-bit value to the bit stream.
BitStreamWriterImpl< 16, false, false > BitStreamWriter16BELSB
16-bit big-endian data, LSB to MSB.
BitStreamWriterImpl< 32, false, true > BitStreamWriter32BEMSB
32-bit big-endian data, MSB to LSB.