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
13struct BitBuffer::BitReader {
14	const uint8*	data;
15	uint64			bitSize;
16	uint32			bitOffset;
17
18	BitReader(const uint8* data, uint64 bitSize, uint32 bitOffset)
19		:
20		data(data),
21		bitSize(bitSize),
22		bitOffset(bitOffset)
23	{
24	}
25
26	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
38	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
65BitBuffer::BitBuffer()
66	:
67	fMissingBits(0)
68{
69}
70
71
72BitBuffer::~BitBuffer()
73{
74}
75
76
77bool
78BitBuffer::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
96bool
97BitBuffer::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
143bool
144BitBuffer::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