/* * DataSource * (C) 1999-2007 Jack Lloyd * 2005 Matthew Gregan * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) #include #endif namespace Botan { /* * Read a single byte from the DataSource */ size_t DataSource::read_byte(uint8_t& out) { return read(&out, 1); } /* * Peek a single byte from the DataSource */ size_t DataSource::peek_byte(uint8_t& out) const { return peek(&out, 1, 0); } /* * Discard the next N bytes of the data */ size_t DataSource::discard_next(size_t n) { uint8_t buf[64] = { 0 }; size_t discarded = 0; while(n) { const size_t got = this->read(buf, std::min(n, sizeof(buf))); discarded += got; n -= got; if(got == 0) break; } return discarded; } /* * Read from a memory buffer */ size_t DataSource_Memory::read(uint8_t out[], size_t length) { const size_t got = std::min(m_source.size() - m_offset, length); copy_mem(out, m_source.data() + m_offset, got); m_offset += got; return got; } bool DataSource_Memory::check_available(size_t n) { return (n <= (m_source.size() - m_offset)); } /* * Peek into a memory buffer */ size_t DataSource_Memory::peek(uint8_t out[], size_t length, size_t peek_offset) const { const size_t bytes_left = m_source.size() - m_offset; if(peek_offset >= bytes_left) return 0; const size_t got = std::min(bytes_left - peek_offset, length); copy_mem(out, &m_source[m_offset + peek_offset], got); return got; } /* * Check if the memory buffer is empty */ bool DataSource_Memory::end_of_data() const { return (m_offset == m_source.size()); } /* * DataSource_Memory Constructor */ DataSource_Memory::DataSource_Memory(const std::string& in) : m_source(cast_char_ptr_to_uint8(in.data()), cast_char_ptr_to_uint8(in.data()) + in.length()), m_offset(0) { } /* * Read from a stream */ size_t DataSource_Stream::read(uint8_t out[], size_t length) { m_source.read(cast_uint8_ptr_to_char(out), length); if(m_source.bad()) throw Stream_IO_Error("DataSource_Stream::read: Source failure"); const size_t got = static_cast(m_source.gcount()); m_total_read += got; return got; } bool DataSource_Stream::check_available(size_t n) { const std::streampos orig_pos = m_source.tellg(); m_source.seekg(0, std::ios::end); const size_t avail = static_cast(m_source.tellg() - orig_pos); m_source.seekg(orig_pos); return (avail >= n); } /* * Peek into a stream */ size_t DataSource_Stream::peek(uint8_t out[], size_t length, size_t offset) const { if(end_of_data()) throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); size_t got = 0; if(offset) { secure_vector buf(offset); m_source.read(cast_uint8_ptr_to_char(buf.data()), buf.size()); if(m_source.bad()) throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); got = static_cast(m_source.gcount()); } if(got == offset) { m_source.read(cast_uint8_ptr_to_char(out), length); if(m_source.bad()) throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); got = static_cast(m_source.gcount()); } if(m_source.eof()) m_source.clear(); m_source.seekg(m_total_read, std::ios::beg); return got; } /* * Check if the stream is empty or in error */ bool DataSource_Stream::end_of_data() const { return (!m_source.good()); } /* * Return a human-readable ID for this stream */ std::string DataSource_Stream::id() const { return m_identifier; } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) /* * DataSource_Stream Constructor */ DataSource_Stream::DataSource_Stream(const std::string& path, bool use_binary) : m_identifier(path), m_source_memory(new std::ifstream(path, use_binary ? std::ios::binary : std::ios::in)), m_source(*m_source_memory), m_total_read(0) { if(!m_source.good()) { throw Stream_IO_Error("DataSource: Failure opening file " + path); } } #endif /* * DataSource_Stream Constructor */ DataSource_Stream::DataSource_Stream(std::istream& in, const std::string& name) : m_identifier(name), m_source(in), m_total_read(0) { } DataSource_Stream::~DataSource_Stream() { // for ~unique_ptr } }