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

randombit / botan / 16293079084

15 Jul 2025 12:20PM UTC coverage: 90.627% (+0.003%) from 90.624%
16293079084

push

github

web-flow
Merge pull request #4990 from randombit/jack/string-and-span

Improve string<->span conversions

99640 of 109945 relevant lines covered (90.63%)

12253617.72 hits per line

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

93.66
/src/lib/filters/pipe.cpp
1
/*
2
* Pipe
3
* (C) 1999-2007 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/pipe.h>
9

10
#include <botan/mem_ops.h>
11
#include <botan/internal/fmt.h>
12
#include <botan/internal/mem_utils.h>
13
#include <botan/internal/out_buf.h>
14
#include <botan/internal/secqueue.h>
15
#include <memory>
16

17
namespace Botan {
18

19
namespace {
20

21
/*
22
* A Filter that does nothing
23
*/
24
class Null_Filter final : public Filter {
4✔
25
   public:
26
      void write(const uint8_t input[], size_t length) override { send(input, length); }
1✔
27

28
      std::string name() const override { return "Null"; }
×
29
};
30

31
}  // namespace
32

33
Pipe::Pipe(Pipe&&) noexcept = default;
×
34

35
Pipe::Invalid_Message_Number::Invalid_Message_Number(std::string_view where, message_id msg) :
1✔
36
      Invalid_Argument(fmt("Pipe::{}: Invalid message number {}", where, msg)) {}
2✔
37

38
/*
39
* Pipe Constructor
40
*/
41
Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : Pipe({f1, f2, f3, f4}) {}
18✔
42

43
/*
44
* Pipe Constructor
45
*/
46
Pipe::Pipe(std::initializer_list<Filter*> args) : m_pipe(nullptr), m_default_read(0), m_inside_msg(false) {
18✔
47
   m_outputs = std::make_unique<Output_Buffers>();
18✔
48

49
   for(auto* arg : args) {
90✔
50
      do_append(arg);
72✔
51
   }
52
}
18✔
53

54
/*
55
* Pipe Destructor
56
*/
57
Pipe::~Pipe() {
18✔
58
   destruct(m_pipe);
18✔
59
}
18✔
60

61
/*
62
* Reset the Pipe
63
*/
64
void Pipe::reset() {
6✔
65
   destruct(m_pipe);
6✔
66
   m_pipe = nullptr;
6✔
67
   m_inside_msg = false;
6✔
68
}
6✔
69

70
/*
71
* Destroy the Pipe
72
*/
73
void Pipe::destruct(Filter* to_kill) {
80✔
74
   if(to_kill == nullptr) {
80✔
75
      return;
76
   }
77

78
   if(dynamic_cast<SecureQueue*>(to_kill) != nullptr) {
49✔
79
      return;
80
   }
81

82
   for(size_t j = 0; j != to_kill->total_ports(); ++j) {
105✔
83
      destruct(to_kill->m_next[j]);
56✔
84
   }
85
   delete to_kill;  // NOLINT(*owning-memory)
49✔
86
}
87

88
/*
89
* Test if the Pipe has any data in it
90
*/
91
bool Pipe::end_of_data() const {
2✔
92
   return (remaining() == 0);
2✔
93
}
94

95
/*
96
* Set the default read message
97
*/
98
void Pipe::set_default_msg(message_id msg) {
3✔
99
   if(msg >= message_count()) {
3✔
100
      throw Invalid_Argument("Pipe::set_default_msg: msg number is too high");
×
101
   }
102
   m_default_read = msg;
3✔
103
}
3✔
104

105
/*
106
* Process a full message at once
107
*/
108
void Pipe::process_msg(const uint8_t input[], size_t length) {
39✔
109
   start_msg();
39✔
110
   write(input, length);
39✔
111
   end_msg();
39✔
112
}
39✔
113

114
void Pipe::process_msg(std::span<const uint8_t> input) {
39✔
115
   this->process_msg(input.data(), input.size());
39✔
116
}
39✔
117

118
/*
119
* Process a full message at once
120
*/
121
void Pipe::process_msg(const secure_vector<uint8_t>& input) {
2✔
122
   this->process_msg(std::span{input});
2✔
123
}
2✔
124

125
void Pipe::process_msg(const std::vector<uint8_t>& input) {
1✔
126
   this->process_msg(std::span{input});
1✔
127
}
1✔
128

129
/*
130
* Process a full message at once
131
*/
132
void Pipe::process_msg(std::string_view input) {
36✔
133
   process_msg(as_span_of_bytes(input));
36✔
134
}
36✔
135

136
/*
137
* Process a full message at once
138
*/
139
void Pipe::process_msg(DataSource& input) {
4✔
140
   start_msg();
4✔
141
   write(input);
4✔
142
   end_msg();
4✔
143
}
4✔
144

145
/*
146
* Start a new message
147
*/
148
void Pipe::start_msg() {
65✔
149
   if(m_inside_msg) {
65✔
150
      throw Invalid_State("Pipe::start_msg: Message was already started");
×
151
   }
152
   if(m_pipe == nullptr) {
65✔
153
      m_pipe = new Null_Filter;  // NOLINT(*-owning-memory)
2✔
154
   }
155
   find_endpoints(m_pipe);
65✔
156
   m_pipe->new_msg();
65✔
157
   m_inside_msg = true;
65✔
158
}
65✔
159

