Skip to content

Commit 06fc63c

Browse files
committed
[#3209] Remove internal bool vectors
src/lib/util/encode/encode.cc BaseNEncoder::encode() BaseNEncoder::decode() - eliminate use of bool vectors as "bit streams"
1 parent 6949dd9 commit 06fc63c

File tree

1 file changed

+66
-60
lines changed

1 file changed

+66
-60
lines changed

src/lib/util/encode/encode.cc

+66-60
Original file line numberDiff line numberDiff line change
@@ -70,38 +70,37 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
7070
return(encoded_output);
7171
}
7272

73-
// Turn the input data into a "bit stream"
74-
/// @todo Can we devise a bit-stream class that can iterate over the input
75-
/// without copying it? The weakness here is inbits could be rather large
76-
/// for long strings since it input size * 8 bytes.
77-
bool inbits[input.size() * 8];
78-
bool* inbit = &inbits[0];
79-
for (auto b : input) {
80-
for (auto i = 0; i < 8; i++) {
81-
bool val = b & 0x80;
82-
*inbit++ = val;
83-
b <<= 1;
84-
}
85-
}
86-
87-
// Now encode the bit stream.
73+
uint8_t cur_bit = 0x0;
8874
int cnt = 0;
8975
int digit_idx = 0;
90-
auto inbit_end = inbit;
91-
inbit = &inbits[0];
92-
for (inbit = &inbits[0]; inbit != inbit_end; ++inbit) {
76+
int cur_byte = 0;
77+
auto bytes = input.begin();
78+
while (1) {
79+
if (!cur_bit) {
80+
if (bytes == input.end()) {
81+
break;
82+
}
83+
84+
cur_byte = *bytes;
85+
cur_bit = 0x80;
86+
++bytes;
87+
}
88+
9389
if (cnt < bits_per_digit_) {
94-
// Shift the index one to accommodate next bit.
9590
digit_idx <<= 1;
9691
} else {
97-
// Have a complete digit index, look it the digit and add it.
92+
// Have a complete digit index, look up digit and add it.
9893
encoded_output.push_back(bitsToDigit(digit_idx));
9994
digit_idx = 0;
10095
cnt = 0;
10196
}
10297

10398
// Add the current bit to the digit index.
104-
digit_idx |= *inbit;
99+
if (cur_byte & cur_bit) {
100+
digit_idx |= 1;
101+
}
102+
103+
cur_bit >>= 1;
105104
++cnt;
106105
}
107106

@@ -128,52 +127,84 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
128127
void
129128
BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& output) {
130129
output.clear();
131-
bool inbits[encoded_str.size() * bits_per_digit_];
132-
bool* inbit = &inbits[0];
133130
size_t dig_cnt = 0;
134131
size_t pad_cnt = 0;
135132
size_t shift_bits = 8 - bits_per_digit_;
133+
uint8_t cur_byte = 0;
134+
size_t cur_bit_cnt = 0;
136135
for (const auto enc_digit : encoded_str) {
137136
if (pad_char_ && enc_digit == pad_char_) {
138137
pad_cnt++;
139138
continue;
140139
}
141140

142-
// translate the b64 digit to bits.
141+
// Translate the b64 digit to bits.
143142
uint8_t dig_bits = digitToBits(enc_digit);
144143

144+
// Skip whitespace.
145145
if (dig_bits == 0xee) {
146-
// skip whitespace
147146
continue;
148147
}
149148

149+
// Error on invalid characters.
150150
if (dig_bits == 0xff) {
151151
isc_throw(isc::BadValue, "attempt to decode a value not in "
152152
<< algorithm_ << " char set" << ": " << encoded_str);
153153
}
154154

155+
// Error if pads are in the middle.
155156
if (pad_cnt) {
156157
isc_throw(isc::BadValue, "pad mixed with digits in "
157158
<< algorithm_ << ": " << encoded_str);
158159
}
159160

161+
// Bump the valid character count.
160162
dig_cnt++;
163+
164+
// Shift off what we don't need.
161165
dig_bits <<= shift_bits;
166+
167+
// Add digit's decoded bits to current byte.
162168
for (auto i = 0; i < bits_per_digit_; ++i) {
163-
*inbit++ = ((dig_bits & 0x80) == 0x80);
169+
if (cur_bit_cnt < 8) {
170+
// Shift contents to make room for next gbit.
171+
cur_byte <<= 1;
172+
} else {
173+
// Add the completed byte to the output.
174+
output.push_back(cur_byte);
175+
cur_byte = 0;
176+
cur_bit_cnt = 0;
177+
}
178+
179+
// Add the next bit if its set.
180+
if (dig_bits & 0x80) {
181+
cur_byte |= 1;
182+
}
183+
184+
// Shift the decoded bits over.
164185
dig_bits <<= 1;
186+
187+
// Update the current byte bit count.
188+
++cur_bit_cnt;
165189
}
166190
}
167191

192+
if (cur_bit_cnt == 8) {
193+
// Whole one left to add.
194+
output.push_back(cur_byte);
195+
} else if (cur_bit_cnt && cur_byte) {
196+
// Left over bits that are not zero.
197+
isc_throw(BadValue, "non-zero bits left over " << encoded_str);
198+
}
199+
168200
if (pad_char_) {
169-
// Check for invalid number of pad characters.
201+
// Check for too many pad characters.
170202
if (pad_cnt > max_pad_) {
171203
isc_throw(isc::BadValue, "too many pad characters for "
172204
<< algorithm_ << ": " << encoded_str);
173205
}
174206

175207
// Check for invalid number of pad characters.
176-
/// @todo is this valid
177208
const size_t padbits = ((pad_cnt * bits_per_digit_) + 7) & ~7;
178209
if (padbits > bits_per_digit_ * (pad_cnt + 1)) {
179210
isc_throw(isc::BadValue, "Invalid padding for "
@@ -186,32 +217,6 @@ BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& outpu
186217
isc_throw (isc::BadValue, "Incomplete input for "
187218
<< algorithm_ << ": " << encoded_str);
188219
}
189-
190-
int cnt = 0;
191-
int digit_idx = 0;
192-
193-
auto inbit_end = inbit;
194-
inbit = &inbits[0];
195-
for (inbit = &inbits[0]; inbit != inbit_end; ++inbit) {
196-
if (cnt < 8) {
197-
digit_idx <<= 1;
198-
} else {
199-
output.push_back(digit_idx);
200-
digit_idx = 0;
201-
cnt = 0;
202-
}
203-
204-
digit_idx |= *inbit;
205-
++cnt;
206-
}
207-
208-
if (cnt == 8) {
209-
// Whole one left to add.
210-
output.push_back(digit_idx);
211-
} else if (cnt && digit_idx) {
212-
// Left over bits that are not zero.
213-
isc_throw(BadValue, "non-zero bits left over " << encoded_str);
214-
}
215220
}
216221

217222
const char* Base64Encoder::DIGIT_SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -282,40 +287,41 @@ const std::vector<uint8_t> Base16Encoder::BITS_TABLE = {
282287

283288
string
284289
encodeBase64(const vector<uint8_t>& binary) {
285-
Base64Encoder encoder;
290+
static Base64Encoder encoder;
286291
return(encoder.encode(binary));
287292
}
288293

289294
void
290295
decodeBase64 (const std::string& encoded_str, std::vector<uint8_t>& output) {
291-
Base64Encoder encoder;
296+
static Base64Encoder encoder;
292297
encoder.decode(encoded_str, output);
293298
}
294299

295300
string
296301
encodeBase32Hex(const vector<uint8_t>& binary) {
297-
Base32HexEncoder encoder;
302+
static Base32HexEncoder encoder;
298303
return(encoder.encode(binary));
299304
}
300305

301306
void
302307
decodeBase32Hex(const std::string& encoded_str, std::vector<uint8_t>& output) {
303-
Base32HexEncoder encoder;
308+
static Base32HexEncoder encoder;
304309
encoder.decode(encoded_str, output);
305310
}
306311

307312
string
308313
encodeHex(const vector<uint8_t>& binary) {
309-
Base16Encoder encoder;
314+
static Base16Encoder encoder;
310315
return(encoder.encode(binary));
311316
}
312317

313318
void
314319
decodeHex(const string& encoded_str, vector<uint8_t>& output) {
315-
Base16Encoder encoder;
320+
static Base16Encoder encoder;
316321
encoder.decode(encoded_str, output);
317322
}
318323

324+
319325
} // namespace encode
320326
} // namespace util
321327
} // namespace isc

0 commit comments

Comments
 (0)