README.md 4.4 KiB
Newer Older
Daniel Friesel's avatar
Daniel Friesel committed
**zlib-deflate-nostdlib** provides a zlib decompressor (RFC 1950) and deflate
reader (RFC 1951) suitable for 8- and 16-bit microcontrollers. It works
fine on MCUs as small as ATMega328P (used, for example, in the Arduino Nano)
and MSP430FR5994. It is compatible with both C (tested with c99) and C++
(tested with c++14). Apart from type definitions for (u)int8\_t, (u)int16\_t,
and (u)int32\_t, which are typically provided by stdint.h, it has no external
dependencies.

zlib-deflate-nostdlib is focused on a low memory footprint. It is not optimized
for speed. Right now, the implementation is naive, but usable. See below for
the current status and TODOs. Be aware that this library has not been
extensively tested yet.

Note: This library *inflates* (i.e., decompresses) data. The source files and
API are named as such, as is the corresponding function in the original zlib
implementation. However, as the algorithm is called *deflate*, the project is
named zlib-*deflate*-nostdlib even though it does not support compression.

Daniel Friesel's avatar
Daniel Friesel committed
## Usage

Embed `inflate.c` and `inflate.h` into your project. You can rename `inflate.c`
to `inflate.cc` and/or compile it with g++ instead of gcc, if you like. Use
`inflate_zlib(input, input_len, output, output_len)` to decompress zlib data,
and `inflate(input, input_len, output, output_len)` to decompress deflate data
Daniel Friesel's avatar
Daniel Friesel committed
without zlib header.

input and output must be `unsigned char *`, input\_len and output\_len are
expected to be unsigned 16-bit integers. Both functions return the number of
bytes written to `output`, or a negative value on error.

Example for zlib decompression (RFC 1950):

```
#include "inflate.h"
Daniel Friesel's avatar
Daniel Friesel committed

unsigned char inflate_input[] = { /* some compressed data, e.g.: */
Daniel Friesel's avatar
Daniel Friesel committed
    120, 156, 243, 72, 205, 201, 201, 215, 81, 8, 207, 47, 202, 73, 177, 87,
    240, 64, 226, 41, 2, 0, 128, 125, 9, 17
};

unsigned char inflate_output[128];
Daniel Friesel's avatar
Daniel Friesel committed

// within some function
{
    int16_t out_bytes = inflate_zlib(inflate_input, sizeof(inflate_input),
                                     inflate_output, sizeof(inflate_output));
Daniel Friesel's avatar
Daniel Friesel committed
    if (out_bytes < 0) {
        // error
    } else {
        // success. inflate_output contains "Hello, World? Hello, World!"
        // out_bytes contains the number of bytes written to inflate_output
Daniel Friesel's avatar
Daniel Friesel committed
    }
}

```

Decompressing deflate (RFC 1951) data works as follows:

```
#include "inflate.h"
Daniel Friesel's avatar
Daniel Friesel committed

unsigned char inflate_input[] = { /* some compressed data, e.g.: */
Daniel Friesel's avatar
Daniel Friesel committed
    243, 72, 205, 201, 201, 215, 81, 8, 207, 47, 202, 73, 177, 87,
    240, 64, 226, 41, 2, 0
};

unsigned char inflate_output[128];
Daniel Friesel's avatar
Daniel Friesel committed

// within some function
{
    int16_t out_bytes = inflate(inflate_input, sizeof(inflate_input),
                                inflate_output, sizeof(inflate_output));
Daniel Friesel's avatar
Daniel Friesel committed
    if (out_bytes < 0) {
        // error
    } else {
        // success. inflate_output contains "Hello, World? Hello, World!"
        // out_bytes contains the number of bytes written to inflate_output
Daniel Friesel's avatar
Daniel Friesel committed
    }
}

```

## Compilation flags

Compile with `-DDEFLATE_CHECKSUM` to enable verification of the zlib ADLER32
checksum in `inflate_zlib`.
Daniel Friesel's avatar
Daniel Friesel committed

## Compliance

`inflate` is fully compliant with RFC 1951 for data with a decompressed size
of up to 65 kB.

When compiled with `-DDEFLATE_CHECKSUM`, `inflate_zlib` is fully compliant with
RFC 1950 (decompression only) for data with a decompressed size of up to 65 kB.
By default (without `-DDEFLATE_CHECKSUM`), it does not verify the ADLER32
checksum embedded into zlib-compressed data and is therefore not compliant with
RFC 1950.

For files larger than 65 kB, you only need to change some size arguments to
`uint32_t`. However, if you are decompressing files of that size, you probably
have more RAM than this library is designed for. In that case, you may be
better off with [udeflate](https://github.com/jlublin/udeflate),
[uzlib](https://github.com/pfalcon/uzlib), or similar.
Daniel Friesel's avatar
Daniel Friesel committed

## Requirements and Performance

RAM usage excludes the space needed for input and output buffer. ROM/RAM usage
rounded up to the next multiple of 16B. Performance tested with text files of
various sizes, minimum file size 500 bytes, maximum file size determined by the
amount of available RAM.

| Architecture | ROM | RAM | Speed
| :--- | ---: | ---: | ---: |
| 8-bit ATMega328P @ 16 MHz | 1440 B | 624 B | 10 .. 22 kB/s |
| 16-bit MSP430FR5994 @ 16 MHz | 2224 B | 432 B | 8 .. 16 kB/s |
| 20-bit MSP430FR5994 @ 16 MHz | 2512 B | 432 B | 8 .. 16 kB/s |
| 32-bit STM32F446RE (ARM Cortex M3) @ 168 MHz | 1552 B | 432 B | 258 .. 898 kB/s |