aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-08-05 12:37:43 +0200
committerSven Gothel <[email protected]>2022-08-05 12:37:43 +0200
commitc82d4c266a80a8b41a184cdadd8ecae37bd635fd (patch)
tree6536f994720cae2d3f058d3d12bf26e597b14921
parentc1be87eb850123ac84f255eedbc28449727a98a7 (diff)
io_util/byte_stream: Decouple from Botan, add iostate and new Byte*Stream* super iostate_func class for std::basic_ios's iostate functionality
The burden of having a compile time header dependency to ByteInStream is too high and may cause 'confusion' if linking unit w/ different settings - to say the very least! In case Botan::DataSource is required, user shall wrap ByteInStream into such desired types. +++ Don't include any iostream header. std::basic_ios's iostate functionality allows us to reuse the std spec for our streaming classes, enforcing a well specified iostate to be defined either by just setting the iostate at read() for non-async sources like file or by dynamical evaluation via rdstate() override for async sources. Use shorter method names, eg check_available() -> available() and iostream affine names, eg bytes_read() -> tellg(). Use 'void*' buffer types for read() and peak(), similar to POSIX, removing the burden for a nonsense cast. Drop ByteInStream_istream.
-rw-r--r--include/jau/byte_stream.hpp516
-rw-r--r--include/jau/io_util.hpp7
-rw-r--r--src/byte_stream.cpp280
-rw-r--r--src/io_util.cpp8
4 files changed, 349 insertions, 462 deletions
diff --git a/include/jau/byte_stream.hpp b/include/jau/byte_stream.hpp
index 220af27..e67d81c 100644
--- a/include/jau/byte_stream.hpp
+++ b/include/jau/byte_stream.hpp
@@ -2,10 +2,6 @@
* Author: Sven Gothel <[email protected]>
* Copyright (c) 2021 Gothel Software e.K.
*
- * ByteInStream, ByteInStream_SecMemory and ByteInStream_istream are derived from Botan under same license:
- * - Copyright (c) 1999-2007 Jack Lloyd
- * - Copyright (c) 2005 Matthew Gregan
- *
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
@@ -38,9 +34,6 @@
#include <jau/ringbuffer.hpp>
#include <jau/file_util.hpp>
-// Include Botan header files before this one to be integrated w/ Botan!
-// #include <botan_all.h>
-
#include <jau/io_util.hpp>
using namespace jau::fractions_i64_literals;
@@ -52,49 +45,153 @@ namespace jau::io {
* @{
*/
-#ifdef BOTAN_VERSION_MAJOR
- #define VIRTUAL_BOTAN
- #define OVERRIDE_BOTAN override
- #define NOEXCEPT_BOTAN
-#else
- #define VIRTUAL_BOTAN virtual
- #define OVERRIDE_BOTAN
- #define NOEXCEPT_BOTAN noexcept
-#endif
+ /**
+ * Mimic std::ios_base::iostate for state functionality, see iostate_func.
+ *
+ * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
+ */
+ enum class iostate : uint32_t {
+ /** No error occurred nor has EOS being reached. Value is no bit set! */
+ none = 0,
+
+ /** No error occurred nor has EOS being reached. Value is no bit set! */
+ goodbit = 0,
+
+ /** Irrecoverable stream error, including loss of integrity of the underlying stream or media. */
+ badbit = 1 << 0,
+
+ /** An input operation reached the end of its stream. */
+ eofbit = 1 << 1,
+
+ /** Input or output operation failed (formatting or extraction error). */
+ failbit = 1 << 2
+ };
+ constexpr uint32_t number(const iostate rhs) noexcept {
+ return static_cast<uint32_t>(rhs);
+ }
+ constexpr iostate operator ~(const iostate rhs) noexcept {
+ return static_cast<iostate> ( ~number(rhs) );
+ }
+ constexpr iostate operator ^(const iostate lhs, const iostate rhs) noexcept {
+ return static_cast<iostate> ( number(lhs) ^ number(rhs) );
+ }
+ constexpr iostate operator |(const iostate lhs, const iostate rhs) noexcept {
+ return static_cast<iostate> ( number(lhs) | number(rhs) );
+ }
+ constexpr iostate operator &(const iostate lhs, const iostate rhs) noexcept {
+ return static_cast<iostate> ( number(lhs) & number(rhs) );
+ }
+ constexpr iostate& operator |=(iostate& lhs, const iostate rhs) noexcept {
+ lhs = static_cast<iostate> ( number(lhs) | number(rhs) );
+ return lhs;
+ }
+ constexpr iostate& operator &=(iostate& lhs, const iostate rhs) noexcept {
+ lhs = static_cast<iostate> ( number(lhs) & number(rhs) );
+ return lhs;
+ }
+ constexpr iostate& operator ^=(iostate& lhs, const iostate rhs) noexcept {
+ lhs = static_cast<iostate> ( number(lhs) ^ number(rhs) );
+ return lhs;
+ }
+ constexpr bool operator ==(const iostate lhs, const iostate rhs) noexcept {
+ return number(lhs) == number(rhs);
+ }
+ constexpr bool operator !=(const iostate lhs, const iostate rhs) noexcept {
+ return !( lhs == rhs );
+ }
+ std::string to_string(const iostate mask) noexcept;
/**
- * This class represents an abstract byte input stream object.
+ * Supporting std::basic_ios's iostate functionality for all ByteInStream implementations.
+ */
+ class iostate_func {
+ private:
+ iostate m_state;
+
+ protected:
+ constexpr iostate rdstate_impl() const noexcept { return m_state; }
+ constexpr void setstate_impl(iostate state) const noexcept { const_cast<iostate_func*>(this)->m_state |= state; }
+
+ public:
+ iostate_func() noexcept
+ : m_state( iostate::goodbit ) {}
+
+ iostate_func(const iostate_func& o) noexcept = default;
+ iostate_func(iostate_func&& o) noexcept = default;
+ iostate_func& operator=(const iostate_func &o) noexcept = default;
+ iostate_func& operator=(iostate_func &&o) noexcept = default;
+
+ virtual ~iostate_func() noexcept {}
+
+ /** Clears state flags by assignment to the given value. */
+ virtual void clear(const iostate state = iostate::goodbit) noexcept { m_state = state; }
+
+ /**
+ * Returns the current state flags.
+ *
+ * Method is marked `virtual` to allow implementations with asynchronous resources
+ * to determine or update the current iostate.
+ *
+ * Method is used throughout all query members and setstate(),
+ * hence they all will use the updated state from a potential override implementation.
+ */
+ virtual iostate rdstate() const noexcept { return m_state; }
+
+ /** Sets state flags, by keeping its previous bits. */
+ void setstate(const iostate state) noexcept { clear( rdstate() | state ); }
+
+ /** Checks if no error nor eof() has occurred i.e. I/O operations are available. */
+ bool good() const noexcept
+ { return iostate::goodbit == rdstate(); }
+
+ /** Checks if end-of-file has been reached. */
+ bool eof() const noexcept
+ { return iostate::none != ( rdstate() & iostate::eofbit ); }
+
+ /** Checks if an error has occurred. */
+ bool fail() const noexcept
+ { return iostate::none != ( rdstate() & ( iostate::badbit | iostate::failbit ) ); }
+
+ /** Checks if an error has occurred, synonym of fail(). */
+ bool operator!() const noexcept { return fail(); }
+
+ /** Checks if no error has occurred, synonym of !fail(). */
+ explicit operator bool() const noexcept { return !fail(); }
+
+ /** Checks if a non-recoverable error has occurred. */
+ bool bad() const noexcept
+ { return iostate::none != ( rdstate() & iostate::badbit ); }
+ };
+
+ /**
+ * Abstract byte input stream object.
*
* @anchor byte_in_stream_properties
* ### ByteInStream Properties
* The byte input stream can originate from a local source w/o delay,
* remote URL like http connection or even from another thread feeding the input buffer.<br />
* Both latter asynchronous resources may expose blocking properties
- * in check_available().
+ * in available().
*
* Asynchronous resources benefit from knowing their content size,
- * as their check_available() implementation may avoid
+ * as their available() implementation may avoid
* blocking and waiting for requested bytes available
* if the stream is already beyond its scope.
*
- * All method implementations are of `noexcept`
- * and declared as such if used standalone w/o Botan.<br/>
- * However, if using Botan, the `noexcept` qualifier is dropped
- * for compatibility with Botan::DataSource virtual function table.
+ * All method implementations are of `noexcept`.
*
- * One may use error() to detect whether an error has occurred,
- * while end_of_data() not only covered the EOS case but includes error().
+ * One may use fail() to detect whether an error has occurred,
+ * while end_of_data() not only covers the end-of-stream (EOS) case but includes fail().
*
* @see @ref byte_in_stream_properties "ByteInStream Properties"
*/
- class ByteInStream
-#ifdef BOTAN_VERSION_MAJOR
- : public Botan::DataSource
-#endif
+ class ByteInStream : public iostate_func
{
public:
- ByteInStream() = default;
- virtual ~ByteInStream() NOEXCEPT_BOTAN = default;
+ ByteInStream() noexcept
+ : iostate_func() {}
+
+ virtual ~ByteInStream() noexcept = default;
ByteInStream& operator=(const ByteInStream&) = delete;
ByteInStream(const ByteInStream&) = delete;
@@ -104,38 +201,56 @@ namespace jau::io {
virtual void close() noexcept = 0;
/**
- * Check whether n bytes are available in the input stream.
+ * Return whether n bytes are available in the input stream,
+ * if has_content_size() or using an asynchronous source.
*
- * This method may be blocking when using an asynchronous source
- * up until the requested bytes are actually available.
+ * If !has_content_size() and not being an asynchronous source,
+ * !end_of_data() is returned.
+ *
+ * Method may be blocking when using an asynchronous source
+ * up until the requested bytes are available.
*
* A subsequent call to read() shall return immediately with at least
- * the requested numbers of bytes available.
+ * the requested numbers of bytes available,
+ * if has_content_size() or using an asynchronous source.
+ *
+ * See details of the implementing class.
*
* @param n byte count to wait for
* @return true if n bytes are available, otherwise false
*
+ * @see has_content_size()
* @see read()
* @see @ref byte_in_stream_properties "ByteInStream Properties"
*/
- VIRTUAL_BOTAN bool check_available(size_t n) NOEXCEPT_BOTAN OVERRIDE_BOTAN = 0;
+ virtual bool available(size_t n) noexcept = 0;
/**
* Read from the source. Moves the internal offset so that every
* call to read will return a new portion of the source.
*
- * Use check_available() to wait and ensure a certain amount of bytes are available.
+ * Use available() to try to wait for a certain amount of bytes available.
+ *
+ * This method shall only block until `min(available, length)` bytes are transfered.
*
- * This method is not blocking.
+ * See details of the implementing class.
*
* @param out the byte array to write the result to
* @param length the length of the byte array out
* @return length in bytes that was actually read and put into out
*
- * @see check_available()
+ * @see available()
* @see @ref byte_in_stream_properties "ByteInStream Properties"
*/
- [[nodiscard]] VIRTUAL_BOTAN size_t read(uint8_t out[], size_t length) NOEXCEPT_BOTAN OVERRIDE_BOTAN = 0;
+ [[nodiscard]] virtual size_t read(void* out, size_t length) noexcept = 0;
+
+ /**
+ * Read one byte.
+ * @param out the byte to read to
+ * @return length in bytes that was actually read and put
+ * into out
+ */
+ size_t read(uint8_t& out) noexcept;
/**
* Read from the source but do not modify the internal
@@ -147,40 +262,7 @@ namespace jau::io {
* @param peek_offset the offset into the stream to read at
* @return length in bytes that was actually read and put into out
*/
- [[nodiscard]] VIRTUAL_BOTAN size_t peek(uint8_t out[], size_t length, size_t peek_offset) const NOEXCEPT_BOTAN OVERRIDE_BOTAN = 0;
-
- /**
- * Test whether the source still has data that can be read.
- *
- * This may include a failure and/or error in the underlying implementation, see error()
- *
- * @return true if there is no more data to read, false otherwise
- * @see error()
- */
- VIRTUAL_BOTAN bool end_of_data() const NOEXCEPT_BOTAN OVERRIDE_BOTAN = 0;
-
- /**
- * Return whether an error has occurred, excluding end_of_data().
- *
- * @return true if an error has occurred, false otherwise
- */
- virtual bool error() const noexcept = 0;
-
-#ifndef BOTAN_VERSION_MAJOR
-
- /**
- * return the id of this data source
- * @return std::string representing the id of this data source
- */
- virtual std::string id() const noexcept { return ""; }
-
- /**
- * Read one byte.
- * @param out the byte to read to
- * @return length in bytes that was actually read and put
- * into out
- */
- size_t read_byte(uint8_t& out) noexcept;
+ [[nodiscard]] virtual size_t peek(void* out, size_t length, size_t peek_offset) noexcept = 0;
/**
* Peek at one byte.
@@ -188,27 +270,38 @@ namespace jau::io {
* @return length in bytes that was actually read and put
* into out
*/
- size_t peek_byte(uint8_t& out) const noexcept;
+ size_t peek(uint8_t& out) noexcept;
/**
* Discard the next N bytes of the data
* @param N the number of bytes to discard
* @return number of bytes actually discarded
*/
- size_t discard_next(size_t N) noexcept;
+ size_t discard(size_t N) noexcept;
-#endif /* BOTAN_VERSION_MAJOR */
+ /**
+ * Test whether the source still has data that can be read, synonym for !good().
+ *
+ * Hence this includes errors in the underlying implementation, see fail()
+ *
+ * @return true if there is no more data to read, false otherwise
+ * @see good()
+ * @see fail()
+ */
+ bool end_of_data() const noexcept { return !good(); }
/**
- * @return number of bytes read so far.
+ * return the id of this data source
+ * @return std::string representing the id of this data source
*/
- VIRTUAL_BOTAN size_t get_bytes_read() const NOEXCEPT_BOTAN OVERRIDE_BOTAN = 0;
+ virtual std::string id() const noexcept { return ""; }
/**
- * Variant of Botan's get_byte_read() using uint64_t for big files on a 32-bit platform.
+ * Returns the input position indicator, similar to std::basic_istream.
+ *
* @return number of bytes read so far.
*/
- virtual uint64_t bytes_read() const noexcept = 0;
+ virtual uint64_t tellg() const noexcept = 0;
/**
* Returns true if implementation is aware of content_size(), otherwise false.
@@ -226,19 +319,15 @@ namespace jau::io {
};
/**
- * This class represents a secure Memory-Based byte input stream
+ * Secure Memory-Based byte input stream
*/
class ByteInStream_SecMemory final : public ByteInStream {
public:
- size_t read(uint8_t[], size_t) NOEXCEPT_BOTAN override;
-
- size_t peek(uint8_t[], size_t, size_t) const NOEXCEPT_BOTAN override;
+ size_t read(void*, size_t) noexcept override;
- bool check_available(size_t n) NOEXCEPT_BOTAN override;
+ size_t peek(void*, size_t, size_t) noexcept override;
- bool end_of_data() const NOEXCEPT_BOTAN override;
-
- bool error() const noexcept override { return false; }
+ bool available(size_t n) noexcept override;
/**
* Construct a secure memory source that reads from a string
@@ -270,11 +359,9 @@ namespace jau::io {
void close() noexcept override;
- ~ByteInStream_SecMemory() NOEXCEPT_BOTAN override { close(); }
-
- size_t get_bytes_read() const NOEXCEPT_BOTAN override { return m_offset; }
+ ~ByteInStream_SecMemory() noexcept override { close(); }
- uint64_t bytes_read() const noexcept override { return m_offset; }
+ uint64_t tellg() const noexcept override { return m_offset; }
bool has_content_size() const noexcept override { return true; }
@@ -288,146 +375,42 @@ namespace jau::io {
};
/**
- * This class represents a std::istream based byte input stream.
- */
- class ByteInStream_istream final : public ByteInStream {
- public:
- size_t read(uint8_t[], size_t) NOEXCEPT_BOTAN override;
- size_t peek(uint8_t[], size_t, size_t) const NOEXCEPT_BOTAN override;
- bool check_available(size_t n) NOEXCEPT_BOTAN override;
- bool end_of_data() const NOEXCEPT_BOTAN override;
- bool error() const noexcept override { return m_source.bad(); }
- std::string id() const NOEXCEPT_BOTAN override;
-
- ByteInStream_istream(std::istream&, const std::string& id = "<std::istream>") noexcept;
-
- ByteInStream_istream(const ByteInStream_istream&) = delete;
-
- ByteInStream_istream& operator=(const ByteInStream_istream&) = delete;
-
- void close() noexcept override;
-
- ~ByteInStream_istream() NOEXCEPT_BOTAN override { close(); }
-
- size_t get_bytes_read() const NOEXCEPT_BOTAN override { return m_bytes_consumed; }
-
- uint64_t bytes_read() const noexcept override { return m_bytes_consumed; }
-
- bool has_content_size() const noexcept override { return false; }
-
- uint64_t content_size() const noexcept override { return 0; }
-
- std::string to_string() const noexcept override;
-
- private:
- const std::string m_identifier;
-
- std::istream& m_source;
- size_t m_bytes_consumed;
- };
-
-
- /**
- * Mimic std::iobase::iostate
+ * File based byte input stream, including named file descriptor.
*
- * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
- */
- enum class iostate : uint32_t {
- /** No error occurred nor has EOS being reached. Value is no bit set! */
- none = 0,
-
- /** No error occurred nor has EOS being reached. Value is no bit set! */
- goodbit = 0,
-
- /** Irrecoverable stream error, including loss of integrity of the underlying stream or media. */
- badbit = 1 << 0,
-
- /** An input operation reached the end of its stream. */
- eofbit = 1 << 1,
-
- /** Input or output operation failed (formatting or extraction error). */
- failbit = 1 << 2
- };
- constexpr uint32_t number(const iostate rhs) noexcept {
- return static_cast<uint32_t>(rhs);
- }
- constexpr iostate operator ~(const iostate rhs) noexcept {
- return static_cast<iostate> ( ~number(rhs) );
- }
- constexpr iostate operator ^(const iostate lhs, const iostate rhs) noexcept {
- return static_cast<iostate> ( number(lhs) ^ number(rhs) );
- }
- constexpr iostate operator |(const iostate lhs, const iostate rhs) noexcept {
- return static_cast<iostate> ( number(lhs) | number(rhs) );
- }
- constexpr iostate operator &(const iostate lhs, const iostate rhs) noexcept {
- return static_cast<iostate> ( number(lhs) & number(rhs) );
- }
- constexpr iostate& operator |=(iostate& lhs, const iostate rhs) noexcept {
- lhs = static_cast<iostate> ( number(lhs) | number(rhs) );
- return lhs;
- }
- constexpr iostate& operator &=(iostate& lhs, const iostate rhs) noexcept {
- lhs = static_cast<iostate> ( number(lhs) & number(rhs) );
- return lhs;
- }
- constexpr iostate& operator ^=(iostate& lhs, const iostate rhs) noexcept {
- lhs = static_cast<iostate> ( number(lhs) ^ number(rhs) );
- return lhs;
- }
- constexpr bool operator ==(const iostate lhs, const iostate rhs) noexcept {
- return number(lhs) == number(rhs);
- }
- constexpr bool operator !=(const iostate lhs, const iostate rhs) noexcept {
- return !( lhs == rhs );
- }
- std::string to_string(const iostate mask) noexcept;
-
- /**
- * This class represents a file based byte input stream, including named file descriptor.
+ * Implementation mimics std::ifstream via OS level file descriptor (FD) operations,
+ * giving more flexibility, allowing reusing existing FD and enabling openat() operations.
*
* If source path denotes a named file descriptor, i.e. jau::fs::file_stats::is_fd() returns true,
- * has_content_size() returns false and check_available() returns true as long the stream is open and EOS hasn't occurred.
+ * has_content_size() returns false and available() returns true as long the stream is open and EOS hasn't occurred.
*/
class ByteInStream_File final : public ByteInStream {
private:
jau::fs::file_stats stats;
- /**
- * We mimic std::ifstream via OS level file descriptor operations,
- * giving us more flexibility and enabling use of openat() operations.
- */
+
int m_fd;
- mutable iostate m_state;
+ bool m_has_content_length;
+ uint64_t m_content_size;
+ uint64_t m_bytes_consumed;
+ uint64_t get_available() const noexcept { return m_has_content_length ? m_content_size - m_bytes_consumed : 0; }
- // Remember: constexpr specifier used in a function or static data member (since C++17) declaration implies inline
+ public:
+ size_t read(void*, size_t) noexcept override;
+ size_t peek(void*, size_t, size_t) noexcept override;
+ bool available(size_t n) noexcept override;
+ /** Checks if the stream has an associated file. */
constexpr bool is_open() const noexcept
{ return 0 <= m_fd; }
- constexpr bool good() const noexcept
- { return iostate::goodbit == m_state; }
+ std::string id() const noexcept override { return stats.path(); }
- constexpr bool eof() const noexcept
- { return iostate::none != ( m_state & iostate::eofbit ); }
-
- constexpr bool fail() const noexcept
- { return iostate::none != ( m_state & ( iostate::badbit | iostate::failbit ) ); }
-
- constexpr bool bad() const noexcept
- { return iostate::none != ( m_state & iostate::badbit ); }
-
- constexpr iostate rdstate() const noexcept { return m_state; }
- void clear(iostate state = iostate::goodbit) const noexcept { m_state = state; }
- void setstate(iostate state) const noexcept { m_state |= state; }
-
- public:
- size_t read(uint8_t[], size_t) NOEXCEPT_BOTAN override;
- size_t peek(uint8_t[], size_t, size_t) const NOEXCEPT_BOTAN override;
- bool check_available(size_t n) NOEXCEPT_BOTAN override;
- bool end_of_data() const NOEXCEPT_BOTAN override;
- bool error() const noexcept override { return fail(); }
- std::string id() const NOEXCEPT_BOTAN override { return stats.path(); }
+ /**
+ * Returns the file descriptor if is_open(), otherwise -1 for no file descriptor.
+ *
+ * @see is_open()
+ */
+ int fd() const noexcept { return m_fd; }
/**
* Construct a stream based byte input stream from filesystem path
@@ -466,23 +449,15 @@ namespace jau::io {
void close() noexcept override;
- ~ByteInStream_File() NOEXCEPT_BOTAN override { close(); }
-
- size_t get_bytes_read() const NOEXCEPT_BOTAN override { return (size_t)m_bytes_consumed; }
+ virtual ~ByteInStream_File() noexcept override { close(); }
- uint64_t bytes_read() const noexcept override { return m_bytes_consumed; }
+ uint64_t tellg() const noexcept override { return m_bytes_consumed; }
bool has_content_size() const noexcept override { return m_has_content_length; }
uint64_t content_size() const noexcept override { return m_content_size; }
std::string to_string() const noexcept override;
-
- private:
- uint64_t get_available() const noexcept { return m_has_content_length ? m_content_size - m_bytes_consumed : 0; }
- bool m_has_content_length;
- uint64_t m_content_size;
- uint64_t m_bytes_consumed;
};
/**
@@ -507,37 +482,35 @@ namespace jau::io {
* @see read()
* @see @ref byte_in_stream_properties "ByteInStream Properties"
*/
- bool check_available(size_t n) NOEXCEPT_BOTAN override;
+ bool available(size_t n) noexcept override;
/**
* Read from the source. Moves the internal offset so that every
* call to read will return a new portion of the source.
*
- * Use check_available() to wait and ensure a certain amount of bytes are available.
+ * Use available() to wait and ensure a certain amount of bytes are available.
*
- * This method is not blocking.
+ * This method is not blocking beyond the transfer of `min(available, length)` bytes.
*
* @param out the byte array to write the result to
* @param length the length of the byte array out
* @return length in bytes that was actually read and put into out
*
- * @see check_available()
+ * @see available()
* @see @ref byte_in_stream_properties "ByteInStream Properties"
*/
- size_t read(uint8_t out[], size_t length) NOEXCEPT_BOTAN override;
-
- size_t peek(uint8_t out[], size_t length, size_t peek_offset) const NOEXCEPT_BOTAN override;
+ size_t read(void* out, size_t length) noexcept override;
- bool end_of_data() const NOEXCEPT_BOTAN override;
+ size_t peek(void* out, size_t length, size_t peek_offset) noexcept override;
- bool error() const noexcept override { return async_io_result_t::FAILED == m_result; }
+ iostate rdstate() const noexcept override;
- std::string id() const NOEXCEPT_BOTAN override { return m_url; }
+ std::string id() const noexcept override { return m_url; }
/**
* Construct a ringbuffer backed Http byte input stream
* @param url the URL of the data to read
- * @param timeout maximum duration in fractions of seconds to wait @ check_available() for next bytes, where fractions_i64::zero waits infinitely
+ * @param timeout maximum duration in fractions of seconds to wait @ available() for next bytes, where fractions_i64::zero waits infinitely
*/
ByteInStream_URL(const std::string& url, const jau::fraction_i64& timeout) noexcept;
@@ -547,11 +520,9 @@ namespace jau::io {
void close() noexcept override;
- ~ByteInStream_URL() NOEXCEPT_BOTAN override { close(); }
+ ~ByteInStream_URL() noexcept override { close(); }
- size_t get_bytes_read() const NOEXCEPT_BOTAN override { return (size_t)m_bytes_consumed; }
-
- uint64_t bytes_read() const noexcept override { return m_bytes_consumed; }
+ uint64_t tellg() const noexcept override { return m_bytes_consumed; }
bool has_content_size() const noexcept override { return m_has_content_length; }
@@ -580,11 +551,11 @@ namespace jau::io {
*
* If the above fails, ByteInStream_File is attempted.
*
- * If non of the above leads to a ByteInStream without ByteInStream::error(), nullptr is returned.
+ * If non of the above leads to a ByteInStream without ByteInStream::fail(), nullptr is returned.
*
* @param path_or_uri given path or uri for with a ByteInStream instance shall be established.
- * @param timeout in case `path_or_uri` resolves to ByteInStream_URL, timeout is being used as maximum duration to wait for next bytes at ByteInStream_URL::check_available(), defaults to 20_s
- * @return a working ByteInStream w/o ByteInStream::error() or nullptr
+ * @param timeout in case `path_or_uri` resolves to ByteInStream_URL, timeout is being used as maximum duration to wait for next bytes at ByteInStream_URL::available(), defaults to 20_s
+ * @return a working ByteInStream w/o ByteInStream::fail() or nullptr
*/
std::unique_ptr<ByteInStream> to_ByteInStream(const std::string& path_or_uri, jau::fraction_i64 timeout=20_s) noexcept;
@@ -606,37 +577,35 @@ namespace jau::io {
* @see read()
* @see @ref byte_in_stream_properties "ByteInStream Properties"
*/
- bool check_available(size_t n) NOEXCEPT_BOTAN override;
+ bool available(size_t n) noexcept override;
/**
* Read from the source. Moves the internal offset so that every
* call to read will return a new portion of the source.
*
- * Use check_available() to wait and ensure a certain amount of bytes are available.
+ * Use available() to wait and ensure a certain amount of bytes are available.
*
- * This method is not blocking.
+ * This method is not blocking beyond the transfer of `min(available, length)` bytes.
*
* @param out the byte array to write the result to
* @param length the length of the byte array out
* @return length in bytes that was actually read and put into out
*
- * @see check_available()
+ * @see available()
* @see @ref byte_in_stream_properties "ByteInStream Properties"
*/
- size_t read(uint8_t out[], size_t length) NOEXCEPT_BOTAN override;
-
- size_t peek(uint8_t out[], size_t length, size_t peek_offset) const NOEXCEPT_BOTAN override;
+ size_t read(void* out, size_t length) noexcept override;
- bool end_of_data() const NOEXCEPT_BOTAN override;
+ size_t peek(void* out, size_t length, size_t peek_offset) noexcept override;
- bool error() const noexcept override { return async_io_result_t::FAILED == m_result; }
+ iostate rdstate() const noexcept override;
- std::string id() const NOEXCEPT_BOTAN override { return m_id; }
+ std::string id() const noexcept override { return m_id; }
/**
* Construct a ringbuffer backed externally provisioned byte input stream
* @param id_name arbitrary identifier for this instance
- * @param timeout maximum duration in fractions of seconds to wait @ check_available() and write(), where fractions_i64::zero waits infinitely
+ * @param timeout maximum duration in fractions of seconds to wait @ available() and write(), where fractions_i64::zero waits infinitely
*/
ByteInStream_Feed(const std::string& id_name, const jau::fraction_i64& timeout) noexcept;
@@ -646,11 +615,9 @@ namespace jau::io {
void close() noexcept override;
- ~ByteInStream_Feed() NOEXCEPT_BOTAN override { close(); }
+ ~ByteInStream_Feed() noexcept override { close(); }
- size_t get_bytes_read() const NOEXCEPT_BOTAN override { return m_bytes_consumed; }
-
- uint64_t bytes_read() const noexcept override { return m_bytes_consumed; }
+ uint64_t tellg() const noexcept override { return m_bytes_consumed; }
bool has_content_size() const noexcept override { return m_has_content_length; }
@@ -659,7 +626,7 @@ namespace jau::io {
/**
* Interrupt a potentially blocked reader.
*
- * Call this method if intended to abort streaming and to interrupt the reader thread's potentially blocked check_available() call,
+ * Call this method if intended to abort streaming and to interrupt the reader thread's potentially blocked available() call,
* i.e. done at set_eof()
*
* @see set_eof()
@@ -699,7 +666,7 @@ namespace jau::io {
*
* @see interruptReader()
*/
- void set_eof(const async_io_result_t result) noexcept { m_result = result; interruptReader(); }
+ void set_eof(const async_io_result_t result) noexcept;
std::string to_string() const noexcept override;
@@ -719,27 +686,26 @@ namespace jau::io {
/**
* This class represents a wrapped byte input stream with the capability
- * to record the byte stream read out at will.
+ * to record the read byte stream at will.
*
* Peek'ed bytes won't be recorded, only read bytes.
*/
class ByteInStream_Recorder final : public ByteInStream {
public:
- size_t read(uint8_t[], size_t) NOEXCEPT_BOTAN override;
+ size_t read(void*, size_t) noexcept override;
- size_t peek(uint8_t out[], size_t length, size_t peek_offset) const NOEXCEPT_BOTAN override {
+ size_t peek(void* out, size_t length, size_t peek_offset) noexcept override {
return m_parent.peek(out, length, peek_offset);
}
- bool check_available(size_t n) NOEXCEPT_BOTAN override {
- return m_parent.check_available(n);
+ bool available(size_t n) noexcept override {
+ return m_parent.available(n);
}
- bool end_of_data() const NOEXCEPT_BOTAN override { return m_parent.end_of_data(); }
-
- bool error() const noexcept override { return m_parent.error(); }
+ void clear(iostate state = iostate::goodbit) noexcept override { m_parent.clear( state ); }
+ iostate rdstate() const noexcept override { return m_parent.rdstate(); }
- std::string id() const NOEXCEPT_BOTAN override { return m_parent.id(); }
+ std::string id() const noexcept override { return m_parent.id(); }
/**
* Construct a byte input stream wrapper using the given parent ByteInStream.
@@ -755,11 +721,9 @@ namespace jau::io {
void close() noexcept override;
- ~ByteInStream_Recorder() NOEXCEPT_BOTAN override { close(); }
-
- size_t get_bytes_read() const NOEXCEPT_BOTAN override { return m_parent.get_bytes_read(); }
+ ~ByteInStream_Recorder() noexcept override { close(); }
- uint64_t bytes_read() const noexcept override { return m_bytes_consumed; }
+ uint64_t tellg() const noexcept override { return m_bytes_consumed; }
bool has_content_size() const noexcept override { return m_parent.has_content_size(); }
diff --git a/include/jau/io_util.hpp b/include/jau/io_util.hpp
index ad91a42..9f28cf7 100644
--- a/include/jau/io_util.hpp
+++ b/include/jau/io_util.hpp
@@ -36,9 +36,6 @@
#include <jau/callocator_sec.hpp>
#include <jau/ringbuffer.hpp>
-// Include Botan header files before this one to be integrated w/ Botan!
-// #include <botan_all.h>
-
namespace jau::io {
/** @defgroup IOUtils IO Utilities
* Input and Output (IO) types and functionality.
@@ -46,11 +43,7 @@ namespace jau::io {
* @{
*/
-#ifdef BOTAN_VERSION_MAJOR
- template<typename T> using secure_vector = std::vector<T, Botan::secure_allocator<T>>;
-#else
template<typename T> using secure_vector = std::vector<T, jau::callocator_sec<T>>;
-#endif
typedef std::basic_string<char, std::char_traits<char>, jau::callocator_sec<char>> secure_string;
diff --git a/src/byte_stream.cpp b/src/byte_stream.cpp
index 9bc088b..b834003 100644
--- a/src/byte_stream.cpp
+++ b/src/byte_stream.cpp
@@ -26,8 +26,6 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <fstream>
-#include <iostream>
#include <chrono>
// #include <botan_all.h>
@@ -74,7 +72,7 @@ using namespace jau::fractions_i64_literals;
const size_t jau::io::BEST_URLSTREAM_RINGBUFFER_SIZE = 2*16384;
#endif
-inline constexpr void copy_mem(uint8_t* out, const uint8_t* in, size_t n) noexcept {
+inline constexpr void copy_mem(void* out, const void* in, size_t n) noexcept {
if(in != nullptr && out != nullptr && n > 0) {
std::memmove(out, in, sizeof(uint8_t)*n);
}
@@ -88,50 +86,49 @@ inline const uint8_t* cast_char_ptr_to_uint8(const char* s) noexcept {
return reinterpret_cast<const uint8_t*>(s);
}
-#ifndef BOTAN_VERSION_MAJOR
-
-size_t ByteInStream::read_byte(uint8_t& out) noexcept {
+size_t ByteInStream::read(uint8_t& out) noexcept {
return read(&out, 1);
}
-size_t ByteInStream::peek_byte(uint8_t& out) const noexcept {
+size_t ByteInStream::peek(uint8_t& out) noexcept {
return peek(&out, 1, 0);
}
-size_t ByteInStream::discard_next(size_t n) noexcept {
- uint8_t buf[64] = { 0 };
+size_t ByteInStream::discard(size_t n) noexcept {
+ uint8_t buf[1024] = { 0 };
size_t discarded = 0;
while(n)
{
- const size_t got = this->read(buf, std::min(n, sizeof(buf)));
+ const size_t got = read(buf, std::min(n, sizeof(buf)));
+ if( 0 == got ) {
+ break;
+ }
discarded += got;
n -= got;
-
- if(got == 0)
- break;
}
return discarded;
}
-#endif /* BOTAN_VERSION_MAJOR */
-
-size_t ByteInStream_SecMemory::read(uint8_t out[], size_t length) NOEXCEPT_BOTAN {
+size_t ByteInStream_SecMemory::read(void* out, size_t length) noexcept {
if( 0 == length || end_of_data() ) {
return 0;
}
const size_t got = std::min<size_t>(m_source.size() - m_offset, length);
copy_mem(out, m_source.data() + m_offset, got);
m_offset += got;
+ if( m_source.size() == m_offset ) {
+ setstate_impl( iostate::eofbit );
+ }
return got;
}
-bool ByteInStream_SecMemory::check_available(size_t n) NOEXCEPT_BOTAN {
+bool ByteInStream_SecMemory::available(size_t n) noexcept {
return m_source.size() - m_offset >= n;
}
-size_t ByteInStream_SecMemory::peek(uint8_t out[], size_t length, size_t peek_offset) const NOEXCEPT_BOTAN {
+size_t ByteInStream_SecMemory::peek(void* out, size_t length, size_t peek_offset) noexcept {
const size_t bytes_left = m_source.size() - m_offset;
if(peek_offset >= bytes_left) {
return 0;
@@ -141,10 +138,6 @@ size_t ByteInStream_SecMemory::peek(uint8_t out[], size_t length, size_t peek_of
return got;
}
-bool ByteInStream_SecMemory::end_of_data() const NOEXCEPT_BOTAN {
- return m_source.size() == m_offset;
-}
-
ByteInStream_SecMemory::ByteInStream_SecMemory(const std::string& in)
: m_source(cast_char_ptr_to_uint8(in.data()),
cast_char_ptr_to_uint8(in.data()) + in.length()),
@@ -160,90 +153,8 @@ std::string ByteInStream_SecMemory::to_string() const noexcept {
return "ByteInStream_SecMemory[content size "+jau::to_decstring(m_source.size())+
", consumed "+jau::to_decstring(m_offset)+
", available "+jau::to_decstring(m_source.size()-m_offset)+
- ", eod "+std::to_string( end_of_data() )+
- ", error "+std::to_string( error() )+
- "]";
-}
-
-size_t ByteInStream_istream::read(uint8_t out[], size_t length) NOEXCEPT_BOTAN {
- if( 0 == length || end_of_data() ) {
- return 0;
- }
- m_source.read(cast_uint8_ptr_to_char(out), length);
- if( error() ) {
- DBG_PRINT("ByteInStream_istream::read: Error occurred in %s", to_string().c_str());
- return 0;
- }
- const size_t got = static_cast<size_t>(m_source.gcount());
- m_bytes_consumed += got;
- return got;
-}
-
-bool ByteInStream_istream::check_available(size_t n) NOEXCEPT_BOTAN {
- // stream size is dynamic, hence can't store size until end
- const std::streampos orig_pos = m_source.tellg();
- m_source.seekg(0, std::ios::end);
- uint64_t avail = static_cast<uint64_t>(m_source.tellg() - orig_pos);
- m_source.seekg(orig_pos);
- return avail >= n;
-}
-
-size_t ByteInStream_istream::peek(uint8_t out[], size_t length, size_t offset) const NOEXCEPT_BOTAN {
- if( 0 == length || end_of_data() ) {
- return 0;
- }
- size_t got = 0;
-
- if( offset ) {
- secure_vector<uint8_t> buf(offset);
- m_source.read(cast_uint8_ptr_to_char(buf.data()), buf.size());
- if( error() ) {
- DBG_PRINT("ByteInStream_istream::peek: Error occurred (offset) in %s", to_string().c_str());
- return 0;
- }
- got = static_cast<size_t>(m_source.gcount());
- }
-
- if(got == offset) {
- m_source.read(cast_uint8_ptr_to_char(out), length);
- if( error() ) {
- DBG_PRINT("ByteInStream_istream::peek: Error occurred (read) in %s", to_string().c_str());
- return 0;
- }
- got = static_cast<size_t>(m_source.gcount());
- }
-
- if( m_source.eof() ) {
- m_source.clear();
- }
- m_source.seekg(m_bytes_consumed, std::ios::beg);
-
- return got;
-}
-
-bool ByteInStream_istream::end_of_data() const NOEXCEPT_BOTAN {
- return !m_source.good();
-}
-
-std::string ByteInStream_istream::id() const NOEXCEPT_BOTAN {
- return m_identifier;
-}
-
-ByteInStream_istream::ByteInStream_istream(std::istream& in, const std::string& name) noexcept
-: m_identifier(name), m_source(in),
- m_bytes_consumed(0)
-{ }
-
-void ByteInStream_istream::close() noexcept {
- // nop
-}
-
-std::string ByteInStream_istream::to_string() const noexcept {
- return "ByteInStream_Stream["+m_identifier+
- ", consumed "+jau::to_decstring(m_bytes_consumed)+
- ", eod "+std::to_string( end_of_data() )+
- ", error "+std::to_string( error() )+
- "]";
+ ", iostate["+jau::io::to_string(rdstate())+
+ "]]";
}
template<typename T>
@@ -271,26 +182,30 @@ std::string jau::io::to_string(const iostate mask) noexcept {
return out;
}
-size_t ByteInStream_File::read(uint8_t out[], size_t length) NOEXCEPT_BOTAN {
+size_t ByteInStream_File::read(void* out, size_t length) noexcept {
if( 0 == length || end_of_data() ) {
return 0;
}
+ uint8_t* out_u8 = static_cast<uint8_t*>(out);
size_t total = 0;
while( total < length ) {
ssize_t len;
- while ( ( len = ::read(m_fd, out+total, length-total) ) < 0 ) {
- if ( errno == EAGAIN || errno == EINTR ) {
+ while ( ( len = ::read(m_fd, out_u8+total, length-total) ) < 0 ) {
+ if ( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) {
// cont temp unavail or interruption
+ // unlikely for regular files and we open w/o O_NONBLOCK
+ // - EAGAIN (file) and EWOULDBLOCK (socket) if blocking
+ // - EINTR (signal)
continue;
}
// Check errno == ETIMEDOUT ??
- setstate( iostate::failbit );
+ setstate_impl( iostate::failbit );
DBG_PRINT("ByteInStream_File::read: Error occurred in %s, errno %d %s", to_string().c_str(), errno, strerror(errno));
return 0;
}
total += static_cast<size_t>(len);
if( 0 == len || ( m_has_content_length && m_bytes_consumed + total >= m_content_size ) ) {
- setstate( iostate::eofbit ); // Note: std::istream also sets iostate::failbit on eof, we don't.
+ setstate_impl( iostate::eofbit ); // Note: std::istream also sets iostate::failbit on eof, we don't.
break;
}
}
@@ -298,7 +213,7 @@ size_t ByteInStream_File::read(uint8_t out[], size_t length) NOEXCEPT_BOTAN {
return total;
}
-size_t ByteInStream_File::peek(uint8_t out[], size_t length, size_t offset) const NOEXCEPT_BOTAN {
+size_t ByteInStream_File::peek(void* out, size_t length, size_t offset) noexcept {
if( 0 == length || end_of_data() || offset > std::numeric_limits<off64_t>::max() ||
( m_has_content_length && m_content_size - m_bytes_consumed < offset + 1 /* min number of bytes to read */ ) ) {
return 0;
@@ -309,7 +224,7 @@ size_t ByteInStream_File::peek(uint8_t out[], size_t length, size_t offset) cons
if( 0 < offset ) {
abs_pos = __posix_lseek64(m_fd, static_cast<off64_t>(offset), SEEK_CUR);
if( 0 > abs_pos ) {
- setstate( iostate::failbit );
+ setstate_impl( iostate::failbit );
DBG_PRINT("ByteInStream_File::peek: Error occurred (offset1 %zd) in %s, errno %d %s",
offset, to_string().c_str(), errno, strerror(errno));
return 0;
@@ -323,7 +238,7 @@ size_t ByteInStream_File::peek(uint8_t out[], size_t length, size_t offset) cons
continue;
}
// Check errno == ETIMEDOUT ??
- setstate( iostate::failbit );
+ setstate_impl( iostate::failbit );
DBG_PRINT("ByteInStream_File::peak: Error occurred (read) in %s, errno %d %s", to_string().c_str(), errno, strerror(errno));
return 0;
}
@@ -331,7 +246,7 @@ size_t ByteInStream_File::peek(uint8_t out[], size_t length, size_t offset) cons
}
if( __posix_lseek64(m_fd, static_cast<off64_t>(m_bytes_consumed), SEEK_SET) < 0 ) {
// even though we were able to fetch the desired data above, let's fail if position reset fails
- setstate( iostate::failbit );
+ setstate_impl( iostate::failbit );
DBG_PRINT("ByteInStream_File::peek: Error occurred (offset2 %zd) in %s, errno %d %s",
offset, to_string().c_str(), errno, strerror(errno));
return 0;
@@ -339,36 +254,31 @@ size_t ByteInStream_File::peek(uint8_t out[], size_t length, size_t offset) cons
return got;
}
-bool ByteInStream_File::check_available(size_t n) NOEXCEPT_BOTAN {
+bool ByteInStream_File::available(size_t n) noexcept {
return is_open() && good() && ( !m_has_content_length || m_content_size - m_bytes_consumed >= (uint64_t)n );
};
-bool ByteInStream_File::end_of_data() const NOEXCEPT_BOTAN {
- return !is_open() || !good() || ( m_has_content_length && m_bytes_consumed >= m_content_size );
-}
-
ByteInStream_File::ByteInStream_File(const int fd) noexcept
-: m_fd(-1), m_state(iostate::goodbit),
- m_has_content_length(false), m_content_size(0), m_bytes_consumed(0)
+: ByteInStream(),
+ stats(fd), m_fd(-1), m_has_content_length(false), m_content_size(0), m_bytes_consumed(0)
{
- stats = jau::fs::file_stats(fd);
if( !stats.exists() || !stats.has_access() ) {
- setstate( iostate::failbit ); // Note: conforming with std::ifstream open
+ setstate_impl( iostate::failbit ); // Note: conforming with std::ifstream open
DBG_PRINT("ByteInStream_File::ctor: Error, not an existing or accessible file in %s, %s", stats.to_string().c_str(), to_string().c_str());
} else {
- m_has_content_length = stats.is_file();
- m_content_size = stats.size();
+ m_has_content_length = stats.has( jau::fs::file_stats::field_t::size );
+ m_content_size = m_has_content_length ? stats.size() : 0;
m_fd = ::dup(fd);
if ( 0 > m_fd ) {
- setstate( iostate::failbit ); // Note: conforming with std::ifstream open
+ setstate_impl( iostate::failbit ); // Note: conforming with std::ifstream open
DBG_PRINT("ByteInStream_File::ctor: Error occurred in %s, %s", stats.to_string().c_str(), to_string().c_str());
}
}
}
ByteInStream_File::ByteInStream_File(const int dirfd, const std::string& path) noexcept
-: m_fd(-1), m_state(iostate::goodbit),
- m_has_content_length(false), m_content_size(0), m_bytes_consumed(0)
+: ByteInStream(),
+ stats(), m_fd(-1), m_has_content_length(false), m_content_size(0), m_bytes_consumed(0)
{
if( jau::io::uri_tk::is_local_file_protocol(path) ) {
// cut of leading `file://`
@@ -378,16 +288,25 @@ ByteInStream_File::ByteInStream_File(const int dirfd, const std::string& path) n
stats = jau::fs::file_stats(dirfd, path);
}
if( !stats.exists() || !stats.has_access() ) {
- setstate( iostate::failbit ); // Note: conforming with std::ifstream open
+ setstate_impl( iostate::failbit ); // Note: conforming with std::ifstream open
DBG_PRINT("ByteInStream_File::ctor: Error, not an existing or accessible file in %s, %s", stats.to_string().c_str(), to_string().c_str());
} else {
- m_has_content_length = stats.is_file();
- m_content_size = stats.size();
- // TODO: Consider O_NONBLOCK, despite being potentially useless on files?
+ if( stats.has( jau::fs::file_stats::field_t::size ) ) {
+ m_has_content_length = true;
+ m_content_size = stats.size();
+ } else {
+ m_has_content_length = false;
+ m_content_size = 0;
+ }
+ // O_NONBLOCK, is useless on files and counter to this class logic
const int src_flags = O_RDONLY|O_BINARY|O_NOCTTY;
- m_fd = __posix_openat64(dirfd, stats.path().c_str(), src_flags);
+ if( stats.has_fd() ) {
+ m_fd = ::dup( stats.fd() );
+ } else {
+ m_fd = __posix_openat64(dirfd, stats.path().c_str(), src_flags);
+ }
if ( 0 > m_fd ) {
- setstate( iostate::failbit ); // Note: conforming with std::ifstream open
+ setstate_impl( iostate::failbit ); // Note: conforming with std::ifstream open
DBG_PRINT("ByteInStream_File::ctor: Error while opening %s, %s", stats.to_string().c_str(), to_string().c_str());
}
}
@@ -404,14 +323,12 @@ void ByteInStream_File::close() noexcept {
}
std::string ByteInStream_File::to_string() const noexcept {
- return "ByteInStream_File[content_length "+jau::to_decstring(m_content_size)+
+ return "ByteInStream_File[content_length "+( has_content_size() ? jau::to_decstring(m_content_size) : "n/a" )+
", consumed "+jau::to_decstring(m_bytes_consumed)+
", available "+jau::to_decstring(get_available())+
- ", open "+std::to_string(is_open())+
- ", iostate["+jau::io::to_string(m_state)+
- "], eod "+std::to_string( end_of_data() )+
- ", error "+std::to_string( error() )+
- ", "+stats.to_string()+
+ ", fd "+std::to_string(m_fd)+
+ ", iostate["+jau::io::to_string(rdstate())+
+ "], "+stats.to_string()+
"]";
}
@@ -446,7 +363,7 @@ void ByteInStream_URL::close() noexcept {
DBG_PRINT("ByteInStream_URL: close.X %s, %s", id().c_str(), to_string_int().c_str());
}
-bool ByteInStream_URL::check_available(size_t n) NOEXCEPT_BOTAN {
+bool ByteInStream_URL::available(size_t n) noexcept {
if( async_io_result_t::NONE != m_result ) {
// url thread ended, only remaining bytes in buffer available left
return m_buffer.size() >= n;
@@ -458,17 +375,17 @@ bool ByteInStream_URL::check_available(size_t n) NOEXCEPT_BOTAN {
return m_buffer.waitForElements(n, m_timeout) >= n;
}
-size_t ByteInStream_URL::read(uint8_t out[], size_t length) NOEXCEPT_BOTAN {
+size_t ByteInStream_URL::read(void* out, size_t length) noexcept {
if( 0 == length || end_of_data() ) {
return 0;
}
- const size_t consumed_bytes = m_buffer.get(out, length, 1);
+ const size_t consumed_bytes = m_buffer.get(static_cast<uint8_t*>(out), length, 1);
m_bytes_consumed += consumed_bytes;
// DBG_PRINT("ByteInStream_Feed::read: size %zu/%zu bytes, %s", consumed_bytes, length, to_string_int().c_str() );
return consumed_bytes;
}
-size_t ByteInStream_URL::peek(uint8_t out[], size_t length, size_t peek_offset) const NOEXCEPT_BOTAN {
+size_t ByteInStream_URL::peek(void* out, size_t length, size_t peek_offset) noexcept {
(void)out;
(void)length;
(void)peek_offset;
@@ -476,21 +393,26 @@ size_t ByteInStream_URL::peek(uint8_t out[], size_t length, size_t peek_offset)
return 0;
}
-bool ByteInStream_URL::end_of_data() const NOEXCEPT_BOTAN {
- return ( async_io_result_t::NONE != m_result && m_buffer.isEmpty() ) ||
- ( m_has_content_length && m_bytes_consumed >= m_content_size );
+iostate ByteInStream_URL::rdstate() const noexcept {
+ if ( ( async_io_result_t::NONE != m_result && m_buffer.isEmpty() ) ||
+ ( m_has_content_length && m_bytes_consumed >= m_content_size ) )
+ {
+ setstate_impl( iostate::eofbit );
+ }
+ if( async_io_result_t::FAILED == m_result ) {
+ setstate_impl( iostate::failbit );
+ }
+ return rdstate_impl();
}
std::string ByteInStream_URL::to_string_int() const noexcept {
- return m_url+", Url[content_length has "+std::to_string(m_has_content_length.load())+
- ", size "+jau::to_decstring(m_content_size.load())+
+ return m_url+", Url[content_length "+( has_content_size() ? jau::to_decstring(m_content_size.load()) : "n/a" )+
", xfered "+jau::to_decstring(m_total_xfered.load())+
", result "+std::to_string((int8_t)m_result.load())+
"], consumed "+jau::to_decstring(m_bytes_consumed)+
", available "+jau::to_decstring(get_available())+
- ", eod "+std::to_string( end_of_data() )+
- ", error "+std::to_string( error() )+
- ", "+m_buffer.toString();
+ ", iostate["+jau::io::to_string(rdstate())+
+ "], "+m_buffer.toString();
}
std::string ByteInStream_URL::to_string() const noexcept {
return "ByteInStream_URL["+to_string_int()+"]";
@@ -501,12 +423,12 @@ std::unique_ptr<ByteInStream> jau::io::to_ByteInStream(const std::string& path_o
jau::io::uri_tk::protocol_supported(path_or_uri) )
{
std::unique_ptr<ByteInStream> res = std::make_unique<ByteInStream_URL>(path_or_uri, timeout);
- if( nullptr != res && !res->error() ) {
+ if( nullptr != res && !res->fail() ) {
return res;
}
}
std::unique_ptr<ByteInStream> res = std::make_unique<ByteInStream_File>(path_or_uri);
- if( nullptr != res && !res->error() ) {
+ if( nullptr != res && !res->fail() ) {
return res;
}
return nullptr;
@@ -530,7 +452,7 @@ void ByteInStream_Feed::close() noexcept {
DBG_PRINT("ByteInStream_Feed: close.X %s, %s", id().c_str(), to_string_int().c_str());
}
-bool ByteInStream_Feed::check_available(size_t n) NOEXCEPT_BOTAN {
+bool ByteInStream_Feed::available(size_t n) noexcept {
if( async_io_result_t::NONE != m_result ) {
// feeder completed, only remaining bytes in buffer available left
return m_buffer.size() >= n;
@@ -542,17 +464,17 @@ bool ByteInStream_Feed::check_available(size_t n) NOEXCEPT_BOTAN {
return m_buffer.waitForElements(n, m_timeout) >= n;
}
-size_t ByteInStream_Feed::read(uint8_t out[], size_t length) NOEXCEPT_BOTAN {
+size_t ByteInStream_Feed::read(void* out, size_t length) noexcept {
if( 0 == length || end_of_data() ) {
return 0;
}
- const size_t consumed_bytes = m_buffer.get(out, length, 1);
- m_bytes_consumed += consumed_bytes;
+ const size_t got = m_buffer.get(static_cast<uint8_t*>(out), length, 1);
+ m_bytes_consumed += got;
// DBG_PRINT("ByteInStream_Feed::read: size %zu/%zu bytes, %s", consumed_bytes, length, to_string_int().c_str() );
- return consumed_bytes;
+ return got;
}
-size_t ByteInStream_Feed::peek(uint8_t out[], size_t length, size_t peek_offset) const NOEXCEPT_BOTAN {
+size_t ByteInStream_Feed::peek(void* out, size_t length, size_t peek_offset) noexcept {
(void)out;
(void)length;
(void)peek_offset;
@@ -560,9 +482,16 @@ size_t ByteInStream_Feed::peek(uint8_t out[], size_t length, size_t peek_offset)
return 0;
}
-bool ByteInStream_Feed::end_of_data() const NOEXCEPT_BOTAN {
- return ( async_io_result_t::NONE != m_result && m_buffer.isEmpty() ) ||
- ( m_has_content_length && m_bytes_consumed >= m_content_size );
+iostate ByteInStream_Feed::rdstate() const noexcept {
+ if ( ( async_io_result_t::NONE != m_result && m_buffer.isEmpty() ) ||
+ ( m_has_content_length && m_bytes_consumed >= m_content_size ) )
+ {
+ setstate_impl( iostate::eofbit );
+ }
+ if( async_io_result_t::FAILED == m_result ) {
+ setstate_impl( iostate::failbit );
+ }
+ return rdstate_impl();
}
void ByteInStream_Feed::write(uint8_t in[], size_t length) noexcept {
@@ -572,16 +501,19 @@ void ByteInStream_Feed::write(uint8_t in[], size_t length) noexcept {
}
}
+void ByteInStream_Feed::set_eof(const async_io_result_t result) noexcept {
+ m_result = result;
+ interruptReader();
+}
+
std::string ByteInStream_Feed::to_string_int() const noexcept {
- return m_id+", ext[content_length has "+std::to_string(m_has_content_length.load())+
- ", size "+jau::to_decstring(m_content_size.load())+
+ return m_id+", ext[content_length "+( has_content_size() ? jau::to_decstring(m_content_size.load()) : "n/a" )+
", xfered "+jau::to_decstring(m_total_xfered.load())+
", result "+std::to_string((int8_t)m_result.load())+
"], consumed "+std::to_string(m_bytes_consumed)+
", available "+std::to_string(get_available())+
- ", eod "+std::to_string( end_of_data() )+
- ", error "+std::to_string( error() )+
- ", "+m_buffer.toString();
+ ", iostate["+jau::io::to_string(rdstate())+
+ "], "+m_buffer.toString();
}
std::string ByteInStream_Feed::to_string() const noexcept {
@@ -610,19 +542,19 @@ void ByteInStream_Recorder::clear_recording() noexcept {
m_rec_offset = 0;
}
-size_t ByteInStream_Recorder::read(uint8_t out[], size_t length) NOEXCEPT_BOTAN {
+size_t ByteInStream_Recorder::read(void* out, size_t length) noexcept {
const size_t consumed_bytes = m_parent.read(out, length);
m_bytes_consumed += consumed_bytes;
if( is_recording() ) {
- m_buffer.insert(m_buffer.end(), out, out+consumed_bytes);
+ uint8_t* out_u8 = static_cast<uint8_t*>(out);
+ m_buffer.insert(m_buffer.end(), out_u8, out_u8+consumed_bytes);
}
return consumed_bytes;
}
std::string ByteInStream_Recorder::to_string() const noexcept {
return "ByteInStream_Recorder[parent "+m_parent.id()+", recording[on "+std::to_string(m_is_recording)+
- " offset "+jau::to_decstring(m_rec_offset)+
+ " offset "+jau::to_decstring(m_rec_offset)+
"], consumed "+jau::to_decstring(m_bytes_consumed)+
- ", eod "+std::to_string(end_of_data())+
- ", error "+std::to_string(error())+"]";
+ ", iostate["+jau::io::to_string(rdstate())+"]]";
}
diff --git a/src/io_util.cpp b/src/io_util.cpp
index 7b43520..943cc5e 100644
--- a/src/io_util.cpp
+++ b/src/io_util.cpp
@@ -23,8 +23,6 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <fstream>
-#include <iostream>
#include <chrono>
// #include <botan_all.h>
@@ -49,7 +47,7 @@ uint64_t jau::io::read_file(const std::string& input_file,
StreamConsumerFunc consumer_fn) noexcept
{
if(input_file == "-") {
- ByteInStream_istream in(std::cin);
+ ByteInStream_File in(0); // stdin
return read_stream(in, buffer, consumer_fn);
} else {
ByteInStream_File in(input_file);
@@ -63,7 +61,7 @@ uint64_t jau::io::read_stream(ByteInStream& in,
uint64_t total = 0;
bool has_more;
do {
- if( in.check_available(1) ) { // at least one byte to stream ..
+ if( in.available(1) ) { // at least one byte to stream ..
buffer.resize(buffer.capacity());
const uint64_t got = in.read(buffer.data(), buffer.capacity());
@@ -89,7 +87,7 @@ uint64_t jau::io::read_stream(ByteInStream& in,
static uint64_t _read_buffer(ByteInStream& in,
secure_vector<uint8_t>& buffer) noexcept {
- if( in.check_available(1) ) { // at least one byte to stream ..
+ if( in.available(1) ) { // at least one byte to stream ..
buffer.resize(buffer.capacity());
const uint64_t got = in.read(buffer.data(), buffer.capacity());
buffer.resize(got);