Coverage Report

Created: 2025-11-12 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/utils/data_src.cpp
Line
Count
Source
1
/*
2
* DataSource
3
* (C) 1999-2007 Jack Lloyd
4
*     2005 Matthew Gregan
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/data_src.h>
10
11
#include <botan/exceptn.h>
12
#include <botan/mem_ops.h>
13
#include <botan/internal/fmt.h>
14
#include <botan/internal/mem_utils.h>
15
#include <algorithm>
16
#include <istream>
17
18
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
19
   #include <fstream>
20
#endif
21
22
namespace Botan {
23
24
/*
25
* Read a single byte from the DataSource
26
*/
27
34.3M
size_t DataSource::read_byte(uint8_t& out) {
28
34.3M
   return read(&out, 1);
29
34.3M
}
30
31
/*
32
* Read a single byte from the DataSource
33
*/
34
17.2M
std::optional<uint8_t> DataSource::read_byte() {
35
17.2M
   uint8_t b = 0;
36
17.2M
   if(this->read(&b, 1) == 1) {
37
16.7M
      return b;
38
16.7M
   } else {
39
487k
      return {};
40
487k
   }
41
17.2M
}
42
43
/*
44
* Peek a single byte from the DataSource
45
*/
46
87.9k
size_t DataSource::peek_byte(uint8_t& out) const {
47
87.9k
   return peek(&out, 1, 0);
48
87.9k
}
49
50
/*
51
* Discard the next N bytes of the data
52
*/
53
1.71M
size_t DataSource::discard_next(size_t n) {
54
1.71M
   uint8_t buf[64] = {0};
55
1.71M
   size_t discarded = 0;
56
57
5.37M
   while(n > 0) {
58
3.66M
      const size_t got = this->read(buf, std::min(n, sizeof(buf)));
59
3.66M
      discarded += got;
60
3.66M
      n -= got;
61
62
3.66M
      if(got == 0) {
63
3.25k
         break;
64
3.25k
      }
65
3.66M
   }
66
67
1.71M
   return discarded;
68
1.71M
}
69
70
/*
71
* Read from a memory buffer
72
*/
73
23.0M
size_t DataSource_Memory::read(uint8_t out[], size_t length) {
74
23.0M
   const size_t got = std::min<size_t>(m_source.size() - m_offset, length);
75
23.0M
   copy_mem(out, m_source.data() + m_offset, got);
76
23.0M
   m_offset += got;
77
23.0M
   return got;
78
23.0M
}
79
80
1.28M
bool DataSource_Memory::check_available(size_t n) {
81
1.28M
   return (n <= (m_source.size() - m_offset));
82
1.28M
}
83
84
/*
85
* Peek into a memory buffer
86
*/
87
869k
size_t DataSource_Memory::peek(uint8_t out[], size_t length, size_t peek_offset) const {
88
869k
   const size_t bytes_left = m_source.size() - m_offset;
89
869k
   if(peek_offset >= bytes_left) {
90
366k
      return 0;
91
366k
   }
92
93
502k
   const size_t got = std::min(bytes_left - peek_offset, length);
94
502k
   copy_mem(out, &m_source[m_offset + peek_offset], got);
95
502k
   return got;
96
869k
}
97
98
/*
99
* Check if the memory buffer is empty
100
*/
101
356k
bool DataSource_Memory::end_of_data() const {
102
356k
   return (m_offset == m_source.size());
103
356k
}
104
105
/*
106
* DataSource_Memory Constructor
107
*/
108
16.4k
DataSource_Memory::DataSource_Memory(std::string_view in) : DataSource_Memory(as_span_of_bytes(in)) {}
109
110
/*
111
* Read from a stream
112
*/
113
0
size_t DataSource_Stream::read(uint8_t out[], size_t length) {
114
0
   m_source.read(cast_uint8_ptr_to_char(out), length);
115
0
   if(m_source.bad()) {
116
0
      throw Stream_IO_Error("DataSource_Stream::read: Source failure");
117
0
   }
118
119
0
   const size_t got = static_cast<size_t>(m_source.gcount());
120
0
   m_total_read += got;
121
0
   return got;
122
0
}
123
124
0
bool DataSource_Stream::check_available(size_t n) {
125
0
   const std::streampos orig_pos = m_source.tellg();
126
0
   m_source.seekg(0, std::ios::end);
127
0
   const size_t avail = static_cast<size_t>(m_source.tellg() - orig_pos);
128
0
   m_source.seekg(orig_pos);
129
0
   return (avail >= n);
130
0
}
131
132
/*
133
* Peek into a stream
134
*/
135
0
size_t DataSource_Stream::peek(uint8_t out[], size_t length, size_t offset) const {
136
0
   if(end_of_data()) {
137
0
      throw Invalid_State("DataSource_Stream: Cannot peek when out of data");
138
0
   }
139
140
0
   size_t got = 0;
141
142
0
   if(offset > 0) {
143
0
      secure_vector<uint8_t> buf(offset);
144
0
      m_source.read(cast_uint8_ptr_to_char(buf.data()), buf.size());
145
0
      if(m_source.bad()) {
146
0
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
147
0
      }
148
0
      got = static_cast<size_t>(m_source.gcount());
149
0
   }
150
151
0
   if(got == offset) {
152
0
      m_source.read(cast_uint8_ptr_to_char(out), length);
153
0
      if(m_source.bad()) {
154
0
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
155
0
      }
156
0
      got = static_cast<size_t>(m_source.gcount());
157
0
   }
158
159
0
   if(m_source.eof()) {
160
0
      m_source.clear();
161
0
   }
162
0
   m_source.seekg(m_total_read, std::ios::beg);
163
164
0
   return got;
165
0
}
166
167
/*
168
* Check if the stream is empty or in error
169
*/
170
0
bool DataSource_Stream::end_of_data() const {
171
0
   return (!m_source.good());
172
0
}
173
174
/*
175
* Return a human-readable ID for this stream
176
*/
177
0
std::string DataSource_Stream::id() const {
178
0
   return m_identifier;
179
0
}
180
181
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
182
183
/*
184
* DataSource_Stream Constructor
185
*/
186
DataSource_Stream::DataSource_Stream(std::string_view path, bool use_binary) :
187
0
      m_identifier(path),
188
0
      m_source_memory(std::make_unique<std::ifstream>(std::string(path), use_binary ? std::ios::binary : std::ios::in)),
189
0
      m_source(*m_source_memory),
190
0
      m_total_read(0) {
191
0
   if(!m_source.good()) {
192
0
      throw Stream_IO_Error(fmt("DataSource: Failure opening file '{}'", path));
193
0
   }
194
0
}
195
196
#endif
197
198
/*
199
* DataSource_Stream Constructor
200
*/
201
DataSource_Stream::DataSource_Stream(std::istream& in, std::string_view name) :
202
0
      m_identifier(name), m_source(in), m_total_read(0) {}
203
204
0
DataSource_Stream::~DataSource_Stream() = default;
205
206
}  // namespace Botan