LangelicArchive (langelic_archive v0.1.0)

Copy Markdown View Source

Read ZIP, RAR, and 7z archives into memory, backed by a Rustler NIF.

Extraction only — this library never creates archives (the RAR backend's license forbids it, and reading is all it exists for). The format is detected from the file's magic bytes, never from its name, so a .cbz that is secretly a RAR extracts fine.

All entries are returned in memory as {name, data} tuples, in archive order. Directory entries are skipped. Nothing is ever written to disk, so hostile entry names (../../etc/passwd) cannot escape anywhere — but do treat names as untrusted input if you persist them.

Example

{:ok, entries} = LangelicArchive.extract("comic.cbr")
Enum.map(entries, fn {name, data} -> {name, byte_size(data)} end)

Decompression-bomb guard

Extraction fails with an :too_large error once the cumulative unpacked size exceeds :max_total_bytes (default 4294967296 bytes — 4 GiB). Raise or lower it per call:

LangelicArchive.extract(path, max_total_bytes: 100 * 1024 * 1024)

Summary

Functions

Detect the archive format from the leading magic bytes.

Extract every file entry of the archive at path into memory.

Extract archive content already held in memory.

List the file entries of the archive at path without decompressing them.

List the file entries of archive content already held in memory.

Types

entry()

@type entry() :: {name :: String.t(), data :: binary()}

format()

@type format() :: :zip | :rar | :sevenz

Functions

detect(data)

@spec detect(binary()) :: format() | :unknown

Detect the archive format from the leading magic bytes.

Accepts the archive's binary content (a prefix is enough). Returns :unknown for anything that is not a ZIP, RAR (v4 or v5), or 7z archive.

extract(path, opts \\ [])

@spec extract(
  Path.t(),
  keyword()
) :: {:ok, [entry()]} | {:error, LangelicArchive.Error.t()}

Extract every file entry of the archive at path into memory.

Returns entries as {name, data} tuples in archive order. Directory entries are skipped.

Options

  • :max_total_bytes — abort with :too_large once cumulative unpacked size exceeds this (default 4 GiB).

extract_binary(data, opts \\ [])

@spec extract_binary(
  binary(),
  keyword()
) :: {:ok, [entry()]} | {:error, LangelicArchive.Error.t()}

Extract archive content already held in memory.

The RAR backend can only read from the filesystem, so the data is staged through a temporary file (removed before returning). Prefer extract/2 when the archive is already on disk.

list(path)

@spec list(Path.t()) ::
  {:ok, [{String.t(), non_neg_integer()}]} | {:error, LangelicArchive.Error.t()}

List the file entries of the archive at path without decompressing them.

Returns {name, unpacked_size} tuples in archive order.

list_binary(data)

@spec list_binary(binary()) ::
  {:ok, [{String.t(), non_neg_integer()}]} | {:error, LangelicArchive.Error.t()}

List the file entries of archive content already held in memory.