///|
pub struct Archive {
entries : Array[Entry]
}///|
pub struct Entry {
name : String // File path within archive
data : Bytes // Uncompressed file content
compression : Compression
data_descriptor : Bool
}///|
pub enum Compression {
Store // No compression
Deflate // DEFLATE algorithm
}///|
test "create archive" {
let archive = @zip.Archive::new()
// Add uncompressed file
archive.add("hello.txt", b"Hello, World!")
// Add compressed file
archive.add("data.txt", b"Large content here...", compression=Deflate)
// List entries
debug_inspect(
archive.entries().map(entry => entry.name()),
content="[\"hello.txt\", \"data.txt\"]",
)
// Get file content
inspect(archive.get("hello.txt") == Some(b"Hello, World!"), content="true")
}///|
test "read archive" {
// Create an archive
let archive = @zip.Archive::new()
archive.add("file1.txt", b"Content 1")
archive.add("file2.txt", b"Content 2")
// Write to bytes
let bytes = @zip.write(archive)
// Read back
let loaded = @zip.read(bytes)
debug_inspect(
loaded.entries().map(entry => entry.name()),
content="[\"file1.txt\", \"file2.txt\"]",
)
inspect(loaded.get("file1.txt") == Some(b"Content 1"), content="true")
}///|
test "gzip" {
let data : Bytes = b"Hello, World! This is some test data to compress."
// Compress
let compressed = @zip.gzip(data)
// Decompress
let decompressed = @zip.gunzip(compressed)
inspect(
decompressed,
content="b\"Hello, World! This is some test data to compress.\"",
)
}///|
test "iterate entries" {
let archive = @zip.Archive::new()
archive.add("a.txt", b"A")
archive.add("b.txt", b"B")
archive.add("c.txt", b"C")
// Iterate over entries
for entry in archive.entries() {
println("File: \{entry.name()}, Size: \{entry.data().length()}")
}
}| Method | Description |
|---|---|
| Archive::new() | Create an empty archive |
| add(name, data, compression?, data_descriptor?) | Add a file to the archive |
| get(name) | Get file content by name, returns Bytes? |
| entries() | Get view of all entries |
| fork() | Create a shallow, independently mutable snapshot |
| bounded_source_package_size(...) | Query non-forgeable pristine bounded-read provenance |
| retained_size_estimate() | Conservatively estimate retained archive memory |
| Function | Description |
|---|---|
| read(bytes) | Parse ZIP bytes into Archive |
| read_limited(bytes, ...) | Parse while enforcing entry and expansion limits |
| write(archive) | Serialize Archive to ZIP bytes |
| write_limited(archive, max_output_bytes=...) | Prove the exact size without byte storage, then stream records and DEFLATE payloads into one fixed buffer below the ceiling |
| gzip(bytes) | Compress bytes using GZIP |
| gunzip(bytes) | Decompress GZIP bytes |
///|
pub suberror ZipError {
OutOfBounds(offset~ : Int)
InvalidSignature(expected~ : Int, actual~ : Int, offset~ : Int)
MissingEndOfCentral
UnsupportedFeature(msg~ : String)
UnsupportedCompression(method_id~ : Int)
InvalidUtf8(offset~ : Int)
OutputLimitExceeded(limit~ : Int)
ResourceLimitExceeded(kind~ : String, limit~ : Int, actual~ : Int)
}///|
test "error handling" {
// Invalid ZIP data
try @zip.read(b"not a zip file") catch {
_ => ()
} noraise {
_ => fail("expected read to raise")
}
}pub suberror ZipError {
OutOfBounds(offset~ : Int)
InvalidSignature(expected~ : Int, actual~ : Int, offset~ : Int)
MissingEndOfCentral
UnsupportedFeature(msg~ : String)
UnsupportedCompression(method_id~ : Int)
InvalidUtf8(offset~ : Int)
OutputLimitExceeded(limit~ : Int)
ResourceLimitExceeded(kind~ : String, limit~ : Int, actual~ : Int)
ReadCancelled
} derive(Debug)type Archivefn Archive::add(self : Archive, name : String, data : BytesView, compression? : Compression, data_descriptor? : Bool) -> Unit#deprecated("implicit trait-method promotion is being removed; call via the trait")
fn Compression::to_repr(Compression) -> Reprtype Entryfn crc32(bytes : BytesView) -> UIntA MoonBit port of the Go excelize library for reading and writing XLSX (Excel) spreadsheets.
Dependencies