160
/*
161
* End the current message
162
*/
163
void Pipe::end_msg() {
65✔
164
   if(!m_inside_msg) {
65✔
165
      throw Invalid_State("Pipe::end_msg: Message was already ended");
×
166
   }
167
   m_pipe->finish_msg();
65✔
168
   clear_endpoints(m_pipe);
65✔
169
   if(dynamic_cast<Null_Filter*>(m_pipe) != nullptr) {
65✔
170
      delete m_pipe;
2✔
171
      m_pipe = nullptr;
2✔
172
   }
173
   m_inside_msg = false;
65✔
174

175
   m_outputs->retire();
65✔
176
}
65✔
177

178
/*
179
* Find the endpoints of the Pipe
180
*/
181
void Pipe::find_endpoints(Filter* f) {
135✔
182
   for(size_t j = 0; j != f->total_ports(); ++j) {
277✔
183
      if(f->m_next[j] != nullptr && dynamic_cast<SecureQueue*>(f->m_next[j]) == nullptr) {
142✔
184
         find_endpoints(f->m_next[j]);
70✔
185
      } else {
186
         SecureQueue* q = new SecureQueue;  // NOLINT(*-owning-memory)
72✔
187
         f->m_next[j] = q;
72✔
188
         m_outputs->add(q);
72✔
189
      }
190
   }
191
}
135✔
192

193
/*
194
* Remove the SecureQueues attached to the Filter
195
*/
196
void Pipe::clear_endpoints(Filter* f) {
207✔
197
   if(!f) {
207✔
198
      return;
199
   }
200
   for(size_t j = 0; j != f->total_ports(); ++j) {
277✔
201
      if(f->m_next[j] && dynamic_cast<SecureQueue*>(f->m_next[j])) {
142✔
202
         f->m_next[j] = nullptr;
72✔
203
      }
204
      clear_endpoints(f->m_next[j]);
142✔
205
   }
206
}
207

208
void Pipe::append(Filter* filter) {
19✔
209
   do_append(filter);
19✔
210
}
17✔
211

212
void Pipe::append_filter(Filter* filter) {
4✔
213
   if(m_outputs->message_count() != 0) {
4✔
214
      throw Invalid_State("Cannot call Pipe::append_filter after start_msg");
2✔
215
   }
216

217
   do_append(filter);
2✔
218
}
2✔
219

220
void Pipe::prepend(Filter* filter) {
5✔
221
   do_prepend(filter);
5✔
222
}
3✔
223

224
void Pipe::prepend_filter(Filter* filter) {
4✔
225
   if(m_outputs->message_count() != 0) {
4✔
226
      throw Invalid_State("Cannot call Pipe::prepend_filter after start_msg");
2✔
227
   }
228

229
   do_prepend(filter);
2✔
230
}
2✔
231

232
/*
233
* Append a Filter to the Pipe
234
*/
235
void Pipe::do_append(Filter* filter) {
93✔
236
   if(!filter) {
93✔
237
      return;
238
   }
239
   if(dynamic_cast<SecureQueue*>(filter)) {
41✔
240
      throw Invalid_Argument("Pipe::append: SecureQueue cannot be used");
1✔
241
   }
242
   if(filter->m_owned) {
40✔
243
      throw Invalid_Argument("Filters cannot be shared among multiple Pipes");
×
244
   }
245

246
   if(m_inside_msg) {
40✔
247
      throw Invalid_State("Cannot append to a Pipe while it is processing");
1✔
248
   }
249

250
   filter->m_owned = true;
39✔
251

252
   if(!m_pipe) {
39✔
253
      m_pipe = filter;
25✔
254
   } else {
255
      m_pipe->attach(filter);
14✔
256
   }
257
}
258

259
/*
260
* Prepend a Filter to the Pipe
261
*/
262
void Pipe::do_prepend(Filter* filter) {
7✔
263
   if(m_inside_msg) {
7✔
264
      throw Invalid_State("Cannot prepend to a Pipe while it is processing");
1✔
265
   }
266
   if(!filter) {
6✔
267
      return;
268
   }
269
   if(dynamic_cast<SecureQueue*>(filter)) {
3✔
270
      throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used");
1✔
271
   }
272
   if(filter->m_owned) {
2✔
273
      throw Invalid_Argument("Filters cannot be shared among multiple Pipes");
×
274
   }
275

276
   filter->m_owned = true;
2✔
277

278
   if(m_pipe) {
2✔
279
      filter->attach(m_pipe);
×
280
   }
281
   m_pipe = filter;
2✔
282
}
283

284
/*
285
* Pop a Filter off the Pipe
286
*/
287
void Pipe::pop() {
10✔
288
   if(m_inside_msg) {
10✔
289
      throw Invalid_State("Cannot pop off a Pipe while it is processing");
1✔
290
   }
291

292
   if(!m_pipe) {
9✔
293
      return;
294
   }
295

296
   if(m_pipe->total_ports() > 1) {
7✔
297
      throw Invalid_State("Cannot pop off a Filter with multiple ports");
×
298
   }
299

300
   size_t to_remove = m_pipe->owns() + 1;
7✔
301

302
   while(to_remove--) {
16✔
303
      std::unique_ptr<Filter> to_destroy(m_pipe);
9✔
304
      m_pipe = m_pipe->m_next[0];
9✔
305
   }
9✔
306
}
307

308
/*
309
* Return the number of messages in this Pipe
310
*/
311
Pipe::message_id Pipe::message_count() const {
243✔
312
   return m_outputs->message_count();
243✔
313
}
314

315
/*
316
* Static Member Variables
317
*/
318
const Pipe::message_id Pipe::LAST_MESSAGE = static_cast<Pipe::message_id>(-2);
319

320
const Pipe::message_id Pipe::DEFAULT_MESSAGE = static_cast<Pipe::message_id>(-1);
321

322
}  // 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

© 2026 Coveralls, Inc