blob: f27ee1bc73ed5c5e913ffa780a3975822ada2731 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert';
import 'dart:typed_data';
import 'data_source.dart';
import 'serialization.dart' show StringInterner;
/// [DataSource] that reads data from a sequence of bytes.
///
/// This data source works together with [BinaryDataSink].
class BinaryDataSource implements DataSource {
int _byteOffset = 0;
final List<int> _bytes;
final StringInterner? _stringInterner;
late final Map<int, int> _deferredOffsetToSize;
BinaryDataSource(this._bytes, {StringInterner? stringInterner})
: _stringInterner = stringInterner {
assert((_bytes as dynamic) != null); // TODO(48820): Remove when sound.
final deferredDataStart = readAtOffset(_bytes.length - 4, _readUint32);
_deferredOffsetToSize = readAtOffset(deferredDataStart, () {
final deferredSizesCount = readInt();
final result = <int, int>{};
for (var i = 0; i < deferredSizesCount; i++) {
final offset = readInt();
final size = readInt();
result[offset] = size;
}
return result;
});
}
@override
void begin(String tag) {}
@override
void end(String tag) {}
int _readByte() => _bytes[_byteOffset++];
@override
String readString() {
int length = readInt();
List<int> bytes = Uint8List(length);
bytes.setRange(0, bytes.length, _bytes, _byteOffset);
_byteOffset += bytes.length;
String string = utf8.decode(bytes);
if (_stringInterner == null) return string;
return _stringInterner!.internString(string);
}
@override
int readInt() {
var byte = _readByte();
if (byte & 0x80 == 0) {
// 0xxxxxxx
return byte;
} else if (byte & 0x40 == 0) {
// 10xxxxxx
return ((byte & 0x3F) << 8) | _readByte();
} else {
// 11xxxxxx
return ((byte & 0x3F) << 24) |
(_readByte() << 16) |
(_readByte() << 8) |
_readByte();
}
}
@override
E readEnum<E>(List<E> values) {
int index = readInt();
assert(
0 <= index && index < values.length,
"Invalid data kind index. "
"Expected one of $values, found index $index.");
return values[index];
}
@override
E readAtOffset<E>(int offset, E reader()) {
final offsetBefore = _byteOffset;
_byteOffset = offset;
final value = reader();
_byteOffset = offsetBefore;
return value;
}
int _readUint32() {
return (_readByte() << 24) |
(_readByte() << 16) |
(_readByte() << 8) |
_readByte();
}
@override
int readDeferred() {
final indexOffset = _byteOffset;
readInt(); // Read collision padding.
final dataOffset = _byteOffset;
final dataLength = _deferredOffsetToSize[indexOffset]!;
_byteOffset += dataLength;
return dataOffset;
}
@override
E readDeferredAsEager<E>(E reader()) {
readInt(); // Read collision padding.
return reader();
}
@override
int get length => _bytes.length;
@override
String get errorContext => ' Offset $_byteOffset in ${_bytes.length}.';
}