diff options
Diffstat (limited to 'include/jau')
-rw-r--r-- | include/jau/byte_stream.hpp | 36 | ||||
-rw-r--r-- | include/jau/io_util.hpp | 72 | ||||
-rw-r--r-- | include/jau/string_util.hpp | 48 |
3 files changed, 141 insertions, 15 deletions
diff --git a/include/jau/byte_stream.hpp b/include/jau/byte_stream.hpp index e68c431..f15c292 100644 --- a/include/jau/byte_stream.hpp +++ b/include/jau/byte_stream.hpp @@ -42,6 +42,8 @@ // Include Botan header files before this one to be integrated w/ Botan! // #include <botan_all.h> +using namespace jau::fractions_i64_literals; + namespace jau::io { /** \addtogroup IOUtils @@ -365,15 +367,19 @@ namespace jau::io { 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(); } + bool error() const noexcept override { return nullptr == m_source || m_source->bad(); } std::string id() const NOEXCEPT_BOTAN override; /** * Construct a Stream-Based byte input stream from filesystem path - * @param file the path to the file + * + * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(), + * the leading `file://` is cut off and the remainder being used. + * + * @param path the path to the file, maybe a local file URI * @param use_binary whether to treat the file as binary (default) or use platform character conversion */ - ByteInStream_File(const std::string& file, bool use_binary = true) noexcept; + ByteInStream_File(const std::string& path, bool use_binary = true) noexcept; ByteInStream_File(const ByteInStream_File&) = delete; @@ -395,7 +401,7 @@ namespace jau::io { private: const std::string m_identifier; - mutable std::ifstream m_source; + mutable std::unique_ptr<std::ifstream> m_source; uint64_t m_content_size; uint64_t m_bytes_consumed; }; @@ -403,7 +409,9 @@ namespace jau::io { /** * This class represents a Ringbuffer-Based byte input stream with a URL connection provisioned data feed. * - * Standard implementation uses curl, hence all protocols supported by curl are supported. + * Standard implementation uses [curl](https://curl.se/), + * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported, + * jau::io::uri::supported_protocols(). */ class ByteInStream_URL final : public ByteInStream { public: @@ -450,7 +458,7 @@ namespace jau::io { /** * 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(), where fractions_i64::zero waits infinitely + * @param timeout maximum duration in fractions of seconds to wait @ check_available() for next bytes, where fractions_i64::zero waits infinitely */ ByteInStream_URL(const std::string& url, const jau::fraction_i64& timeout) noexcept; @@ -483,11 +491,25 @@ namespace jau::io { jau::relaxed_atomic_uint64 m_content_size; jau::relaxed_atomic_uint64 m_total_xfered; relaxed_atomic_async_io_result_t m_result; - std::thread m_url_thread; + std::unique_ptr<std::thread> m_url_thread; uint64_t m_bytes_consumed; }; /** + * Parses the given path_or_uri, if it matches a supported protocol, see jau::io::uri::protocol_supported(), + * but is not a local file, see jau::io::uri::is_local_file_protocol(), ByteInStream_URL is being attempted. + * + * If the above fails, ByteInStream_File is attempted. + * + * If non of the above leads to a ByteInStream without ByteInStream::error(), nullptr is returned. + * + * @param path_or_uri given path or uri for with a ByteInStream instance shall be established. + * @param timeout a timeout in case ByteInStream_URL is being used as maximum dureation to wait for next bytes at ByteInStream_URL::check_available(), defaults to 20_s + * @return a working ByteInStream w/o ByteInStream::error() or nullptr + */ + std::unique_ptr<ByteInStream> to_ByteInStream(const std::string& path_or_uri, jau::fraction_i64 timeout=20_s) noexcept; + + /** * This class represents a Ringbuffer-Based byte input stream with an externally provisioned data feed. */ class ByteInStream_Feed final : public ByteInStream { diff --git a/include/jau/io_util.hpp b/include/jau/io_util.hpp index c74a875..2ca8475 100644 --- a/include/jau/io_util.hpp +++ b/include/jau/io_util.hpp @@ -84,14 +84,63 @@ namespace jau::io { StreamConsumerFunc consumer_fn) noexcept; /** + * Limited URI scheme functionality to query whether implementation may handle the protocol. + * + * The URI scheme functionality exposed here is limited and only provided to decide whether the used implementation + * is able to handle the protocol. This is not a replacement for a proper URI class. + */ + namespace uri { + /** + * Returns a list of supported protocol supported by [*libcurl* network protocols](https://curl.se/docs/url-syntax.html), + * queried at runtime. + * @see protocol_supported() + */ + std::vector<std::string_view> supported_protocols() noexcept; + + /** + * Returns the valid uri-scheme-view from given uri-view, + * which is empty if no valid scheme is included. + * + * @param uri an uri-view + * @return valid uri-scheme-view, empty if non found + */ + std::string_view get_scheme(const std::string_view& uri) noexcept; + + /** + * Returns true if the uri-scheme of given uri-view matches a supported by [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) otherwise false. + * + * The *libcurl* supported protocols is queried at runtime, see supported_protocols(). + * + * @param uri an uri-view to test + * @return true if the uri-scheme of given uri is supported, otherwise false. + * @see supported_protocols() + * @see get_scheme() + */ + bool protocol_supported(const std::string_view& uri) noexcept; + + /** + * Returns true if the uri-scheme of given uri-view matches the local `file` protocol, i.e. starts with `file://`. + * @param uri an uri-view to test + */ + bool is_local_file_protocol(const std::string_view& uri) noexcept; + } + + /** * Synchronous URL stream reader using the given StreamConsumerFunc consumer_fn. * * To abort streaming, user may return `false` from the given `consumer_func`. * + * Standard implementation uses [curl](https://curl.se/), + * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported, + * see jau::io::uri::supported_protocols(). + * + * If the uri-sheme doesn't match a supported protocol, see jau::io::uri::protocol_supported(), + * function returns immediately with zero bytes. + * * @param url the URL to open a connection to and stream bytes from * @param buffer secure std::vector buffer, passed down to consumer_fn * @param consumer_fn StreamConsumerFunc consumer for each received heap of bytes, returning true to continue stream of false to abort. - * @return total bytes read or 0 if error + * @return total bytes read or 0 if transmission error or protocol of given url is not supported */ uint64_t read_url_stream(const std::string& url, secure_vector<uint8_t>& buffer, @@ -102,20 +151,27 @@ namespace jau::io { * * To abort streaming, user may set given reference `results` to a value other than async_io_result_t::NONE. * + * Standard implementation uses [curl](https://curl.se/), + * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported, + * see jau::io::uri::supported_protocols(). + * + * If the uri-sheme doesn't match a supported protocol, see jau::io::uri::protocol_supported(), + * function returns with nullptr. + * * @param url the URL to open a connection to and stream bytes from * @param buffer the ringbuffer destination to write into * @param has_content_length indicating whether content_length is known from server * @param content_length tracking the content_length * @param total_read tracking the total_read * @param result reference to tracking async_io_result_t. If set to other than async_io_result_t::NONE while streaming, streaming is aborted. - * @return the url background reading thread + * @return the url background reading thread unique-pointer or nullptr if protocol of given url is not supported */ - std::thread read_url_stream(const std::string& url, - ByteRingbuffer& buffer, - jau::relaxed_atomic_bool& has_content_length, - jau::relaxed_atomic_uint64& content_length, - jau::relaxed_atomic_uint64& total_read, - relaxed_atomic_async_io_result_t& result) noexcept; + std::unique_ptr<std::thread> read_url_stream(const std::string& url, + ByteRingbuffer& buffer, + jau::relaxed_atomic_bool& has_content_length, + jau::relaxed_atomic_uint64& content_length, + jau::relaxed_atomic_uint64& total_read, + relaxed_atomic_async_io_result_t& result) noexcept; void print_stats(const std::string& prefix, const uint64_t& out_bytes_total, const jau::fraction_i64& td) noexcept; diff --git a/include/jau/string_util.hpp b/include/jau/string_util.hpp index 6673171..8a6a37f 100644 --- a/include/jau/string_util.hpp +++ b/include/jau/string_util.hpp @@ -201,9 +201,31 @@ namespace jau { { return std::to_string(ref); } + + template< class value_type, + std::enable_if_t<!std::is_integral_v<value_type> && + !std::is_floating_point_v<value_type> && + std::is_base_of_v<std::string, value_type>, + bool> = true> + inline std::string to_string(const value_type & ref) { + return ref; + } + + template< class value_type, + std::enable_if_t<!std::is_integral_v<value_type> && + !std::is_floating_point_v<value_type> && + !std::is_base_of_v<std::string, value_type> && + std::is_base_of_v<std::string_view, value_type>, + bool> = true> + inline std::string to_string(const value_type & ref) { + return std::string(ref); + } + template< class value_type, std::enable_if_t<!std::is_integral_v<value_type> && !std::is_floating_point_v<value_type> && + !std::is_base_of_v<std::string, value_type> && + !std::is_base_of_v<std::string_view, value_type> && std::is_pointer_v<value_type>, bool> = true> inline std::string to_string(const value_type & ref) @@ -214,6 +236,8 @@ namespace jau { template< class value_type, std::enable_if_t<!std::is_integral_v<value_type> && !std::is_floating_point_v<value_type> && + !std::is_base_of_v<std::string, value_type> && + !std::is_base_of_v<std::string_view, value_type> && !std::is_pointer_v<value_type> && jau::has_toString_v<value_type>, bool> = true> @@ -224,6 +248,8 @@ namespace jau { template< class value_type, std::enable_if_t<!std::is_integral_v<value_type> && !std::is_floating_point_v<value_type> && + !std::is_base_of_v<std::string, value_type> && + !std::is_base_of_v<std::string_view, value_type> && !std::is_pointer_v<value_type> && !jau::has_toString_v<value_type> && jau::has_to_string_v<value_type>, @@ -235,6 +261,8 @@ namespace jau { template< class value_type, std::enable_if_t<!std::is_integral_v<value_type> && !std::is_floating_point_v<value_type> && + !std::is_base_of_v<std::string, value_type> && + !std::is_base_of_v<std::string_view, value_type> && !std::is_pointer_v<value_type> && !jau::has_toString_v<value_type> && !jau::has_to_string_v<value_type> && @@ -247,6 +275,8 @@ namespace jau { template< class value_type, std::enable_if_t<!std::is_integral_v<value_type> && !std::is_floating_point_v<value_type> && + !std::is_base_of_v<std::string, value_type> && + !std::is_base_of_v<std::string_view, value_type> && !std::is_pointer_v<value_type> && !jau::has_toString_v<value_type> && !jau::has_to_string_v<value_type> && @@ -257,6 +287,24 @@ namespace jau { return "jau::to_string<T> not available for "+type_cue<value_type>::print("unknown", TypeTraitGroup::ALL); } + template<typename T> + std::string to_string(std::vector<T> const &list, const std::string& delim) + { + if ( list.empty() ) { + return std::string(); + } + bool need_delim = false; + std::string res; + for(const T& e : list) { + if( need_delim ) { + res.append( delim ).append( " " ); + } + res.append( to_string( e ) ); + need_delim = true; + } + return res; + } + /**@}*/ } // namespace jau |