• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 14559772276

20 Apr 2025 01:07PM UTC coverage: 91.315% (+0.006%) from 91.309%
14559772276

Pull #4832

github

web-flow
Merge b622bf23c into 7f66c45b3
Pull Request #4832: Replace std::vector with std::array in codec_base to avoid allocations

95530 of 104616 relevant lines covered (91.31%)

13166151.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.7
/src/lib/utils/codec_base.h
1
/*
2
* Base Encoding and Decoding
3
* (C) 2018 Erwan Chaussy
4
* (C) 2018 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#ifndef BOTAN_BASE_CODEC_H_
10
#define BOTAN_BASE_CODEC_H_
11

12
#include <botan/exceptn.h>
13
#include <botan/mem_ops.h>
14
#include <array>
15
#include <string>
16
#include <type_traits>
17

18
namespace Botan {
19

20
/**
21
* Perform encoding using the base provided
22
* @param base object giving access to the encodings specifications
23
* @param output an array of at least base.encode_max_output bytes
24
* @param input is some binary data
25
* @param input_length length of input in bytes
26
* @param input_consumed is an output parameter which says how many
27
*        bytes of input were actually consumed. If less than
28
*        input_length, then the range input[consumed:length]
29
*        should be passed in later along with more input.
30
* @param final_inputs true iff this is the last input, in which case
31
         padding chars will be applied if needed
32
* @return number of bytes written to output
33
*/
34
template <class Base>
35
size_t base_encode(
2,533✔
36
   Base&& base, char output[], const uint8_t input[], size_t input_length, size_t& input_consumed, bool final_inputs) {
37
   input_consumed = 0;
2,533✔
38

39
   // TODO(Botan4) Check if we can use just base. or Base:: here instead
40
   constexpr size_t encoding_bytes_in = std::remove_reference_t<Base>::encoding_bytes_in();
2,533✔
41
   constexpr size_t encoding_bytes_out = std::remove_reference_t<Base>::encoding_bytes_out();
2,533✔
42

43
   size_t input_remaining = input_length;
2,533✔
44
   size_t output_produced = 0;
2,533✔
45

46
   while(input_remaining >= encoding_bytes_in) {
2,181,668✔
47
      base.encode(output + output_produced, input + input_consumed);
2,179,135✔
48

49
      input_consumed += encoding_bytes_in;
2,179,135✔
50
      output_produced += encoding_bytes_out;
2,179,135✔
51
      input_remaining -= encoding_bytes_in;
2,179,135✔
52
   }
53

54
   if(final_inputs && input_remaining) {
2,533✔
55
      std::array<uint8_t, encoding_bytes_in> remainder{};
2,134✔
56
      for(size_t i = 0; i != input_remaining; ++i) {
5,356✔
57
         remainder[i] = input[input_consumed + i];
3,222✔
58
      }
59

60
      base.encode(output + output_produced, remainder.data());
2,134✔
61

62
      const size_t bits_consumed = base.bits_consumed();
2,134✔
63
      const size_t remaining_bits_before_padding = base.remaining_bits_before_padding();
2,134✔
64

65
      size_t empty_bits = 8 * (encoding_bytes_in - input_remaining);
2,134✔
66
      size_t index = output_produced + encoding_bytes_out - 1;
2,134✔
67
      while(empty_bits >= remaining_bits_before_padding) {
5,371✔
68
         output[index--] = '=';
3,237✔
69
         empty_bits -= bits_consumed;
3,237✔
70
      }
71

72
      input_consumed += input_remaining;
2,134✔
73
      output_produced += encoding_bytes_out;
2,134✔
74
   }
75

76
   return output_produced;
2,533✔
77
}
78

79
template <typename Base>
80
std::string base_encode_to_string(Base&& base, const uint8_t input[], size_t input_length) {
2,527✔
81
   const size_t output_length = base.encode_max_output(input_length);
2,527✔
82
   std::string output(output_length, 0);
2,527✔
83

84
   size_t consumed = 0;
2,527✔
85
   size_t produced = 0;
2,527✔
86

87
   if(output_length > 0) {
2,527✔
88
      produced = base_encode(base, &output.front(), input, input_length, consumed, true);
2,525✔
89
   }
90

91
   BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input");
2,527✔
92
   BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size");
2,527✔
93

94
   return output;
2,527✔
95
}
×
96

