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