# deflate.gzip

> A module of deflate's API.

gzip (RFC 1952) framing over the raw DEFLATE in `raw.mojo`.

`gunzip` decodes a whole `.gz` file: every member of a concatenated stream,
each one's header (all five flags: FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT)
parsed and skipped, and each one's CRC-32 and ISIZE checked against what it
decoded to. `gunzip_at` decodes one member and reports where it ended, as
`inflate_at` does for raw streams. `gzip` writes a single member.

The CRC-32 is the zlib/gzip one (reflected polynomial 0xEDB88320), slice-by-8
as in hashes.mojo's `crc32`. It is repeated here rather than imported so the
tin keeps no sibling dependency: a consumer still needs nothing but
`-I deflate.mojo/src`.

## Functions

### `crc32_backend`

```mojo
def crc32_backend() -> String
```

`armv8-crc` or `slice-by-8`: which CRC-32 this build uses.

### `gunzip`

```mojo
def gunzip(data: Span[UInt8]) -> List[UInt8]
```

Decompress a gzip file: all of its members, concatenated.

Each member's CRC-32 and length are verified. Zero bytes after the last
member are padding (as gzip(1) and Python's `gzip` accept); anything else
there raises, as does an empty input.

### `gunzip_at`

```mojo
def gunzip_at(data: Span[UInt8], mut end: Int) -> List[UInt8]
```

Decompress the one gzip member at the start of `data`, verifying its CRC-32 and length, and set `end` to the offset just past its trailer.

For walking a multi-member file one member at a time, so only one
member's output is held at once:

```mojo
var pos = 0
while pos < len(data):
    var end = 0
    var part = gunzip_at(Span(data)[pos:], end)
    pos += end
```

### `gzip`

```mojo
def gzip(data: Span[UInt8], level: Int = Int(6)) -> List[UInt8]
```

Compress `data` into a single gzip member.

`level` 0 writes stored (uncompressed) DEFLATE blocks; 1 to 9 all use
`deflate`'s one fixed-Huffman strategy, so they produce the same bytes.
The header carries no name, comment or timestamp (MTIME 0, OS 255).
