koni_archive 0.9.0
koni_archive: ^0.9.0 copied to clipboard
Format-agnostic archive reading and writing for Dart — one streaming-first API over ZIP, TAR, GZIP, 7z, and RAR. Facade of the koni_archive ecosystem.
Changelog #
0.9.0 - 2026-07-17 #
- Read-side decompression-bomb guards (
ArchiveReadOptions.maxEntrySize/maxEntryCount, new inkoni_archive_core0.9.0) flow through the facade: pass them toArchive.open/openBytes/openArchiveFile. Streaming an entry pastmaxEntrySizeaborts the decode withSizeLimitExceededException;readBytes's ownmaxSizestill applies as an additional, tighter per-call bound. A third guard,maxContainerDecodeSize, bounds bulk decodes that are not a per-entry stream (a.tar.gzcontainer decode; a 7z header/solid folder). Motivated by reading untrusted archives (e.g. CBZ/CBR from user files or remote sources).
0.8.0 - 2026-07-16 #
ArchiveWriteOptions.allowUnsafePaths(new inkoni_archive_core0.8.0) is available through the facade and honored by the ZIP, TAR, and 7z writers. Set it to author an archive whose entry paths are deliberately hostile (..escapes, absolute paths, drive letters), which the writers otherwise reject with anArgumentError; the intended use is a test fixture that exercises a consumer's path-traversal ("Zip Slip") defenses. Reading is unaffected and stays safe either way.
0.7.0 - 2026-07-16 #
- RAR reading is substantially more complete through the facade (via
koni_rar0.7.0): RAR4 PPMd (variant H, solid and non-solid, including a mid-file PPMd→method-29 block switch), the generic RarVM filter interpreter (any method-29 filter program, not just the standard four), RAR4-hpencrypted headers, RAR 2.0/2.6 (v20/v26) LZ, solid RAR4, and multi-volume RAR sets, the last via the newArchiveReadOptions.nextVolumeresolver. Many archives that previously threw a typed error now decode.
0.6.0 - 2026-07-15 #
- Phase 4 (write-side encryption) flows through the facade:
ArchiveWriteOptions.passwordencrypts ZIP (WinZip AES-256) and 7z (AES-256) output, andencryptHeaderdrives 7z-mhe. Every writer's encrypted output is interop-verified against 7-Zip. - Remote archives: pair the facade with the new
koni_http_sourcepackage (HttpRangeByteSource) to read entries out of a remote archive over HTTP Range requests, without downloading the whole file. - First release published to pub.dev.
0.5.0 - 2026-07-15 #
- Phase 3 (decryption, read side): opening a password-protected archive now
works across every format. Pass
ArchiveReadOptions.password. ZIP (zipcrypto + WinZip AES), 7z (AES-256, incl.-mheheaders), RAR5 (-p), and RAR4 (-ma4 -p). Re-exports the newInvalidPasswordException. Encrypted headers for RAR (-hp) and write-side encryption stay out of scope; seedoc/encryption-scope.md.
0.4.0 - 2026-07-15 #
-
P2-4b: 7z writing is now format-faithful: LZMA2 is the default coder (was deflate), with LZMA (v1) also selectable per entry or globally, and headers are LZMA-compressed (kEncodedHeader) whenever that is smaller. Powered by the new koni_codecs encoders (liblzma- and 7zz-interop-verified);
7zz t/7zz xvalidate and extract every coder byte-for-byte, including multi-chunk LZMA2 with uncompressed-chunk fallbacks. LZMA folders buffer the entry's uncompressed bytes while encoding (the buffer is the match window); Copy/Deflate entries still stream. Solid folders remain deferred (one folder per file). -
P2-4a:
SevenZWriteFormatre-exported from the facade: write.7z/.cb7viaArchive.create(sink, format: const SevenZWriteFormat()). Copy and Deflate (default at the time) folders, one per non-empty file; full container (signature/start header, PackInfo/UnpackInfo with per-folder CRC-32, uncompressed FilesInfo), UTF-16 names, FILETIME mtimes, unix modes, directories, empty files, and symlinks.7zzvalidates and extracts our output byte-for-byte (interop; 300-entry archive exercises multi-byte 7z numbers, symlink restored via-snl).- Not streaming, by construction: 7z's leading signature header
references the trailing header's position, so the writer buffers the
compressed packed streams in memory until
close()(peak memory ≈ compressed archive size). Inherent to appending a random-access format, unlike TAR/ZIP writing. - Deferred to P2-4b (tracked): LZMA/LZMA2 folders (and the default codec switching deflate → LZMA2), compressed headers, and solid folders (today one folder per file, so no cross-file compression).
- Not streaming, by construction: 7z's leading signature header
references the trailing header's position, so the writer buffers the
compressed packed streams in memory until
-
P2-3:
ZipWriteFormatre-exported from the facade: write.zip/.cbzviaArchive.create(sink, format: const ZipWriteFormat()). Stored + deflate compression (per-entry or global), streaming append-only output (data descriptors, no seek-back), ZIP64 when count/size overflows 32 bits, directories, and symlinks. Info-ZIPunzipvalidates and extracts our output byte-for-byte (interop, incl. a 70k-entry ZIP64 archive). -
P2-2:
TarWriteFormatre-exported from the facade: write.tar/.cbtviaArchive.create(sink, format: const TarWriteFormat())without a direct koni_tar dependency. -
P2-1:
Archive.create(sink, format:)and thecreateArchiveFile(io.dart) write sugar, plus the write types re-exported. No built-in write formats registered yet.
0.3.0 - 2026-07-15 #
- M10: RAR4 support: RAR5 and RAR4
.rar/.cbrarchives open throughArchive.open. Phase 1 complete: ZIP, TAR, GZIP, 7z, and RAR all read behind the one format-agnostic API, on VM and web. The real-world CBR corpus (RAR4) decodes byte-identically to reference tools. - M9:
RarFormatregistered inbuiltInFormats: RAR5.rar/.cbrarchives open throughArchive.open. RAR4 is a typed error (M10).
0.2.0 - 2026-07-15 #
- M8:
SevenZFormatregistered inbuiltInFormats:.7z/.cb7archives open throughArchive.open; CB7 page-flip served by the solid-block LRU cache.
0.1.0 - 2026-07-15 #
- M6: the facade layers TAR into gzip:
.tar.gz/.tgzopens as the inner TAR throughArchive.open(format auto-detection unchanged). - M5: first release point: CBZ works end-to-end (deflate wired into the ZIP reader). Facade README and example (a CBZ page extractor with preloading) added.
- M4:
GzipFormatregistered inbuiltInFormats(between zip and tar): bare.gzfiles open as single-entry archives throughArchive.open. - M3:
ZipFormatregistered inbuiltInFormats(before TAR, precise magic first): stored.zip/.cbzarchives open throughArchive.open;ArchiveReadOptions(verifyChecksums) accepted byArchive.open/openBytesand the platform sugar. - M2:
TarFormatregistered inbuiltInFormats:.tarand.cbtarchives open throughArchive.openwith format auto-detection. - M1: the
Archivefacade.Archive.open(auto-detection viabuiltInFormatsor a custom registry,format:escape hatch) andArchive.openBytes; platform sugaropenArchiveFile(io.dart) andopenArchiveBlob(web.dart).- Entry access:
entries(index order, duplicates included),entry()/exists()(exact, case-sensitive, last-wins). - Streaming-first reads:
openRead/openReadPath,readByteswithmaxSizebomb protection; concurrent entry streams;close()errors in-flight streams withArchiveClosedExceptionand is idempotent. - VFS view:
walk()(documented depth-first pre-order),files,directories(implicit directories synthesized),glob(). - No formats are registered yet; they land per milestone (TAR at M2).
- M0: package scaffolding: pub workspace membership, shared strict lints, CI matrix (VM on Linux/macOS/Windows; web via dart2js and dart2wasm).