TruncatedStreams

Documentation for TruncatedStreams.

TruncatedStreams.FixedLengthSourceType
FixedLengthSource(io, length) <: TruncatedSource

A truncated source that reads io up to length bytes.

julia> io = IOBuffer(collect(0x00:0xff));

julia> fio = FixedLengthSource(io, 10);

julia> read(fio)
10-element Vector{UInt8}:
 0x00
 0x01
 0x02
 0x03
 0x04
 0x05
 0x06
 0x07
 0x08
 0x09

julia> eof(fio)
true

As soon as a read from a FixedLengthSource object would read past length bytes of the underlying IO stream, EOF is signalled, potentially leading to an EOFError being thrown.

julia> read(fio, Int)
ERROR: EOFError: read end of file
[...]

Seeking does not affect the length at which the stream is truncated, but may affect how many bytes are available to read.

julia> seek(fio, 8); read(fio)
2-element Vector{UInt8}:
 0x08
 0x09
source
TruncatedStreams.SentinelizedSourceType
SentinelizedSource(io, sentinel) <: TruncatedSource

A truncated source that reads io until sentinel is found.

julia> io = IOBuffer(repeat(collect(0x00:0x0f), 2));

julia> sio = SentinelizedSource(io, [0x0a, 0x0b]);

julia> read(sio)
10-element Vector{UInt8}:
 0x00
 0x01
 0x02
 0x03
 0x04
 0x05
 0x06
 0x07
 0x08
 0x09

julia> eof(sio)
true

As soon as a read from a SentinelizedSource object would read the start of a byte sequence matching sentinel from the underlying IO stream, EOF is signalled, potentially leading to an EOFError being thrown.

julia> read(sio, Int)
ERROR: EOFError: read end of file
[...]

Seeking works as if the stream ends at the first byte of the sentinel: backwards seeking will always succeed if the wrapped stream allows it, and forward seeking will only seek up to the sentinel. Note that forward seeking will consume bytes from the wrapped stream.

julia> seek(sio, 8); read(sio)
2-element Vector{UInt8}:
 0x08
 0x09

Detection of eof can be reset with the Base.reseteof() method. Use this if the sentinel that was read is determined upon further inspection to be bogus.

julia> Base.reseteof(sio)  # that last sentinel was fake, so reset EOF and read again

julia> read(sio)  # returns the first sentinel found and continues to read until the next one is found
16-element Vector{UInt8}:
 0x0a
 0x0b
 0x0c
 0x0d
 0x0e
 0x0f
 0x00
 0x01
 0x02
 0x03
 0x04
 0x05
 0x06
 0x07
 0x08
 0x09
Note

If the wrapped stream does not contain a sentinel, reading to the end of the stream will throw EOFError.

julia> io = IOBuffer(collect(0x00:0x07)); sio = SentinelizedSource(io, [0xff, 0xfe]);

julia> read(sio)
ERROR: EOFError: read end of file
[...]
source
TruncatedStreams.TruncatedSourceType
TruncatedSource <: IO

Wrap an IO object to read only as much as should be read and not a byte more.

Objects inheriting from this abstract type pass along all read-oriented IO methods to the wrapped stream except for bytesavailable(io) and eof(io). Inherited types must implement:

  • TruncatedStreams.unwrap(::TruncatedSource)::IO: return the wrapped IO stream.
  • Base.eof(::TruncatedSource)::Bool: report whether the stream cannot produce any more bytes.

In order to implement truncation, some number of these methods will likely need to be implemented:

  • Base.unsafe_read(::TruncatedSource, p::Ptr{UInt8}, n::UInt)::Nothing: copy n bytes from the stream into memory pointed to by p.
  • Base.read(::TruncatedSource, T::Type)::T: read and return an object of type T from the stream.
  • Base.bytesavailable(::TruncatedSource)::Int: report the number of bytes available to read from the stream until EOF or a buffer refill is necessary.
  • Base.seek(::TruncatedSource, p::Integer) and Base.seekend(::TruncatedSource): seek stream to position p or end of stream.
  • Base.reset(::TruncatedSource): reset a marked stream to the saved position.
  • Base.reseteof(::TruncatedSource)::Nothing: reset EOF status.
  • Base.peek(::TruncatedSource[, T::Type])::T: read and return the next object of type T from the stream, but leave the bytes available in the stream for the next read.

The following methods must be implemented by the wrapped IO type for all the functionality of the TruncatedSource to work at all:

  • Base.eof(::IO)::Bool
  • Base.read(::IO, ::Type{UInt8})::UInt8

The wrapped stream also must implement Base.seek and Base.skip for seeking and skipping of the truncated stream to work properly. Additionally, Base.position needs to be implemented for some implementations of Base.seek to work properly.

source