blob: 707c77be550ddb6b50b9342143d9d4ae51a1de04 [file] [log] [blame]
part of archive_io;
class InputFileStream {
String path;
io.RandomAccessFile _file;
final int byteOrder;
int _fileSize = 0;
int _filePosition = 0;
List<int> _buffer;
int _bufferSize = 0;
int _bufferPosition = 0;
int _maxBufferSize;
static const int _kDefaultBufferSize = 4096;
InputFileStream(this.path, {this.byteOrder: LITTLE_ENDIAN,
int bufferSize: _kDefaultBufferSize}) {
_maxBufferSize = bufferSize;
_buffer = new Uint8List(_maxBufferSize);
_file = new io.File(path).openSync();
_fileSize = _file.lengthSync();
_readBuffer();
}
InputFileStream.file(io.File file, {this.byteOrder: LITTLE_ENDIAN,
int bufferSize: _kDefaultBufferSize}) {
_maxBufferSize = bufferSize;
_buffer = new Uint8List(_maxBufferSize);
_file = file.openSync();
_fileSize = _file.lengthSync();
_readBuffer();
}
void close() {
_file.closeSync();
_fileSize = 0;
}
int get length => _fileSize;
int get position => _filePosition;
bool get isEOS => (_filePosition >= _fileSize) &&
(_bufferPosition >= _bufferSize);
int get bufferSize => _bufferSize;
int get bufferPosition => _bufferPosition;
int get bufferRemaining => _bufferSize - _bufferPosition;
int get fileRemaining => _fileSize - _filePosition;
void reset() {
_filePosition = 0;
_file.setPositionSync(0);
_readBuffer();
}
void skip(int length) {
if ((_bufferPosition + length) < _bufferSize) {
_bufferPosition += length;
} else {
int remaining = length - (_bufferSize - _bufferPosition);
while (!isEOS) {
_readBuffer();
if (remaining < _bufferSize) {
_bufferPosition += remaining;
break;
}
remaining -= _bufferSize;
}
}
}
/**
* Read [count] bytes from an [offset] of the current read position, without
* moving the read position.
*/
InputStream peekBytes(int count, [int offset = 0]) {
int end = _bufferPosition + offset + count;
if (end > 0 && end < _bufferSize) {
List<int> bytes = _buffer.sublist(_bufferPosition + offset, end);
return new InputStream(bytes);
}
Uint8List bytes = new Uint8List(count);
int remaining = _bufferSize - (_bufferPosition + offset);
if (remaining > 0) {
List<int> bytes1 = _buffer.sublist(_bufferPosition + offset, _bufferSize);
bytes.setRange(0, remaining, bytes1);
}
_file.readIntoSync(bytes, remaining, count);
_file.setPositionSync(_filePosition);
return new InputStream(bytes);
}
void rewind(int count) {
if (_bufferPosition - count < 0) {
int remaining = (_bufferPosition - count).abs();
_filePosition = _filePosition - _bufferSize - remaining;
if (_filePosition < 0) {
_filePosition = 0;
}
_file.setPositionSync(_filePosition);
_readBuffer();
return;
}
_bufferPosition -= count;
}
int readByte() {
if (isEOS) {
return 0;
}
if (_bufferPosition >= _bufferSize) {
_readBuffer();
}
if (_bufferPosition >= _bufferSize) {
return 0;
}
return _buffer[_bufferPosition++] & 0xff;
}
/**
* Read a 16-bit word from the stream.
*/
int readUint16() {
int b1 = 0;
int b2 = 0;
if ((_bufferPosition + 2) < _bufferSize) {
b1 = _buffer[_bufferPosition++] & 0xff;
b2 = _buffer[_bufferPosition++] & 0xff;
} else {
b1 = readByte();
b2 = readByte();
}
if (byteOrder == BIG_ENDIAN) {
return (b1 << 8) | b2;
}
return (b2 << 8) | b1;
}
/**
* Read a 24-bit word from the stream.
*/
int readUint24() {
int b1 = 0;
int b2 = 0;
int b3 = 0;
if ((_bufferPosition + 3) < _bufferSize) {
b1 = _buffer[_bufferPosition++] & 0xff;
b2 = _buffer[_bufferPosition++] & 0xff;
b3 = _buffer[_bufferPosition++] & 0xff;
} else {
b1 = readByte();
b2 = readByte();
b3 = readByte();
}
if (byteOrder == BIG_ENDIAN) {
return b3 | (b2 << 8) | (b1 << 16);
}
return b1 | (b2 << 8) | (b3 << 16);
}
/**
* Read a 32-bit word from the stream.
*/
int readUint32() {
int b1 = 0;
int b2 = 0;
int b3 = 0;
int b4 = 0;
if ((_bufferPosition + 4) < _bufferSize) {
b1 = _buffer[_bufferPosition++] & 0xff;
b2 = _buffer[_bufferPosition++] & 0xff;
b3 = _buffer[_bufferPosition++] & 0xff;
b4 = _buffer[_bufferPosition++] & 0xff;
} else {
b1 = readByte();
b2 = readByte();
b3 = readByte();
b4 = readByte();
}
if (byteOrder == BIG_ENDIAN) {
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
}
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
}
/**
* Read a 64-bit word form the stream.
*/
int readUint64() {
int b1 = 0;
int b2 = 0;
int b3 = 0;
int b4 = 0;
int b5 = 0;
int b6 = 0;
int b7 = 0;
int b8 = 0;
if ((_bufferPosition + 8) < _bufferSize) {
b1 = _buffer[_bufferPosition++] & 0xff;
b2 = _buffer[_bufferPosition++] & 0xff;
b3 = _buffer[_bufferPosition++] & 0xff;
b4 = _buffer[_bufferPosition++] & 0xff;
b5 = _buffer[_bufferPosition++] & 0xff;
b6 = _buffer[_bufferPosition++] & 0xff;
b7 = _buffer[_bufferPosition++] & 0xff;
b8 = _buffer[_bufferPosition++] & 0xff;
} else {
b1 = readByte();
b2 = readByte();
b3 = readByte();
b4 = readByte();
b5 = readByte();
b6 = readByte();
b7 = readByte();
b8 = readByte();
}
if (byteOrder == BIG_ENDIAN) {
return (b1 << 56) | (b2 << 48) | (b3 << 40) | (b4 << 32) |
(b5 << 24) | (b6 << 16) | (b7 << 8) | b8;
}
return (b8 << 56) | (b7 << 48) | (b6 << 40) | (b5 << 32) |
(b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
}
InputStream readBytes(int length) {
if (isEOS) {
return null;
}
if (_bufferPosition == _bufferSize) {
_readBuffer();
}
if (_remainingBufferSize >= length) {
List<int> bytes = _buffer.sublist(_bufferPosition,
_bufferPosition + length);
_bufferPosition += length;
return new InputStream(bytes);
}
int total_remaining = fileRemaining + _remainingBufferSize;
if (length > total_remaining) {
length = total_remaining;
}
Uint8List bytes = new Uint8List(length);
int offset = 0;
while (length > 0) {
int remaining = _bufferSize - _bufferPosition;
int end = (length > remaining) ? _bufferSize : (_bufferPosition + length);
List<int> l = _buffer.sublist(_bufferPosition, end);
// TODO probably better to use bytes.setRange here.
for (int i = 0; i < l.length; ++i) {
bytes[offset + i] = l[i];
}
offset += l.length;
length -= l.length;
_bufferPosition = end;
if (length > 0 && _bufferPosition == _bufferSize) {
_readBuffer();
if (_bufferSize == 0) {
break;
}
}
}
return new InputStream(bytes);
}
/**
* Read a null-terminated string, or if [len] is provided, that number of
* bytes returned as a string.
*/
String readString([int len]) {
if (len == null) {
List<int> codes = [];
while (!isEOS) {
int c = readByte();
if (c == 0) {
return new String.fromCharCodes(codes);
}
codes.add(c);
}
throw new ArchiveException('EOF reached without finding string terminator');
}
InputStream s = readBytes(len);
Uint8List bytes = s.toUint8List();
String str = new String.fromCharCodes(bytes);
return str;
}
int get _remainingBufferSize => _bufferSize - _bufferPosition;
void _readBuffer() {
_bufferPosition = 0;
_bufferSize = _file.readIntoSync(_buffer);
if (_bufferSize == 0) {
return;
}
_filePosition += _bufferSize;
}
}