sections method

Stream<CarSection> sections()

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',
      );
    }
  }
}