1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "BitBuffer.h"
8
9
10 // #pragma mark - BitReader
11
12
13 struct BitBuffer::BitReader {
14 const uint8* data;
15 uint64 bitSize;
16 uint32 bitOffset;
17
BitReaderBitBuffer::BitReader18 BitReader(const uint8* data, uint64 bitSize, uint32 bitOffset)
19 :
20 data(data),
21 bitSize(bitSize),
22 bitOffset(bitOffset)
23 {
24 }
25
ReadByteBitBuffer::BitReader26 uint8 ReadByte()
27 {
28 uint8 byte = *data;
29 data++;
30 bitSize -= 8;
31
32 if (bitOffset == 0)
33 return byte;
34
35 return (byte << bitOffset) | (*data >> (8 - bitOffset));
36 }
37
ReadBitsBitBuffer::BitReader38 uint8 ReadBits(uint32 count)
39 {
40 uint8 byte = *data;
41 bitSize -= count;
42 bitOffset += count;
43
44 if (bitOffset <= 8) {
45 if (bitOffset == 8) {
46 bitOffset = 0;
47 data++;
48 return byte & ((1 << count) - 1);
49 }
50
51 return (byte >> (8 - bitOffset)) & ((1 << count) - 1);
52 }
53
54 data++;
55 bitOffset -= 8;
56 return ((byte << bitOffset) | (*data >> (8 - bitOffset)))
57 & ((1 << count) - 1);
58 }
59 };
60
61
62 // #pragma mark - BitBuffer
63
64
BitBuffer()65 BitBuffer::BitBuffer()
66 :
67 fMissingBits(0)
68 {
69 }
70
71
~BitBuffer()72 BitBuffer::~BitBuffer()
73 {
74 }
75
76
77 bool
AddBytes(const void * data,size_t size)78 BitBuffer::AddBytes(const void* data, size_t size)
79 {
80 if (size == 0)
81 return true;
82
83 if (fMissingBits == 0) {
84 size_t oldSize = fBytes.Size();
85 if (!fBytes.AddUninitialized(size))
86 return false;
87
88 memcpy(fBytes.Elements() + oldSize, data, size);
89 return true;
90 }
91
92 return AddBits(data, (uint64)size * 8, 0);
93 }
94
95
96 bool
AddBits(const void * _data,uint64 bitSize,uint32 bitOffset)97 BitBuffer::AddBits(const void* _data, uint64 bitSize, uint32 bitOffset)
98 {
99 if (bitSize == 0)
100 return true;
101
102 const uint8* data = (const uint8*)_data + bitOffset / 8;
103 bitOffset %= 8;
104
105 BitReader reader(data, bitSize, bitOffset);
106
107 // handle special case first: no more bits than missing
108 size_t oldSize = fBytes.Size();
109 if (fMissingBits > 0 && bitSize <= fMissingBits) {
110 fMissingBits -= bitSize;
111 uint8 bits = reader.ReadBits(bitSize) << fMissingBits;
112 fBytes[oldSize - 1] |= bits;
113 return true;
114 }
115
116 // resize the buffer
117 if (!fBytes.AddUninitialized((reader.bitSize - fMissingBits + 7) / 8))
118 return false;
119
120 // fill in missing bits
121 if (fMissingBits > 0) {
122 fBytes[oldSize - 1] |= reader.ReadBits(fMissingBits);
123 fMissingBits = 0;
124 }
125
126 // read full bytes as long as we can
127 uint8* buffer = fBytes.Elements() + oldSize;
128 while (reader.bitSize >= 8) {
129 *buffer = reader.ReadByte();
130 buffer++;
131 }
132
133 // If we have left-over bits, write a partial byte.
134 if (reader.bitSize > 0) {
135 fMissingBits = 8 - reader.bitSize;
136 *buffer = reader.ReadBits(reader.bitSize) << fMissingBits;
137 }
138
139 return true;
140 }
141
142
143 bool
AddZeroBits(uint64 bitSize)144 BitBuffer::AddZeroBits(uint64 bitSize)
145 {
146 if (bitSize == 0)
147 return true;
148
149 // handle special case first: no more bits than missing
150 size_t oldSize = fBytes.Size();
151 if (fMissingBits > 0 && bitSize <= fMissingBits) {
152 fMissingBits -= bitSize;
153 return true;
154 }
155
156 // resize the buffer
157 if (!fBytes.AddUninitialized((bitSize - fMissingBits + 7) / 8))
158 return false;
159
160 // fill in missing bits
161 if (fMissingBits > 0) {
162 bitSize -= fMissingBits;
163 fMissingBits = 0;
164 }
165
166 // zero the remaining bytes, including a potentially partial last byte
167 uint8* buffer = fBytes.Elements() + oldSize;
168 memset(buffer, 0, (bitSize + 7) / 8);
169 bitSize %= 8;
170
171 if (bitSize > 0)
172 fMissingBits = 8 - bitSize;
173
174 return true;
175 }
176