Class Reader

extends Object implements Reader
A source of bytes.
Inheritance
Implementations must implement read_ and may override content-size.

Class summary


constructor
constructor data/ByteArray
Constructs a new reader that uses the given data as source.

Constructors

Constructs a new reader that uses the given data as source.

Statics

Constructs a new reader that wraps the old-style reader r.
This constructor will be removed and should only be used temporarily.

Methods

Provides endian-aware functions to read from this instance.
The big-endian byte order reads higher-order (big) bytes first. For example, if the source of the read operation is a byte array, then first byte read (from position 0) is the most significant byte of the number that is read.
Examples

import io

main:
  reader := io.Reader #[0x12, 0x34, 0x56, 0x78]
  number := reader.big-endian.read-int32
  // The most significant byte 0x12 was at index 0.
  print "0x$(%x number)"  // => 0x12345678

buffer-all -> none
Buffers all the remaining data of this reader.
Use buffered-size to determine how much data was buffered.
Use read-bytes to read the buffered data.

The amount of buffered data.
This function does not read any new data from the resource, but only uses the buffered data.

clear -> none
Clears any buffered data.
Any cleared data is not considered processed.

The total number of bytes that this reader can produce.
This value is not updated when data is consumed.
If the reader does not know the size, returns null.

do --lines/True --keep-newlines/bool=false [block] -> none
Calls the given block for each remaining line.

drain -> none
Drains the reader without buffering or returning the data.

Ensures that at least n bytes are buffered.
Errors
At least n bytes must be available. Use try-ensure-buffered for a non-throwing version.

index-of byte/int --to/int=null --throw-if-absent/bool=false -> int
Searches forwards for the byte.
Consumes no bytes.
If to is specified the search is limited to the given range.
Returns the index of the first occurrence of the byte.
If throw-if-absent is true and byte is not in the remaining data throws.
Returns -1 if throw-if-absent is false (the default) and the byte is not in the remaining data.

Whether n bytes are available in the internal buffer.
This function does not read any new data from the resource, but only uses the buffered data.

Provides endian-aware functions to read from this instance.
The little-endian byte order reads lower-order ("little") bytes first. For example, if the source of the read operation is a byte array, then first byte read (from position 0) is the least significant byte of the number that is read.
Examples

import io

main:
  reader := io.Reader #[0x78, 0x56, 0x34, 0x12]
  number := reader.little-endian.read-int32
  // The least significant byte 0x78 was at index 0.
  print "0x$(%x number)"  // => 0x12345678

operator == other/any -> bool
Whether this object is equal to the other.
By default, identical is used for equality.
Inheritance
Classes overwrite this operator to get an equality specific to their needs. Equality operators often compare the type and field contents. For example:

class Pin:
  number/int

  constructor .number:

  operator == other:
    if other is not Pin: return false
    return number == other.number
A class doesn't have to follow the above format, but it must keep the operator in sync with any hash-code method. That is, if a class has a hash-code member, then the equality and hash-code must agree. If two instances are equal (a == b), then their hash codes must also be equal (a.hash-code == b.hash-code).

Gets the n th byte from our current position.
Does not consume the data, but caches it in this instance.
If enough data is already cached simply returns the byte without requesting more data.
Errors
At least n + 1 bytes must be available.

Gets the n next bytes.
Does not consume the data, but caches it in this instance.
If enough data is already cached simply returns the bytes without requesting more data.
Errors
At least n bytes must be available.

Gets the first n bytes and returns them as string.
Does not consume the data, but caches it in this instance.
Errors
The peeked bytes must be convertible to a UTF8 string.
At least n bytes must be available.
Examples

class MyReader implements Reader:
  read -> ByteArray?: return "hellø".to-byte-array

main:
  reader := BufferedReader MyReader
  print
    reader.peek-string 6  // >> Hellø
  print
    reader.peek-string 5  // >> Error!

The number of bytes that have been produced by this reader so far.

