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

randombit / botan / 5395967798

28 Jun 2023 12:28AM UTC coverage: 91.737% (+0.01%) from 91.726%
5395967798

push

github

randombit
Merge GH #3606 Add example of custom entropy source

78190 of 85233 relevant lines covered (91.74%)

12513919.75 hits per line

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

83.84
/src/lib/compression/compress_utils.cpp
1
/*
2
* Compression Utils
3
* (C) 2014,2016 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/compress_utils.h>
9

10
#include <botan/exceptn.h>
11
#include <botan/internal/fmt.h>
12
#include <botan/internal/safeint.h>
13
#include <cstdlib>
14

15
namespace Botan {
16

17
Compression_Error::Compression_Error(const char* func_name, ErrorType type, int rc) :
×
18
      Exception(fmt("Compression API {} failed with return code {}", func_name, rc)), m_type(type), m_rc(rc) {}
×
19

20
void* Compression_Alloc_Info::do_malloc(size_t n, size_t size) {
1,148✔
21
   if(!BOTAN_CHECKED_MUL(n, size).has_value()) [[unlikely]] {
1,148✔
22
      return nullptr;
×
23
   }
24

25
   void* ptr = std::calloc(n, size);  // NOLINT(*-no-malloc)
1,148✔
26

27
   /*
28
   * Return null rather than throwing here as we are being called by a
29
   * C library and it may not be possible for an exception to unwind
30
   * the call stack from here. The compression library is expecting a
31
   * function written in C and a null return on error, which it will
32
   * send upwards to the compression wrappers.
33
   */
34

35
   if(ptr) {
1,148✔
36
      m_current_allocs[ptr] = n * size;
1,148✔
37
   }
38

39
   return ptr;
1,148✔
40
}
41

42
void Compression_Alloc_Info::do_free(void* ptr) {
1,268✔
43
   if(ptr) {
1,268✔
44
      auto i = m_current_allocs.find(ptr);
1,148✔
45

46
      if(i == m_current_allocs.end()) {
1,148✔
47
         throw Internal_Error("Compression_Alloc_Info::free got pointer not allocated by us");
×
48
      }
49

50
      secure_scrub_memory(ptr, i->second);
1,148✔
51
      std::free(ptr);  // NOLINT(*-no-malloc)
1,148✔
52
      m_current_allocs.erase(i);
1,148✔
53
   }
54
}
1,268✔
55

56
void Stream_Compression::clear() {
126✔
57
   m_stream.reset();
×
58
}
×
59

60
void Stream_Compression::start(size_t level) {
126✔
61
   m_stream = make_stream(level);
126✔
62
}
126✔
63

64
void Stream_Compression::process(secure_vector<uint8_t>& buf, size_t offset, uint32_t flags) {
279✔
65
   BOTAN_ASSERT(m_stream, "Initialized");
279✔
66
   BOTAN_ASSERT(buf.size() >= offset, "Offset is sane");
279✔
67

68
   // bzip doesn't like being called with no input and BZ_RUN
69
   if(buf.size() == offset && flags == m_stream->run_flag()) {
279✔
70
      return;
71
   }
72

73
   if(m_buffer.size() < buf.size() + offset) {
259✔
74
      m_buffer.resize(buf.size() + offset);
106✔
75
   }
76

77
   // If the output buffer has zero length, .data() might return nullptr. This would
78
   // make some compression algorithms (notably those provided by zlib) fail.
79
   // Any small positive value works fine, but we choose 32 as it is the smallest power
80
   // of two that is large enough to hold all the headers and trailers of the common
81
   // formats, preventing further resizings to make room for output data.
82
   if(m_buffer.empty()) {
259✔
83
      m_buffer.resize(32);
70✔
84
   }
85

86
   m_stream->next_in(buf.data() + offset, buf.size() - offset);
259✔
87
   m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);
259✔
88

