packkit/seven_z

7z archive — minimal pure-Gleam reader.

The reader handles the common case produced by 7z a on a small payload: a single packed stream wrapped in a single folder that uses one coder. Recognised single-coder ids:

Types

Coder selection for the single-folder 7z encoder. Mirrors the 7z a -m0=<method> CLI option: every entry’s body is concatenated, then the whole buffer is fed through the chosen coder and emitted as one folder. The decoder side accepts the same set plus extra coder ids it doesn’t yet have an encoder for (LZMA2, BCJ family, Delta).

pub opaque type Method

Values

pub fn bzip2() -> Method

Method constructor: full bzip2 stream (with BZh magic and CRCs). The concatenated entry bodies go through packkit/bzip2.encode. Equivalent to 7z a -m0=BZip2.

pub fn copy() -> Method

Method constructor: identity (no compression). Equivalent to 7z a -m0=Copy. The packed bytes stored in the folder are the concatenated entry bodies verbatim.

pub fn decode(
  bytes bytes: BitArray,
) -> Result(archive.Archive, error.ArchiveError)

Decode a 7z byte stream using the default limits.

pub fn decode_with_limits(
  bytes bytes: BitArray,
  limits limits: limit.Limits,
) -> Result(archive.Archive, error.ArchiveError)

Decode a 7z byte stream using explicit limits. Enforces max_input_bytes at entry, max_output_bytes against the declared unpack size before invoking the LZMA/LZMA2 decoder, and max_members / max_entry_depth while materialising the logical entry list.

pub fn decode_with_password(
  bytes bytes: BitArray,
  password password: String,
) -> Result(archive.Archive, error.ArchiveError)

Decode a 7z byte stream that contains an AES-256 encrypted folder. password is applied to every AES-coded folder via the SHA-256 key-derivation routine p7zip uses (numCyclesPower rounds of sha256(salt || utf16le(password) || u64_le(counter))); folders without an AES coder decode unchanged. A wrong password produces garbage plaintext that the downstream coder (typically LZMA2) rejects with the usual typed ArchiveInvalid error — there’s no authentication tag on the AES layer.

pub fn decode_with_password_and_limits(
  bytes bytes: BitArray,
  password password: String,
  limits limits: limit.Limits,
) -> Result(archive.Archive, error.ArchiveError)

Same as decode_with_password but with explicit limits.

pub fn deflate() -> Method

Method constructor: raw DEFLATE (no zlib / gzip wrapper). The concatenated entry bodies go through packkit/deflate.encode. Equivalent to 7z a -m0=Deflate.

pub fn encode(
  archive archive_value: archive.Archive,
) -> Result(BitArray, error.ArchiveError)

Encode a logical archive to a 7z byte stream.

The encoder produces a single-folder, single-coder archive that uses a raw LZMA1 coder for the packed stream. All file bodies are concatenated into one logical substream which is then fed to packkit/internal/lzma.encode_literal_only; if the archive holds more than one entry, the per-substream sizes are emitted via SubStreamsInfo so the standard decoder can split the decompressed bytes back into individual entries.

Restrictions: only File entries are accepted (no directories, symlinks, or hardlinks — these would require the EmptyStream / Attribute / WinAttributes blocks the reader does not yet validate). Empty archives are rejected because the 7z format requires MainStreamsInfo to be present once a Header block exists.

pub fn encode_with_method(
  archive archive_value: archive.Archive,
  method method: Method,
) -> Result(BitArray, error.ArchiveError)

Same as encode/1 but lets the caller pick the coder. All four methods produce a single-folder, single-coder archive — Copy is just the raw bytes; Deflate / BZip2 / LZMA dispatch to the corresponding packkit codec. Cross-method round-trips work because the decoder accepts each of these coder ids.

pub fn encode_with_password(
  archive archive_value: archive.Archive,
  password password: String,
) -> Result(BitArray, error.ArchiveError)

Encode a logical archive to a 7z byte stream with AES-256-CBC payload encryption (coder id 06 F1 07 01). Plumbed into the folder as a 2-coder chain [AES, <method>] so the existing decode_with_password path reads it back verbatim.

The encoder uses empty salt and a 16-byte all-zero IV for determinism — without an FFI into a platform CSPRNG there is no good source of randomness in pure Gleam. This is fine for archives that go to a trusted recipient over an authenticated channel, but it is NOT a substitute for randomised encryption — two archives encrypted with the same password produce identical ciphertext blocks for identical plaintext prefixes, which leaks information about the payload. If you need randomised encryption, encrypt the payload yourself before passing it in or pre-generate a 16-byte IV from a CSPRNG and feed it back through a future BYO-IV API.

The inner coder defaults to LZMA — matching what 7z a -p<pw> emits — and the key derivation runs the canonical 2^19 = 524288 SHA-256 iterations, which on the JS target is slow (multiple seconds per archive).

pub fn encode_with_password_and_header_encryption(
  archive archive_value: archive.Archive,
  password password: String,
) -> Result(BitArray, error.ArchiveError)

Encode an archive with both the payload AND the next-header bytes AES-encrypted — the on-disk equivalent of 7z a -p<pw> -mhe=on. The signature header points at an “encoded next header” (NID 0x17) whose StreamsInfo block tells the decoder where the AES-encrypted next-header pack lives; the next header itself is plain bytes AES-CBC-encrypted with the user’s password (no inner compression — the header is small enough that LZMA isn’t worth the dispatch cost).

The same determinism caveat as encode_with_password applies: salt is empty and IV is all zeros.

pub fn encode_with_password_and_header_encryption_and_method(
  archive archive_value: archive.Archive,
  password password: String,
  method method: Method,
) -> Result(BitArray, error.ArchiveError)

Like encode_with_password_and_header_encryption but lets the caller pick the inner coder for the payload. The header is always wrapped in just AES (no inner method).

pub fn encode_with_password_and_method(
  archive archive_value: archive.Archive,
  password password: String,
  method method: Method,
) -> Result(BitArray, error.ArchiveError)

Same as encode_with_password but lets the caller pick the inner coder (Copy / Deflate / BZip2 / LZMA). Salt + IV are still empty / all-zero — see encode_with_password for the determinism caveat.

pub fn format() -> archive.ArchiveFormat

7z archive format marker.

pub fn lzma() -> Method

Default Method: raw LZMA1 with the historical 7z a defaults (lc=3 / lp=0 / pb=2, 64 KiB dictionary). Equivalent to passing seven_z.lzma() to encode_with_method.

pub fn new() -> archive.Archive

Create an empty 7z archive value.

Search Document