jaulib v1.4.0-2-g788cf73
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-2025 Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11
12#ifndef JAU_IO_BYTE_STREAM_HPP_
13#define JAU_IO_BYTE_STREAM_HPP_
14
15#include <cstdint>
16#include <string>
17
18#include <jau/basic_types.hpp>
19#include <jau/byte_util.hpp>
20#include <jau/enum_util.hpp>
21#include <jau/io/file_util.hpp>
22#include <jau/io/io_util.hpp>
23#include <jau/ringbuffer.hpp>
24
25using namespace jau::fractions_i64_literals;
26
27namespace jau::io {
28
29 using namespace jau::enums;
30
31 /** \addtogroup IOUtils
32 *
33 * @{
34 */
35
36 /*
37 * Mimic std::ios_base::iostate for state functionality, see iostate_func.
38 *
39 * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
40 */
41 enum class iostate_t : uint32_t {
42 /** No error occurred nor has EOS being reached. Value is no bit set! */
43 none = 0,
44
45 /** No error occurred nor has EOS being reached. Value is no bit set! */
47
48 /** Irrecoverable stream error, including loss of integrity of the underlying stream or media. */
49 badbit = 1U << 0,
50
51 /** An input operation reached the end of its stream (EOS). */
52 eofbit = 1U << 1,
53
54 /** Input or output operation failed (formatting or extraction error). */
55 failbit = 1U << 2,
56
57 /** Input or output operation failed due to timeout. */
58 timeout = 1U << 3
59 };
61
62 /** Stream I/O mode, e.g. read and/or write. */
63 enum class iomode_t : uint32_t {
64 /** No capabilities */
65 none = 0,
66 /** Read capabilities */
67 read = 1U << 0,
68 /** Write capabilities */
69 write = 1U << 1,
70 /** Read and write capabilities, i.e. `read|write` */
72 /** Seek to end of (file) stream when opened */
73 atend = 1U << 2,
74 /** Truncate existing (file) stream when opened with write */
75 trunc = 1U << 3,
76 /** Write capabilities and truncate existing (file) stream, i.e. `write|trunc` */
78 };
80
81 /**
82 * Supporting std::basic_ios's iostate capabilities for all ByteStream implementations.
83 */
84 class IOStateCap {
85 private:
86 iostate_t m_state;
87
88 protected:
89 constexpr iostate_t rdstate_impl() const noexcept { return m_state; }
90 constexpr void addstate_impl(iostate_t state) const noexcept { const_cast<IOStateCap*>(this)->m_state |= state; }
91
92 public:
93 IOStateCap() noexcept
94 : m_state(iostate_t::goodbit) { }
95
96 IOStateCap(const IOStateCap& o) noexcept = default;
97 IOStateCap(IOStateCap&& o) noexcept = default;
98 IOStateCap& operator=(const IOStateCap& o) noexcept = default;
99 IOStateCap& operator=(IOStateCap&& o) noexcept = default;
100
101 virtual ~IOStateCap() noexcept = default;
102
103 /**
104 * Clears state flags by assignment to the given value.
105 *
106 * \deprecated { Use assignState() for clarity. }
107 *
108 * @see assignState()
109 */
110 void clear(const iostate_t state = iostate_t::goodbit) noexcept { assignState(state); }
111
112 /** Assigns given state to current value. */
113 virtual void assignState(const iostate_t state = iostate_t::goodbit) noexcept { m_state = state; }
114
115 /** Clears given state flags from current value. */
116 void clearStateFlags(const iostate_t clr) noexcept { assignState(rdstate() & ~clr); }
117
118 /**
119 * Returns the current state flags.
120 *
121 * Method is marked `virtual` to allow implementations with asynchronous resources
122 * to determine or update the current iostate.
123 *
124 * Method is used throughout all query members and addState(),
125 * hence they all will use the updated state from a potential override implementation.
126 */
127 virtual iostate_t rdstate() const noexcept { return rdstate_impl(); }
128
129 /**
130 * Sets state flags, by keeping its previous bits.
131 *
132 * \deprecated { Use addState() for clarity. }
133 *
134 * @see addState()
135 */
136 void setstate(const iostate_t state) noexcept { addState(state); }
137
138 /** Adds given state flags to existing rdstate() bits. */
139 void addState(const iostate_t state) noexcept { assignState(rdstate() | state); }
140
141 /** Checks if no error nor eof() has occurred i.e. I/O operations are available. */
142 bool good() const noexcept { return iostate_t::goodbit == rdstate(); }
143
144 /** Checks if end-of-file has been reached. */
145 bool eof() const noexcept { return iostate_t::none != (rdstate() & iostate_t::eofbit); }
146
147 /** Checks if an error has occurred. */
149
150 /** Checks if an error has occurred, synonym of fail(). */
151 bool operator!() const noexcept { return fail(); }
152
153 /** Checks if no error has occurred, synonym of !fail(). */
154 explicit operator bool() const noexcept { return !fail(); }
155
156 /** Checks if a non-recoverable error has occurred. */
157 bool bad() const noexcept { return iostate_t::none != (rdstate() & iostate_t::badbit); }
158
159 /** Checks if a timeout (non-recoverable) has occurred. */
160 bool timeout() const noexcept { return iostate_t::none != (rdstate() & iostate_t::timeout); }
161 };
162
163 /**
164 * Byte stream interface.
165 *
166 * @anchor byte_in_stream_properties
167 * ### ByteInStream Properties
168 * The byte input stream can originate from a local source w/o delay,
169 * remote URL like http connection or even from another thread feeding the input buffer.<br />
170 * Both latter asynchronous resources may expose blocking properties
171 * in available().
172 *
173 * Asynchronous resources benefit from knowing their content size,
174 * as their available() implementation may avoid
175 * blocking and waiting for requested bytes available
176 * if the stream is already beyond its scope.
177 *
178 * All method implementations are of `noexcept`.
179 *
180 * One may use fail() to detect whether an error has occurred,
181 * while end_of_data() not only covers the end-of-stream (EOS) case but includes fail().
182 *
183 * @see @ref byte_in_stream_properties "ByteInStream Properties"
184 */
185 class ByteStream : public IOStateCap {
186 public:
187 /// uint64_t size data type, bit position and count
188 typedef uint64_t size_type;
189
190 protected:
193
194 /// Fallback slow discard implementation usind read() in case of unknown stream size.
195 size_t discardRead(size_t n) noexcept;
196
197 public:
198 /** Invalid position constant, denoting unset mark() or invalid position. Value: `std::numeric_limits<size_type>::max()` */
199 constexpr static size_type npos = std::numeric_limits<size_type>::max();
200
201 /**
202 * @param mode iomode_t
203 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
204 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
205 */
208
209 ~ByteStream() noexcept override = default;
210
211 constexpr iomode_t mode() const noexcept { return m_iomode; }
212
213 /** Clears iomode_t::write from mode() */
214 void setImmutable() noexcept { m_iomode &= ~iomode_t::write; }
215
216 /**
217 * Returns endian byte-order of stream storage.
218 *
219 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc.
220 */
221 constexpr lb_endian_t byteOrder() const noexcept { return m_byteOrder; }
222
223 /** Returns true in case stream has iomode::read capabilities. */
224 constexpr bool canRead() const noexcept { return is_set(m_iomode, iomode_t::read); }
225
226 /** Returns true in case stream has iomode::write capabilities. */
227 constexpr bool canWrite() const noexcept { return is_set(m_iomode, iomode_t::write); }
228
229 /** Checks if the stream has an associated file. */
230 virtual bool isOpen() const noexcept = 0;
231
232 /**
233 * Close the stream if supported by the underlying mechanism.
234 */
235 virtual void close() noexcept = 0;
236
237 /**
238 * return the id of this data source
239 * @return std::string representing the id of this data source
240 */
241 virtual std::string id() const noexcept { return ""; }
242
243 /**
244 * Returns true if implementation is aware of content_size(), otherwise false.
245 * @see content_size()
246 */
247 virtual bool hasContentSize() const noexcept = 0;
248
249 /**
250 * Returns the content_size if known.
251 * @see has_content_size()
252 */
253 virtual size_type contentSize() const noexcept = 0;
254
255 /**
256 * Returns the position indicator, similar to e.g. std::basic_istream.
257 *
258 * @return number of bytes read or written so far.
259 */
260 virtual size_type position() const noexcept = 0;
261
262 /**
263 * Returns the remaining bytes, i.e. content_size() - position(), if content_size if known, otherwise zero.
264 * @see has_content_size()
265 * @see content_size()
266 * @see position()
267 */
268 virtual size_type remaining() const noexcept { return hasContentSize() ? contentSize() - position() : 0; }
269
270 /**
271 * Return true if implementation supports random rewinding the stream, i.e. seek() below position().
272 *
273 * If random rewind is not supported and method returns false,
274 * one can still rewind in range [mark() .. position()).
275 *
276 * @see seek()
277 * @see setMark()
278 */
279 virtual bool canRewind() const noexcept = 0;
280
281 /**
282 * Sets position indicator for output-streams or input-streams with known length, similar to e.g. std::basic_istream.
283 *
284 * No change occurs if fail() was set or the input-stream has no known length.
285 *
286 * If newPos is >= stream-length, iostate::eofbit is set and position set to stream-length,
287 * otherwise iostate::eofbit is cleared.
288 *
289 * Certain implementations may not allow random rewinding of the stream, see canRewind().
290 * In this case, rewinding is limited to mark(), see setMark(), and may return ByteStream::npos if none set or exceeding range.
291 *
292 * A ByteInStream's mark is cleared if > newPos.
293 *
294 * @param newPos desired absolute byte-offset (position)
295 * @return resulting position if successful (incl eofbit) or ByteStream::npos otherwise having an unchanged position().
296 * @see canRewind()
297 * @see setMark()
298 */
299 [[nodiscard]] virtual size_type seek(size_type newPos) noexcept = 0;
300
301 virtual std::string toString() const noexcept = 0;
302
303 //
304 // I/O
305 //
306
307 /**
308 * Set `markpos` to current position, allowing the stream to be seekMark().
309 *
310 * seek() will clear `markpos` if > newPos.
311 *
312 * For implementations where seek() doesn't allow random rewinding of the stream,
313 * setMark() will allow rewinding back to `markpos` if not exceeding `readLimit`.
314 *
315 * @param readlimit maximum number of bytes able to read before invalidating the `markpos`.
316 * @return true if marks is set successfully, otherwise false
317 * @see seek()
318 * @see canRewind()
319 */
320 [[nodiscard]] virtual bool setMark(size_type readLimit) noexcept = 0;
321
322 /** Returns the `markpos` set via setMark() or ByteStream::npos if unset. */
323 virtual size_type mark() const noexcept = 0;
324
325 /** Returns the `readLimit` set via setMark(). If unset either 0 or implicit limit. */
326 virtual size_type markReadLimit() const noexcept = 0;
327
328 /**
329 * Seeks stream position to `markpos` as set via setMark().
330 *
331 * `markpos` is kept, hence seekMark() can be called multiple times.
332 *
333 * @return true if successful (incl eofbit),
334 * otherwise false with unchanged position due to I/O failure (iostate::fail set) or setMark() not set.
335 */
336 [[nodiscard]] virtual bool seekMark() noexcept = 0;
337
338 //
339 // Input Stream
340 //
341
342 /**
343 * Return whether n bytes are available in the input stream,
344 * if has_content_size() or using an asynchronous source.
345 *
346 * If !has_content_size() and not being an asynchronous source,
347 * !end_of_data() is returned.
348 *
349 * Method may be blocking when using an asynchronous source
350 * up until the requested bytes are available.
351 *
352 * A subsequent call to read() shall return immediately with at least
353 * the requested numbers of bytes available,
354 * if has_content_size() or using an asynchronous source.
355 *
356 * See details of the implementing class.
357 *
358 * Input stream operation, returns false if !is_input().
359 *
360 * @param n byte count to wait for
361 * @return true if n bytes are available, otherwise false
362 *
363 * @see has_content_size()
364 * @see read()
365 * @see @ref byte_in_stream_properties "ByteInStream Properties"
366 */
367 virtual bool available(size_t n) noexcept = 0;
368
369 /**
370 * Read from the source. Moves the internal offset so that every
371 * call to read will return a new portion of the source.
372 *
373 * Use available() to try to wait for a certain amount of bytes available.
374 *
375 * This method shall only block until `min(available, length)` bytes are transfered.
376 *
377 * See details of the implementing class.
378 *
379 * Input stream operation, returns zero if !is_input().
380 *
381 * @param out the byte array to write the result to
382 * @param length the length of the byte array out
383 * @return length in bytes that was actually read and put into out
384 *
385 * @see available()
386 * @see @ref byte_in_stream_properties "ByteInStream Properties"
387 */
388 [[nodiscard]] virtual size_t read(void* out, size_t length) noexcept = 0;
389
390 /**
391 * Read one byte, `uint8_t`
392 * @param bits reference to result
393 * @return true if successful, otherwise false
394 */
395 [[nodiscard]] bool read(uint8_t& bits) noexcept {
396 return 1 != read(&bits, 1);
397 }
398
399 /**
400 * Read from the source but do not modify the internal
401 * offset. Consecutive calls to peek() will return portions of
402 * the source starting at the same position.
403 *
404 * Input stream operation, returns zero if !is_input().
405 *
406 * @param out the byte array to write the output to
407 * @param length the length of the byte array out
408 * @param peek_offset offset from current stream position to read at
409 * @return length in bytes that was actually read and put into out
410 */
411 [[nodiscard]] virtual size_t peek(void* out, size_t length, size_type peek_offset) noexcept = 0;
412
413 /**
414 * Peek one byte at current position
415 *
416 * Input stream operation, returns false if !is_input().
417 *
418 * @param out an output byte
419 * @return true if one byte has been peeked, false otherwise
420 */
421 [[nodiscard]] bool peek(uint8_t& out) noexcept {
422 return 1 == peek(&out, 1, 0);
423 }
424
425 /**
426 * Discard the next N bytes of the data
427 *
428 * Input stream operation, returns zero if !is_input().
429 *
430 * @param N the number of bytes to discard
431 * @return number of bytes actually discarded
432 */
433 [[nodiscard]] virtual size_t discard(size_t N) noexcept = 0;
434
435 /**
436 * Read `uint16_t`.
437 *
438 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
439 * @param bits reference to result
440 * @return true if successful, otherwise false
441 */
442 [[nodiscard]] bool readU16(uint16_t& bits) noexcept {
443 if ( 2 != read(&bits, 2) ) {
444 return false;
445 }
447 bits = jau::bswap(bits);
448 }
449 return true;
450 }
451 /**
452 * Read `int16_t`.
453 *
454 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
455 * @param bits reference to result
456 * @return true if successful, otherwise false
457 */
458 [[nodiscard]] bool readS16(int16_t& bits) noexcept { return readU16( *reinterpret_cast<uint16_t*>(&bits) ); }
459
460 /**
461 * Read incoming `uint32_t`.
462 *
463 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
464 * @param bits reference to result
465 * @return true if successful, otherwise false
466 */
467 [[nodiscard]] bool readU32(uint32_t& bits) noexcept {
468 if ( 4 != read(&bits, 4) ) {
469 return false;
470 }
472 bits = jau::bswap(bits);
473 }
474 return true;
475 }
476 /**
477 * Read `int32_t`.
478 *
479 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
480 * @param bits reference to result
481 * @return true if successful, otherwise false
482 */
483 [[nodiscard]] bool readS32(int32_t& bits) noexcept { return readU32( *reinterpret_cast<uint32_t*>(&bits) ); }
484
485 /**
486 * Read incoming `uint64_t` w/o considering `bigEndian`, i.e. no byte swap is performed.
487 * @param bits reference to result
488 * @return true if successful, otherwise false
489 */
490 [[nodiscard]] bool readU64Raw(uint64_t &bits) noexcept {
491 if ( 4 != read(&bits, 8) ) {
492 return false;
493 }
494 return true;
495 }
496 /**
497 * Read incoming `uint64_t`.
498 *
499 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
500 * @param bits reference to result
501 * @return true if successful, otherwise false
502 */
503 [[nodiscard]] bool readU64(uint64_t &bits) noexcept {
504 if ( 4 != read(&bits, 8) ) {
505 return false;
506 }
508 bits = jau::bswap(bits);
509 }
510 return true;
511 }
512 /**
513 * Read `int64_t`.
514 *
515 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
516 *
517 * @param bits reference to result
518 * @return true if successful, otherwise false
519 */
520 [[nodiscard]] bool readS64(int64_t &bits) noexcept { return readU64(*reinterpret_cast<uint64_t *>(&bits)); }
521
522 //
523 // Output Stream
524 //
525
526 /**
527 * Write to the data sink. Moves the internal offset so that every
528 * call to write will be appended to the sink.
529 *
530 * This method is not blocking beyond the transfer length bytes.
531 *
532 * Output stream operation, returns zero if !is_output().
533 *
534 * @param in the input bytes to write out
535 * @param length the length of the byte array in
536 * @return length in bytes that were actually written
537 */
538 [[nodiscard]] virtual size_t write(const void* in, size_t length) noexcept = 0;
539
540 /**
541 * Write one byte, `uint8_t`.
542 *
543 * Output stream operation, returns false if !is_output().
544 *
545 * @param in the byte to be written
546 * @return true if one byte has been written, otherwise false
547 */
548 [[nodiscard]] bool write(uint8_t in) noexcept {
549 return 1 == write(&in, 1);
550 }
551
552 /**
553 * Synchronizes all output operations, or do nothing.
554 */
555 virtual void flush() noexcept = 0;
556
557 /**
558 * Write the given `uint16_t`.
559 *
560 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
561 *
562 * @param bits data to write
563 * @return true if successful, otherwise false
564 */
565 [[nodiscard]] bool writeU16(uint16_t bits) noexcept {
567 bits = jau::bswap(bits);
568 }
569 return 2 == write(&bits, 2);
570 }
571 /**
572 * Write the given `int16_t`.
573 *
574 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
575 *
576 * @param bits data to write
577 * @return true if successful, otherwise false
578 */
579 [[nodiscard]] bool writeS16(int16_t bits) noexcept { return writeU16(*reinterpret_cast<uint16_t*>(&bits)); }
580
581 /**
582 * Write the given `uint32_t`.
583 *
584 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
585 *
586 * @param bits data to write
587 * @return true if successful, otherwise false
588 */
589 [[nodiscard]] bool writeU32(uint32_t bits) noexcept {
591 bits = jau::bswap(bits);
592 }
593 return 4 == write(&bits, 4);
594 }
595 /**
596 * Write the given `int32_t`.
597 *
598 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
599 *
600 * @param bits data to write
601 * @return true if successful, otherwise false
602 */
603 [[nodiscard]] bool writeS32(int32_t bits) noexcept { return writeU32(*reinterpret_cast<uint32_t*>(&bits)); }
604
605 /**
606 * Write the given `uint64_t` w/o considering `bigEndian`, i.e. no byte swap is performed.
607 *
608 * @param bits data to write
609 * @return true if successful, otherwise false
610 */
611 [[nodiscard]] bool writeU64Raw(uint64_t bits) noexcept {
612 return 8 == write(&bits, 8);
613 }
614 /**
615 * Write the given `uint64_t`.
616 *
617 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
618 *
619 * @param bits data to write
620 * @return true if successful, otherwise false
621 */
622 [[nodiscard]] bool writeU64(uint64_t bits) noexcept {
624 bits = jau::bswap(bits);
625 }
626 return 8 == write(&bits, 8);
627 }
628 /**
629 * Write the given `int64_t`.
630 *
631 * If stream byteOrder() != jau::lb_endian_t::native, result is bytes swapped via jau::bswap().
632 *
633 * @param bits data to write
634 * @return true if successful, otherwise false
635 */
636 [[nodiscard]] bool writeS64(int64_t bits) noexcept { return writeU64(*reinterpret_cast<uint64_t*>(&bits)); }
637 };
638
639 inline std::ostream& operator<<(std::ostream& os, const ByteStream& v) { return os << v.toString(); }
640
641 /**
642 * Secure Memory-Based byte input stream
643 */
644 class ByteStream_SecMemory final : public ByteStream {
645 public:
646 /**
647 * Construct a secure memory source that reads from a string, iomode_t::read.
648 * @param in the string to read from
649 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
650 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
651 */
652 explicit ByteStream_SecMemory(const std::string& in, lb_endian_t byteOrder=lb_endian_t::little);
653
654 /**
655 * Construct a secure memory source using a sized byte array
656 * @param length the length of the byte array
657 * @param iomode determines whether file should be opened iomode_t::read, iomode_t::write or iomode_t::rw
658 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
659 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
660 */
662 : ByteStream(mode, byteOrder), m_source(length), m_offset(0), m_mark(npos) { }
663
664 /**
665 * Construct a secure memory source copying data from a byte array
666 * @param in the byte array to read from, copied over
667 * @param length the length of the byte array
668 * @param iomode determines whether file should be opened iomode_t::read, iomode_t::write or iomode_t::rw
669 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
670 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
671 */
673 : ByteStream(mode, byteOrder), m_source(in, in + length), m_offset(0), m_mark(npos) { }
674
675 /**
676 * Construct a secure memory source copying data from a secure_vector
677 * @param in the MemoryRegion to read from, this instance assumes ownership
678 * @param iomode determines whether file should be opened iomode_t::read, iomode_t::write or iomode_t::rw
679 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
680 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
681 */
684
685 /**
686 * Construct a secure memory source copying data from a std::vector
687 * @param in the MemoryRegion to read from, copied over
688 * @param iomode determines whether file should be opened iomode_t::read, iomode_t::write or iomode_t::rw
689 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
690 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
691 */
693 : ByteStream(mode, byteOrder), m_source(in.begin(), in.end()), m_offset(0), m_mark(npos) { }
694
695 ~ByteStream_SecMemory() noexcept override { close(); }
696
697 bool isOpen() const noexcept override { return true; }
698
699 void close() noexcept override;
700
701 bool hasContentSize() const noexcept override { return true; }
702
703 size_type contentSize() const noexcept override { return m_source.size(); }
704
705 size_type position() const noexcept override { return m_offset; }
706
707 bool canRewind() const noexcept override { return true; }
708
709 [[nodiscard]] size_type seek(size_type newPos) noexcept override;
710
711 std::string toString() const noexcept override;
712
713 [[nodiscard]] bool setMark(size_type readLimit) noexcept override;
714 size_type mark() const noexcept override { return m_mark; }
715 size_type markReadLimit() const noexcept override { return contentSize(); }
716 [[nodiscard]] bool seekMark() noexcept override;
717
718 bool available(size_t n) noexcept override;
719 [[nodiscard]] size_t read(void*, size_t) noexcept override;
720 [[nodiscard]] size_t peek(void*, size_t, size_type) noexcept override;
721 [[nodiscard]] size_t discard(size_t N) noexcept override;
722
723 [[nodiscard]] size_t write(const void*, size_t) noexcept override;
724 void flush() noexcept override { }
725
726 private:
728 size_t m_offset;
729 size_type m_mark;
730 };
731
732 /**
733 * File based byte input stream, including named file descriptor.
734 *
735 * Implementation mimics std::ifstream via OS level file descriptor (FD) operations,
736 * giving more flexibility, allowing reusing existing FD and enabling openat() operations.
737 *
738 * If source path denotes a named file descriptor, i.e. jau::fs::file_stats::is_fd() returns true,
739 * has_content_size() returns false and available() returns true as long the stream is open and EOS hasn't occurred.
740 */
741 class ByteStream_File final : public ByteStream {
742 private:
744
745 int m_fd;
746
747 bool m_has_content_length;
748 size_type m_content_size;
749 size_type m_offset;
750 size_type m_mark;
751 size_type get_available() const noexcept { return m_has_content_length ? m_content_size - m_offset : 0; }
752
753 public:
754 /**
755 * Construct a stream based byte stream from filesystem path,
756 * either an existing or new file.
757 *
758 * In case the file already exists and iomode has iomode_t::atend, the underlying file offset is positioned at the end of the file.
759 *
760 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
761 * the leading `file://` is cut off and the remainder being used.
762 *
763 * @param path the path to the file, maybe a local file URI
764 * @param iomode determines whether file should be opened iomode_t::read, iomode_t::write or iomode_t::rw (default)
765 * @param fmode file protection mode for a new file, otherwise ignored. Defaults to fs::fmode_t::def_file_prot.
766 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
767 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
768 */
769 ByteStream_File(const std::string& path,
770 iomode_t iomode = iomode_t::rw,
773
774 /**
775 * Construct a stream based byte stream from filesystem path and parent directory file descriptor,
776 * either an existing or new file.
777 *
778 * In case the file already exists and iomode has iomode_t::atend, the underlying file offset is positioned at the end of the file.
779 *
780 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
781 * the leading `file://` is cut off and the remainder being used.
782 *
783 * @param dirfd parent directory file descriptor
784 * @param path the path to the file, maybe a local file URI
785 * @param iomode determines whether file should be opened iomode_t::read, iomode_t::write or iomode_t::rw (default)
786 * @param fmode file protection mode for a new file, otherwise ignored. Defaults to fs::fmode_t::def_file_prot.
787 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
788 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
789 */
790 ByteStream_File(const int dirfd, const std::string& path,
791 iomode_t iomode = iomode_t::rw,
794
795 /**
796 * Construct a stream based byte stream by duplicating given file descriptor
797 *
798 * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
799 * the leading `file://` is cut off and the remainder being used.
800 *
801 * @param fd file descriptor to duplicate leaving the given `fd` untouched
802 * @param iomode determines whether file descriptor is iomode_t::read, iomode_t::write or iomode_t::rw (default)
803 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
804 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
805 */
807
809
811
812 ~ByteStream_File() noexcept override { close(); }
813
814 const jau::io::fs::file_stats& stats() const noexcept { return m_stats; }
815
816 /**
817 * Returns the file descriptor if is_open(), otherwise -1 for no file descriptor.
818 *
819 * @see is_open()
820 */
821 int fd() const noexcept { return m_fd; }
822
823 bool isOpen() const noexcept override { return 0 <= m_fd; }
824 void close() noexcept override;
825 std::string id() const noexcept override { return m_stats.path(); }
826
827 bool hasContentSize() const noexcept override { return m_has_content_length; }
828 size_type contentSize() const noexcept override { return m_content_size; }
829 size_type position() const noexcept override { return m_offset; }
830 bool canRewind() const noexcept override { return true; }
831 [[nodiscard]] size_type seek(size_type newPos) noexcept override;
832 std::string toString() const noexcept override;
833
834 [[nodiscard]] bool setMark(size_type readLimit) noexcept override;
835 size_type mark() const noexcept override { return m_mark; }
836 size_type markReadLimit() const noexcept override { return contentSize(); }
837 [[nodiscard]] bool seekMark() noexcept override;
838
839 bool available(size_t n) noexcept override;
840 [[nodiscard]] size_t read(void*, size_t) noexcept override;
841 [[nodiscard]] size_t peek(void*, size_t, size_type) noexcept override;
842 [[nodiscard]] size_t discard(size_t N) noexcept override;
843
844 [[nodiscard]] size_t write(const void*, size_t) noexcept override;
845 void flush() noexcept override;
846 };
847
848 namespace impl {
849 /**
850 * Rewind buffer support for mark/setMark, read and reset/seekMark
851 *
852 * m - m_mark (stream space)
853 * o - m_offset (stream space)
854 * p - m_offset (stream space)
855 *
856 * g - got bytes (relative)
857 *
858 * q - m_offset - m_mark (buffer space, relative stream)
859 * r - m_end (buffer space, relative stream)
860 *
861 * <-- q = o-m ->
862 * <- g ->
863 * stream [0 ... m ... p ... o)
864 * buffer [0 ... q ... r)
865 */
867 private:
868 std::vector<uint8_t> m_buffer;
869 size_t m_end;
870
871 public:
873
874 typedef jau::function<size_t(void* out, size_t length)> DataProvider;
875
876 RewindBuffer() noexcept : m_buffer(0), m_end(0) {}
877
878 constexpr bool covered(const size_type m, size_type o) const noexcept {
879 return ByteStream::npos != m && m <= o && o < m + m_end;
880 }
881
882 constexpr size_type capacity() const noexcept { return m_buffer.size(); }
883 constexpr size_type end() const noexcept { return m_end; }
884 std::string toString() const noexcept {
885 return "Rew[end " + std::to_string(end()) + ", capacity " + std::to_string(capacity()) + "]";
886 }
887
888 bool setMark(const size_type m, size_type o, size_type readLimit) noexcept {
889 // DBG_PRINT("RewindBuffer.setMark.0 mark %" PRIu64 ", offset %" PRIu64 ", %s", m, o, toString().c_str());
892 if ( readLimit > std::numeric_limits<size_t>::max() ) {
893 return false;
894 }
896 if ( covered(m, o) ) {
897 const size_t q = o - m;
898 const size_t l0 = m_end - q;
899 if ( q > 0 ) {
900 std::memmove(m_buffer.data(), m_buffer.data() + q, l0);
901 }
902 m_end = l0;
903 // DBG_PRINT("RewindBuffer.setMark.1 src-q %" PRIu64 ", len %" PRIu64 ", %s.", q, l0, toString().c_str());
904 } else {
905 m_end = 0;
906 }
907 if ( readLimit > m_buffer.size() ) {
908 m_buffer.resize(readLimit, 0);
909 }
910 return true;
911 }
912 size_t read(size_type& m, size_type& o, DataProvider newData, void* out, const size_t length) noexcept {
913 [[maybe_unused]] size_t l0 = length;
914 size_t g1 = 0, g2 = 0;
915 if ( covered(m, o) ) {
916 const size_t p0 = o - m;
917 g1 = std::min(m + m_end - o, l0);
918 std::memcpy(out, m_buffer.data() + p0, g1);
919 o += g1;
920 l0 -= g1;
921 }
922 if ( l0 > 0 ) {
923 g2 = newData((char*)out + g1, l0);
924 if ( g2 > 0 && ByteStream::npos != m ) {
925 if ( m_end + g2 > m_buffer.size() ) {
927 m_end = 0;
928 } else {
929 std::memcpy(m_buffer.data() + m_end, (const char*)out + g1, g2);
930 m_end += g2;
931 }
932 }
933 o += g2;
934 l0 -= g2;
935 }
936 // DBG_PRINT("ByteInStream::read.X: size (%zu + %zu = %zu) / %zu (-> %zu) bytes, %s",
937 // g1, g2, g1+g2, length, l0, toString().c_str() );
938 return g1 + g2;
939 }
940 };
941 } // namespace impl
942
943 /**
944 * Ringbuffer-Based byte input stream with a URL connection provisioned data feed.
945 *
946 * Standard implementation uses [curl](https://curl.se/),
947 * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported,
948 * jau::io::uri::supported_protocols().
949 */
950 class ByteInStream_URL final : public ByteStream {
951 public:
952 /**
953 * Construct a ringbuffer backed Http byte input stream
954 * @param url the URL of the data to read
955 * @param timeout maximum duration in fractions of seconds to wait @ available() for next bytes, where fractions_i64::zero waits infinitely
956 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
957 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
958 */
960
962
964
965 ~ByteInStream_URL() noexcept override { close(); }
966
967 iostate_t rdstate() const noexcept override;
968
969 bool isOpen() const noexcept override;
970 void close() noexcept override;
971 std::string id() const noexcept override { return m_url; }
972
973 bool hasContentSize() const noexcept override;
974 size_type contentSize() const noexcept override { return m_stream_resp->content_length; }
975 size_type position() const noexcept override { return m_offset; }
976
977 bool canRewind() const noexcept override { return false; }
978
979 /// newPos < position() limited to `markpos`, see setMark().
980 [[nodiscard]] size_type seek(size_type newPos) noexcept override;
981
982 std::string toString() const noexcept override;
983
984 [[nodiscard]] bool setMark(size_type readLimit) noexcept override;
985 size_type mark() const noexcept override { return m_mark; }
986 size_type markReadLimit() const noexcept override { return m_rewindbuf.capacity(); }
987 [[nodiscard]] bool seekMark() noexcept override;
988
989 /**
990 * Check whether n bytes are available in the input stream.
991 *
992 * Wait up to timeout duration set in constructor until n bytes become available, where fractions_i64::zero waits infinitely.
993 *
994 * This method is blocking.
995 *
996 * @param n byte count to wait for
997 * @return true if n bytes are available, otherwise false
998 *
999 * @see read()
1000 * @see @ref byte_in_stream_properties "ByteInStream Properties"
1001 */
1002 bool available(size_t n) noexcept override;
1003
1004 /**
1005 * Read from the source. Moves the internal offset so that every
1006 * call to read will return a new portion of the source.
1007 *
1008 * Use available() to wait and ensure a certain amount of bytes are available.
1009 *
1010 * This method is not blocking beyond the transfer of `min(available, length)` bytes.
1011 *
1012 * @param out the byte array to write the result to
1013 * @param length the length of the byte array out
1014 * @return length in bytes that was actually read and put into out
1015 *
1016 * @see available()
1017 * @see @ref byte_in_stream_properties "ByteInStream Properties"
1018 */
1019 [[nodiscard]] size_t read(void* out, size_t length) noexcept override;
1020
1021 [[nodiscard]] size_t peek(void* out, size_t length, size_type peek_offset) noexcept override;
1022
1023 /// Implemented by skipping input stream via read
1024 [[nodiscard]] size_t discard(size_t N) noexcept override;
1025
1026 [[nodiscard]] size_t write(const void*, size_t) noexcept override { return 0; }
1027 void flush() noexcept override { }
1028
1029 private:
1030 size_type get_available() const noexcept { return m_stream_resp->has_content_length ? m_stream_resp->content_length - m_offset : 0; }
1031 std::string to_string_int() const noexcept;
1032
1033 const std::string m_url;
1034 jau::fraction_i64 m_timeout;
1035 ByteRingbuffer m_buffer;
1036 jau::io::AsyncStreamResponseRef m_stream_resp;
1037
1038 size_type m_offset;
1039 size_type m_mark;
1040 impl::RewindBuffer m_rewindbuf;
1041
1042 impl::RewindBuffer::DataProvider newData = [&](void* out, size_t length) -> size_t {
1043 bool timeout_occured = false;
1044 const size_t g = m_buffer.getBlocking(static_cast<uint8_t*>(out), length, 1, m_timeout, timeout_occured);
1045 if ( timeout_occured ) {
1046 addstate_impl(iostate_t::timeout);
1047 if ( m_stream_resp->processing() ) {
1048 m_stream_resp->result = io_result_t::FAILED;
1049 }
1050 m_buffer.interruptWriter();
1051 }
1052 return g;
1053 };
1054 };
1055
1056 /**
1057 * Parses the given path_or_uri, if it matches a supported protocol, see jau::io::uri::protocol_supported(),
1058 * but is not a local file, see jau::io::uri::is_local_file_protocol(), ByteInStream_URL is being attempted.
1059 *
1060 * If the above fails, ByteStream_File (read-only) is attempted.
1061 *
1062 * If non of the above leads to a ByteStream without ByteStream::fail(), nullptr is returned.
1063 *
1064 * @param path_or_uri given path or uri for with a ByteInStream instance shall be established.
1065 * @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
1066 * @return a working ByteInStream w/o ByteInStream::fail() or nullptr
1067 */
1068 std::unique_ptr<ByteStream> to_ByteInStream(const std::string& path_or_uri, jau::fraction_i64 timeout = 20_s) noexcept;
1069
1070 /**
1071 * Ringbuffer-Based byte input stream with an externally provisioned data feed.
1072 */
1073 class ByteInStream_Feed final : public ByteStream {
1074 public:
1075 /**
1076 * Construct a ringbuffer backed externally provisioned byte input stream
1077 * @param id_name arbitrary identifier for this instance
1078 * @param timeout maximum duration in fractions of seconds to wait @ available() and write(), where fractions_i64::zero waits infinitely
1079 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
1080 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
1081 */
1083
1085
1087
1088 ~ByteInStream_Feed() noexcept override { close(); }
1089
1090 /**
1091 * Interrupt a potentially blocked reader.
1092 *
1093 * Call this method if intended to abort streaming and to interrupt the reader thread's potentially blocked available() call,
1094 * i.e. done at set_eof()
1095 *
1096 * @see set_eof()
1097 */
1098 void interruptReader() noexcept {
1099 m_buffer.interruptReader();
1100 }
1101
1102 /**
1103 * Set known content size, informal only.
1104 * @param content_length the content size in bytes
1105 */
1106 void setContentSize(const size_type size) noexcept {
1107 m_content_size = size;
1108 m_has_content_length = true;
1109 }
1110
1111 /**
1112 * Set end-of-data (EOS), i.e. when feeder completed provisioning bytes.
1113 *
1114 * Implementation issues interruptReader() to unblock a potentially blocked reader thread.
1115 *
1116 * @param result should be either result_t::FAILED or result_t::SUCCESS.
1117 *
1118 * @see interruptReader()
1119 */
1120 void setEOF(const io_result_t result) noexcept;
1121
1122 iostate_t rdstate() const noexcept override;
1123
1124 bool isOpen() const noexcept override;
1125
1126 void close() noexcept override;
1127
1128 std::string id() const noexcept override { return m_id; }
1129
1130 bool hasContentSize() const noexcept override { return m_has_content_length; }
1131
1132 size_type contentSize() const noexcept override { return m_content_size; }
1133
1134 size_type position() const noexcept override { return m_offset; }
1135
1136 bool canRewind() const noexcept override { return false; }
1137
1138 /// newPos < position() limited to `markpos`, see setMark().
1139 [[nodiscard]] size_type seek(size_type newPos) noexcept override;
1140
1141 std::string toString() const noexcept override;
1142
1143 [[nodiscard]] bool setMark(size_type readLimit) noexcept override;
1144 size_type mark() const noexcept override { return m_mark; }
1145 size_type markReadLimit() const noexcept override { return m_rewindbuf.capacity(); }
1146 [[nodiscard]] bool seekMark() noexcept override;
1147
1148 /**
1149 * Check whether n bytes are available in the input stream.
1150 *
1151 * Wait up to timeout duration set in constructor until n bytes become available, where fractions_i64::zero waits infinitely.
1152 *
1153 * This method is blocking.
1154 *
1155 * @param n byte count to wait for
1156 * @return true if n bytes are available, otherwise false
1157 *
1158 * @see read()
1159 * @see @ref byte_in_stream_properties "ByteInStream Properties"
1160 */
1161 bool available(size_t n) noexcept override;
1162
1163 /**
1164 * Read from the source. Moves the internal offset so that every
1165 * call to read will return a new portion of the source.
1166 *
1167 * Use available() to wait and ensure a certain amount of bytes are available.
1168 *
1169 * This method is not blocking beyond the transfer of `min(available, length)` bytes.
1170 *
1171 * @param out the byte array to write the result to
1172 * @param length the length of the byte array out
1173 * @return length in bytes that was actually read and put into out
1174 *
1175 * @see available()
1176 * @see @ref byte_in_stream_properties "ByteInStream Properties"
1177 */
1178 [[nodiscard]] size_t read(void* out, size_t length) noexcept override;
1179
1180 /// Not implemented, returns 0
1181 [[nodiscard]] size_t peek(void* out, size_t length, size_type peek_offset) noexcept override;
1182
1183 /// Implemented by skipping input stream via read
1184 [[nodiscard]] size_t discard(size_t N) noexcept override;
1185
1186 /**
1187 * Write given bytes to the async ringbuffer using explicit given timeout.
1188 *
1189 * Wait up to explicit given timeout duration until ringbuffer space is available, where fractions_i64::zero waits infinitely.
1190 *
1191 * This method is blocking.
1192 *
1193 * @param n byte count to wait for
1194 * @param in the byte array to transfer to the async ringbuffer
1195 * @param length the length of the byte array in
1196 * @param timeout explicit given timeout for async ringbuffer put operation
1197 * @return true if successful, otherwise false on timeout or stopped feeder and subsequent calls to good() will return false.
1198 */
1199 [[nodiscard]] size_t write(const void* in, size_t length, const jau::fraction_i64& timeout) noexcept;
1200
1201 /**
1202 * Write given bytes to the async ringbuffer, feeding the input stream.
1203 *
1204 * Wait up to timeout duration set in constructor until ringbuffer space is available, where fractions_i64::zero waits infinitely.
1205 *
1206 * This method is blocking.
1207 *
1208 * @param in the byte array to transfer to the async ringbuffer
1209 * @param length the length of the byte array in
1210 * @return length if successful, otherwise zero on timeout or stopped feeder and subsequent calls to good() will return false.
1211 */
1212 [[nodiscard]] size_t write(const void* in, size_t length) noexcept override {
1213 return write(in, length, m_timeout);
1214 }
1215
1216 void flush() noexcept override { }
1217
1218 private:
1219 size_type getAvailable() const noexcept { return m_has_content_length ? m_content_size - m_offset : 0; }
1220 std::string toStringInt() const noexcept;
1221
1222 const std::string m_id;
1223 jau::fraction_i64 m_timeout;
1224 ByteRingbuffer m_buffer;
1225 jau::relaxed_atomic_bool m_has_content_length;
1226 jau::relaxed_atomic_uint64 m_content_size;
1227 jau::relaxed_atomic_uint64 m_total_xfered;
1228 relaxed_atomic_io_result_t m_result;
1229
1230 size_type m_offset;
1231 size_type m_mark;
1232 impl::RewindBuffer m_rewindbuf;
1233
1234 impl::RewindBuffer::DataProvider newData = [&](void* out, size_t length) -> size_t {
1235 bool timeout_occured = false;
1236 // set_eof() unblocks ringbuffer via set_end_of_input(true) permanently, hence blocking call on !m_has_content_length is OK.
1237 const size_t g = m_buffer.getBlocking(static_cast<uint8_t*>(out), length, 1, m_timeout, timeout_occured);
1238 if ( timeout_occured ) {
1239 addstate_impl(iostate_t::timeout);
1240 if ( io_result_t::NONE == m_result ) {
1241 m_result = io_result_t::FAILED;
1242 }
1243 m_buffer.interruptWriter();
1244 }
1245 return g;
1246 };
1247 };
1248
1249 /**
1250 * Wrapped byte input stream with the capability
1251 * to record the read byte stream at will.
1252 *
1253 * Peek'ed, seek'ed or discard'ed bytes won't be recorded, only read bytes.
1254 */
1255 class ByteStream_Recorder final : public ByteStream {
1256 public:
1257 /**
1258 * Construct a byte input stream wrapper using the given parent ByteInStream.
1259 * @param parent the parent ByteInStream
1260 * @param buffer a user defined buffer for the recording
1261 * @param byteOrder endian byte-order of stream storage, defaults to lb_endian_t::little.
1262 * Only affects multi-byte r/w operations, e.g. readU16(), writeU16(), etc
1263 */
1265 : ByteStream(parent.mode(), byteOrder), m_parent(parent), m_offset(0), m_buffer(buffer), m_rec_offset(0), m_is_recording(false) { };
1266
1268
1270
1271 ~ByteStream_Recorder() noexcept override { close(); }
1272
1273 /**
1274 * Starts the recording.
1275 * <p>
1276 * A potential previous recording will be cleared.
1277 * </p>
1278 */
1279 void startRecording() noexcept;
1280
1281 /**
1282 * Stops the recording.
1283 * <p>
1284 * The recording persists.
1285 * </p>
1286 */
1287 void stopRecording() noexcept;
1288
1289 /**
1290 * Clears the recording.
1291 * <p>
1292 * If the recording was ongoing, also stops the recording.
1293 * </p>
1294 */
1295 void clearRecording() noexcept;
1296
1297 /** Returns the reference of the recording buffer given by user. */
1298 io::secure_vector<uint8_t>& get_recording() noexcept { return m_buffer; }
1299
1300 size_t getRecordedBytes() noexcept { return m_buffer.size(); }
1301
1302 /** Returns the recording start position. */
1303 size_type get_recording_start_pos() noexcept { return m_rec_offset; }
1304
1305 bool isRecording() noexcept { return m_is_recording; }
1306
1307 void assignState(const iostate_t state = iostate_t::goodbit) noexcept override { m_parent.assignState(state); }
1308 iostate_t rdstate() const noexcept override { return m_parent.rdstate(); }
1309
1310 bool isOpen() const noexcept override { return m_parent.isOpen(); }
1311
1312 void close() noexcept override;
1313
1314 size_type position() const noexcept override { return m_offset; }
1315
1316 bool hasContentSize() const noexcept override { return m_parent.hasContentSize(); }
1317
1318 size_type contentSize() const noexcept override { return m_parent.contentSize(); }
1319
1320 std::string toString() const noexcept override;
1321
1322 std::string id() const noexcept override { return m_parent.id(); }
1323
1324 bool canRewind() const noexcept override { return m_parent.canRewind(); }
1325
1326 [[nodiscard]] size_type seek(size_type newPos) noexcept override {
1327 m_offset = m_parent.seek(newPos);
1328 return m_offset;
1329 }
1330 [[nodiscard]] size_t discard(size_t N) noexcept override {
1331 size_t n = m_parent.discard(N);
1332 m_offset = m_parent.position();
1333 return n;
1334 }
1335
1336 [[nodiscard]] bool setMark(size_type readLimit) noexcept override { return m_parent.setMark(readLimit); }
1337 size_type mark() const noexcept override { return m_parent.mark(); }
1338 size_type markReadLimit() const noexcept override { return m_parent.markReadLimit(); }
1339 [[nodiscard]] bool seekMark() noexcept override {
1340 if ( m_parent.seekMark() ) {
1341 m_offset = m_parent.position();
1342 return true;
1343 } else {
1344 return false;
1345 }
1346 }
1347
1348 [[nodiscard]] size_t read(void*, size_t) noexcept override;
1349
1350 [[nodiscard]] size_t peek(void* out, size_t length, size_type peek_offset) noexcept override {
1351 return m_parent.peek(out, length, peek_offset);
1352 }
1353
1354 bool available(size_t n) noexcept override { return m_parent.available(n); }
1355
1356 [[nodiscard]] size_t write(const void*, size_t) noexcept override;
1357 void flush() noexcept override { m_parent.flush(); }
1358
1359 private:
1360 ByteStream& m_parent;
1361 size_type m_offset;
1363 size_type m_rec_offset;
1364 bool m_is_recording;
1365 };
1366
1367 /**@}*/
1368
1369} // namespace jau::io
1370
1371#endif /* JAU_IO_BYTE_STREAM_HPP_ */
Class template jau::function is a general-purpose static-polymorphic function wrapper.
~ByteInStream_Feed() noexcept override
ByteInStream_Feed & operator=(const ByteInStream_Feed &)=delete
bool canRewind() const noexcept override
Return true if implementation supports random rewinding the stream, i.e.
void interruptReader() noexcept
Interrupt a potentially blocked reader.
void setContentSize(const size_type size) noexcept
Set known content size, informal only.
ByteInStream_Feed(std::string id_name, const jau::fraction_i64 &timeout, lb_endian_t byteOrder=lb_endian_t::little) noexcept
Construct a ringbuffer backed externally provisioned byte input stream.
size_type position() const noexcept override
Returns the position indicator, similar to e.g.
size_type contentSize() const noexcept override
Returns the content_size if known.
void close() noexcept override
Close the stream if supported by the underlying mechanism.
void flush() noexcept override
Synchronizes all output operations, or do nothing.
ByteInStream_Feed(const ByteInStream_Feed &)=delete
size_t write(const void *in, size_t length, const jau::fraction_i64 &timeout) noexcept
Write given bytes to the async ringbuffer using explicit given timeout.
bool hasContentSize() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
size_type markReadLimit() const noexcept override
Returns the readLimit set via setMark().
size_type mark() const noexcept override
Returns the markpos set via setMark() or ByteStream::npos if unset.
ByteInStream_URL(const ByteInStream_URL &)=delete
void flush() noexcept override
Synchronizes all output operations, or do nothing.
size_type markReadLimit() const noexcept override
Returns the readLimit set via setMark().
ByteInStream_URL(std::string url, const jau::fraction_i64 &timeout, lb_endian_t byteOrder=lb_endian_t::little) noexcept
Construct a ringbuffer backed Http byte input stream.
ByteInStream_URL & operator=(const ByteInStream_URL &)=delete
~ByteInStream_URL() noexcept override
size_type position() const noexcept override
Returns the position indicator, similar to e.g.
size_t write(const void *, size_t) noexcept override
Write to the data sink.
void close() noexcept override
Close the stream if supported by the underlying mechanism.
size_type mark() const noexcept override
Returns the markpos set via setMark() or ByteStream::npos if unset.
bool canRewind() const noexcept override
Return true if implementation supports random rewinding the stream, i.e.
size_type contentSize() const noexcept override
Returns the content_size if known.
size_type seek(size_type newPos) noexcept override
Sets position indicator for output-streams or input-streams with known length, similar to e....
size_type mark() const noexcept override
Returns the markpos set via setMark() or ByteStream::npos if unset.
size_t peek(void *, size_t, size_type) noexcept override
Read from the source but do not modify the internal offset.
bool setMark(size_type readLimit) noexcept override
Set markpos to current position, allowing the stream to be seekMark().
size_t discard(size_t N) noexcept override
Discard the next N bytes of the data.
size_type position() const noexcept override
Returns the position indicator, similar to e.g.
bool hasContentSize() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
size_type contentSize() const noexcept override
Returns the content_size if known.
bool canRewind() const noexcept override
Return true if implementation supports random rewinding the stream, i.e.
~ByteStream_File() noexcept override
void close() noexcept override
Close the stream if supported by the underlying mechanism.
void flush() noexcept override
Synchronizes all output operations, or do nothing.
ByteStream_File(const ByteStream_File &)=delete
ByteStream_File & operator=(const ByteStream_File &)=delete
bool isOpen() const noexcept override
Checks if the stream has an associated file.
int fd() const noexcept
Returns the file descriptor if is_open(), otherwise -1 for no file descriptor.
size_type markReadLimit() const noexcept override
Returns the readLimit set via setMark().
std::string toString() const noexcept override
ByteStream_File(const std::string &path, iomode_t iomode=iomode_t::rw, const jau::io::fs::fmode_t fmode=fs::fmode_t::def_file_prot, lb_endian_t byteOrder=lb_endian_t::little) noexcept
Construct a stream based byte stream from filesystem path, either an existing or new file.
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...
const jau::io::fs::file_stats & stats() const noexcept
bool seekMark() noexcept override
Seeks stream position to markpos as set via setMark().
ByteStream_Recorder(ByteStream &parent, io::secure_vector< uint8_t > &buffer, lb_endian_t byteOrder=lb_endian_t::little) noexcept
Construct a byte input stream wrapper using the given parent ByteInStream.
bool hasContentSize() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
size_type get_recording_start_pos() noexcept
Returns the recording start position.
size_t getRecordedBytes() noexcept
size_t discard(size_t N) noexcept override
Discard the next N bytes of the data.
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...
bool isOpen() const noexcept override
Checks if the stream has an associated file.
void close() noexcept override
Close the stream if supported by the underlying mechanism.
io::secure_vector< uint8_t > & get_recording() noexcept
Returns the reference of the recording buffer given by user.
size_type mark() const noexcept override
Returns the markpos set via setMark() or ByteStream::npos if unset.
void flush() noexcept override
Synchronizes all output operations, or do nothing.
bool canRewind() const noexcept override
Return true if implementation supports random rewinding the stream, i.e.
size_type contentSize() const noexcept override
Returns the content_size if known.
size_t peek(void *out, size_t length, size_type peek_offset) noexcept override
Read from the source but do not modify the internal offset.
ByteStream_Recorder & operator=(const ByteStream_Recorder &)=delete
bool seekMark() noexcept override
Seeks stream position to markpos as set via setMark().
~ByteStream_Recorder() noexcept override
size_type seek(size_type newPos) noexcept override
Sets position indicator for output-streams or input-streams with known length, similar to e....
ByteStream_Recorder(const ByteStream_Recorder &)=delete
size_type position() const noexcept override
Returns the position indicator, similar to e.g.
iostate_t rdstate() const noexcept override
Returns the current state flags.
void assignState(const iostate_t state=iostate_t::goodbit) noexcept override
Assigns given state to current value.
bool setMark(size_type readLimit) noexcept override
Set markpos to current position, allowing the stream to be seekMark().
size_type markReadLimit() const noexcept override
Returns the readLimit set via setMark().
bool canRewind() const noexcept override
Return true if implementation supports random rewinding the stream, i.e.
void close() noexcept override
Close the stream if supported by the underlying mechanism.
std::string toString() const noexcept override
size_type position() const noexcept override
Returns the position indicator, similar to e.g.
bool hasContentSize() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
ByteStream_SecMemory(size_t length, iomode_t mode, lb_endian_t byteOrder=lb_endian_t::little)
Construct a secure memory source using a sized byte array.
~ByteStream_SecMemory() noexcept override
size_t discard(size_t N) noexcept override
Discard the next N bytes of the data.
size_t peek(void *, size_t, size_type) noexcept override
Read from the source but do not modify the internal offset.
ByteStream_SecMemory(io::secure_vector< uint8_t > &&in, iomode_t mode, lb_endian_t byteOrder=lb_endian_t::little)
Construct a secure memory source copying data from a secure_vector.
size_type contentSize() const noexcept override
Returns the content_size if known.
bool setMark(size_type readLimit) noexcept override
Set markpos to current position, allowing the stream to be seekMark().
bool isOpen() const noexcept override
Checks if the stream has an associated file.
size_type seek(size_type newPos) noexcept override
Sets position indicator for output-streams or input-streams with known length, similar to e....
void flush() noexcept override
Synchronizes all output operations, or do nothing.
ByteStream_SecMemory(const uint8_t in[], size_t length, iomode_t mode, lb_endian_t byteOrder=lb_endian_t::little)
Construct a secure memory source copying data from a byte array.
bool seekMark() noexcept override
Seeks stream position to markpos as set via setMark().
size_type mark() const noexcept override
Returns the markpos set via setMark() or ByteStream::npos if unset.
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...
size_type markReadLimit() const noexcept override
Returns the readLimit set via setMark().
ByteStream_SecMemory(const std::vector< uint8_t > &in, iomode_t mode, lb_endian_t byteOrder=lb_endian_t::little)
Construct a secure memory source copying data from a std::vector.
ByteStream_SecMemory(const std::string &in, lb_endian_t byteOrder=lb_endian_t::little)
Construct a secure memory source that reads from a string, iomode_t::read.
Byte stream interface.
bool write(uint8_t in) noexcept
Write one byte, uint8_t.
bool readU64(uint64_t &bits) noexcept
Read incoming uint64_t.
bool writeS64(int64_t bits) noexcept
Write the given int64_t.
virtual void flush() noexcept=0
Synchronizes all output operations, or do nothing.
bool readS16(int16_t &bits) noexcept
Read int16_t.
virtual size_t read(void *out, size_t length) noexcept=0
Read from the source.
virtual bool isOpen() const noexcept=0
Checks if the stream has an associated file.
constexpr bool canWrite() const noexcept
Returns true in case stream has iomode::write capabilities.
virtual size_type mark() const noexcept=0
Returns the markpos set via setMark() or ByteStream::npos if unset.
bool writeS32(int32_t bits) noexcept
Write the given int32_t.
virtual bool seekMark() noexcept=0
Seeks stream position to markpos as set via setMark().
bool writeU32(uint32_t bits) noexcept
Write the given uint32_t.
constexpr bool canRead() const noexcept
Returns true in case stream has iomode::read capabilities.
virtual size_t write(const void *in, size_t length) noexcept=0
Write to the data sink.
virtual size_type markReadLimit() const noexcept=0
Returns the readLimit set via setMark().
size_t discardRead(size_t n) noexcept
Fallback slow discard implementation usind read() in case of unknown stream size.
bool readS32(int32_t &bits) noexcept
Read int32_t.
~ByteStream() noexcept override=default
virtual size_t discard(size_t N) noexcept=0
Discard the next N bytes of the data.
virtual bool setMark(size_type readLimit) noexcept=0
Set markpos to current position, allowing the stream to be seekMark().
bool writeU64(uint64_t bits) noexcept
Write the given uint64_t.
virtual std::string toString() const noexcept=0
bool writeS16(int16_t bits) noexcept
Write the given int16_t.
virtual bool hasContentSize() const noexcept=0
Returns true if implementation is aware of content_size(), otherwise false.
bool readS64(int64_t &bits) noexcept
Read int64_t.
void setImmutable() noexcept
Clears iomode_t::write from mode()
lb_endian_t m_byteOrder
bool peek(uint8_t &out) noexcept
Peek one byte at current position.
virtual void close() noexcept=0
Close the stream if supported by the underlying mechanism.
virtual size_type contentSize() const noexcept=0
Returns the content_size if known.
bool readU32(uint32_t &bits) noexcept
Read incoming uint32_t.
constexpr lb_endian_t byteOrder() const noexcept
Returns endian byte-order of stream storage.
bool readU64Raw(uint64_t &bits) noexcept
Read incoming uint64_t w/o considering bigEndian, i.e.
virtual bool canRewind() const noexcept=0
Return true if implementation supports random rewinding the stream, i.e.
bool writeU16(uint16_t bits) noexcept
Write the given uint16_t.
uint64_t size_type
uint64_t size data type, bit position and count
bool readU16(uint16_t &bits) noexcept
Read uint16_t.
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...
virtual size_type position() const noexcept=0
Returns the position indicator, similar to e.g.
virtual size_t peek(void *out, size_t length, size_type peek_offset) noexcept=0
Read from the source but do not modify the internal offset.
ByteStream(iomode_t mode, lb_endian_t byteOrder=lb_endian_t::little) noexcept
virtual size_type remaining() const noexcept
Returns the remaining bytes, i.e.
virtual size_type seek(size_type newPos) noexcept=0
Sets position indicator for output-streams or input-streams with known length, similar to e....
constexpr iomode_t mode() const noexcept
bool writeU64Raw(uint64_t bits) noexcept
Write the given uint64_t w/o considering bigEndian, i.e.
static constexpr size_type npos
Invalid position constant, denoting unset mark() or invalid position.
void addState(const iostate_t state) noexcept
Adds given state flags to existing rdstate() bits.
virtual void assignState(const iostate_t state=iostate_t::goodbit) noexcept
Assigns given state to current value.
bool fail() const noexcept
Checks if an error has occurred.
virtual iostate_t rdstate() const noexcept
Returns the current state flags.
void clearStateFlags(const iostate_t clr) noexcept
Clears given state flags from current value.
bool operator!() const noexcept
Checks if an error has occurred, synonym of fail().
bool good() const noexcept
Checks if no error nor eof() has occurred i.e.
IOStateCap & operator=(IOStateCap &&o) noexcept=default
bool eof() const noexcept
Checks if end-of-file has been reached.
IOStateCap(const IOStateCap &o) noexcept=default
void setstate(const iostate_t state) noexcept
Sets state flags, by keeping its previous bits.
void clear(const iostate_t state=iostate_t::goodbit) noexcept
Clears state flags by assignment to the given value.
bool timeout() const noexcept
Checks if a timeout (non-recoverable) has occurred.
bool bad() const noexcept
Checks if a non-recoverable error has occurred.
constexpr iostate_t rdstate_impl() const noexcept
IOStateCap(IOStateCap &&o) noexcept=default
virtual ~IOStateCap() noexcept=default
constexpr void addstate_impl(iostate_t state) const noexcept
IOStateCap & operator=(const IOStateCap &o) noexcept=default
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
jau::function< size_t(void *out, size_t length)> DataProvider
jau::io::ByteStream::size_type size_type
bool setMark(const size_type m, size_type o, size_type readLimit) noexcept
constexpr size_type end() const noexcept
size_t read(size_type &m, size_type &o, DataProvider newData, void *out, const size_t length) noexcept
std::string toString() const noexcept
constexpr bool covered(const size_type m, size_type o) const noexcept
constexpr size_type capacity() const noexcept
constexpr uint16_t bswap(uint16_t const source) noexcept
Definition byte_util.hpp:88
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
@ native
Identifier for native platform type, one of the above.
@ little
Identifier for little endian, equivalent to endian::little.
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 PRAGMA_DISABLE_WARNING_TYPE_RANGE_LIMIT
#define JAU_MAKE_BITFIELD_ENUM_STRING(type,...)
constexpr bool is_set(const E mask, const E bits) noexcept
std::ostream & operator<<(std::ostream &os, const T v)
#define PRAGMA_DISABLE_WARNING_PUSH
constexpr E & write(E &store, const E bits, bool set) noexcept
If set==true, sets the bits in store, i.e.
#define PRAGMA_DISABLE_WARNING_POP
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
iomode_t
Stream I/O mode, e.g.
io_result_t
I/O operation result value.
Definition io_util.hpp:55
std::string toString(io_result_t v) noexcept
Definition io_util.hpp:67
std::unique_ptr< ByteStream > 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...
std::vector< T, jau::callocator_sec< T > > secure_vector
Definition io_util.hpp:33
@ rw
Read and write capabilities, i.e.
@ writetrunc
Write capabilities and truncate existing (file) stream, i.e.
@ atend
Seek to end of (file) stream when opened.
@ trunc
Truncate existing (file) stream when opened with write.
@ read
Read capabilities.
@ write
Write capabilities.
@ read
Read intent.
@ write
Write intend.
@ 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 (EOS).
@ 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 (c) 2024 Gothel Software e.K.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
STL namespace.