@@ -70,38 +70,37 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
70
70
return (encoded_output);
71
71
}
72
72
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 ;
88
74
int cnt = 0 ;
89
75
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
+
93
89
if (cnt < bits_per_digit_) {
94
- // Shift the index one to accommodate next bit.
95
90
digit_idx <<= 1 ;
96
91
} 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.
98
93
encoded_output.push_back (bitsToDigit (digit_idx));
99
94
digit_idx = 0 ;
100
95
cnt = 0 ;
101
96
}
102
97
103
98
// 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 ;
105
104
++cnt;
106
105
}
107
106
@@ -128,52 +127,84 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
128
127
void
129
128
BaseNEncoder::decode (const std::string& encoded_str, std::vector<uint8_t >& output) {
130
129
output.clear ();
131
- bool inbits[encoded_str.size () * bits_per_digit_];
132
- bool * inbit = &inbits[0 ];
133
130
size_t dig_cnt = 0 ;
134
131
size_t pad_cnt = 0 ;
135
132
size_t shift_bits = 8 - bits_per_digit_;
133
+ uint8_t cur_byte = 0 ;
134
+ size_t cur_bit_cnt = 0 ;
136
135
for (const auto enc_digit : encoded_str) {
137
136
if (pad_char_ && enc_digit == pad_char_) {
138
137
pad_cnt++;
139
138
continue ;
140
139
}
141
140
142
- // translate the b64 digit to bits.
141
+ // Translate the b64 digit to bits.
143
142
uint8_t dig_bits = digitToBits (enc_digit);
144
143
144
+ // Skip whitespace.
145
145
if (dig_bits == 0xee ) {
146
- // skip whitespace
147
146
continue ;
148
147
}
149
148
149
+ // Error on invalid characters.
150
150
if (dig_bits == 0xff ) {
151
151
isc_throw (isc::BadValue, " attempt to decode a value not in "
152
152
<< algorithm_ << " char set" << " : " << encoded_str);
153
153
}
154
154
155
+ // Error if pads are in the middle.
155
156
if (pad_cnt) {
156
157
isc_throw (isc::BadValue, " pad mixed with digits in "
157
158
<< algorithm_ << " : " << encoded_str);
158
159
}
159
160
161
+ // Bump the valid character count.
160
162
dig_cnt++;
163
+
164
+ // Shift off what we don't need.
161
165
dig_bits <<= shift_bits;
166
+
167
+ // Add digit's decoded bits to current byte.
162
168
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.
164
185
dig_bits <<= 1 ;
186
+
187
+ // Update the current byte bit count.
188
+ ++cur_bit_cnt;
165
189
}
166
190
}
167
191
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
+
168
200
if (pad_char_) {
169
- // Check for invalid number of pad characters.
201
+ // Check for too many pad characters.
170
202
if (pad_cnt > max_pad_) {
171
203
isc_throw (isc::BadValue, " too many pad characters for "
172
204
<< algorithm_ << " : " << encoded_str);
173
205
}
174
206
175
207
// Check for invalid number of pad characters.
176
- // / @todo is this valid
177
208
const size_t padbits = ((pad_cnt * bits_per_digit_) + 7 ) & ~7 ;
178
209
if (padbits > bits_per_digit_ * (pad_cnt + 1 )) {
179
210
isc_throw (isc::BadValue, " Invalid padding for "
@@ -186,32 +217,6 @@ BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& outpu
186
217
isc_throw (isc::BadValue, " Incomplete input for "
187
218
<< algorithm_ << " : " << encoded_str);
188
219
}
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
- }
215
220
}
216
221
217
222
const char * Base64Encoder::DIGIT_SET = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -282,40 +287,41 @@ const std::vector<uint8_t> Base16Encoder::BITS_TABLE = {
282
287
283
288
string
284
289
encodeBase64 (const vector<uint8_t >& binary) {
285
- Base64Encoder encoder;
290
+ static Base64Encoder encoder;
286
291
return (encoder.encode (binary));
287
292
}
288
293
289
294
void
290
295
decodeBase64 (const std::string& encoded_str, std::vector<uint8_t >& output) {
291
- Base64Encoder encoder;
296
+ static Base64Encoder encoder;
292
297
encoder.decode (encoded_str, output);
293
298
}
294
299
295
300
string
296
301
encodeBase32Hex (const vector<uint8_t >& binary) {
297
- Base32HexEncoder encoder;
302
+ static Base32HexEncoder encoder;
298
303
return (encoder.encode (binary));
299
304
}
300
305
301
306
void
302
307
decodeBase32Hex (const std::string& encoded_str, std::vector<uint8_t >& output) {
303
- Base32HexEncoder encoder;
308
+ static Base32HexEncoder encoder;
304
309
encoder.decode (encoded_str, output);
305
310
}
306
311
307
312
string
308
313
encodeHex (const vector<uint8_t >& binary) {
309
- Base16Encoder encoder;
314
+ static Base16Encoder encoder;
310
315
return (encoder.encode (binary));
311
316
}
312
317
313
318
void
314
319
decodeHex (const string& encoded_str, vector<uint8_t >& output) {
315
- Base16Encoder encoder;
320
+ static Base16Encoder encoder;
316
321
encoder.decode (encoded_str, output);
317
322
}
318
323
324
+
319
325
} // namespace encode
320
326
} // namespace util
321
327
} // namespace isc
0 commit comments