]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3209] Remove internal bool vectors
authorThomas Markwalder <tmark@isc.org>
Wed, 31 Jan 2024 19:00:37 +0000 (14:00 -0500)
committerThomas Markwalder <tmark@isc.org>
Wed, 7 Feb 2024 13:58:47 +0000 (13:58 +0000)
src/lib/util/encode/encode.cc
    BaseNEncoder::encode()
    BaseNEncoder::decode() - eliminate use of bool vectors
    as "bit streams"

src/lib/util/encode/encode.cc

index cb06cdac0d3bbac8ae37eda158b66712e21e782e..f671cb860b5c72033e47fd620b56e212c9efc473 100644 (file)
@@ -70,38 +70,37 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
         return(encoded_output);
     }
 
-    // Turn the input data into a "bit stream"
-    /// @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.
+    uint8_t cur_bit = 0x0;
     int cnt = 0;
     int digit_idx = 0;
-    auto inbit_end = inbit;
-    inbit = &inbits[0];
-    for (inbit = &inbits[0]; inbit != inbit_end; ++inbit) {
+    int cur_byte = 0;
+    auto bytes = input.begin();
+    while (1) {
+        if (!cur_bit) {
+            if (bytes == input.end()) {
+                break;
+            }
+
+            cur_byte = *bytes;
+            cur_bit = 0x80;
+            ++bytes;
+        }
+
         if (cnt < bits_per_digit_) {
-            // Shift the index one to accommodate next bit.
             digit_idx <<= 1;
         } 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));
             digit_idx = 0;
             cnt = 0;
         }
 
         // Add the current bit to the digit index.
-        digit_idx |= *inbit;
+        if (cur_byte & cur_bit) {
+            digit_idx |= 1;
+        }
+
+        cur_bit >>= 1;
         ++cnt;
     }
 
@@ -128,52 +127,84 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
 void
 BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& output) {
     output.clear();
-    bool inbits[encoded_str.size() * bits_per_digit_];
-    bool* inbit = &inbits[0];
     size_t dig_cnt = 0;
     size_t pad_cnt = 0;
     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) {
         if (pad_char_ && enc_digit == pad_char_) {
            pad_cnt++;
            continue;
         }
 
-        // translate the b64 digit to bits.
+        // Translate the b64 digit to bits.
         uint8_t dig_bits = digitToBits(enc_digit);
 
+        // Skip whitespace.
         if (dig_bits == 0xee) {
-            // skip whitespace
             continue;
         }
 
+        // Error on invalid characters.
         if (dig_bits == 0xff) {
             isc_throw(isc::BadValue, "attempt to decode a value not in "
                       << algorithm_ << " char set" << ": " << encoded_str);
         }
 
+        // Error if pads are in the middle.
         if (pad_cnt) {
             isc_throw(isc::BadValue, "pad mixed with digits in "
                       << algorithm_ << ": " << encoded_str);
         }
 
+        // Bump the valid character count.
         dig_cnt++;
+
+        // Shift off what we don't need.
         dig_bits <<= shift_bits;
+
+        // Add digit's decoded bits to current byte.
         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;
+
+            // 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_) {
-        // Check for invalid number of pad characters.
+        // Check for too many pad characters.
         if (pad_cnt > max_pad_) {
             isc_throw(isc::BadValue, "too many pad characters for "
                       << algorithm_ << ": " << encoded_str);
         }
 
         // Check for invalid number of pad characters.
-        /// @todo is this valid
         const size_t padbits = ((pad_cnt * bits_per_digit_) + 7) & ~7;
         if (padbits > bits_per_digit_ * (pad_cnt + 1)) {
             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 "
                    << 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"
@@ -282,40 +287,41 @@ const std::vector<uint8_t> Base16Encoder::BITS_TABLE = {
 
 string
 encodeBase64(const vector<uint8_t>& binary) {
-    Base64Encoder encoder;
+    static Base64Encoder encoder;
     return(encoder.encode(binary));
 }
 
 void
 decodeBase64 (const std::string& encoded_str, std::vector<uint8_t>& output) {
-    Base64Encoder encoder;
+    static Base64Encoder encoder;
     encoder.decode(encoded_str, output);
 }
 
 string
 encodeBase32Hex(const vector<uint8_t>& binary) {
-    Base32HexEncoder encoder;
+    static Base32HexEncoder encoder;
     return(encoder.encode(binary));
 }
 
 void
 decodeBase32Hex(const std::string& encoded_str, std::vector<uint8_t>& output) {
-    Base32HexEncoder encoder;
+    static Base32HexEncoder encoder;
     encoder.decode(encoded_str, output);
 }
 
 string
 encodeHex(const vector<uint8_t>& binary) {
-    Base16Encoder encoder;
+    static Base16Encoder encoder;
     return(encoder.encode(binary));
 }
 
 void
 decodeHex(const string& encoded_str, vector<uint8_t>& output) {
-    Base16Encoder encoder;
+    static Base16Encoder encoder;
     encoder.decode(encoded_str, output);
 }
 
+
 } // namespace encode
 } // namespace util
 } // namespace isc