1 /** 2 * DataSource 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 2012 Markus Wanner 8 * 9 * License: 10 * Botan is released under the Simplified BSD License (see LICENSE.md) 11 */ 12 module botan.filters.data_src; 13 14 import botan.constants; 15 import memutils.allocators; 16 import memutils.utils; 17 import memutils.vector; 18 import botan.utils.types; 19 import std.stdio; 20 import botan.utils.exceptn; 21 import botan.utils.mem_ops; 22 import std.algorithm; 23 24 alias DataSource = RefCounted!(DataSourceImpl, AppMem); 25 alias DataSourceMemory = RefCounted!(DataSourceMemoryImpl, AppMem); 26 alias DataSourceStream = RefCounted!(DataSourceStreamImpl, AppMem); 27 28 /** 29 * This class represents an abstract data source object. 30 */ 31 interface DataSourceImpl 32 { 33 public: 34 /** 35 * Read from the source. Moves the internal offset so that every 36 * call to read will return a new portion of the source. 37 * 38 * Params: 39 * output = the ubyte array to write the result to 40 * length = the length of the ubyte array out 41 * Returns: length in bytes that was actually read and put 42 * into out 43 */ 44 size_t read(ubyte* output, size_t length); 45 46 /** 47 * Read from the source but do not modify the internal 48 * offset. Consecutive calls to peek() will return portions of 49 * the source starting at the same position. 50 * 51 * Params: 52 * output = the ubyte array to write the output to 53 * length = the length of the ubyte array out 54 * peek_offset = the offset into the stream to read at 55 * Returns: length in bytes that was actually read and put 56 * into out 57 */ 58 size_t peek(ubyte* output, size_t length, size_t peek_offset) const; 59 60 /** 61 * Test whether the source still has data that can be read. 62 * Returns: true if there is still data to read, false otherwise 63 */ 64 bool endOfData() const; 65 /** 66 * return the id of this data source 67 * Returns: string representing the id of this data source 68 */ 69 string id() const; 70 71 /** 72 * Read one ubyte. 73 * 74 * Params: 75 * output = the ubyte to read to 76 * Returns: length in bytes that was actually read and put 77 * into out 78 */ 79 final size_t readByte(ref ubyte output) 80 { 81 return read(&output, 1); 82 } 83 84 85 /** 86 * Peek at one ubyte. 87 * 88 * Params: 89 * output = an output ubyte 90 * Returns: length in bytes that was actually read and put 91 * into out 92 */ 93 final size_t peekByte(ref ubyte output) const 94 { 95 return peek(&output, 1, 0); 96 } 97 98 99 /** 100 * Discard the next N bytes of the data 101 * Params: 102 * n = the number of bytes to discard 103 * Returns: number of bytes actually discarded 104 */ 105 final size_t discardNext(size_t n) 106 { 107 size_t discarded = 0; 108 ubyte dummy; 109 foreach (size_t j; 0 .. n) 110 discarded += readByte(dummy); 111 return discarded; 112 } 113 114 115 /** 116 * Returns: number of bytes read so far. 117 */ 118 size_t getBytesRead() const; 119 120 } 121 122 123 /** 124 * This class represents a Memory-Based DataSource 125 */ 126 class DataSourceMemoryImpl : DataSourceImpl 127 { 128 public: 129 override size_t read(ubyte* output, size_t length) 130 { 131 if (m_offset == m_source.length) return 0; 132 size_t got = std.algorithm.min(m_source.length - m_offset, length); 133 copyMem(output, &m_source[m_offset], got); 134 m_offset += got; 135 return got; 136 } 137 138 /* 139 * Peek into a memory buffer 140 */ 141 override size_t peek(ubyte* output, size_t length, size_t peek_offset) const 142 { 143 const size_t bytes_left = m_source.length - m_offset; 144 if (peek_offset >= bytes_left) return 0; 145 146 size_t got = std.algorithm.min(bytes_left - peek_offset, length); 147 copyMem(output, &m_source[m_offset + peek_offset], got); 148 return got; 149 } 150 151 /* 152 * Check if the memory buffer is empty 153 */ 154 override bool endOfData() const 155 { 156 return (m_offset == m_source.length); 157 } 158 159 160 /** 161 * Construct a memory source that reads from a string 162 * Params: 163 * input = the string to read from 164 */ 165 this(in string input) 166 { 167 m_source = SecureVector!ubyte((cast(const(ubyte)*)input.ptr)[0 .. input.length]); 168 m_offset = 0; 169 } 170 171 172 /** 173 * Construct a memory source that reads from a ubyte array 174 * Params: 175 * input = the ubyte array to read from 176 * length = the length of the ubyte array 177 */ 178 this(const(ubyte)* input, size_t length) 179 { 180 m_source = SecureVector!ubyte(input[0 .. length]); 181 m_offset = 0; 182 } 183 184 /** 185 * Construct a memory source that reads from a referenced vector 186 * Params: 187 * input = the MemoryRegion to read from 188 */ 189 this(T, ALLOC)(auto const ref RefCounted!(Vector!(T, ALLOC), ALLOC) input) 190 { 191 m_source = SecureVector!ubyte(input[]); 192 m_offset = 0; 193 } 194 195 /** 196 * Construct a memory source that reads from a vector 197 * Params: 198 * input = the MemoryRegion to read from 199 */ 200 this(T, ALLOC)(auto const ref Vector!(T, ALLOC) input) { 201 m_source = SecureVector!ubyte(input.ptr[0 .. input.length]); 202 m_offset = 0; 203 } 204 205 /** 206 * Construct a memory source that reads from a vector* 207 * Params: 208 * input = the MemoryRegion to read from 209 */ 210 this(T, ALLOC)(const Vector!(T, ALLOC)* input) { 211 m_source = SecureVector!ubyte(input.ptr[0 .. input.length]); 212 m_offset = 0; 213 } 214 215 override size_t getBytesRead() const { return m_offset; } 216 override string id() const { return ""; } 217 private: 218 SecureVector!ubyte m_source; 219 size_t m_offset; 220 } 221 222 /** 223 * This class represents a Stream-Based DataSource. 224 */ 225 class DataSourceStreamImpl : DataSourceImpl 226 { 227 public: 228 /* 229 * Read from a stream 230 */ 231 override size_t read(ubyte* output, size_t length) 232 { 233 //logTrace("Read for ", cast(void*)this, " len: ", length, " offset ", m_total_read); 234 ubyte[] data; 235 try data = m_source.rawRead(output[0..length]); 236 catch (Exception e) 237 throw new StreamIOError("read: Source failure..." ~ e.toString()); 238 239 size_t got = data.length; 240 m_total_read += got; 241 //logTrace("Read total: ", m_total_read, " end of stream? ", endOfData().to!string); 242 return got; 243 } 244 245 /* 246 * Peek into a stream 247 */ 248 override size_t peek(ubyte* output, size_t length, size_t offset) const 249 { 250 //logTrace("Peek for ", cast(void*)this, " len: ", length, " offset ", offset, " total read ", m_total_read); 251 File file; 252 if (endOfData()) { 253 file = File(m_identifier, "rb"); 254 } 255 // throw new InvalidState("DataSourceStream: Cannot peek when out of data " ~ m_source.name); 256 else file = cast(File)m_source; 257 size_t got = 0; 258 259 file.seek(offset, SEEK_SET); 260 ubyte[] data; 261 ubyte[] output_buf = output[0 .. length]; 262 try data = file.rawRead(output_buf); 263 catch (Exception e) 264 throw new StreamIOError("peek: Source failure..." ~ e.toString()); 265 266 got = data.length; 267 //logTrace("Read total: ", got, " data: ", data); 268 if (!file.isOpen) { 269 file = File(m_identifier, "r"); 270 } 271 else 272 if (file.eof || file.error()) { 273 file.clearerr(); 274 file.rewind(); 275 } 276 277 file.seek(m_total_read, SEEK_SET); 278 return got; 279 } 280 281 /* 282 * Check if the stream is empty or in error 283 */ 284 override bool endOfData() const 285 { 286 return !m_source.isOpen || m_source.eof || m_source.error(); 287 } 288 289 /* 290 * Return a human-readable ID for this stream 291 */ 292 override string id() const 293 { 294 return m_identifier; 295 } 296 297 /* 298 * DataSourceStream Constructor 299 */ 300 this(ref File input, in string name) 301 { 302 m_identifier = name; 303 m_source = input; 304 m_total_read = 0; 305 } 306 307 /** 308 * Construct a Stream-Based DataSource from file 309 * Params: 310 * path = the name of the file 311 * use_binary = whether to treat the file as binary or not 312 */ 313 this(in string path, bool use_binary = false) 314 { 315 316 m_identifier = path; 317 m_source = File(path, use_binary ? "rb" : "r"); 318 m_source.open(path); 319 m_total_read = 0; 320 if (m_source.error()) 321 { 322 throw new StreamIOError("DataSource: Failure opening file " ~ path); 323 } 324 } 325 326 /* 327 * DataSourceStream Destructor 328 */ 329 ~this() 330 { 331 332 } 333 334 override size_t getBytesRead() const { return m_total_read; } 335 private: 336 const string m_identifier; 337 338 File m_source; 339 size_t m_total_read; 340 }