KiteArchive¶
KiteArchive implements compression codecs and archive readers in pure Kotlin, for Kotlin Multiplatform. Gunzip a buffer or read a ZIP on iOS and in the browser, as well as on the JVM.
There is no JNI, no cinterop and no native binary. The core artifact depends on
kotlin-stdlib and nothing else, so it builds anywhere Kotlin builds.
A first example¶
import io.github.yuroyami.kitearchive.KiteArchive
import io.github.yuroyami.kitearchive.archive.ByteArrayRandomAccessSource
import io.github.yuroyami.kitearchive.security.PathGuard
val gz = KiteArchive.gzip.compress("hello".encodeToByteArray())
val back = KiteArchive.gzip.decompress(gz)
KiteArchive.sniff(bytes) // -> ArchiveFormat.ZIP / TAR / GZIP / ...
val reader = KiteArchive.open(ByteArrayRandomAccessSource(zipBytes))
for (entry in reader.entries()) {
// The reader returns names unchanged. Sanitize one before you join it to a path.
println(PathGuard.sanitize(entry.name))
}
Two things to know first¶
Everything is whole-array. You pass a ByteArray and get a ByteArray back,
so the payload sits fully in memory. There is no streaming API.
PathGuard is a function you call, not a guard the readers apply. Every
reader returns the entry name exactly as the archive stored it, including a name
such as ../../etc/passwd. Joining that to an output directory is the Zip-Slip
vulnerability, where an archive entry escapes the folder you meant to extract
into. Call PathGuard.sanitize on every name before you use it as a path.
Modules¶
| Module | What it holds | Targets |
|---|---|---|
kitearchive |
Codecs, archive readers, a ZIP writer, checksums, a sniffer and the safety checks. See the table below | Android, iOS, JVM, JS |
kitearchive-io |
Four convenience adapters over kotlinx-io RawSource. No RawSink bridge and no seekable file handle |
Android, iOS, JVM |
What kitearchive contains:
| Area | Contents |
|---|---|
| Codecs | DEFLATE, gzip, zlib, LZ4 and Snappy |
| Archives | ZIP reader and writer (ZIP64, STORE and DEFLATE), plus TAR, ar and cpio readers |
| Checksums | CRC-32, CRC-32C, Adler-32, CRC-64/XZ and xxHash32 |
| Safety | A magic sniffer, plus the opt-in PathGuard and ArchiveLimits checks |
kitearchive-io has no JS target. It cannot go in the same commonMain as
the core in a project that builds for JS.
Not implemented¶
CodecId names bzip2, LZMA, LZMA2, xz, zstd, brotli and PPMd, and the sniffer
recognizes several of them. None of them has an implementation, and
KiteArchive.codec(id) returns null for those ids. ZIP is the only container
with a writer.