mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-01 06:25:34 +00:00
[#3209] Remove internal bool vectors
src/lib/util/encode/encode.cc BaseNEncoder::encode() BaseNEncoder::decode() - eliminate use of bool vectors as "bit streams"
This commit is contained in:
@@ -70,38 +70,37 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
|
|||||||
return(encoded_output);
|
return(encoded_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn the input data into a "bit stream"
|
uint8_t cur_bit = 0x0;
|
||||||
/// @todo Can we devise a bit-stream class that can iterate over the input
|
|
||||||
/// without copying it? The weakness here is inbits could be rather large
|
|
||||||
/// for long strings since it input size * 8 bytes.
|
|
||||||
bool inbits[input.size() * 8];
|
|
||||||
bool* inbit = &inbits[0];
|
|
||||||
for (auto b : input) {
|
|
||||||
for (auto i = 0; i < 8; i++) {
|
|
||||||
bool val = b & 0x80;
|
|
||||||
*inbit++ = val;
|
|
||||||
b <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now encode the bit stream.
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int digit_idx = 0;
|
int digit_idx = 0;
|
||||||
auto inbit_end = inbit;
|
int cur_byte = 0;
|
||||||
inbit = &inbits[0];
|
auto bytes = input.begin();
|
||||||
for (inbit = &inbits[0]; inbit != inbit_end; ++inbit) {
|
while (1) {
|
||||||
|
if (!cur_bit) {
|
||||||
|
if (bytes == input.end()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_byte = *bytes;
|
||||||
|
cur_bit = 0x80;
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
|
||||||
if (cnt < bits_per_digit_) {
|
if (cnt < bits_per_digit_) {
|
||||||
// Shift the index one to accommodate next bit.
|
|
||||||
digit_idx <<= 1;
|
digit_idx <<= 1;
|
||||||
} else {
|
} else {
|
||||||
// Have a complete digit index, look it the digit and add it.
|
// Have a complete digit index, look up digit and add it.
|
||||||
encoded_output.push_back(bitsToDigit(digit_idx));
|
encoded_output.push_back(bitsToDigit(digit_idx));
|
||||||
digit_idx = 0;
|
digit_idx = 0;
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the current bit to the digit index.
|
// Add the current bit to the digit index.
|
||||||
digit_idx |= *inbit;
|
if (cur_byte & cur_bit) {
|
||||||
|
digit_idx |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_bit >>= 1;
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,52 +127,84 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
|
|||||||
void
|
void
|
||||||
BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& output) {
|
BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& output) {
|
||||||
output.clear();
|
output.clear();
|
||||||
bool inbits[encoded_str.size() * bits_per_digit_];
|
|
||||||
bool* inbit = &inbits[0];
|
|
||||||
size_t dig_cnt = 0;
|
size_t dig_cnt = 0;
|
||||||
size_t pad_cnt = 0;
|
size_t pad_cnt = 0;
|
||||||
size_t shift_bits = 8 - bits_per_digit_;
|
size_t shift_bits = 8 - bits_per_digit_;
|
||||||
|
uint8_t cur_byte = 0;
|
||||||
|
size_t cur_bit_cnt = 0;
|
||||||
for (const auto enc_digit : encoded_str) {
|
for (const auto enc_digit : encoded_str) {
|
||||||
if (pad_char_ && enc_digit == pad_char_) {
|
if (pad_char_ && enc_digit == pad_char_) {
|
||||||
pad_cnt++;
|
pad_cnt++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate the b64 digit to bits.
|
// Translate the b64 digit to bits.
|
||||||
uint8_t dig_bits = digitToBits(enc_digit);
|
uint8_t dig_bits = digitToBits(enc_digit);
|
||||||
|
|
||||||
|
// Skip whitespace.
|
||||||
if (dig_bits == 0xee) {
|
if (dig_bits == 0xee) {
|
||||||
// skip whitespace
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error on invalid characters.
|
||||||
if (dig_bits == 0xff) {
|
if (dig_bits == 0xff) {
|
||||||
isc_throw(isc::BadValue, "attempt to decode a value not in "
|
isc_throw(isc::BadValue, "attempt to decode a value not in "
|
||||||
<< algorithm_ << " char set" << ": " << encoded_str);
|
<< algorithm_ << " char set" << ": " << encoded_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error if pads are in the middle.
|
||||||
if (pad_cnt) {
|
if (pad_cnt) {
|
||||||
isc_throw(isc::BadValue, "pad mixed with digits in "
|
isc_throw(isc::BadValue, "pad mixed with digits in "
|
||||||
<< algorithm_ << ": " << encoded_str);
|
<< algorithm_ << ": " << encoded_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bump the valid character count.
|
||||||
dig_cnt++;
|
dig_cnt++;
|
||||||
|
|
||||||
|
// Shift off what we don't need.
|
||||||
dig_bits <<= shift_bits;
|
dig_bits <<= shift_bits;
|
||||||
|
|
||||||
|
// Add digit's decoded bits to current byte.
|
||||||
for (auto i = 0; i < bits_per_digit_; ++i) {
|
for (auto i = 0; i < bits_per_digit_; ++i) {
|
||||||
*inbit++ = ((dig_bits & 0x80) == 0x80);
|
if (cur_bit_cnt < 8) {
|
||||||
|
// Shift contents to make room for next gbit.
|
||||||
|
cur_byte <<= 1;
|
||||||
|
} else {
|
||||||
|
// Add the completed byte to the output.
|
||||||
|
output.push_back(cur_byte);
|
||||||
|
cur_byte = 0;
|
||||||
|
cur_bit_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the next bit if its set.
|
||||||
|
if (dig_bits & 0x80) {
|
||||||
|
cur_byte |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift the decoded bits over.
|
||||||
dig_bits <<= 1;
|
dig_bits <<= 1;
|
||||||
|
|
||||||
|
// Update the current byte bit count.
|
||||||
|
++cur_bit_cnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cur_bit_cnt == 8) {
|
||||||
|
// Whole one left to add.
|
||||||
|
output.push_back(cur_byte);
|
||||||
|
} else if (cur_bit_cnt && cur_byte) {
|
||||||
|
// Left over bits that are not zero.
|
||||||
|
isc_throw(BadValue, "non-zero bits left over " << encoded_str);
|
||||||
|
}
|
||||||
|
|
||||||
if (pad_char_) {
|
if (pad_char_) {
|
||||||
// Check for invalid number of pad characters.
|
// Check for too many pad characters.
|
||||||
if (pad_cnt > max_pad_) {
|
if (pad_cnt > max_pad_) {
|
||||||
isc_throw(isc::BadValue, "too many pad characters for "
|
isc_throw(isc::BadValue, "too many pad characters for "
|
||||||
<< algorithm_ << ": " << encoded_str);
|
<< algorithm_ << ": " << encoded_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for invalid number of pad characters.
|
// Check for invalid number of pad characters.
|
||||||
/// @todo is this valid
|
|
||||||
const size_t padbits = ((pad_cnt * bits_per_digit_) + 7) & ~7;
|
const size_t padbits = ((pad_cnt * bits_per_digit_) + 7) & ~7;
|
||||||
if (padbits > bits_per_digit_ * (pad_cnt + 1)) {
|
if (padbits > bits_per_digit_ * (pad_cnt + 1)) {
|
||||||
isc_throw(isc::BadValue, "Invalid padding for "
|
isc_throw(isc::BadValue, "Invalid padding for "
|
||||||
@@ -186,32 +217,6 @@ BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& outpu
|
|||||||
isc_throw (isc::BadValue, "Incomplete input for "
|
isc_throw (isc::BadValue, "Incomplete input for "
|
||||||
<< algorithm_ << ": " << encoded_str);
|
<< algorithm_ << ": " << encoded_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cnt = 0;
|
|
||||||
int digit_idx = 0;
|
|
||||||
|
|
||||||
auto inbit_end = inbit;
|
|
||||||
inbit = &inbits[0];
|
|
||||||
for (inbit = &inbits[0]; inbit != inbit_end; ++inbit) {
|
|
||||||
if (cnt < 8) {
|
|
||||||
digit_idx <<= 1;
|
|
||||||
} else {
|
|
||||||
output.push_back(digit_idx);
|
|
||||||
digit_idx = 0;
|
|
||||||
cnt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
digit_idx |= *inbit;
|
|
||||||
++cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt == 8) {
|
|
||||||
// Whole one left to add.
|
|
||||||
output.push_back(digit_idx);
|
|
||||||
} else if (cnt && digit_idx) {
|
|
||||||
// Left over bits that are not zero.
|
|
||||||
isc_throw(BadValue, "non-zero bits left over " << encoded_str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Base64Encoder::DIGIT_SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
const char* Base64Encoder::DIGIT_SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
@@ -282,40 +287,41 @@ const std::vector<uint8_t> Base16Encoder::BITS_TABLE = {
|
|||||||
|
|
||||||
string
|
string
|
||||||
encodeBase64(const vector<uint8_t>& binary) {
|
encodeBase64(const vector<uint8_t>& binary) {
|
||||||
Base64Encoder encoder;
|
static Base64Encoder encoder;
|
||||||
return(encoder.encode(binary));
|
return(encoder.encode(binary));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decodeBase64 (const std::string& encoded_str, std::vector<uint8_t>& output) {
|
decodeBase64 (const std::string& encoded_str, std::vector<uint8_t>& output) {
|
||||||
Base64Encoder encoder;
|
static Base64Encoder encoder;
|
||||||
encoder.decode(encoded_str, output);
|
encoder.decode(encoded_str, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
encodeBase32Hex(const vector<uint8_t>& binary) {
|
encodeBase32Hex(const vector<uint8_t>& binary) {
|
||||||
Base32HexEncoder encoder;
|
static Base32HexEncoder encoder;
|
||||||
return(encoder.encode(binary));
|
return(encoder.encode(binary));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decodeBase32Hex(const std::string& encoded_str, std::vector<uint8_t>& output) {
|
decodeBase32Hex(const std::string& encoded_str, std::vector<uint8_t>& output) {
|
||||||
Base32HexEncoder encoder;
|
static Base32HexEncoder encoder;
|
||||||
encoder.decode(encoded_str, output);
|
encoder.decode(encoded_str, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
encodeHex(const vector<uint8_t>& binary) {
|
encodeHex(const vector<uint8_t>& binary) {
|
||||||
Base16Encoder encoder;
|
static Base16Encoder encoder;
|
||||||
return(encoder.encode(binary));
|
return(encoder.encode(binary));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decodeHex(const string& encoded_str, vector<uint8_t>& output) {
|
decodeHex(const string& encoded_str, vector<uint8_t>& output) {
|
||||||
Base16Encoder encoder;
|
static Base16Encoder encoder;
|
||||||
encoder.decode(encoded_str, output);
|
encoder.decode(encoded_str, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace encode
|
} // namespace encode
|
||||||
} // namespace util
|
} // namespace util
|
||||||
} // namespace isc
|
} // namespace isc
|
||||||
|
Reference in New Issue
Block a user