89
   while(true) {
347✔
90
      const bool stream_end = m_stream->run(flags);
347✔
91

92
      if(stream_end) {
347✔
93
         BOTAN_ASSERT(m_stream->avail_in() == 0, "After stream is done, no input remains to be processed");
136✔
94
         m_buffer.resize(m_buffer.size() - m_stream->avail_out());
136✔
95
         break;
136✔
96
      } else if(m_stream->avail_out() == 0) {
211✔
97
         const size_t added = 8 + m_buffer.size();
88✔
98
         m_buffer.resize(m_buffer.size() + added);
88✔
99
         m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
88✔
100
      } else if(m_stream->avail_in() == 0) {
123✔
101
         m_buffer.resize(m_buffer.size() - m_stream->avail_out());
123✔
102
         break;
123✔
103
      }
104
   }
105

106
   copy_mem(m_buffer.data(), buf.data(), offset);
259✔
107
   buf.swap(m_buffer);
259✔
108
}
109

110
void Stream_Compression::update(secure_vector<uint8_t>& buf, size_t offset, bool flush) {
153✔
111
   BOTAN_ASSERT(m_stream, "Initialized");
153✔
112
   process(buf, offset, flush ? m_stream->flush_flag() : m_stream->run_flag());
153✔
113
}
153✔
114

115
void Stream_Compression::finish(secure_vector<uint8_t>& buf, size_t offset) {
126✔
116
   BOTAN_ASSERT(m_stream, "Initialized");
126✔
117
   process(buf, offset, m_stream->finish_flag());
126✔
118
   clear();
126✔
119
}
126✔
120

121
void Stream_Decompression::clear() {
103✔
122
   m_stream.reset();
×
123
}
×
124

125
void Stream_Decompression::start() {
103✔
126
   m_stream = make_stream();
103✔
127
}
103✔
128

129
void Stream_Decompression::process(secure_vector<uint8_t>& buf, size_t offset, uint32_t flags) {
103✔
130
   BOTAN_ASSERT(m_stream, "Initialized");
103✔
131
   BOTAN_ASSERT(buf.size() >= offset, "Offset is sane");
103✔
132

133
   if(m_buffer.size() < buf.size() + offset) {
103✔
134
      m_buffer.resize(buf.size() + offset);
33✔
135
   }
136

137
   m_stream->next_in(buf.data() + offset, buf.size() - offset);
103✔
138
   m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);
103✔
139

140
   while(true) {
219✔
141
      const bool stream_end = m_stream->run(flags);
219✔
142

143
      if(stream_end) {
219✔
144
         if(m_stream->avail_in() == 0)  // all data consumed?
103✔
145
         {
146
            m_buffer.resize(m_buffer.size() - m_stream->avail_out());
103✔
147
            clear();
103✔
148
            break;
149
         }
150

151
         // More data follows: try to process as a following stream
152
         const size_t read = (buf.size() - offset) - m_stream->avail_in();
×
153
         start();
×
154
         m_stream->next_in(buf.data() + offset + read, buf.size() - offset - read);
×
155
      }
156

157
      if(m_stream->avail_out() == 0) {
116✔
158
         const size_t added = 8 + m_buffer.size();
116✔
159
         m_buffer.resize(m_buffer.size() + added);
116✔
160
         m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
116✔
161
      } else if(m_stream->avail_in() == 0) {
×
162
         m_buffer.resize(m_buffer.size() - m_stream->avail_out());
×
163
         break;
×
164
      }
165
   }
166

167
   copy_mem(m_buffer.data(), buf.data(), offset);
103✔
168
   buf.swap(m_buffer);
103✔
169
}
103✔
170

171
void Stream_Decompression::update(secure_vector<uint8_t>& buf, size_t offset) {
103✔
172
   process(buf, offset, m_stream->run_flag());
103✔
173
}
103✔
174

175
void Stream_Decompression::finish(secure_vector<uint8_t>& buf, size_t offset) {
103✔
176
   if(buf.size() != offset || m_stream.get()) {
103✔
177
      process(buf, offset, m_stream->finish_flag());
×
178
   }
179

180
   if(m_stream) {
103✔
181
      throw Invalid_State(fmt("{} finished but not at stream end", name()));
×
182
   }
183
}
103✔
184

185
}  // namespace Botan
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

© 2025 Coveralls, Inc