blob: f14fea1cbf4e54d489bc58a5a8647db806b3be7f [file] [log] [blame]
part of archive;
/**
* A helper class to work with List and TypedData in a way similar to pointers
* in C.
*/
class MemPtr {
var buffer;
int offset;
int _length;
int byteOrder;
MemPtr(List<int> other, [this.offset = 0, this._length = -1,
this.byteOrder = LITTLE_ENDIAN]) {
buffer = other;
if (_length < 0 || _length > buffer.length) {
_length = buffer.length;
}
}
MemPtr.from(MemPtr other, [this.offset = 0, this._length = -1]) {
buffer = other.buffer;
offset += other.offset;
byteOrder = other.byteOrder;
if (_length < 0) {
_length = other.length;
}
if (_length > buffer.length) {
_length = buffer.length;
}
}
/**
* Are we at the end of the buffer?
*/
bool get isEOS => offset >= _length;
/**
* Get a byte in the buffer relative to the current read position.
*/
int operator[](int index) => buffer[offset + index];
/**
* Set a byte in the buffer relative to the current read position.
*/
operator[]=(int index, int value) => buffer[offset + index] = value;
/**
* The number of bytes remaining in the buffer.
*/
int get length => _length - offset;
/**
* Copy data from [other] to this buffer, at [start] offset from the
* current read position, and [length] number of bytes. [offset] is
* the offset in [other] to start reading.
*/
void memcpy(int start, int length, other, [int offset = 0]) {
if (other is MemPtr) {
buffer.setRange(this.offset + start, this.offset + start + length,
other.buffer, other.offset + offset);
} else {
buffer.setRange(this.offset + start, this.offset + start + length,
other, offset);
}
}
/**
* Set a range of bytes in this buffer to [value], at [start] offset from the
* current read position, and [length] number of bytes.
*/
void memset(int start, int length, int value) {
buffer.fillRange(offset + start, offset + start + length, value);
}
/**
* Read a single byte.
*/
int readByte() {
return buffer[offset++];
}
/**
* Read [count] bytes from the buffer.
*/
List<int> readBytes(int count) {
if (buffer is Uint8List) {
Uint8List bytes = new Uint8List.view(buffer.buffer,
buffer.offsetInBytes + offset,
count);
offset += bytes.length;
return bytes;
}
List<int> bytes = (buffer as List<int>).sublist(offset, offset + count);
offset += bytes.length;
return 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');
}
return new String.fromCharCodes(readBytes(len));
}
/**
* Read a 16-bit word from the stream.
*/
int readUint16() {
int b1 = buffer[offset++] & 0xff;
int b2 = buffer[offset++] & 0xff;
if (byteOrder == BIG_ENDIAN) {
return (b1 << 8) | b2;
}
return (b2 << 8) | b1;
}
/**
* Read a 24-bit word from the stream.
*/
int readUint24() {
int b1 = buffer[offset++] & 0xff;
int b2 = buffer[offset++] & 0xff;
int b3 = buffer[offset++] & 0xff;
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 = buffer[offset++] & 0xff;
int b2 = buffer[offset++] & 0xff;
int b3 = buffer[offset++] & 0xff;
int b4 = buffer[offset++] & 0xff;
if (byteOrder == BIG_ENDIAN) {
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
}
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
}
/**
* This assumes buffer is a Typed
*/
Uint8List toUint8List([int offset = 0]) {
return new Uint8List.view(buffer.buffer,
buffer.offsetInBytes + this.offset + offset);
}
/**
* This assumes buffer is a Typed
*/
Uint32List toUint32List([int offset = 0]) {
return new Uint32List.view(buffer.buffer,
buffer.offsetInBytes + this.offset + offset);
}
}