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#

Examples#

silk
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#

silk
pub enum ZipError

The reason a ZIP archive was refused.

Truncated#

silk
Truncated

A record runs past the end of the archive, or no end of central directory record is found.

InvalidDirectory#

silk
InvalidDirectory

The 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#

silk
UnsupportedMember

The archive spans disks, or a member is encrypted or uses a method other than stored or DEFLATE.

UnsafePath#

silk
UnsafePath

A member name is absolute, holds a backslash, a colon, or a NUL, or has an empty, ., or .. segment.

InvalidData#

silk
InvalidData

A member's data does not decode, or decodes to a length other than the one its record declares.

BadChecksum#

silk
BadChecksum

A member's decoded data does not match its CRC-32.

LimitExceeded#

silk
LimitExceeded

The decoded lengths the central directory declares go over the limit given to ZipReader.open.

Implementation ZipError#

silk
impl ZipError

Associated function describe#

silk
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#

silk
impl Debug for ZipError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as Truncated.

ZipKind#

silk
pub enum ZipKind

What a ZIP member is.

File#

silk
File

A regular file. ZipMember.content returns its bytes.

Directory#

silk
Directory

A directory. Its name has no trailing /, and it has no content.

silk
SymbolicLink

A Unix symbolic link. ZipMember.content returns the path it points to, which the reader does not check.

ZipMember#

silk
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#

silk
pub name: &'a [u8]

The member's path, with / between segments and no trailing /. The reader has refused absolute paths and .. segments.

Field kind#

silk
pub kind: ZipKind

Whether the member is a file, a directory, or a symbolic link.

Field executable#

silk
pub executable: bool

Whether the member is a file whose Unix mode, as a Unix archiver records it, has an execute permission bit.

Field compressed#

silk
pub compressed: &'a [u8]

The member's data as it is stored in the archive.

Field deflated#

silk
pub deflated: bool

Whether compressed is raw DEFLATE data. Otherwise it is stored as is.

Field length#

silk
pub length: u64

The decoded length the central directory declares.

Field checksum#

silk
pub checksum: u32

The CRC-32 of the decoded data the central directory declares.

ZipReader#

silk
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>#

silk
impl<'a> ZipReader<'a>

Associated function open#

silk
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#

  • ZipError with Truncated when no end of central directory record is found, InvalidDirectory when the end records point outside the archive, UnsupportedMember when the archive spans disks.

Method next#

silk
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#

  • ZipError when 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>#

silk
impl<'a> ZipMember<'a>

Method content#

silk
pub effect fn content(self: &ZipMember<'a>) -> Bytes ! ZipError | OutOfMemoryError ? &mut Allocator

Returns the decoded data of self: a file's bytes, a link's target, or nothing for a directory.

Errors#

  • ZipError with InvalidData when the data does not decode to exactly length bytes, or BadChecksum when its CRC-32 is not checksum.

  • OutOfMemoryError if the Allocator fails.

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.

View the source of this page