blob: 9868871cf5f2136cb87231b6ae6147fb47bd29e2 [file] [log] [blame]
import 'dart:async';
import 'dart:typed_data';
import 'byte_order.dart';
import 'input_stream.dart';
/// A buffer that can be read as a stream of bytes
class InputStreamMemory extends InputStream {
late Uint8List buffer;
// The read offset into the buffer.
int _position;
late int _length;
/// Create a [InputStream] for reading from a Uint8List
InputStreamMemory(Uint8List bytes,
{super.byteOrder = ByteOrder.littleEndian, int? offset, int? length})
: _position = 0 {
offset ??= 0;
length ??= bytes.buffer.lengthInBytes - offset;
final requestedLength = bytes.offsetInBytes + offset + length;
if (requestedLength > bytes.buffer.lengthInBytes) {
length = bytes.buffer.lengthInBytes - (bytes.offsetInBytes + offset);
}
buffer = Uint8List.view(bytes.buffer, bytes.offsetInBytes + offset, length);
_length = buffer.length;
}
InputStreamMemory.empty()
: buffer = Uint8List(0),
_position = 0,
_length = 0,
super(byteOrder: ByteOrder.littleEndian);
InputStreamMemory.fromList(List<int> bytes,
{super.byteOrder = ByteOrder.littleEndian})
: buffer = Uint8List.fromList(bytes),
_position = 0,
_length = bytes.length;
/// Create a copy of [other].
InputStreamMemory.from(InputStreamMemory other)
: buffer = other.buffer,
_position = other._position,
_length = other._length,
super(byteOrder: other.byteOrder);
/// The current read position relative to the start of the buffer.
@override
int get position => _position;
/// How many bytes are left in the stream.
@override
int get length => buffer.length - _position;
/// Is the current position at the end of the stream?
@override
bool get isEOS => _position >= _length;
@override
Future<void> setPosition(int v) async {
_position = v;
}
/// Reset to the beginning of the stream.
@override
Future<void> reset() async {
_position = 0;
}
@override
Future<bool> open() async => true;
@override
Future<void> close() async {
_position = 0;
}
/// Rewind the read head of the stream by the given number of bytes.
@override
Future<void> rewind([int length = 1]) async {
_position -= length;
_position = _position.clamp(0, _length);
}
/// Move the read position by [count] bytes.
@override
Future<void> skip(int count) async {
_position += count;
_position = _position.clamp(0, _length);
}
/// Access the buffer relative from the current position.
int operator [](int index) => buffer[_position + index];
/// Return an [InputStream] to read a subset of this stream. It does not
/// move the read position of this stream. [position] is specified relative
/// to the start of the buffer. If [position] is not specified, the current
/// read position is used. If [length] is not specified, the remainder of this
/// stream is used.
@override
Future<InputStream> subset({int? position, int? length}) async {
position ??= _position;
length ??= _length - position;
return InputStreamMemory(buffer,
byteOrder: byteOrder, offset: position, length: length);
}
/// Read a single byte.
@override
Future<int> readByte() async {
final b = buffer[_position++];
return b;
}
@override
Future<Uint8List> toUint8List() async {
var len = length;
if ((_position + len) > buffer.length) {
len = buffer.length - _position;
}
final bytes =
Uint8List.view(buffer.buffer, buffer.offsetInBytes + _position, len);
return bytes;
}
}