read --max-size/int=null -> ByteArray
Reads from the reader.
If data has been buffered returns the buffered data first. Otherwise, attempts to read new data from the resource.
The read bytes are consumed.
If max-size is specified the returned byte array will never be larger than that size, but it may be smaller, even if there is more data available from the underlying resource. Use read-bytes to read exactly n bytes.
Returns null if no more data is available.

Reads the rest of the data and returns it.

Reads the first byte.
The read byte is consumed.
Errors
At least 1 byte must be available.

Reads the first n bytes from the reader.
The read bytes are consumed.
At least n bytes must be available. That is, a call to try-ensure-buffered n must return true.
If you want to read either n bytes, if they are available, or the maximum number of available bytes otherwise, use the following code:

read-exactly-or-drain reader/BufferedReader n/int -> ByteArray?:
  if can-ensure n: return reader.read-bytes n
  reader.buffer-all
  if reader.buffered == 0: return null
  return reader.read-bytes reader.buffered

Reads the bytes before the delimiter.
The read bytes and the delimiter are consumed.
The returned bytes do not include the delimiter.
Errors
The delimiter must be available.

read-line --keep-newline/bool=false -> string
Reads a line as a string.
If keep-newline is true, the returned string includes the newline character.
If keep-newline is false (the default), trims the trailing '\r\n' or '\n'. This method removes a '\r' even if the platform is not Windows. If the '\r' needs to be preserved, set keep-newline to true and remove the trailing '\n' manually.
If the input ends with a newline, then all further reads return null.
If the input ends without a newline, then the last line is returned without any newline character (even if keep-newline) is true, and all further reads return null.
Returns null if no more data is available.

read-lines --keep-newlines/bool=false -> List
Reads the remaining data as lines.

Reads the first n bytes as a string.
The read bytes are consumed.
Errors
The read bytes must be convertible to a UTF8 string.
At least n bytes must be available.
Examples

class MyReader implements Reader:
  read -> ByteArray?: return "hellø".to-byte-array

main:
  reader := BufferedReader MyReader
  print
    reader.read-string 6  // >> Hellø
  print
    reader.read-string 5  // >> Error!

read-string --max-size/int=null -> string
Reads at most max-size bytes as a string.
The read bytes are consumed.
Note that this method is different from read followed by ByteArray.to-string as it ensures that the data is split into valid UTF-8 chunks.
If max-size is specified the returned string will never be larger than that size (in bytes), but it may be smaller, even if there is more data available from the underlying reader.
Returns null if the stream has ended.
Errors
The read bytes must be convertible to a legal UTF8 string, but this method will read a number of bytes such that legal UTF-8 characters are not chopped up.
May throw an end-of-stream exception if the stream ends in the middle of a malformed UTF-8 character.
Instead of returning a zero length string it throws an exception. This can happen if max-size is less than 4 bytes and the next thing is a UTF-8 character that is coded in more bytes than were requested. This also means max-size should never be zero.

Reads the string before the delimiter.
The read bytes and the delimiter are consumed.
The returned string does not include the delimiter.
Errors
The delimiter must be available.

skip n/int -> none
Skips over the next n bytes.
Errors
At least n bytes must be available.

skip-up-to delimiter/int --to/int=null --throw-if-absent/bool=false -> int
Skips all bytes up to and including the given delimiter.
Returns the number of bytes skipped including the delimiter.
If to is given, then the search is limited to the given range.
If throw-if-absent is true and the delimiter is not in the remaining data, throws.
If throw-if-absent is false (the default) and the delimiter is not in the remaining data, skips all remaining data.

Stringifies this object.
Inheritance
Objects that need a human-friendly string representation should overwrite this method. The default string is based on the internal class-ID.

Attempts to buffer at least n bytes.
Returns whether it was able to.

unget value/ByteArray --hand-over/bool=false -> none
Prepends the values in the value byte-array.
These will be the first bytes to be read in subsequent read operations.
If hand-over is true, then this instance takes ownership of value. In this case, its content must not be modified after being given to this method.