ArchiveReader.decode constructor

ArchiveReader.decode(
  1. Uint8List bytes,
  2. ArchiveFormat format
)

Decodes bytes as format into an indexed reader. Throws StateError when the archive exceeds maxArchiveBytes or fails to decode.

Implementation

factory ArchiveReader.decode(Uint8List bytes, ArchiveFormat format) {
  if (bytes.length > maxArchiveBytes) {
    throw StateError(
      'Archive is too large to read in memory '
      '(${bytes.length} bytes > $maxArchiveBytes byte limit)',
    );
  }
  // ZipDecoder is lenient with garbage input (it yields an empty archive);
  // every real ZIP — even an empty one — starts with a PK record
  // signature, so reject non-ZIP bytes up front (omp's framing rejects a
  // missing end-of-central-directory record the same way).
  if (format == ArchiveFormat.zip &&
      (bytes.length < 2 || bytes[0] != 0x50 || bytes[1] != 0x4B)) {
    throw StateError('Cannot read archive: not a ZIP file');
  }
  final Archive decoded;
  try {
    decoded = switch (format) {
      ArchiveFormat.zip => ZipDecoder().decodeBytes(bytes),
      ArchiveFormat.tar => TarDecoder().decodeBytes(bytes),
      ArchiveFormat.tarGz => TarDecoder().decodeBytes(
        GZipDecoder().decodeBytes(bytes),
      ),
    };
  } on Object catch (error) {
    throw StateError('Cannot read archive: $error');
  }

  final entries = <_IndexEntry>[];
  for (final file in decoded.files) {
    final normalizedPath = _normalizeArchiveEntryPath(file.name);
    if (normalizedPath == null) continue;
    final isDirectory =
        !file.isFile || file.name.endsWith('/') || file.name.endsWith('\\');
    entries.add(
      _IndexEntry(
        path: normalizedPath,
        isDirectory: isDirectory,
        size: isDirectory ? 0 : file.size,
        file: isDirectory ? null : file,
      ),
    );
  }
  return ArchiveReader._(format, entries);
}