silk.compress.zip.
Read the files and directories of a ZIP archive held in memory.
When to use#
Use a ZipReader to unpack a .zip download, such as a vendor SDK or a release archive. Open
the archive with ZipReader.open, call ZipReader.next until it returns none, and decode
each file with ZipMember.content. This module does not write archives.
Details#
The reader walks the central directory at the end of the archive, so it accepts archives with a
trailing comment, data descriptors, extra fields, and ZIP64 sizes and offsets. Each member must
be stored or DEFLATE-compressed, unencrypted, and on one disk. A member's local header must agree
with its central record on method and name, and its data must lie before the central directory.
Names are checked before a member is returned: an absolute name, a backslash, a colon, a NUL, an
empty segment, or a . or .. segment refuses the archive, so a caller that joins a name to a
directory and creates no symbolic links never writes outside it. A link's target is not checked,
so skip SymbolicLink members unless you check it. The reader does not detect repeated names.
ZipMember.content decodes one member and checks its length and CRC-32. The reader bounds the
sum of the decoded lengths that the central directory declares, so a caller can bound memory
before decoding anything.
Errors#
ZipErrorfromZipReader.open,ZipReader.next, andZipMember.contentwhen the archive is malformed, uses a feature this module does not read, or goes over the limit.OutOfMemoryErrorfromZipMember.contentif theAllocatorfails.
Examples#
import silk.compress.zip {ZipError, ZipKind, ZipMember, ZipReader}
import silk.core.option {Option}
import silk.core.result {Result}
// Counts the regular files of `archive`, or answers -1 when it is not a valid ZIP archive.
fn files(archive: &[u8]) -> i32 {
let mut reader = match ZipReader.open(archive, 1048576) {
Result.Success {value} => move value
Result.Failure {..} => { return -1 }
}
let mut count = 0
while true {
match ZipReader.next(&mut reader) {
Result<Option<ZipMember>, ZipError>.Success {value} => match move value {
Option<ZipMember>.Some {value: member} => { if member.kind == ZipKind.File { count = count + 1 } }
Option<ZipMember>.None => { return count }
}
Result<Option<ZipMember>, ZipError>.Failure {..} => { return -1 }
}
}
return count
}
pub fn main() -> i32 {
return files(b"PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
}Import as ZipReader with import silk.compress.zip { ZipReader }.
Public declarations: 4.
ZipError#
pub enum ZipErrorThe reason a ZIP archive was refused.
Truncated#
TruncatedA record runs past the end of the archive, or no end of central directory record is found.
InvalidDirectory#
InvalidDirectoryThe end record, the central directory, or a local header is inconsistent: a bad signature, a size or offset outside the archive, or a local header that disagrees with its central record.
UnsupportedMember#
UnsupportedMemberThe archive spans disks, or a member is encrypted or uses a method other than stored or DEFLATE.
UnsafePath#
UnsafePathA member name is absolute, holds a backslash, a colon, or a NUL, or has an empty, ., or ..
segment.
InvalidData#
InvalidDataA member's data does not decode, or decodes to a length other than the one its record declares.
BadChecksum#
BadChecksumA member's decoded data does not match its CRC-32.
LimitExceeded#
LimitExceededThe decoded lengths the central directory declares go over the limit given to
ZipReader.open.
Implementation ZipError#
impl ZipErrorAssociated function describe#
pub fn describe(error: ZipError) -> string<'static>Returns a short sentence that describes error, such as "the ZIP archive is truncated".
Implementation Debug for ZipError#
impl Debug for ZipErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Truncated.
ZipKind#
pub enum ZipKindWhat a ZIP member is.
File#
FileA regular file. ZipMember.content returns its bytes.
Directory#
DirectoryA directory. Its name has no trailing /, and it has no content.
SymbolicLink#
SymbolicLinkA Unix symbolic link. ZipMember.content returns the path it points to, which the reader
does not check.
ZipMember#
pub struct ZipMember<'a>One member of a ZIP archive: its checked name and metadata, and its data still compressed.
Details#
The slices borrow the archive given to ZipReader.open. length and checksum come from the
central directory, and ZipMember.content checks the decoded data against them.
Field name#
pub name: &'a [u8]The member's path, with / between segments and no trailing /. The reader has refused
absolute paths and .. segments.
Field kind#
pub kind: ZipKindWhether the member is a file, a directory, or a symbolic link.
Field executable#
pub executable: boolWhether the member is a file whose Unix mode, as a Unix archiver records it, has an execute permission bit.
Field compressed#
pub compressed: &'a [u8]The member's data as it is stored in the archive.
Field deflated#
pub deflated: boolWhether compressed is raw DEFLATE data. Otherwise it is stored as is.
Field length#
pub length: u64The decoded length the central directory declares.
Field checksum#
pub checksum: u32The CRC-32 of the decoded data the central directory declares.
ZipReader#
pub struct ZipReader<'a>A position in the central directory of a ZIP archive held in memory.
When to use#
Make one with ZipReader.open and call ZipReader.next until it returns none.
Details#
The reader does not allocate and borrows the archive. Each member it returns has passed the name, bounds, and local header checks. After a failure, discard the reader.
Implementation ZipReader<'a>#
impl<'a> ZipReader<'a>Associated function open#
pub fn open(archive: &'a [u8], maxDecodedBytes: u64) -> Result<ZipReader<'a>, ZipError>Opens archive and checks its end records, allowing at most maxDecodedBytes of decoded
data across all members.
Errors#
ZipErrorwithTruncatedwhen no end of central directory record is found,InvalidDirectorywhen the end records point outside the archive,UnsupportedMemberwhen the archive spans disks.
Method next#
pub fn next(self: &mut ZipReader<'a>) -> Result<Option<ZipMember<'a>>, ZipError>Returns the next member in central directory order, or none after the last.
Errors#
ZipErrorwhen the member's records are truncated or inconsistent, it is encrypted or uses an unsupported method, its name is unsafe, or its declared length goes over the limit.
Implementation ZipMember<'a>#
impl<'a> ZipMember<'a>Method content#
pub effect fn content(self: &ZipMember<'a>) -> Bytes ! ZipError | OutOfMemoryError ? &mut AllocatorReturns the decoded data of self: a file's bytes, a link's target, or nothing for a
directory.
Errors#
ZipErrorwithInvalidDatawhen the data does not decode to exactlylengthbytes, orBadChecksumwhen its CRC-32 is notchecksum.OutOfMemoryErrorif theAllocatorfails.
Category: Data formats.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.