sections method
Returns a stream that yields each CarSection in file order.
Implementation
Stream<CarSection> sections() async* {
final payload = await _loadV1Payload();
var offset = 0;
final (varintLen, headerSize) = _readVarint(payload, 0);
offset += varintLen;
final headerBytes = payload.sublist(offset, offset + headerSize);
offset += headerSize;
// Ensure header can be parsed (validates DAG-CBOR).
await CarHeader._fromBytes(headerBytes);
final seenCids = <String>{};
while (offset < payload.length) {
final (varintLen, sectionLen) = _readVarint(payload, offset);
offset += varintLen;
if (offset + sectionLen > payload.length) {
throw CarSectionException(
'Truncated CAR section at offset $offset: '
'declared $sectionLen bytes, ${payload.length - offset} available',
);
}
final (cid, cidLen) = _parseCid(payload, offset);
final blockOffset = offset + cidLen;
final blockLen = sectionLen - cidLen;
if (blockLen < 0) {
throw CarSectionException(
'CAR section length $sectionLen is smaller than CID length $cidLen',
);
}
final blockBytes = payload.sublist(blockOffset, blockOffset + blockLen);
yield CarSection(cid: cid, bytes: blockBytes);
seenCids.add(cid.encode());
offset += sectionLen;
}
// Validate that every root appears in the data section.
final hdr = await _loadHeader();
for (final root in hdr.roots) {
if (!seenCids.contains(root.encode())) {
throw CarHeaderException(
'Root CID ${root.encode()} is missing from the data section',
);
}
}
}