Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/utils/data_src.cpp
Line
Count
Source (jump to first uncovered line)
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 <algorithm>
15
#include <istream>
16
17
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
18
   #include <fstream>
19
#endif
20
21
namespace Botan {
22
23
/*
24
* Read a single byte from the DataSource
25
*/
26
40.3M
size_t DataSource::read_byte(uint8_t& out) {
27
40.3M
   return read(&out, 1);
28
40.3M
}
29
30
/*
31
* Peek a single byte from the DataSource
32
*/
33
53.0k
size_t DataSource::peek_byte(uint8_t& out) const {
34
53.0k
   return peek(&out, 1, 0);
35
53.0k
}
36
37
/*
38
* Discard the next N bytes of the data
39
*/
40
2.34M
size_t DataSource::discard_next(size_t n) {
41
2.34M
   uint8_t buf[64] = {0};
42
2.34M
   size_t discarded = 0;
43
44
6.59M
   while(n) {
45
4.24M
      const size_t got = this->read(buf, std::min(n, sizeof(buf)));
46
4.24M
      discarded += got;
47
4.24M
      n -= got;
48
49
4.24M
      if(got == 0) {
50
2.95k
         break;
51
2.95k
      }
52
4.24M
   }
53
54
2.34M
   return discarded;
55
2.34M
}
56
57
/*
58
* Read from a memory buffer
59
*/
60
22.2M
size_t DataSource_Memory::read(uint8_t out[], size_t length) {
61
22.2M
   const size_t got = std::min<size_t>(m_source.size() - m_offset, length);
62
22.2M
   copy_mem(out, m_source.data() + m_offset, got);
63
22.2M
   m_offset += got;
64
22.2M
   return got;
65
22.2M
}
66
67
784k
bool DataSource_Memory::check_available(size_t n) {
68
784k
   return (n <= (m_source.size() - m_offset));
69
784k
}
70
71
/*
72
* Peek into a memory buffer
73
*/
74
682k
size_t DataSource_Memory::peek(uint8_t out[], size_t length, size_t peek_offset) const {
75
682k
   const size_t bytes_left = m_source.size() - m_offset;
76
682k
   if(peek_offset >= bytes_left) {
77
297k
      return 0;
78
297k
   }
79
80
384k
   const size_t got = std::min(bytes_left - peek_offset, length);
81
384k
   copy_mem(out, &m_source[m_offset + peek_offset], got);
82
384k
   return got;
83
682k
}
84
85
/*
86
* Check if the memory buffer is empty
87
*/
88
2.49M
bool DataSource_Memory::end_of_data() const {
89
2.49M
   return (m_offset == m_source.size());
90
2.49M
}
91
92
/*
93
* DataSource_Memory Constructor
94
*/
95
DataSource_Memory::DataSource_Memory(std::string_view in) :
96
13.8k
      m_source(cast_char_ptr_to_uint8(in.data()), cast_char_ptr_to_uint8(in.data()) + in.length()), m_offset(0) {}
97
98
/*
99
* Read from a stream
100
*/
101
0
size_t DataSource_Stream::read(uint8_t out[], size_t length) {
102
0
   m_source.read(cast_uint8_ptr_to_char(out), length);
103
0
   if(m_source.bad()) {
104
0
      throw Stream_IO_Error("DataSource_Stream::read: Source failure");
105
0
   }
106
107
0
   const size_t got = static_cast<size_t>(m_source.gcount());
108
0
   m_total_read += got;
109
0
   return got;
110
0
}
111
112
0
bool DataSource_Stream::check_available(size_t n) {
113
0
   const std::streampos orig_pos = m_source.tellg();
114
0
   m_source.seekg(0, std::ios::end);
115
0
   const size_t avail = static_cast<size_t>(m_source.tellg() - orig_pos);
116
0
   m_source.seekg(orig_pos);
117
0
   return (avail >= n);
118
0
}
119
120
/*
121
* Peek into a stream
122
*/
123
0
size_t DataSource_Stream::peek(uint8_t out[], size_t length, size_t offset) const {
124
0
   if(end_of_data()) {
125
0
      throw Invalid_State("DataSource_Stream: Cannot peek when out of data");
126
0
   }
127
128
0
   size_t got = 0;
129
130
0
   if(offset) {
131
0
      secure_vector<uint8_t> buf(offset);
132
0
      m_source.read(cast_uint8_ptr_to_char(buf.data()), buf.size());
133
0
      if(m_source.bad()) {
134
0
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
135
0
      }
136
0
      got = static_cast<size_t>(m_source.gcount());
137
0
   }
138
139
0
   if(got == offset) {
140
0
      m_source.read(cast_uint8_ptr_to_char(out), length);
141
0
      if(m_source.bad()) {
142
0
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
143
0
      }
144
0
      got = static_cast<size_t>(m_source.gcount());
145
0
   }
146
147
0
   if(m_source.eof()) {
148
0
      m_source.clear();
149
0
   }
150
0
   m_source.seekg(m_total_read, std::ios::beg);
151
152
0
   return got;
153
0
}
154
155
/*
156
* Check if the stream is empty or in error
157
*/
158
0
bool DataSource_Stream::end_of_data() const {
159
0
   return (!m_source.good());
160
0
}
161
162
/*
163
* Return a human-readable ID for this stream
164
*/
165
0
std::string DataSource_Stream::id() const {
166
0
   return m_identifier;
167
0
}
168
169
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
170
171
/*
172
* DataSource_Stream Constructor
173
*/
174
DataSource_Stream::DataSource_Stream(std::string_view path, bool use_binary) :
175
0
      m_identifier(path),
176
0
      m_source_memory(std::make_unique<std::ifstream>(std::string(path), use_binary ? std::ios::binary : std::ios::in)),
177
0
      m_source(*m_source_memory),
178
0
      m_total_read(0) {
179
0
   if(!m_source.good()) {
180
0
      throw Stream_IO_Error(fmt("DataSource: Failure opening file '{}'", path));
181
0
   }
182
0
}
183
184
#endif
185
186
/*
187
* DataSource_Stream Constructor
188
*/
189
DataSource_Stream::DataSource_Stream(std::istream& in, std::string_view name) :
190
0
      m_identifier(name), m_source(in), m_total_read(0) {}
191
192
0
DataSource_Stream::~DataSource_Stream() = default;
193
194
}  // namespace Botan