MoonBit · the interface
The whole public surface, one block per format. Generated from each package by moon info and the /// comments in its source, so what you read is what the compiler checks. New here? Read the guide first.
Adler-32 taken a piece at a time, for a body that is never held whole. The
running state and the folding come from mooncrypt/sum/adler32.
| inner | @adler32.Adler32 |
pub fn Adler::finish(Self) -> UInt32
returns UInt32
pub fn Adler::new() -> Self
returns Self
pub fn Adler::push(Self, BytesView) -> Unit
| BytesView | — | positional |
returns Unit
CRC-32C taken a piece at a time, for a body that is never held whole.
| state | UInt32 |
pub fn Castagnoli::finish(Self) -> UInt32
returns UInt32
pub fn Castagnoli::new() -> Self
returns Self
pub fn Castagnoli::push(Self, BytesView) -> Unit
| BytesView | — | positional |
returns Unit
CRC-32 taken a piece at a time, for a body that is never held whole.
A container that compresses a body it never holds cannot checksum it in one
call either: the streaming writers in gzip and zip keep one of these
beside their compressor and hand it each chunk as it goes past. The running
state and the folding come from mooncrypt/sum/crc32.
| inner | @crc32.Crc32 |
pub fn Crc::finish(Self) -> UInt32
returns UInt32
pub fn Crc::new() -> Self
returns Self
pub fn Crc::push(Self, BytesView) -> Unit
| BytesView | — | positional |
returns Unit
Why a compressed stream could not be read.
The offset is where the reader was when it gave up, in bytes from the start of the stream — enough to find the damage in a file, which "corrupt data" is not.
| Truncated | at~ : Int32 | The stream ends in the middle of something. |
| Header | at~ : Int32, what~ : String | A header field that is not what the format allows: a block type DEFLATE does not define, a compression method gzip does not name, a reserved flag. |
| Code | at~ : Int32 | A Huffman code no symbol is assigned to, or a code table that does not add up. |
| Distance | at~ : Int32 | A back-reference that reaches before the start of the output. |
| Checksum | want~ : UInt32, got~ : UInt32 | The trailing checksum does not match what was decompressed. |
| Length | want~ : UInt32, got~ : Int32 | The trailing length does not match what was decompressed. |
| TooBig | limit~ : Int32 | The output passed the bound the caller set. A compressed stream says nothing about how far it expands, so a reader handling input from elsewhere says how much it is prepared to hold. |
pub fn Refused::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Refused::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Refused::output(Self, &Logger) -> Unit
Derived trait glue.
| &Logger | — | positional |
returns Unit
pub fn Refused::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
pub fn Refused::to_string(Self) -> String
Derived trait glue.
returns String
implements Show
pub fn adler32(BytesView) -> UInt32
Adler-32 (RFC 1950): two running sums modulo the largest prime below 65536.
Cheaper than a CRC and weaker, which is the trade zlib made. The folding is
mooncrypt/sum/adler32, reached from here for the same reason crc32 is.
| BytesView | — | positional |
returns UInt32
pub fn crc32(BytesView) -> UInt32
CRC-32 as gzip, ZIP and PNG use it (RFC 1952): the reflected form of the IEEE 802.3 polynomial, starting and ending complemented.
The folding is mooncrypt/sum/crc32; it is reached from here so the formats
that specify it — gzip in its trailer, zip in every entry and again in the
central directory — find it in one place instead of each importing the other.
| BytesView | — | positional |
returns UInt32
pub fn crc32c(BytesView) -> UInt32
CRC-32C, the Castagnoli polynomial: the checksum that has hardware support on every x86 since Nehalem and every ARM since v8, which is why Snappy and iSCSI chose it over the older CRC-32 that gzip and ZIP use.
It lives here beside the other two for the same reason they are here: it is a checksum the formats specify, not something a format invents, and a caller comparing two of them should find them in one place.
| BytesView | — | positional |
returns UInt32
pub fn mask_crc32c(UInt32) -> UInt32
The mask Snappy applies to a CRC-32C before putting it in a frame, so that a checksum never looks like the length in front of it — and so that a reader that echoes the bytes back cannot be fooled into accepting them.
| UInt32 | — | positional |
returns UInt32
Which block types the writer may emit.
A DEFLATE stream is a run of blocks, and a block may be stored verbatim, coded with the fixed Huffman table, or coded with a table of its own. All three are ordinary DEFLATE; they differ only in size.
| Auto | Let the writer choose per block: it writes each candidate, measures, and keeps the smallest. This is what zlib does, and on the short bodies a response compressor sees the measurement usually lands on fixed — a dynamic block must carry its own code tables, which costs more than it saves on a few hundred bytes. | |
| Fixed | Fixed Huffman codes only. Exactly what this library wrote before 0.4.0, for a caller whose output bytes are pinned. | |
| Dynamic | Dynamic Huffman codes only: the writer must carry its own code tables. The largest output on text, and the reason to have it on at all. | |
| Stored | No compression at all: the input verbatim in stored blocks. This is what
|
pub fn Blocks::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Blocks::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Blocks::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
Decompress a raw DEFLATE stream a piece at a time.
push takes whatever has arrived and hands back whatever it decoded;
finish says no more is coming, and it is an error for the stream to be
unfinished when it is called. Between calls the reader holds the input it
has not got to yet and nothing else — a response body can be decompressed
as it downloads, without the whole of it, or of the output, being held.
The one-shot inflate is this reader fed once and finished.
pub fn Reader::done(Self) -> Bool
Whether the last block has been read, which is what a container checks before it looks for a trailer.
returns Bool
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
Say the stream is complete. An unfinished block is a truncated stream.
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(limit? : Int32) -> Self
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
Feed a chunk, take the bytes it decoded to.
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
pub fn Reader::rest(Self) -> Bytes
Input handed to the reader that the DEFLATE stream did not use, and the reader's buffer emptied.
A container that wraps DEFLATE needs this. The reader stops the moment the
last block ends, so a gzip trailer or a second member is still sitting in
the buffer — and the container is the only thing that knows what to do with
it. gunzip takes its eight-byte trailer from here.
returns Bytes
Compress into a DEFLATE stream a piece at a time.
The point of the streaming writer is that a body need not be held to be
compressed: push takes whatever has arrived and hands back whatever is
ready, and the only thing kept between calls is the last 32 KiB — the
window, which is as far back as a back-reference may reach. A block is
emitted every 32 KiB of input, and matches may reach back across block
boundaries into the retained window, exactly as they would in a stream
written in one piece.
The stream is not finished until finish is called: that is what writes the
last block, and a caller who stops pushing without it has an unterminated
stream.
pub fn Writer::finish(Self) -> Bytes
Finish the stream: the last block, and the last bytes of it. Nothing may be pushed afterwards.
returns Bytes
pub fn Writer::new(level? : Int32, window? : Int32, chain? : Int32, blocks? : Blocks) -> Self
| level | Int32 | labelled, optional |
| window | Int32 | labelled, optional |
| chain | Int32 | labelled, optional |
| blocks | Blocks | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
Feed a chunk, take the compressed bytes it produced.
| BytesView | — | positional |
returns Bytes
pub fn deflate(BytesView, level? : Int32, window? : Int32, chain? : Int32, blocks? : Blocks) -> Bytes
Compress into a DEFLATE stream, one block over the whole input.
LZ77 finds back-references with a hash chain over the window, capped so the
search stays linear in the input. blocks decides how the result is coded.
level runs 0 to 9 and means what it means in the format's reference: 0 stores the
input without compressing it, 9 searches hardest, and 6 is the default every
mainstream encoder uses. It sets how far back the match finder looks, with the
same numbers the reference tables give it.
window is how far a back-reference may reach — 32 KiB is the most DEFLATE
allows and the only value a reader can be assumed to handle. chain sets
the search depth directly for a caller who would rather not go through a
level.
level=0 writes stored blocks, which is what "no compression" means
everywhere; blocks then has nothing to choose between.
| BytesView | — | positional |
| level | Int32 | labelled, optional |
| window | Int32 | labelled, optional |
| chain | Int32 | labelled, optional |
| blocks | Blocks | labelled, optional |
returns Bytes
pub fn inflate(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Decompress a raw DEFLATE stream.
All three block types: stored, fixed Huffman, and the dynamic Huffman blocks that carry their own code tables — which is what zlib, gzip and every browser actually emit, so a reader without them reads almost nothing.
limit bounds the output. A compressed stream says nothing about how much it
expands to, and a small one can expand to more memory than the machine has;
a reader handling input from elsewhere should say how much it is prepared to
hold. Unbounded by default, which is what every library does.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
A gzip reader that takes the stream a piece at a time.
The header is gathered across pushes, because a chunk boundary can fall
anywhere in it, and the trailer is checked when the body ends. One member
only: a stream of concatenated members is what gunzip walks, since it
has the whole thing in hand and knows where the next member starts.
The checks are the ones gunzip offers, and each has the same default and
the same reason.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
Say the stream is complete: check the trailer, or say why it cannot be.
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(checksum? : Bool, length? : Bool, header_crc? : Bool, limit? : Int32) -> Self
A reader with the same checks gunzip offers.
| checksum | Bool | labelled, optional |
| length | Bool | labelled, optional |
| header_crc | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
Feed a chunk of the stream, take the bytes it decompressed to.
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
A gzip writer that takes the body a piece at a time.
This is the shape a response compressor wants: the header goes out with the first chunk, each chunk is compressed and handed straight back, and the trailer is written when the body is declared over. Neither the body nor the compressed form is ever held whole — only the 32 KiB window the compressor needs for its back-references and the four bytes of running checksum.
mbt nochecklet w = @gzip.Writer::new(level=9)
let mut out : Array[Byte] = []
for part in parts {
for b in w.push(part[:]) {
out.push(b)
}
}
for b in w.finish() {
out.push(b)
}pub fn Writer::finish(Self) -> Bytes
Finish the stream: whatever the compressor still holds, then the trailer. Nothing may be pushed afterwards.
returns Bytes
pub fn Writer::new(level? : Int32, window? : Int32, chain? : Int32, mtime? : UInt32, name? : String, comment? : String, os? : Int32, blocks? : @deflate.Blocks) -> Self
A writer whose header says what gzip would have been told.
| level | Int32 | labelled, optional |
| window | Int32 | labelled, optional |
| chain | Int32 | labelled, optional |
| mtime | UInt32 | labelled, optional |
| name | String | labelled, optional |
| comment | String | labelled, optional |
| os | Int32 | labelled, optional |
| blocks | @deflate.Blocks | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
Compress a chunk and take the compressed bytes it produced, the header included the first time anything comes out.
Nothing may come back for a while on a small body: the compressor holds
input until it has a block's worth, which is what makes the output small.
All of it comes back by finish.
| BytesView | — | positional |
returns Bytes
pub fn crc32(BytesView) -> UInt32
CRC-32, where the container that specifies it names it.
The implementation is @moonzip.crc32: zip writes the same checksum, and
neither container should have to import the other to reach it.
| BytesView | — | positional |
returns UInt32
pub fn gunzip(BytesView, checksum? : Bool, length? : Bool, header_crc? : Bool, limit? : Int32) -> Bytes raise @moonzip.Refused
Read a gzip container and decompress what is in it.
The trailing CRC-32 and length are checked, because a container that carries a checksum and does not look at it is not a container. Each check is a parameter for the cases where a stream is known to be truncated and the part that arrived is still wanted.
limit bounds the output, for a stream that came from elsewhere.
| BytesView | — | positional |
| checksum | Bool | labelled, optional |
| length | Bool | labelled, optional |
| header_crc | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn gzip(BytesView, level? : Int32, window? : Int32, chain? : Int32, mtime? : UInt32, name? : String, comment? : String, os? : Int32) -> Bytes
Wrap DEFLATE output in a gzip container.
The modification time is zero and the name is absent unless asked for, so
the same input gives the same bytes. A compressor that stamped the clock
would make a build unreproducible and a cache entry never match — which is
why Go's gzip.Writer also writes zero unless told otherwise. Set mtime
when the output is a file that should carry one.
level, window and chain go straight through to the compressor.
| BytesView | — | positional |
| level | Int32 | labelled, optional |
| window | Int32 | labelled, optional |
| chain | Int32 | labelled, optional |
| mtime | UInt32 | labelled, optional |
| name | String | labelled, optional |
| comment | String | labelled, optional |
| os | Int32 | labelled, optional |
returns Bytes
A zlib reader that takes the stream a piece at a time.
Two bytes of header, then DEFLATE, then four bytes of checksum — and the header can be split across two pushes, which is why the reader keeps them rather than assuming a chunk is at least that long.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
Say the stream is complete: check the checksum, or say why it cannot be.
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(checksum? : Bool, limit? : Int32) -> Self
A reader with the same checks unzlib offers.
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
Feed a chunk of the stream, take the bytes it decompressed to.
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
pub fn Reader::window(Self) -> Int32
The window the stream's header declared, in bytes.
returns Int32
A zlib writer that takes the body a piece at a time.
The two-byte header goes out with the first chunk, each chunk is compressed
and handed straight back, and the big-endian Adler-32 goes out when the body
is declared over. zlib is the container HTTP calls deflate, so this is
what a server compressing a response body wants beside it.
pub fn Writer::finish(Self) -> Bytes
Finish the stream: what the compressor still holds, then the checksum.
returns Bytes
pub fn Writer::new(level? : Int32, window? : Int32, chain? : Int32, blocks? : @deflate.Blocks) -> Self
A writer whose header says what zlib would have been told.
| level | Int32 | labelled, optional |
| window | Int32 | labelled, optional |
| chain | Int32 | labelled, optional |
| blocks | @deflate.Blocks | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
Compress a chunk and take what it produced, the header included the first time anything comes out.
| BytesView | — | positional |
returns Bytes
pub fn adler32(BytesView) -> UInt32
Adler-32, where the container that specifies it names it.
The implementation is @moonzip.adler32; keeping it here as well means a
caller who has the container in hand does not have to reach for the root
package to checksum what it read.
| BytesView | — | positional |
returns UInt32
pub fn unzlib(BytesView, checksum? : Bool, limit? : Int32) -> Bytes raise @moonzip.Refused
Read a zlib container and decompress what is in it.
checksum is what makes it a container rather than a wrapper; limit
bounds the output, for a stream that came from elsewhere.
| BytesView | — | positional |
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn zlib(BytesView, level? : Int32, window? : Int32, chain? : Int32) -> Bytes
Wrap DEFLATE output in a zlib container.
This, not raw DEFLATE, is what HTTP's Content-Encoding: deflate was
specified to mean — a detail that half the servers on the web got wrong,
which is why gzip won.
level, window and chain go straight through to the compressor; the
header says which window was used, so a reader knows how much history it
must keep.
| BytesView | — | positional |
| level | Int32 | labelled, optional |
| window | Int32 | labelled, optional |
| chain | Int32 | labelled, optional |
returns Bytes
fn id(Self) -> Int32
fn pack(Self, BytesView) -> Bytes
fn unpack(Self, BytesView, Int32?) -> Bytes
One member of an archive.
data is the content itself: decompressed when read, as-is when written.
An archive is a directory of whole files, so handing back half of one would
be handing back something that is not the file.
| name | String | The path inside the archive, with forward slashes — APPNOTE.TXT §4.4.17 says so, on every platform. |
| data | Bytes | The content. |
| kind | Kind | How it is held. |
| mtime | Int64 | Last modification, in Unix seconds. ZIP records MS-DOS date and time, which has two-second resolution and no zone, so a value read back is the one that was written rounded down to an even second. |
| comment | String | The per-entry comment, which most archives leave empty. |
pub fn Entry::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Entry::new(String, Bytes, kind? : Kind, mtime? : Int64, comment? : String) -> Self
An entry with only a name and its content, deflated, stamped at the epoch.
The epoch rather than the clock: a library has no clock, and an archive that stamped the time would give different bytes for the same input and make a build unreproducible. A caller with a real modification time passes it.
| String | — | positional |
| Bytes | — | positional |
| kind | Kind | labelled, optional |
| mtime | Int64 | labelled, optional |
| comment | String | labelled, optional |
returns Self
pub fn Entry::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Entry::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
How an entry's bytes are held in the archive.
The format calls it the compression method; the field is kind, which is
what this family calls "which variant of this enum" and is not a word
MoonBit reserves.
The two that are actually in use. APPNOTE.TXT names a dozen more — shrink, implode, six reduce levels — and no tool has written one since the 1990s; a reader that meets one refuses it rather than guessing.
| Stored | Not compressed. What an already-compressed member should use: running DEFLATE over a JPEG costs time and makes it bigger. | |
| Deflated | DEFLATE, which is what every archive in the wild uses for everything else. | |
| Other | Int32 | A method this package does not implement, by its APPNOTE.TXT number —
bzip2 is 12, LZMA is 14. A |
pub fn Kind::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Kind::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Kind::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
Walk an archive from the front, one member at a time.
unzip reads the central directory at the end, which is what a file on
disk allows and what makes an entry addressable by name. A reader that is
*receiving* an archive — from a socket, from a pipe, out of a decompressor —
has no end to seek to, and the local headers are all it has. This is that
reader.
It also reads what a streaming writer writes: an entry whose checksum and sizes sit in a data descriptor after its data rather than in its header. That case is why this reader feeds DEFLATE until the stream says it has ended instead of trusting a length in front of it.
pub fn Reader::new(BytesView) -> Self
A reader at the start of archive.
| BytesView | — | positional |
returns Self
pub fn Reader::next(Self, limit? : Int32, codecs? : ArrayView[&Codec], password? : String) -> Entry? raise @moonzip.Refused
The next member, or None when the members have run out.
limit bounds what one member may expand to, as everywhere else.
| limit | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| password | String | labelled, optional |
returns Entry? · raises @moonzip.Refused
Build an archive a member at a time.
zip is this writer with every entry added and then finished, which is
the shape a caller with the whole archive in hand wants. A caller that is
receiving members one at a time — a backup running, a directory being
walked — wants this instead: add hands back the bytes for that member
immediately, and only the central directory waits for the end.
Three knobs decide the bytes beyond the content itself:
zip64 widens the size and offset fields to sixty-four bits. It turns
itself on when an entry or an offset does not fit in thirty-two, which is
the only reason it exists; forcing it is for a caller whose reader expects
the wider form.
descriptor puts each entry's checksum and sizes after its data instead of
in its local header (APPNOTE.TXT §4.3.9). That is what a writer that streams
a member it has not finished reading must do — it cannot know the sizes when
it writes the header — and it costs twelve bytes a member.
password? encrypts each member. With no aes strength it uses ZipCrypto,
which the format called encryption for fifteen years and which is not a
security boundary (see zipcrypt_encrypt). With an aes
strength of 128, 192 or 256 it uses WinZip AES instead (see
aes_encrypt), which is.
pub fn Writer::add(Self, Entry, codecs? : ArrayView[&Codec]) -> Bytes
Add a member and take the bytes it occupies: a local header, its data, and a data descriptor if one was asked for.
The compressed form is kept only if it is smaller than the input. A member
that grew by being compressed is stored instead, which is what zip itself
does and what makes an archive of already-compressed files the size of the
files.
| Entry | — | positional |
| codecs | ArrayView[&Codec] | labelled, optional |
returns Bytes
pub fn Writer::finish(Self) -> Bytes
Close the archive: the central directory, then the end record — and the Zip64 end record and its locator as well if any entry needed widening.
returns Bytes
pub fn Writer::new(level? : Int32, zip64? : Bool, descriptor? : Bool, password? : String, aes? : Int32, ae? : Int32) -> Self
A writer that has written nothing yet.
| level | Int32 | labelled, optional |
| zip64 | Bool | labelled, optional |
| descriptor | Bool | labelled, optional |
| password | String | labelled, optional |
| aes | Int32 | labelled, optional |
| ae | Int32 | labelled, optional |
returns Self
pub fn aes_decrypt(BytesView, String, Int32) -> Bytes raise @moonzip.Refused
Decrypt what aes_encrypt wrote.
The salt names the key, the verification value rejects a wrong password before any ciphertext is touched, and the authentication tag is checked before the bytes are handed back — a truncated HMAC is a message authentication code, and skipping it would turn a tampered archive into a silent decompression error three layers down.
| BytesView | — | positional |
| String | — | positional |
| Int32 | — | positional |
returns Bytes · raises @moonzip.Refused
pub fn aes_encrypt(BytesView, String, String, Int64, Int64, strength? : Int32) -> Bytes
Encrypt data under password with WinZip AES.
strength is 128, 192 or 256. Returns the bytes that go where the payload
used to: salt, verification value, ciphertext, authentication tag. The AE-1
versus AE-2 choice belongs to the writer, because it is a choice about the
CRC in the header rather than about the ciphertext.
| BytesView | — | positional |
| String | — | positional |
| String | — | positional |
| Int64 | — | positional |
| Int64 | — | positional |
| strength | Int32 | labelled, optional |
returns Bytes
pub fn entry(BytesView, String, limit? : Int32, codecs? : ArrayView[&Codec], password? : String) -> Entry? raise @moonzip.Refused
One entry by name, expanding only that one.
None for a name the archive does not hold — asking whether something is in
an archive is a question, not a failure. A name that is there but whose
content is damaged still raises: that is a broken archive, not an absent
member.
| BytesView | — | positional |
| String | — | positional |
| limit | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| password | String | labelled, optional |
returns Entry? · raises @moonzip.Refused
pub fn join(ArrayView[Bytes]) -> Bytes
Put the volumes back together, in the order they were split.
The result is the archive the volumes were cut from, which is what
unzip and names expect.
| ArrayView[Bytes] | — | positional |
returns Bytes
pub let level : Int32
pub fn names(BytesView) -> Array[String] raise @moonzip.Refused
Every entry's name, without decompressing anything.
The central directory is a table at the end of the archive that names every
member; reading it costs nothing next to expanding them. This is what a
caller listing an archive wants, and what zipfile.namelist() is.
| BytesView | — | positional |
returns Array[String] · raises @moonzip.Refused
pub fn split(BytesView, Int32) -> Array[Bytes]
Cut a finished archive into volumes of at most size bytes, in order.
Every volume but the last is exactly size bytes; the last holds the rest,
which may be less. An archive that fits in one volume comes back as a single
volume, and an empty one as an empty array. size must be positive: a volume
that holds nothing would be a loop that never advances.
| BytesView | — | positional |
| Int32 | — | positional |
returns Array[Bytes]
pub fn unzip(BytesView, limit? : Int32, codecs? : ArrayView[&Codec], password? : String) -> Array[Entry] raise @moonzip.Refused
Every entry, expanded.
limit bounds what one entry may expand to. An archive is worth bounding
even more than a single stream is: a few kilobytes of archive can declare a
hundred members that each claim to be a gigabyte.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| password | String | labelled, optional |
returns Array[Entry] · raises @moonzip.Refused
pub fn unzip_spanned(ArrayView[Bytes], limit? : Int32, codecs? : ArrayView[&Codec], password? : String) -> Array[Entry] raise @moonzip.Refused
Read an archive that arrived as spanned volumes.
The volumes are joined, each directory record's disk and relative offset are
translated back to one coordinate space, and the result is read exactly as
unzip reads a single buffer. Volumes must be in disk order.
| ArrayView[Bytes] | — | positional |
| limit | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| password | String | labelled, optional |
returns Array[Entry] · raises @moonzip.Refused
pub fn unzip_split(ArrayView[Bytes], limit? : Int32, codecs? : ArrayView[&Codec], password? : String) -> Array[Entry] raise @moonzip.Refused
Read an archive that arrived as several volumes.
The volumes are joined first — a split archive is the same bytes cut at
boundaries, so the pieces in order are the archive — and then read exactly as
unzip reads one buffer.
| ArrayView[Bytes] | — | positional |
| limit | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| password | String | labelled, optional |
returns Array[Entry] · raises @moonzip.Refused
pub fn volume_names(String, Int32) -> Array[String]
The file names a split archive conventionally uses.
For an archive called base, the first count - 1 volumes are base.z01,
base.z02, … and the last is base.zip — the extension the tools look for,
which is why the final volume carries the one that says "zip" rather than
another number. A single volume is just base.zip.
| String | — | positional |
| Int32 | — | positional |
returns Array[String]
pub fn zip(ArrayView[Entry], level? : Int32, codecs? : ArrayView[&Codec], zip64? : Bool, descriptor? : Bool, password? : String, aes? : Int32, ae? : Int32) -> Bytes
Write an archive.
Entries are written in the order they are given, each with a local header, then the central directory, then the end record — the layout APPNOTE.TXT describes and the one every reader expects.
level reaches the compressor for the deflated entries; Stored ones carry
their bytes unchanged. An entry that deflates to no less than it started as
is stored instead, which is what zip itself does: a member should never
grow by being compressed.
zip64, descriptor, password, aes and ae are the
Writer's knobs, and they mean the same thing here. aes is 0
for no AES (ZipCrypto if a password is given), or 128, 192 or 256 for WinZip
AES at that strength. This function is that writer with every entry in hand
at once.
| ArrayView[Entry] | — | positional |
| level | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| zip64 | Bool | labelled, optional |
| descriptor | Bool | labelled, optional |
| password | String | labelled, optional |
| aes | Int32 | labelled, optional |
| ae | Int32 | labelled, optional |
returns Bytes
pub fn zip_spanned(ArrayView[Entry], Int32, level? : Int32, codecs? : ArrayView[&Codec], descriptor? : Bool, password? : String, aes? : Int32, ae? : Int32) -> Array[Bytes]
Write an archive as spanned volumes of at most size bytes each.
Each member's central-directory record is rewritten with the disk it starts
on and its offset from that disk's first byte, and the end record is rewritten
with the last disk's number and the directory's disk-relative offset. The
arguments after size are zip's.
A caller with a file system writes volume i under the name
volume_names gives it. The result differs from a
split only in those header fields: the bytes of the members are
the same, so a mode that has no need of disk numbers should use the simpler
one.
| ArrayView[Entry] | — | positional |
| Int32 | — | positional |
| level | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| descriptor | Bool | labelled, optional |
| password | String | labelled, optional |
| aes | Int32 | labelled, optional |
| ae | Int32 | labelled, optional |
returns Array[Bytes]
pub fn zip_split(ArrayView[Entry], Int32, level? : Int32, codecs? : ArrayView[&Codec], zip64? : Bool, descriptor? : Bool, password? : String, aes? : Int32, ae? : Int32) -> Array[Bytes]
Write an archive and split it in one step.
The arguments are zip's, plus the volume size. This is the call a
caller with a large archive and a size limit wants: it never builds the whole
stream twice, and the volumes are the ones unzip_split
reads back.
| ArrayView[Entry] | — | positional |
| Int32 | — | positional |
| level | Int32 | labelled, optional |
| codecs | ArrayView[&Codec] | labelled, optional |
| zip64 | Bool | labelled, optional |
| descriptor | Bool | labelled, optional |
| password | String | labelled, optional |
| aes | Int32 | labelled, optional |
| ae | Int32 | labelled, optional |
returns Array[Bytes]
pub fn zipcrypt_decrypt(BytesView, String, Byte) -> Bytes raise @moonzip.Refused
Decrypt what zipcrypt_encrypt wrote.
The check byte is compared before any of the body is handed back, so a wrong password says so instead of turning into a decompressor error three layers further in — which is the difference between "you typed the password wrong" and "this archive is damaged".
| BytesView | — | positional |
| String | — | positional |
| Byte | — | positional |
returns Bytes · raises @moonzip.Refused
pub fn zipcrypt_encrypt(BytesView, String, String, Int64, Byte) -> Bytes
Encrypt data under password.
check is the byte a reader compares after decrypting the header: the high
byte of the CRC-32, or — when the entry's sizes are in a data descriptor
rather than its local header — the high byte of the MS-DOS time. The caller
knows which, because the caller owns the flags.
| BytesView | — | positional |
| String | — | positional |
| String | — | positional |
| Int64 | — | positional |
| Byte | — | positional |
returns Bytes
One member of an archive.
| name | String | The path inside the archive, with forward slashes. |
| data | Bytes | The content. Empty for anything that is not a file. |
| kind | Tarball | What it is. |
| mode | Int32 | Permission bits, which tar keeps as a whole 07777 — setuid and sticky
included, because a tar that dropped them could not restore |
| mtime | Int64 | Last modification, in Unix seconds. |
| uid | Int32 | |
| gid | Int32 | |
| uname | String | The owner's name, which is what a reader prefers over the number when the archive is restored on a different machine. |
| gname | String | The group's name. |
| link | String | The target of a link. |
pub fn Entry::directory(String, mode? : Int32) -> Self
A directory entry.
| String | — | positional |
| mode | Int32 | labelled, optional |
returns Self
pub fn Entry::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Entry::new(String, Bytes, kind? : Tarball, mode? : Int32, mtime? : Int64) -> Self
A file with only a name and its content.
| String | — | positional |
| Bytes | — | positional |
| kind | Tarball | labelled, optional |
| mode | Int32 | labelled, optional |
| mtime | Int64 | labelled, optional |
returns Self
pub fn Entry::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Entry::symlink(String, String) -> Self
A symbolic link.
| String | — | positional |
| String | — | positional |
returns Self
pub fn Entry::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
What a member of an archive is.
tar carries more than files: a directory, a symbolic link, a hard link to a
member further up, and the three device nodes. The ones a caller is likely to
meet are here; the rest are kept as Other so that reading an
archive with a device node in it does not fail, and so that writing one back
out produces what came in.
| File | A regular file. The only one with bytes in it. | |
| Directory | A directory. Its name ends with a slash and its size is zero. | |
| Symlink | A symbolic link, whose target is in the entry's | |
| Hardlink | A hard link to a member already in the archive, by the name in | |
| Other | Byte | A character or block device, a FIFO, or a type this package does not name. |
pub fn Tarball::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Tarball::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Tarball::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
pub fn names(BytesView) -> Array[String] raise @moonzip.Refused
Every entry's name, which still has to walk the archive: tar has no index.
| BytesView | — | positional |
returns Array[String] · raises @moonzip.Refused
pub fn tar(ArrayView[Entry]) -> Bytes
Write an archive.
Members go out in the order they are given, each as a header, its bytes padded to a block boundary, then two empty blocks to say the archive is over.
A name longer than a hundred bytes is carried in a pax extended header,
which is a member of its own whose content is a list of keyword=value
records. That is the POSIX answer, and it is what GNU tar and bsdtar both
read; the older GNU L record is read but not written, because one way to
say a thing is enough.
The archive is reproducible: the modification time comes from the entry and
the owner is nobody, so the same entries always give the same bytes. Set
mtime and uid on an entry when it should carry something else.
| ArrayView[Entry] | — | positional |
returns Bytes
pub fn targz(ArrayView[Entry], level? : Int32) -> Bytes
A tarball: the archive gzipped, which is what .tar.gz and .tgz are.
The two formats stack cleanly — gzip compresses the bytes, and the bytes are a tar archive — so this is three lines rather than a format of its own. The compression is of the whole archive, which is why a tarball compresses far better than the same files compressed one at a time: gzip sees every member's redundancy, not just each member's own.
| ArrayView[Entry] | — | positional |
| level | Int32 | labelled, optional |
returns Bytes
pub fn untar(BytesView, limit? : Int32) -> Array[Entry] raise @moonzip.Refused
Read an archive.
Both ustar and pax come out, and the GNU long-name records that older
archives use are understood on the way. limit bounds what one member may
expand to, and tar needs it more than most: an archive is a header claiming a
length, and a header can claim anything.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Array[Entry] · raises @moonzip.Refused
pub fn untargz(BytesView, limit? : Int32) -> Array[Entry] raise @moonzip.Refused
Read a tarball.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Array[Entry] · raises @moonzip.Refused
A frame reader that is fed a piece at a time.
The unit is again one block: the reader holds the bytes of the block it is waiting for and decodes it the moment it is complete, so the memory it needs is the frame's declared block size whatever the body's length. A block that arrives in pieces produces nothing until it is whole, and one that arrives whole is handed back by the same push.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(checksum? : Bool, limit? : Int32) -> Self
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
A frame writer that takes the body a piece at a time.
A frame is a sequence of independent blocks, so the unit of work is one block: what is held between calls is the sixty-four kilobytes being filled and the running content checksum, never the body. A push that does not fill a block produces nothing, which is the format's own granularity rather than a choice made here.
moonbit nochecklet w = @lz4.Writer::new(level=0)
let mut out : Array[Byte] = []
for part in parts {
for b in w.push(part[:]) {
out.push(b)
}
}
for b in w.finish() {
out.push(b)
}pub fn Writer::finish(Self) -> Bytes
returns Bytes
pub fn Writer::new(level? : Int32) -> Self
| level | Int32 | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
| BytesView | — | positional |
returns Bytes
The same hash, fed a piece at a time.
A frame's content checksum covers the bytes before they were compressed, so a writer that never holds the whole body needs the hash as a state machine. What is left between calls is the four lanes, the length so far, and the bytes that did not fill a sixteen-byte stripe — which is what the four-byte and one-byte loops of the one-shot form would have read.
moonbit nochecklet h = @lz4.Xxh32::new()
h.push(part_one[:])
h.push(part_two[:])
let sum = h.finish()| seed | UInt32 | |
| v1 | UInt32 | |
| v2 | UInt32 | |
| v3 | UInt32 | |
| v4 | UInt32 | |
| total | Int32 | |
| held | Array[Byte] |
pub fn Xxh32::finish(Self) -> UInt32
returns UInt32
pub fn Xxh32::new(seed? : UInt32) -> Self
| seed | UInt32 | labelled, optional |
returns Self
pub fn Xxh32::push(Self, BytesView) -> Unit
| BytesView | — | positional |
returns Unit
pub fn frame(BytesView, level? : Int32) -> Bytes
Wrap LZ4 blocks in a frame: a header, the blocks, an end mark and a content checksum.
Blocks are independent, so a decoder can start at any of them; the content checksum is over the original bytes rather than the compressed ones, so it catches a decoder that produced the wrong thing rather than only a link that flipped a bit.
A block that does not compress is stored as it is with the high bit of its length set, which is how the format says "this one is verbatim".
| BytesView | — | positional |
| level | Int32 | labelled, optional |
returns Bytes
pub fn lz4(BytesView, level? : Int32) -> Bytes
Compress into the LZ4 block format.
A block is a run of sequences. Each is a token whose high nibble is how many
literals follow and whose low nibble is the match length minus four, then the
literals, then a two-byte back-reference, then the match length's overflow
bytes. The last sequence carries literals only, and the format reserves the
last five bytes of the input for them — a decoder relies on both, which is
why match_start stops twelve bytes short of the end.
level picks the search depth: 0 uses one candidate per position, which is
what LZ4's own "fast" mode does; higher values walk a chain. The ratio gain
above the default is small and the cost is real — this is a format chosen for
speed.
| BytesView | — | positional |
| level | Int32 | labelled, optional |
returns Bytes
pub fn unframe(BytesView, checksum? : Bool, limit? : Int32) -> Bytes raise @moonzip.Refused
Read a frame back.
checksum is what turns "some bytes came out" into "the right bytes came
out"; a caller recovering what it can from a damaged transfer turns it off.
A skippable frame — the format's way of saying "not mine, step over it" — is
stepped over rather than refused.
| BytesView | — | positional |
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn unlz4(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Decompress an LZ4 block.
There is no length in the format, so limit is the only thing standing
between a hostile block and the heap.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn xxh32(BytesView, seed? : UInt32) -> UInt32
The hash itself.
| BytesView | — | positional |
| seed | UInt32 | labelled, optional |
returns UInt32
A framed reader that is fed a piece at a time.
A chunk is the largest thing held: its header says its length, so a reader waits for exactly that many bytes and then decodes, and the memory it needs is one chunk whatever the body's length.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(checksum? : Bool, limit? : Int32) -> Self
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
A framed writer that takes the body a piece at a time.
The framing format's unit is a sixty-four-kilobyte chunk with its own checksum, so a writer can hand each one over as soon as it fills and hold nothing else. That is why the format exists: a receiver reads a chunk, checks it, and appends.
moonbit nochecklet w = @snappy.Writer::new()
let mut out : Array[Byte] = []
for part in parts {
for b in w.push(part[:]) {
out.push(b)
}
}
for b in w.finish() {
out.push(b)
}pub fn Writer::finish(Self) -> Bytes
returns Bytes
pub fn Writer::new() -> Self
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
| BytesView | — | positional |
returns Bytes
pub fn frame(BytesView) -> Bytes
Wrap Snappy blocks in the framing format.
The stream identifier comes first, then a chunk per sixty-four kilobytes — compressed with a masked CRC-32C when compressing helped, verbatim with one when it did not. A chunk that grew would be a chunk that cost time to decode and bytes to store, so the format has a way to say "verbatim" and this uses it.
| BytesView | — | positional |
returns Bytes
pub fn snappy(BytesView) -> Bytes
Compress into the Snappy block format.
A block starts with the uncompressed length as a varint — the one thing a
decoder is told up front, and the reason Snappy needs no bound of its own to
be safe — and then a run of tags. A tag is a literal or a copy, and its two
low bits say which: 00 a literal, 01 a copy with an eleven-bit offset,
10 one with a sixteen-bit offset, 11 one with a thirty-two-bit offset.
The three copy forms exist so that the common cases cost two bytes.
The compressor is greedy: one candidate per position from a hash of four bytes, extended as far as it runs. Snappy's own encoder is not much cleverer, because the format's whole point is that decompression be quick.
| BytesView | — | positional |
returns Bytes
pub fn unframe(BytesView, checksum? : Bool, limit? : Int32) -> Bytes raise @moonzip.Refused
Read a framed stream back.
checksum is what makes the CRC-32C in each chunk mean something; a caller
recovering what arrived from a broken transfer turns it off. A skippable chunk
— the format's way of letting a caller put its own data in the middle — is
stepped over, and an unskippable one is refused, because that is the
difference the two ranges of type numbers exist to make.
| BytesView | — | positional |
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn unsnappy(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Decompress a Snappy block.
The length in front is a claim, not a fact, so limit still applies: a
sixteen-byte block can claim four gigabytes. The claim is also what lets this
reader refuse a stream that ends early rather than return what it got.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
A decoder that can be fed a stream in pieces, which is what LZMA2 needs: the dictionary and the learned probabilities survive across chunks, and only the range coder restarts.
pub fn Decoder::append(Self, BytesView) -> Unit
Append bytes decoded elsewhere — an LZMA2 chunk that was stored rather than ranged-coded still belongs in the dictionary, or the next chunk's matches would land on the wrong bytes.
| BytesView | — | positional |
returns Unit
pub fn Decoder::feed(Self, BytesView, Int32) -> Int32 raise @moonzip.Refused
Decode until want bytes have been produced, or — when want is negative —
until the end marker. Returns the number produced by this call.
Everything is measured against out, which is both the answer and the
dictionary: a back-reference is an index into what has already been produced,
so there is nothing else to keep.
| BytesView | — | positional |
| Int32 | — | positional |
returns Int32 · raises @moonzip.Refused
pub fn Decoder::length(Self) -> Int32
How much has been produced — the mark a caller keeps before a chunk.
returns Int32
pub fn Decoder::new(limit? : Int32) -> Self
A decoder with the default probabilities and nothing decoded.
| limit | Int32 | labelled, optional |
returns Self
pub fn Decoder::output(Self) -> Bytes
The bytes decoded so far, which for a container is also the dictionary.
returns Bytes
pub fn Decoder::properties(Self, Int32) -> Unit raise @moonzip.Refused
Adopt a properties byte: literally pb * 5 * 9 + lp * 9 + lc, which is how
LZMA packs three small numbers into one.
| Int32 | — | positional |
returns Unit · raises @moonzip.Refused
pub fn Decoder::reset(Self) -> Unit
Forget everything but the model's shape: the start of a stream, or a dictionary reset in LZMA2.
returns Unit
pub fn Decoder::since(Self, Int32) -> Bytes
The bytes produced since mark, which is how a chunk's output is taken
without copying the whole dictionary.
| Int32 | — | positional |
returns Bytes
pub fn Decoder::trim(Self, Int32) -> Unit
Drop everything a back-reference can no longer reach, keeping keep bytes.
This is what makes a streaming reader's memory the dictionary rather than the
stream.
| Int32 | — | positional |
returns Unit
A .lzma reader that is fed a piece at a time.
There are no blocks to wait for, so the reader stops wherever a token ends and keeps the range coder's three registers — the range, the code and the read position — to carry on from. What it will not do is stop in the middle of a token: the probabilities have been updated by then, and a token cannot be decoded twice. A token can consume at most a few hundred bytes, which is why the reader waits until that much is in hand rather than trying and rewinding.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(limit? : Int32) -> Self
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
An .lzma writer that takes the body a piece at a time.
The format is a single range-coded stream with no block structure, so there is no boundary to reset at: what is held between calls is the dictionary a match may reach into, the hash chains over it, and the learned probabilities. That is a window, not a body — which is what lets a two-gigabyte file be written by a process that never holds two gigabytes.
The size in the header is left unknown and the stream ends with an end marker, because a writer that has not seen the end of the body cannot promise a length.
moonbit nochecklet w = @lzma.Writer::new(level=6)
let mut out : Array[Byte] = []
for part in parts {
for b in w.push(part[:]) {
out.push(b)
}
}
for b in w.finish() {
out.push(b)
}pub fn Writer::finish(Self) -> Bytes
returns Bytes
pub fn Writer::new(level? : Int32) -> Self
| level | Int32 | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
| BytesView | — | positional |
returns Bytes
pub let chunk_size : Int32
pub fn decoded_dict(Int32) -> Int32
| Int32 | — | positional |
returns Int32
pub fn dict_code(Int32) -> Int32
The LZMA2 dictionary-size code: the smallest property whose decoded size is at least what was asked for, because a decoder has to know how much memory to reserve before it starts.
| Int32 | — | positional |
returns Int32
pub fn dictionary_for(Int32) -> Int32
The dictionary size a level asks for. It bounds how far back a match may
reach, and therefore how much a decoder must hold; 8 MiB at the top is what
xz -9 uses.
| Int32 | — | positional |
returns Int32
pub fn encode(BytesView, Int32, Int32, level? : Int32) -> Bytes
Compress with LZMA, using the given properties and dictionary size.
The match finder is a hash chain over three bytes, walked greedily: the first match of three or more bytes wins, and the repeat distance is tried before the chain because it costs a handful of bits instead of a distance. That is a long way from an optimal parse, and it is the same order of effort a mainstream level-six encoder makes — the point here is a stream that real decoders read, not the last three percent.
| BytesView | — | positional |
| Int32 | — | positional |
| Int32 | — | positional |
| level | Int32 | labelled, optional |
returns Bytes
pub fn lzma(BytesView, level? : Int32) -> Bytes
Compress into the .lzma "alone" container: thirteen bytes of header, then
the range-coded stream.
The header says the properties (how many context bits the literals use), the
dictionary size, and the uncompressed size — which is written, so the stream
does not need an end marker. level maps to the same presets xz uses, and
the dictionary is capped at what a decoder can be asked to hold.
| BytesView | — | positional |
| level | Int32 | labelled, optional |
returns Bytes
pub fn lzma2(BytesView, Int32, Int32) -> Bytes
LZMA2: LZMA in chunks, each with its own range coder, and a control byte that says how much state to throw away first.
Every chunk resets the state and the properties, which costs a few hundred forgettable decisions per megabyte and makes each chunk independent; the dictionary is the only thing carried across. The first chunk must reset the dictionary too — a decoder has none to start from.
| BytesView | — | positional |
| Int32 | — | positional |
| Int32 | — | positional |
returns Bytes
pub fn properties_of(Int32, Int32, Int32) -> Int32
The properties byte for a set of parameters.
| Int32 | — | positional |
| Int32 | — | positional |
| Int32 | — | positional |
returns Int32
pub fn unlzma(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Read a .lzma "alone" container.
A stream may leave its length unknown and end with a marker instead, which is what every encoder did before sizes could be trusted; both are read here.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn unlzma2(BytesView, Int32, Decoder) -> (Bytes, Int32) raise @moonzip.Refused
Decode the LZMA2 chunks starting at at, and say where they ended.
| BytesView | — | positional |
| Int32 | — | positional |
| Decoder | — | positional |
returns (Bytes, Int32) · raises @moonzip.Refused
The check an xz block carries: a checksum over the uncompressed data, after the block's padding.
CRC-64 is xz's default; CRC-32 and none exist for streams that want them. SHA-256 is in the format and is read here without being verified, because verifying it would mean carrying a hash function this library does not have — the stream still decodes, and the gap is stated rather than hidden.
| None | ||
| Crc32 | ||
| Crc64 |
pub fn Check::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Check::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Check::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
CRC-64 as xz uses it: the reflected ECMA-182 polynomial, starting and ending complemented. Sixty-four bits because a block can be a gigabyte, and a thirty-two-bit checksum over that much is a weaker claim than the format wanted to make.
The struct is the same checksum kept as a state, which is what a block that is still arriving needs: the check covers the bytes before they were compressed, and a streaming writer never holds them all.
| sum | UInt64 |
pub fn Crc64::finish(Self) -> UInt64
returns UInt64
pub fn Crc64::new() -> Self
returns Self
pub fn Crc64::push(Self, BytesView) -> Unit
| BytesView | — | positional |
returns Unit
A reader that is fed an xz stream a piece at a time.
A chunk states both sizes, so the reader waits for exactly the bytes it needs and decodes one chunk at a time; the dictionary it keeps is the one the block header named. The index and the footer are checked at the end, which is the only place a truncated file can be told from a whole one.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(limit? : Int32) -> Self
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
An xz writer that takes the body a piece at a time.
The container is built for this: a block holds a run of LZMA2 chunks, each with its own range coder and its own sizes, so a chunk can be handed over as soon as it fills. What is held between calls is one chunk — a megabyte — and the two counters the index and the check need. The index is written at the end because that is where the format puts it, and because its sizes are only known then.
moonbit nochecklet w = @xz.Writer::new(level=6)
let mut out : Array[Byte] = []
for part in parts {
for b in w.push(part[:]) {
out.push(b)
}
}
for b in w.finish() {
out.push(b)
}pub fn Writer::finish(Self) -> Bytes
returns Bytes
pub fn Writer::new(level? : Int32, check? : Check) -> Self
| level | Int32 | labelled, optional |
| check | Check | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
| BytesView | — | positional |
returns Bytes
pub fn unxz(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Read an xz stream.
The header, the block header, the index and the footer are each checked against their own CRC, and the block against the check the header named. A stream that disagrees with itself is refused rather than decoded into something plausible.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn xz(BytesView, level? : Int32, check? : Check) -> Bytes
Compress into an xz stream.
One block holds everything; a stream of several blocks is what a parallel compressor produces and a reader does not care either way. The block names LZMA2 with a stated dictionary, the index follows it, and the footer closes it — all three of which a reader checks before trusting a byte.
The block's data is padded to a four-byte boundary *before* its check, not after: that is where the specification puts it, and a stream that pads afterwards reads its own check three bytes early and is rejected by every other implementation.
| BytesView | — | positional |
| level | Int32 | labelled, optional |
| check | Check | labelled, optional |
returns Bytes
A reader that is fed a piece at a time.
A bzip2 block cannot be decoded until all of it has arrived, so a push that does not complete a block produces nothing. What survives between pushes is the bit position of the block that is being waited for — a *bit* position, not a byte one, because the format does not pad between blocks: the next marker starts at the next bit, which is why this reader keeps an accumulator rather than an offset.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(checksum? : Bool, limit? : Int32) -> Self
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
A compressor that is fed a piece at a time.
bzip2 cannot emit anything until a block is complete — the sort needs all of it — so what is held between calls is one block's worth of the run-length stage plus a block of output. That is the format's own memory bound, not an arbitrary one, and it is why the level is a memory setting.
moonbit nochecklet w = @bzip2.Writer::new(level=9)
let mut out = w.push(part_one[:])
out = out + w.push(part_two[:])
out = out + w.finish()pub fn Writer::finish(Self) -> Bytes
returns Bytes
pub fn Writer::new(level? : Int32) -> Self
| level | Int32 | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
| BytesView | — | positional |
returns Bytes
pub fn bunzip2(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Decompress a bzip2 stream.
limit is how much output the caller is prepared to hold; a compressed stream
says nothing about how far it expands, so a reader of untrusted input should
say. Past it, TooBig rather than an allocation.
moonbit nochecklet plain = @bzip2.bunzip2(packed[:])| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn bzip2(BytesView, level? : Int32) -> Bytes
Compress into bzip2.
level is one to nine and means what it means everywhere else: how much memory
the compressor may use on a block, and so how far back a match can reach. Nine
is the default because the format's own default is nine, and a caller who cares
has an opinion.
moonbit nochecklet packed = @bzip2.bzip2(body[:], level=9)| BytesView | — | positional |
| level | Int32 | labelled, optional |
returns Bytes
One member of an archive.
data is empty for a directory and for a file that had no content, which are
two different things: kind tells them apart, and size does not.
| name | String | |
| data | Bytes | |
| kind | Kind | |
| mtime | Int64 | Last modification, in Unix seconds. 7-Zip stores a Windows FILETIME, which is a hundred-nanosecond count since 1601, so a value read back is exact and a value that was never recorded is zero. |
| attributes | UInt32 | The Windows attribute word, kept because it is the only place 7-Zip records "hidden", "read-only" and "directory". |
pub fn Entry::directory(String, mtime? : Int64) -> Self
| String | — | positional |
| mtime | Int64 | labelled, optional |
returns Self
pub fn Entry::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Entry::new(String, Bytes, mtime? : Int64, attributes? : UInt32) -> Self
| String | — | positional |
| Bytes | — | positional |
| mtime | Int64 | labelled, optional |
| attributes | UInt32 | labelled, optional |
returns Self
pub fn Entry::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Entry::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
What an entry is. 7-Zip records it in the file attributes rather than in a type field, which is why this is derived rather than read.
| File | ||
| Directory |
pub fn Kind::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Kind::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Kind::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
How the writer compresses. 7z is a container, so this is a choice rather than a property of the format: the same archive can hold a folder of LZMA and a folder of copies.
| Copy | Nothing at all. The folder exists so the file table has something to point
at, which is what makes a | |
| Lzma | LZMA, which is what 7-Zip's own default is for text. | |
| Lzma2 | LZMA2, the chunked form. Same codec, resettable state. |
pub fn Method::equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Method::label(Self) -> String
The name a log line wants.
returns String
pub fn Method::not_equal(Self, Self) -> Bool
Derived trait glue.
returns Bool
pub fn Method::to_repr(Self) -> @debug.Repr
Derived trait glue.
returns @debug.Repr
implements Debug, Eq
pub fn names(BytesView) -> Array[String] raise @moonzip.Refused
The names in an archive, without decompressing anything.
Reading a directory should not cost the directory's contents, which for a solid archive would be the whole thing.
| BytesView | — | positional |
returns Array[String] · raises @moonzip.Refused
pub fn sevenz(ArrayView[Entry], level? : Int32, how? : Method, solid? : Bool) -> Bytes
Build a 7z archive.
moonbit nochecklet archive = @sevenz.sevenz(members[:], level=6)
solid is 7-Zip's own default and the format's reason for existing: one
folder holds every file, so the compressor sees them all at once and a
repeated phrase across two files is paid for once. The cost is that reading
the last file means decompressing the first ones, which is why it is an
argument.
| ArrayView[Entry] | — | positional |
| level | Int32 | labelled, optional |
| how | Method | labelled, optional |
| solid | Bool | labelled, optional |
returns Bytes
pub fn un7z(BytesView, limit? : Int32) -> Array[Entry] raise @moonzip.Refused
Read a 7z archive.
moonbit nochecklet members = @sevenz.un7z(archive[:])
limit is how much output the caller is prepared to hold. An archive declares
its unpacked sizes, so this is checked before the allocation rather than after.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Array[Entry] · raises @moonzip.Refused
A frame reader that is fed a piece at a time.
The blocks of a frame are not independent — the repeat offsets and the four entropy tables carry from one to the next — so what a reader keeps is the frame's state, trimmed to its window: a back-reference reaches at most that far, and the bytes past it can never be asked for again.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(checksum? : Bool, limit? : Int32) -> Self
| checksum | Bool | labelled, optional |
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
A frame writer that takes the body a piece at a time.
A zstd frame is a run of blocks, each with its own literals and sequences, so the unit of work is one block: what is held between calls is the sixty-four kilobytes being filled. The frame says its window in the header instead of its content size, because a writer that has not seen the body cannot promise one.
moonbit nochecklet w = @zstd.Writer::new(level=3)
let mut out : Array[Byte] = []
for part in parts {
for b in w.push(part[:]) {
out.push(b)
}
}
for b in w.finish() {
out.push(b)
}pub fn Writer::finish(Self) -> Bytes
returns Bytes
pub fn Writer::new(level? : Int32) -> Self
| level | Int32 | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
| BytesView | — | positional |
returns Bytes
pub fn unzstd(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Decompress a zstd frame.
moonbit nochecklet plain = @zstd.unzstd(packed[:])| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused
pub fn zstd(BytesView, level? : Int32) -> Bytes
Compress into a zstd frame.
moonbit nochecklet packed = @zstd.zstd(body[:])
The block is an LZ77 parse coded with the *predefined* FSE tables, and the
literals are sent raw. That is a legal frame that any decoder reads, and it
compresses: what it gives up against zstd -19 is the per-block table
selection and the Huffman coding of literals, which are the two parts of the
reference encoder that are about ratio rather than about the format.
| BytesView | — | positional |
| level | Int32 | labelled, optional |
returns Bytes
A reader that is fed a piece at a time.
A meta-block cannot be decoded in halves, so the reader keeps the bytes it was given and tries again when more arrive — starting from the last meta-block boundary, because the bit cursor, the distance ring and the byte count are all only consistent there. The retry threshold doubles what has to arrive before the next attempt, so a body delivered a byte at a time is not quadratic.
pub fn Reader::finish(Self) -> Bytes raise @moonzip.Refused
returns Bytes · raises @moonzip.Refused
pub fn Reader::new(limit? : Int32) -> Self
| limit | Int32 | labelled, optional |
returns Self
pub fn Reader::push(Self, BytesView) -> Bytes raise @moonzip.Refused
| BytesView | — | positional |
returns Bytes · raises @moonzip.Refused
A writer that takes the body a piece at a time.
A stream is a run of meta-blocks, and a meta-block is a megabyte, so the unit of work is one of those: what is held between calls is that megabyte and the window a copy may reach back into — the window is why a match found in one meta-block can still be used in the next, which is what a periodic file needs.
moonbit nochecklet w = @brotli.Writer::new(quality=9)
let mut out : Array[Byte] = []
for part in parts {
for b in w.push(part[:]) {
out.push(b)
}
}
for b in w.finish() {
out.push(b)
}pub fn Writer::finish(Self) -> Bytes
returns Bytes
pub fn Writer::new(window? : Int32, quality? : Int32) -> Self
| window | Int32 | labelled, optional |
| quality | Int32 | labelled, optional |
returns Self
pub fn Writer::push(Self, BytesView) -> Bytes
| BytesView | — | positional |
returns Bytes
pub fn brotli(BytesView, window? : Int32, quality? : Int32) -> Bytes
Brotli, RFC 7932.
The writer does all of what earns the format its ratio: literal context modelling, block types for the literal and command streams, the static dictionary, and short distance codes. At quality 9 — the default — it is level with the reference encoder on this repository's own documentation, and somewhat ahead of it below that.
window is the log of the window size, 10 to 24: how far back a copy may
reach. Larger windows find more matches and cost nothing but memory while
writing, since the reader keeps whatever it needs.
quality is 0 to 11 and is how hard the writer looks, not which features it
uses. Up to 8 it sets the number of hash-chain candidates walked and whether a
lazy step is taken, which is the whole of a greedy parse. From 10 the parse is
chosen rather than taken: an optimal walk over the block keeps the cheapest
price of reaching every position, prices come from the codes the previous
round produced, and each round's result is encoded to see which is genuinely
smaller. That is seven times the work of quality 9 on a 35 KB body — 193 ms
against 28 — and four and a half per cent off the output, because the parse is
where the last of the ratio lives. Ten and eleven differ only in how many
candidates the search walks, which on text changes almost nothing once the
parse is chosen.
A higher quality never produces more bytes and always takes longer.
| BytesView | — | positional |
| window | Int32 | labelled, optional |
| quality | Int32 | labelled, optional |
returns Bytes
pub fn unbrotli(BytesView, limit? : Int32) -> Bytes raise @moonzip.Refused
Un-brotli a complete stream.
| BytesView | — | positional |
| limit | Int32 | labelled, optional |
returns Bytes · raises @moonzip.Refused