jaulib v1.3.6
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
byte_stream.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021-2023 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef JAU_BYTE_STREAM_HPP_
26#define JAU_BYTE_STREAM_HPP_
27
28#include <string>
29#include <cstdint>
30#include <thread>
31
32#include <jau/basic_types.hpp>
33#include <jau/ringbuffer.hpp>
34#include <jau/file_util.hpp>
35#include <jau/enum_util.hpp>
36
37#include <jau/io_util.hpp>
38
39using namespace jau::fractions_i64_literals;
40
41namespace jau::io {
42
43 using namespace jau::enums;
44
45 /** \addtogroup IOUtils
46 *
47 * @{
48 */
49
50 /*
51 * Mimic std::ios_base::iostate for state functionality, see iostate_func.
52 *
53 * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
54 */
55 enum class iostate : uint32_t {
56 /** No error occurred nor has EOS being reached. Value is no bit set! */
57 none = 0,
58
59 /** No error occurred nor has EOS being reached. Value is no bit set! */
61
62 /** Irrecoverable stream error, including loss of integrity of the underlying stream or media. */
63 badbit = 1U << 0,
64
65 /** An input operation reached the end of its stream. */
66 eofbit = 1U << 1,
67
68 /** Input or output operation failed (formatting or extraction error). */
69 failbit = 1U << 2,
70
71 /** Input or output operation failed due to timeout. */
72 timeout = 1U << 3
73 };
75
76 /**
77 * Supporting std::basic_ios's iostate functionality for all ByteInStream implementations.
78 */
80 private:
81 iostate m_state;
82
83 protected:
84 constexpr iostate rdstate_impl() const noexcept { return m_state; }
85 constexpr void setstate_impl(iostate state) const noexcept { const_cast<iostate_func*>(this)->m_state |= state; }
86
87 public:
88 iostate_func() noexcept
89 : m_state( iostate::goodbit ) {}
90
91 iostate_func(const iostate_func& o) noexcept = default;
92 iostate_func(iostate_func&& o) noexcept = default;
93 iostate_func& operator=(const iostate_func &o) noexcept = default;
94 iostate_func& operator=(iostate_func &&o) noexcept = default;
95
96 virtual ~iostate_func() noexcept = default;
97
98 /** Clears state flags by assignment to the given value. */
99 virtual void clear(const iostate state = iostate::goodbit) noexcept { m_state = state; }
100
101 /**
102 * Returns the current state flags.
103 *
104 * Method is marked `virtual` to allow implementations with asynchronous resources
105 * to determine or update the current iostate.
106 *
107 * Method is used throughout all query members and setstate(),
108 * hence they all will use the updated state from a potential override implementation.
109 */
110 virtual iostate rdstate() const noexcept { return m_state; }
111
112 /** Sets state flags, by keeping its previous bits. */
113 void setstate(const iostate state) noexcept { clear( rdstate() | state ); }
114
115 /** Checks if no error nor eof() has occurred i.e. I/O operations are available. */
116 bool good() const noexcept
117 { return iostate::goodbit == rdstate(); }
118
119 /** Checks if end-of-file has been reached. */
120 bool eof() const noexcept
121 { return iostate::none != ( rdstate() & iostate::eofbit ); }
122
123 /** Checks if an error has occurred. */
124 bool fail() const noexcept
126
127 /** Checks if an error has occurred, synonym of fail(). */
128 bool operator!() const noexcept { return fail(); }
129
130 /** Checks if no error has occurred, synonym of !fail(). */
131 explicit operator bool() const noexcept { return !fail(); }
132
133 /** Checks if a non-recoverable error has occurred. */
134 bool bad() const noexcept
135 { return iostate::none != ( rdstate() & iostate::badbit ); }
136
137 /** Checks if a timeout (non-recoverable) has occurred. */
138 bool timeout() const noexcept
139 { return iostate::none != ( rdstate() & iostate::timeout ); }
140 };
141
142 /**
143 * Abstract byte input stream object.
144 *
145 * @anchor byte_in_stream_properties
146 * ### ByteInStream Properties
147 * The byte input stream can originate from a local source w/o delay,
148 * remote URL like http connection or even from another thread feeding the input buffer.<br />
149 * Both latter asynchronous resources may expose blocking properties
150 * in available().
151 *
152 * Asynchronous resources benefit from knowing their content size,
153 * as their available() implementation may avoid
154 * blocking and waiting for requested bytes available
155 * if the stream is already beyond its scope.
156 *
157 * All method implementations are of `noexcept`.
158 *
159 * One may use fail() to detect whether an error has occurred,
160 * while end_of_data() not only covers the end-of-stream (EOS) case but includes fail().
161 *
162 * @see @ref byte_in_stream_properties "ByteInStream Properties"
163 */
165 {
166 public:
167 ByteInStream() noexcept
168 : iostate_func() {}
169
170 ~ByteInStream() noexcept override = default;
171 ByteInStream& operator=(const ByteInStream&) = delete;
172 ByteInStream(const ByteInStream&) = delete;
173
174 /** Checks if the stream has an associated file. */
175 virtual bool is_open() const noexcept = 0;
176
177 /**
178 * Close the stream if supported by the underlying mechanism.
179 */
180 virtual void close() noexcept = 0;
181
182 /**
183 * Return whether n bytes are available in the input stream,
184 * if has_content_size() or using an asynchronous source.
185 *
186 * If !has_content_size() and not being an asynchronous source,
187 * !end_of_data() is returned.
188 *
189 * Method may be blocking when using an asynchronous source
190 * up until the requested bytes are available.
191 *
192 * A subsequent call to read() shall return immediately with at least
193 * the requested numbers of bytes available,
194 * if has_content_size() or using an asynchronous source.
195 *
196 * See details of the implementing class.
197 *
198 * @param n byte count to wait for
199 * @return true if n bytes are available, otherwise false
200 *
201 * @see has_content_size()
202 * @see read()
203 * @see @ref byte_in_stream_properties "ByteInStream Properties"
204 */
205 virtual bool available(size_t n) noexcept = 0;
206
207 /**
208 * Read from the source. Moves the internal offset so that every
209 * call to read will return a new portion of the source.
210 *
211 * Use available() to try to wait for a certain amount of bytes available.
212 *
213 * This method shall only block until `min(available, length)` bytes are transfered.
214 *
215 * See details of the implementing class.
216 *
217 * @param out the byte array to write the result to
218 * @param length the length of the byte array out
219 * @return length in bytes that was actually read and put into out
220 *
221 * @see available()
222 * @see @ref byte_in_stream_properties "ByteInStream Properties"
223 */
224 [[nodiscard]] virtual size_t read(void* out, size_t length) noexcept = 0;
225
226 /**
227 * Read one byte.
228 * @param out the byte to read to
229 * @return true if one byte has been read, false otherwise
230 */
231 [[nodiscard]] bool read(uint8_t& out) noexcept;
232
233 /**
234 * Read from the source but do not modify the internal
235 * offset. Consecutive calls to peek() will return portions of
236 * the source starting at the same position.
237 *
238 * @param out the byte array to write the output to
239 * @param length the length of the byte array out
240 * @param peek_offset the offset into the stream to read at
241 * @return length in bytes that was actually read and put into out
242 */
243 [[nodiscard]] virtual size_t peek(void* out, size_t length, size_t peek_offset) noexcept = 0;
244
245 /**
246 * Peek at one byte.
247 * @param out an output byte
248 * @return true if one byte has been peeked, false otherwise
249 */
250 [[nodiscard]] bool peek(uint8_t& out) noexcept;
251
252 /**
253 * Discard the next N bytes of the data
254 * @param N the number of bytes to discard
255 * @return number of bytes actually discarded
256 */
257 [[nodiscard]] size_t discard(size_t N) noexcept;
258
259 /**
260 * return the id of this data source
261 * @return std::string representing the id of this data source
262 */
263 virtual std::string id() const noexcept { return ""; }
264
265 /**
266 * Returns the input position indicator, similar to std::basic_istream.
267 *
268 * @return number of bytes read so far.
269 */
270 virtual uint64_t tellg() const noexcept = 0;
271
272 /**
273 * Returns true if implementation is aware of content_size(), otherwise false.
274 * @see content_size()
275 */
276 virtual bool has_content_size() const noexcept = 0;
277
278 /**
279 * Returns the content_size if known.
280 * @see has_content_size()
281 */
282 virtual uint64_t content_size() const noexcept = 0;
283
284 virtual std::string to_string() const noexcept = 0;
285 };
286
287 /**
288 * Secure Memory-Based byte input stream
289 */
291 public:
292 [[nodiscard]] size_t read(void*, size_t) noexcept override;
293
294 [[nodiscard]] size_t peek(void*, size_t, size_t) noexcept override;
295
296 bool available(size_t n) noexcept override;
297
298 /**
299 * Construct a secure memory source that reads from a string
300 * @param in the string to read from
301 */
302 explicit ByteInStream_SecMemory(const std::string& in);
303
304 /**
305 * Construct a secure memory source that reads from a byte array
306 * @param in the byte array to read from
307 * @param length the length of the byte array
308 */
309 ByteInStream_SecMemory(const uint8_t in[], size_t length)
310 : m_source(in, in + length), m_offset(0) {}
311
312 /**
313 * Construct a secure memory source that reads from a secure_vector
314 * @param in the MemoryRegion to read from
315 */
317 : m_source(std::move(in)), m_offset(0) {}
318
319 /**
320 * Construct a secure memory source that reads from a std::vector
321 * @param in the MemoryRegion to read from
322 */
323 explicit ByteInStream_SecMemory(const std::vector<uint8_t>& in)
324 : m_source(in.begin(), in.end()), m_offset(0) {}
325
326 bool is_open() const noexcept override { return true; }
327
328 void close() noexcept override;
329
330 ~ByteInStream_SecMemory() noexcept override { close(); }
331
332 uint64_t tellg() const noexcept override { return m_offset; }
333
334 bool has_content_size() const noexcept override { return true; }
335
336 uint64_t content_size() const noexcept override { return m_source.size(); }
337
338 std::string to_string() const noexcept override;
339
340 private:
341 io::secure_vector<uint8_t> m_source;
342 size_t m_offset;
343 };
344
345 /**
346 * File based byte input stream, including named file descriptor.
347 *
348 * Implementation mimics std::ifstream via OS level file descriptor (FD) operations,
349 * giving more flexibility, allowing reusing existing FD and enabling openat() operations.
350 *
351 * If source path denotes a named file descriptor, i.e. jau::fs::file_stats::is_fd() returns true,
352 * has_content_size() returns false and available() returns true as long the stream is open and EOS hasn't occurred.
353 */
354 class ByteInStream_File final : public ByteInStream {
355 private:
357
358 int m_fd;
359
360 bool m_has_content_length;
361 uint64_t m_content_size;
362 uint64_t m_bytes_consumed;
363 uint64_t get_available() const noexcept { return m_has_content_length ? m_content_size - m_bytes_consumed : 0; }
364
365 public:
366 [[nodiscard]] size_t read(void*, size_t) noexcept override;
367 [[nodiscard]] size_t peek(void*, size_t, size_t) noexcept override;
368 bool available(size_t n) noexcept override;
369
370 bool is_open() const noexcept override { return 0 <= m_fd; }
371
372 std::string id() const noexcept override { return stats.path(); }
373
374 /**
375 * Returns the file descriptor if is_open(), otherwise -1 for no file descriptor.
376 *
377 * @see is_open()
378 */
379 int fd() const noexcept { return m_fd; }
380
381 /**
382 * Construct a stream based byte input stream from filesystem path
383 *
384 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
385 * the leading `file://` is cut off and the remainder being used.
386 *
387 * @param path the path to the file, maybe a local file URI
388 */
389 ByteInStream_File(const std::string& path) noexcept;
390
391 /**
392 * Construct a stream based byte input stream from filesystem path and parent directory file descriptor
393 *
394 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
395 * the leading `file://` is cut off and the remainder being used.
396 *
397 * @param dirfd parent directory file descriptor
398 * @param path the path to the file, maybe a local file URI
399 */
400 ByteInStream_File(const int dirfd, const std::string& path) noexcept;
401
402 /**
403 * Construct a stream based byte input stream by duplicating given file descriptor
404 *
405 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
406 * the leading `file://` is cut off and the remainder being used.
407 *
408 * @param fd file descriptor to duplicate leaving the given `fd` untouched
409 */
410 ByteInStream_File(const int fd) noexcept;
411
413
415
416 void close() noexcept override;
417
418 ~ByteInStream_File() noexcept override { close(); }
419
420 uint64_t tellg() const noexcept override { return m_bytes_consumed; }
421
422 bool has_content_size() const noexcept override { return m_has_content_length; }
423
424 uint64_t content_size() const noexcept override { return m_content_size; }
425
426 std::string to_string() const noexcept override;
427 };
428
429 /**
430 * Ringbuffer-Based byte input stream with a URL connection provisioned data feed.
431 *
432 * Standard implementation uses [curl](https://curl.se/),
433 * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported,
434 * jau::io::uri::supported_protocols().
435 */
436 class ByteInStream_URL final : public ByteInStream {
437 public:
438 /**
439 * Check whether n bytes are available in the input stream.
440 *
441 * Wait up to timeout duration set in constructor until n bytes become available, where fractions_i64::zero waits infinitely.
442 *
443 * This method is blocking.
444 *
445 * @param n byte count to wait for
446 * @return true if n bytes are available, otherwise false
447 *
448 * @see read()
449 * @see @ref byte_in_stream_properties "ByteInStream Properties"
450 */
451 bool available(size_t n) noexcept override;
452
453 /**
454 * Read from the source. Moves the internal offset so that every
455 * call to read will return a new portion of the source.
456 *
457 * Use available() to wait and ensure a certain amount of bytes are available.
458 *
459 * This method is not blocking beyond the transfer of `min(available, length)` bytes.
460 *
461 * @param out the byte array to write the result to
462 * @param length the length of the byte array out
463 * @return length in bytes that was actually read and put into out
464 *
465 * @see available()
466 * @see @ref byte_in_stream_properties "ByteInStream Properties"
467 */
468 [[nodiscard]] size_t read(void* out, size_t length) noexcept override;
469
470 [[nodiscard]] size_t peek(void* out, size_t length, size_t peek_offset) noexcept override;
471
472 iostate rdstate() const noexcept override;
473
474 std::string id() const noexcept override { return m_url; }
475
476 /**
477 * Construct a ringbuffer backed Http byte input stream
478 * @param url the URL of the data to read
479 * @param timeout maximum duration in fractions of seconds to wait @ available() for next bytes, where fractions_i64::zero waits infinitely
480 */
481 ByteInStream_URL(std::string url, const jau::fraction_i64& timeout) noexcept;
482
484
486
487 bool is_open() const noexcept override;
488
489 void close() noexcept override;
490
491 ~ByteInStream_URL() noexcept override { close(); }
492
493 uint64_t tellg() const noexcept override { return m_bytes_consumed; }
494
495 bool has_content_size() const noexcept override { return m_has_content_length; }
496
497 uint64_t content_size() const noexcept override { return m_content_size; }
498
499 std::string to_string() const noexcept override;
500
501 private:
502 uint64_t get_available() const noexcept { return m_has_content_length ? m_content_size - m_bytes_consumed : 0; }
503 std::string to_string_int() const noexcept;
504
505 const std::string m_url;
506 jau::fraction_i64 m_timeout;
507 ByteRingbuffer m_buffer;
508 jau::io::url_header_sync m_header_sync;
509 jau::relaxed_atomic_bool m_has_content_length;
510 jau::relaxed_atomic_uint64 m_content_size;
511 jau::relaxed_atomic_uint64 m_total_xfered;
513 std::unique_ptr<std::thread> m_url_thread;
514 uint64_t m_bytes_consumed;
515 };
516
517 /**
518 * Parses the given path_or_uri, if it matches a supported protocol, see jau::io::uri::protocol_supported(),
519 * but is not a local file, see jau::io::uri::is_local_file_protocol(), ByteInStream_URL is being attempted.
520 *
521 * If the above fails, ByteInStream_File is attempted.
522 *
523 * If non of the above leads to a ByteInStream without ByteInStream::fail(), nullptr is returned.
524 *
525 * @param path_or_uri given path or uri for with a ByteInStream instance shall be established.
526 * @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
527 * @return a working ByteInStream w/o ByteInStream::fail() or nullptr
528 */
529 std::unique_ptr<ByteInStream> to_ByteInStream(const std::string& path_or_uri, jau::fraction_i64 timeout=20_s) noexcept;
530
531 /**
532 * Ringbuffer-Based byte input stream with an externally provisioned data feed.
533 */
534 class ByteInStream_Feed final : public ByteInStream {
535 public:
536 /**
537 * Check whether n bytes are available in the input stream.
538 *
539 * Wait up to timeout duration set in constructor until n bytes become available, where fractions_i64::zero waits infinitely.
540 *
541 * This method is blocking.
542 *
543 * @param n byte count to wait for
544 * @return true if n bytes are available, otherwise false
545 *
546 * @see read()
547 * @see @ref byte_in_stream_properties "ByteInStream Properties"
548 */
549 bool available(size_t n) noexcept override;
550
551 /**
552 * Read from the source. Moves the internal offset so that every
553 * call to read will return a new portion of the source.
554 *
555 * Use available() to wait and ensure a certain amount of bytes are available.
556 *
557 * This method is not blocking beyond the transfer of `min(available, length)` bytes.
558 *
559 * @param out the byte array to write the result to
560 * @param length the length of the byte array out
561 * @return length in bytes that was actually read and put into out
562 *
563 * @see available()
564 * @see @ref byte_in_stream_properties "ByteInStream Properties"
565 */
566 [[nodiscard]] size_t read(void* out, size_t length) noexcept override;
567
568 [[nodiscard]] size_t peek(void* out, size_t length, size_t peek_offset) noexcept override;
569
570 iostate rdstate() const noexcept override;
571
572 std::string id() const noexcept override { return m_id; }
573
574 /**
575 * Construct a ringbuffer backed externally provisioned byte input stream
576 * @param id_name arbitrary identifier for this instance
577 * @param timeout maximum duration in fractions of seconds to wait @ available() and write(), where fractions_i64::zero waits infinitely
578 */
579 ByteInStream_Feed(std::string id_name, const jau::fraction_i64& timeout) noexcept;
580
582
584
585 bool is_open() const noexcept override;
586
587 void close() noexcept override;
588
589 ~ByteInStream_Feed() noexcept override { close(); }
590
591 uint64_t tellg() const noexcept override { return m_bytes_consumed; }
592
593 bool has_content_size() const noexcept override { return m_has_content_length; }
594
595 uint64_t content_size() const noexcept override { return m_content_size; }
596
597 /**
598 * Interrupt a potentially blocked reader.
599 *
600 * Call this method if intended to abort streaming and to interrupt the reader thread's potentially blocked available() call,
601 * i.e. done at set_eof()
602 *
603 * @see set_eof()
604 */
605 void interruptReader() noexcept {
606 m_buffer.interruptReader();
607 }
608
609 /**
610 * Write given bytes to the async ringbuffer using explicit given timeout.
611 *
612 * Wait up to explicit given timeout duration until ringbuffer space is available, where fractions_i64::zero waits infinitely.
613 *
614 * This method is blocking.
615 *
616 * @param n byte count to wait for
617 * @param in the byte array to transfer to the async ringbuffer
618 * @param length the length of the byte array in
619 * @param timeout explicit given timeout for async ringbuffer put operation
620 * @return true if successful, otherwise false on timeout or stopped feeder and subsequent calls to good() will return false.
621 */
622 [[nodiscard]] bool write(uint8_t in[], size_t length, const jau::fraction_i64& timeout) noexcept;
623
624 /**
625 * Write given bytes to the async ringbuffer.
626 *
627 * Wait up to timeout duration set in constructor until ringbuffer space is available, where fractions_i64::zero waits infinitely.
628 *
629 * This method is blocking.
630 *
631 * @param n byte count to wait for
632 * @param in the byte array to transfer to the async ringbuffer
633 * @param length the length of the byte array in
634 * @return true if successful, otherwise false on timeout or stopped feeder and subsequent calls to good() will return false.
635 */
636 [[nodiscard]] bool write(uint8_t in[], size_t length) noexcept {
637 return write(in, length, m_timeout);
638 }
639
640 /**
641 * Set known content size, informal only.
642 * @param content_length the content size in bytes
643 */
644 void set_content_size(const uint64_t size) noexcept {
645 m_content_size = size;
646 m_has_content_length = true;
647 }
648
649 /**
650 * Set end-of-data (EOS), i.e. when feeder completed provisioning bytes.
651 *
652 * Implementation issues interruptReader() to unblock a potentially blocked reader thread.
653 *
654 * @param result should be either result_t::FAILED or result_t::SUCCESS.
655 *
656 * @see interruptReader()
657 */
658 void set_eof(const async_io_result_t result) noexcept;
659
660 std::string to_string() const noexcept override;
661
662 private:
663 uint64_t get_available() const noexcept { return m_has_content_length ? m_content_size - m_bytes_consumed : 0; }
664 std::string to_string_int() const noexcept;
665
666 const std::string m_id;
667 jau::fraction_i64 m_timeout;
668 ByteRingbuffer m_buffer;
669 jau::relaxed_atomic_bool m_has_content_length;
670 jau::relaxed_atomic_uint64 m_content_size;
671 jau::relaxed_atomic_uint64 m_total_xfered;
673 uint64_t m_bytes_consumed;
674 };
675
676 /**
677 * Wrapped byte input stream with the capability
678 * to record the read byte stream at will.
679 *
680 * Peek'ed bytes won't be recorded, only read bytes.
681 */
682 class ByteInStream_Recorder final : public ByteInStream {
683 public:
684 [[nodiscard]] size_t read(void*, size_t) noexcept override;
685
686 [[nodiscard]] size_t peek(void* out, size_t length, size_t peek_offset) noexcept override {
687 return m_parent.peek(out, length, peek_offset);
688 }
689
690 bool available(size_t n) noexcept override {
691 return m_parent.available(n);
692 }
693
694 void clear(const iostate state = iostate::goodbit) noexcept override { m_parent.clear( state ); }
695 iostate rdstate() const noexcept override { return m_parent.rdstate(); }
696
697 std::string id() const noexcept override { return m_parent.id(); }
698
699 /**
700 * Construct a byte input stream wrapper using the given parent ByteInStream.
701 * @param parent the parent ByteInStream
702 * @param buffer a user defined buffer for the recording
703 */
705 : m_parent(parent), m_bytes_consumed(0), m_buffer(buffer), m_rec_offset(0), m_is_recording(false) {};
706
708
710
711 bool is_open() const noexcept override { return m_parent.is_open(); }
712
713 void close() noexcept override;
714
715 ~ByteInStream_Recorder() noexcept override { close(); }
716
717 uint64_t tellg() const noexcept override { return m_bytes_consumed; }
718
719 bool has_content_size() const noexcept override { return m_parent.has_content_size(); }
720
721 uint64_t content_size() const noexcept override { return m_parent.content_size(); }
722
723 /**
724 * Starts the recording.
725 * <p>
726 * A potential previous recording will be cleared.
727 * </p>
728 */
729 void start_recording() noexcept;
730
731 /**
732 * Stops the recording.
733 * <p>
734 * The recording persists.
735 * </p>
736 */
737 void stop_recording() noexcept;
738
739 /**
740 * Clears the recording.
741 * <p>
742 * If the recording was ongoing, also stops the recording.
743 * </p>
744 */
745 void clear_recording() noexcept;
746
747 /** Returns the reference of the recording buffer given by user. */
748 io::secure_vector<uint8_t>& get_recording() noexcept { return m_buffer; }
749
750 size_t get_bytes_recorded() noexcept { return m_buffer.size(); }
751
752 /** Returns the recording start position. */
753 uint64_t get_recording_start_pos() noexcept { return m_rec_offset; }
754
755 bool is_recording() noexcept { return m_is_recording; }
756
757 std::string to_string() const noexcept override;
758
759 private:
760 ByteInStream& m_parent;
761 uint64_t m_bytes_consumed;
762 io::secure_vector<uint8_t>& m_buffer;
763 uint64_t m_rec_offset;
764 bool m_is_recording;
765 };
766
767 /**
768 * Abstract byte output stream object,
769 * to write data to a sink.
770 *
771 * All method implementations are of `noexcept`.
772 *
773 * One may use fail() to detect whether an error has occurred.
774 */
776 {
777 public:
778 ByteOutStream() = default;
779 ~ByteOutStream() noexcept override = default;
780 ByteOutStream& operator=(const ByteOutStream&) = delete;
781 ByteOutStream(const ByteOutStream&) = delete;
782
783 /** Checks if the stream has an associated file. */
784 virtual bool is_open() const noexcept = 0;
785
786 /**
787 * Close the stream if supported by the underlying mechanism.
788 */
789 virtual void close() noexcept = 0;
790
791 /**
792 * Write to the data sink. Moves the internal offset so that every
793 * call to write will be appended to the sink.
794 *
795 * This method is not blocking beyond the transfer length bytes.
796 *
797 * @param in the input bytes to write out
798 * @param length the length of the byte array in
799 * @return length in bytes that were actually written
800 */
801 [[nodiscard]] virtual size_t write(const void* in, size_t length) noexcept = 0;
802
803 /**
804 * Write one byte.
805 * @param in the byte to be written
806 * @return true if one byte has been written, otherwise false
807 */
808 [[nodiscard]] bool write(const uint8_t& in) noexcept;
809
810 /**
811 * return the id of this data source
812 * @return std::string representing the id of this data source
813 */
814 virtual std::string id() const noexcept { return ""; }
815
816 /**
817 * Returns the output position indicator.
818 *
819 * @return number of bytes written so far.
820 */
821 virtual uint64_t tellp() const noexcept = 0;
822
823 virtual std::string to_string() const noexcept = 0;
824 };
825
826 /**
827 * File based byte output stream, including named file descriptor.
828 */
829 class ByteOutStream_File final : public ByteOutStream {
830 private:
832 /**
833 * We mimic std::ofstream via OS level file descriptor operations,
834 * giving us more flexibility and enabling use of openat() operations.
835 */
836 int m_fd;
837
838 // Remember: constexpr specifier used in a function or static data member (since C++17) declaration implies inline
839
840 public:
841 bool is_open() const noexcept override { return 0 <= m_fd; }
842
843 [[nodiscard]] size_t write(const void*, size_t) noexcept override;
844
845 std::string id() const noexcept override { return stats.path(); }
846
847 /**
848 * Returns the file descriptor if is_open(), otherwise -1 for no file descriptor.
849 *
850 * @see is_open()
851 */
852 int fd() const noexcept { return m_fd; }
853
854 /**
855 * Construct a stream based byte output stream from filesystem path,
856 * either an existing or new file.
857 *
858 * In case the file already exists, the underlying file offset is positioned at the end of the file.
859 *
860 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
861 * the leading `file://` is cut off and the remainder being used.
862 *
863 * @param path the path to the file, maybe a local file URI
864 * @param mode file protection mode for a new file, otherwise ignored.
865 */
866 ByteOutStream_File(const std::string& path, const jau::fs::fmode_t mode = jau::fs::fmode_t::def_file_prot) noexcept;
867
868 /**
869 * Construct a stream based byte output stream from filesystem path and parent directory file descriptor,
870 * either an existing or new file.
871 *
872 * In case the file already exists, the underlying file offset is positioned at the end of the file.
873 *
874 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
875 * the leading `file://` is cut off and the remainder being used.
876 *
877 * @param dirfd parent directory file descriptor
878 * @param path the path to the file, maybe a local file URI
879 * @param mode file protection mode for a new file, otherwise ignored.
880 */
881 ByteOutStream_File(const int dirfd, const std::string& path, const jau::fs::fmode_t mode = jau::fs::fmode_t::def_file_prot) noexcept;
882
883 /**
884 * Construct a stream based byte output stream by duplicating given file descriptor
885 *
886 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
887 * the leading `file://` is cut off and the remainder being used.
888 *
889 * @param fd file descriptor to duplicate leaving the given `fd` untouched
890 */
891 ByteOutStream_File(const int fd) noexcept;
892
894
896
897 void close() noexcept override;
898
899 ~ByteOutStream_File() noexcept override { close(); }
900
901 uint64_t tellp() const noexcept override { return m_bytes_consumed; }
902
903 std::string to_string() const noexcept override;
904
905 private:
906 uint64_t m_bytes_consumed;
907 };
908
909
910 /**@}*/
911
912} // namespace elevator::io
913
914#endif /* JAU_BYTE_STREAM_HPP_ */
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
Ringbuffer-Based byte input stream with an externally provisioned data feed.
void set_content_size(const uint64_t size) noexcept
Set known content size, informal only.
ByteInStream_Feed & operator=(const ByteInStream_Feed &)=delete
uint64_t tellg() const noexcept override
Returns the input position indicator, similar to std::basic_istream.
void interruptReader() noexcept
Interrupt a potentially blocked reader.
bool has_content_size() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
ByteInStream_Feed(std::string id_name, const jau::fraction_i64 &timeout) noexcept
Construct a ringbuffer backed externally provisioned byte input stream.
void close() noexcept override
Close the stream if supported by the underlying mechanism.
ByteInStream_Feed(const ByteInStream_Feed &)=delete
bool write(uint8_t in[], size_t length) noexcept
Write given bytes to the async ringbuffer.
uint64_t content_size() const noexcept override
Returns the content_size if known.
std::string id() const noexcept override
return the id of this data source
File based byte input stream, including named file descriptor.
uint64_t content_size() const noexcept override
Returns the content_size if known.
ByteInStream_File(const std::string &path) noexcept
Construct a stream based byte input stream from filesystem path.
int fd() const noexcept
Returns the file descriptor if is_open(), otherwise -1 for no file descriptor.
ByteInStream_File(const ByteInStream_File &)=delete
std::string id() const noexcept override
return the id of this data source
bool is_open() const noexcept override
Checks if the stream has an associated file.
bool has_content_size() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
uint64_t tellg() const noexcept override
Returns the input position indicator, similar to std::basic_istream.
ByteInStream_File & operator=(const ByteInStream_File &)=delete
size_t get_bytes_recorded() noexcept
uint64_t tellg() const noexcept override
Returns the input position indicator, similar to std::basic_istream.
bool available(size_t n) noexcept override
Return whether n bytes are available in the input stream, if has_content_size() or using an asynchron...
iostate rdstate() const noexcept override
Returns the current state flags.
std::string id() const noexcept override
return the id of this data source
io::secure_vector< uint8_t > & get_recording() noexcept
Returns the reference of the recording buffer given by user.
bool is_open() const noexcept override
Checks if the stream has an associated file.
ByteInStream_Recorder(ByteInStream &parent, io::secure_vector< uint8_t > &buffer) noexcept
Construct a byte input stream wrapper using the given parent ByteInStream.
ByteInStream_Recorder & operator=(const ByteInStream_Recorder &)=delete
void clear(const iostate state=iostate::goodbit) noexcept override
Clears state flags by assignment to the given value.
size_t peek(void *out, size_t length, size_t peek_offset) noexcept override
Read from the source but do not modify the internal offset.
uint64_t get_recording_start_pos() noexcept
Returns the recording start position.
bool has_content_size() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
uint64_t content_size() const noexcept override
Returns the content_size if known.
ByteInStream_Recorder(const ByteInStream_Recorder &)=delete
bool has_content_size() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
uint64_t content_size() const noexcept override
Returns the content_size if known.
ByteInStream_SecMemory(io::secure_vector< uint8_t > in)
Construct a secure memory source that reads from a secure_vector.
ByteInStream_SecMemory(const std::string &in)
Construct a secure memory source that reads from a string.
uint64_t tellg() const noexcept override
Returns the input position indicator, similar to std::basic_istream.
ByteInStream_SecMemory(const std::vector< uint8_t > &in)
Construct a secure memory source that reads from a std::vector.
ByteInStream_SecMemory(const uint8_t in[], size_t length)
Construct a secure memory source that reads from a byte array.
bool is_open() const noexcept override
Checks if the stream has an associated file.
Ringbuffer-Based byte input stream with a URL connection provisioned data feed.
ByteInStream_URL(const ByteInStream_URL &)=delete
uint64_t tellg() const noexcept override
Returns the input position indicator, similar to std::basic_istream.
ByteInStream_URL & operator=(const ByteInStream_URL &)=delete
ByteInStream_URL(std::string url, const jau::fraction_i64 &timeout) noexcept
Construct a ringbuffer backed Http byte input stream.
uint64_t content_size() const noexcept override
Returns the content_size if known.
bool has_content_size() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
void close() noexcept override
Close the stream if supported by the underlying mechanism.
std::string id() const noexcept override
return the id of this data source
Abstract byte input stream object.
virtual void close() noexcept=0
Close the stream if supported by the underlying mechanism.
virtual bool has_content_size() const noexcept=0
Returns true if implementation is aware of content_size(), otherwise false.
virtual uint64_t content_size() const noexcept=0
Returns the content_size if known.
virtual size_t peek(void *out, size_t length, size_t peek_offset) noexcept=0
Read from the source but do not modify the internal offset.
virtual bool is_open() const noexcept=0
Checks if the stream has an associated file.
size_t discard(size_t N) noexcept
Discard the next N bytes of the data.
virtual uint64_t tellg() const noexcept=0
Returns the input position indicator, similar to std::basic_istream.
virtual std::string to_string() const noexcept=0
~ByteInStream() noexcept override=default
virtual size_t read(void *out, size_t length) noexcept=0
Read from the source.
virtual bool available(size_t n) noexcept=0
Return whether n bytes are available in the input stream, if has_content_size() or using an asynchron...
File based byte output stream, including named file descriptor.
ByteOutStream_File(const std::string &path, const jau::fs::fmode_t mode=jau::fs::fmode_t::def_file_prot) noexcept
Construct a stream based byte output stream from filesystem path, either an existing or new file.
ByteOutStream_File & operator=(const ByteOutStream_File &)=delete
std::string id() const noexcept override
return the id of this data source
int fd() const noexcept
Returns the file descriptor if is_open(), otherwise -1 for no file descriptor.
uint64_t tellp() const noexcept override
Returns the output position indicator.
bool is_open() const noexcept override
Checks if the stream has an associated file.
ByteOutStream_File(const ByteOutStream_File &)=delete
virtual bool is_open() const noexcept=0
Checks if the stream has an associated file.
virtual std::string to_string() const noexcept=0
virtual uint64_t tellp() const noexcept=0
Returns the output position indicator.
virtual size_t write(const void *in, size_t length) noexcept=0
Write to the data sink.
virtual void close() noexcept=0
Close the stream if supported by the underlying mechanism.
~ByteOutStream() noexcept override=default
bool fail() const noexcept
Checks if an error has occurred.
iostate_func & operator=(const iostate_func &o) noexcept=default
iostate_func & operator=(iostate_func &&o) noexcept=default
constexpr iostate rdstate_impl() const noexcept
iostate_func(iostate_func &&o) noexcept=default
void setstate(const iostate state) noexcept
Sets state flags, by keeping its previous bits.
bool good() const noexcept
Checks if no error nor eof() has occurred i.e.
bool bad() const noexcept
Checks if a non-recoverable error has occurred.
bool operator!() const noexcept
Checks if an error has occurred, synonym of fail().
virtual ~iostate_func() noexcept=default
bool eof() const noexcept
Checks if end-of-file has been reached.
bool timeout() const noexcept
Checks if a timeout (non-recoverable) has occurred.
iostate_func(const iostate_func &o) noexcept=default
virtual iostate rdstate() const noexcept
Returns the current state flags.
virtual void clear(const iostate state=iostate::goodbit) noexcept
Clears state flags by assignment to the given value.
constexpr void setstate_impl(iostate state) const noexcept
ordered_atomic< bool, std::memory_order_relaxed > relaxed_atomic_bool
Relaxed non-SC atomic integral scalar boolean.
ordered_atomic< uint64_t, std::memory_order_relaxed > relaxed_atomic_uint64
Relaxed non-SC atomic integral scalar uint64_t.
#define JAU_MAKE_BITFIELD_ENUM_STRING(type,...)
constexpr E & write(E &store, const E bits, bool set) noexcept
If set==true, sets the bits in store, i.e.
fmode_t
Generic file type and POSIX protection mode bits as used in file_stats, touch(), mkdir() etc.
@ def_file_prot
Default file protection bit: Safe default: POSIX S_IRUSR | S_IWUSR | S_IRGRP or read_usr | write_usr ...
fraction< int64_t > fraction_i64
fraction using int64_t as integral type
std::unique_ptr< ByteInStream > to_ByteInStream(const std::string &path_or_uri, jau::fraction_i64 timeout=20_s) noexcept
Parses the given path_or_uri, if it matches a supported protocol, see jau::io::uri::protocol_supporte...
async_io_result_t
Asynchronous I/O operation result value.
Definition io_util.hpp:68
jau::ringbuffer< uint8_t, size_t > ByteRingbuffer
Definition io_util.hpp:50
std::vector< T, jau::callocator_sec< T > > secure_vector
Definition io_util.hpp:46
jau::ordered_atomic< async_io_result_t, std::memory_order_relaxed > relaxed_atomic_async_io_result_t
Definition io_util.hpp:78
@ goodbit
No error occurred nor has EOS being reached.
@ none
No error occurred nor has EOS being reached.
@ failbit
Input or output operation failed (formatting or extraction error).
@ eofbit
An input operation reached the end of its stream.
@ timeout
Input or output operation failed due to timeout.
@ badbit
Irrecoverable stream error, including loss of integrity of the underlying stream or media.
Author: Sven Gothel sgothel@jausoft.com Copyright Gothel Software e.K.
Definition enum_util.hpp:65
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
STL namespace.