97
/**
98
* Perform decoding using the base provided
99
* @param base object giving access to the encodings specifications
100
* @param output an array of at least Base::decode_max_output bytes
101
* @param input some base input
102
* @param input_length length of input in bytes
103
* @param input_consumed is an output parameter which says how many
104
*        bytes of input were actually consumed. If less than
105
*        input_length, then the range input[consumed:length]
106
*        should be passed in later along with more input.
107
* @param final_inputs true iff this is the last input, in which case
108
         padding is allowed
109
* @param ignore_ws ignore whitespace on input; if false, throw an
110
                   exception if whitespace is encountered
111
* @return number of bytes written to output
112
*/
113
template <typename Base>
114
size_t base_decode(Base&& base,
16,437✔
115
                   uint8_t output[],
116
                   const char input[],
117
                   size_t input_length,
118
                   size_t& input_consumed,
119
                   bool final_inputs,
120
                   bool ignore_ws = true) {
121
   // TODO(Botan4) Check if we can use just base. or Base:: here instead
122
   constexpr size_t decoding_bytes_in = std::remove_reference_t<Base>::decoding_bytes_in();
16,437✔
123
   constexpr size_t decoding_bytes_out = std::remove_reference_t<Base>::decoding_bytes_out();
16,437✔
124

125
   uint8_t* out_ptr = output;
16,437✔
126
   std::array<uint8_t, decoding_bytes_in> decode_buf{};
16,437✔
127
   size_t decode_buf_pos = 0;
16,437✔
128
   size_t final_truncate = 0;
16,437✔
129

130
   clear_mem(output, base.decode_max_output(input_length));
16,437✔
131

132
   for(size_t i = 0; i != input_length; ++i) {
22,129,857✔
133
      const uint8_t bin = base.lookup_binary_value(input[i]);
22,113,496✔
134

135
      // This call might throw Invalid_Argument
136
      if(base.check_bad_char(bin, input[i], ignore_ws)) {
22,113,496✔
137
         decode_buf[decode_buf_pos] = bin;
21,748,786✔
138
         ++decode_buf_pos;
21,748,786✔
139
      }
140

141
      /*
142
      * If we're at the end of the input, pad with 0s and truncate
143
      */
144
      if(final_inputs && (i == input_length - 1)) {
22,113,420✔
145
         if(decode_buf_pos) {
16,346✔
146
            for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j) {
28,650✔
147
               decode_buf[j] = 0;
16,556✔
148
            }
149

150
            final_truncate = decoding_bytes_in - decode_buf_pos;
12,094✔
151
            decode_buf_pos = decoding_bytes_in;
152
         }
153
      }
154

155
      if(decode_buf_pos == decoding_bytes_in) {
22,097,074✔
156
         base.decode(out_ptr, decode_buf.data());
5,441,224✔
157

158
         out_ptr += decoding_bytes_out;
5,441,224✔
159
         decode_buf_pos = 0;
5,441,224✔
160
         input_consumed = i + 1;
5,441,224✔
161
      }
162
   }
163

164
   while(input_consumed < input_length && base.lookup_binary_value(input[input_consumed]) == 0x80) {
21,565✔
165
      ++input_consumed;
5,204✔
166
   }
167

168
   size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate);
16,361✔
169

170
   return written;
16,361✔
171
}
172

173
template <typename Base>
174
size_t base_decode_full(Base&& base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws) {
16,435✔
175
   size_t consumed = 0;
16,435✔
176
   const size_t written = base_decode(base, output, input, input_length, consumed, true, ignore_ws);
16,435✔
177

178
   if(consumed != input_length) {
16,359✔
179
      throw Invalid_Argument(base.name() + " decoding failed, input did not have full bytes");
56✔
180
   }
181

182
   return written;
16,345✔
183
}
184

185
template <typename Vector, typename Base>
186
Vector base_decode_to_vec(Base&& base, const char input[], size_t input_length, bool ignore_ws) {
16,418✔
187
   const size_t output_length = base.decode_max_output(input_length);
16,418✔
188
   Vector bin(output_length);
16,418✔
189

190
   const size_t written = base_decode_full(base, bin.data(), input, input_length, ignore_ws);
16,418✔
191

192
   bin.resize(written);
16,328✔
193
   return bin;
16,328✔
194
}
90✔
195

196
}  // namespace Botan
197

198
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc