Just Deflate
A pure Dart implementation of DEFLATE (RFC 1951) compression and decompression, with the zlib (RFC 1950) and gzip (RFC 1952) formats around it.
It has no dependencies and no dart:io, dart:ffi or native code, so it runs the same everywhere: Flutter on every platform, the web (dart2js) and Wasm (dart2wasm). It was written for the just_tiled package, where Tiled stores tile layers as zlib or gzip data, and for the Just Game Engine's level maps.
Features
- zlib, gzip and raw DEFLATE, encoding and decoding.
- Real compression: LZ77 matching and dynamic Huffman codes, with zlib's settings for levels 0 to 9. Output is about the size of zlib's at the same level.
- The same bytes on every platform. Compressing the same data gives the same output on native, web and Wasm, so saved files don't change depending on where they were saved.
- Reads anything zlib writes: every block type, any window size, multi-member gzip files and gzip's optional header fields (name, comment, extra field, header CRC).
- Checked decoding: Adler-32 and CRC-32 checksums are verified, damaged data throws a
FormatException, andmaxOutputSizestops damaged or hostile data from unpacking without end. adler32andcrc32checksum functions.
Getting started
Add just_deflate to your pubspec.yaml:
dependencies:
just_deflate: ^0.1.0
Usage
zlib
import 'dart:typed_data';
import 'package:just_deflate/just_deflate.dart';
void main() {
final data = Uint8List(64 * 64 * 4); // an empty 64 x 64 tile layer
const zlib = ZlibCodec(); // level 6, zlib's default
final packed = zlib.encode(data);
print('${data.length} bytes -> ${packed.length} bytes');
try {
final unpacked = zlib.decode(packed, maxOutputSize: data.length);
print('Decoded ${unpacked.length} bytes.');
} on FormatException catch (e) {
print('Invalid zlib data: $e');
}
}
gzip and raw DEFLATE
GzipCodec and DeflateCodec work the same way:
const gzip = GzipCodec(level: 9); // smallest output
final packed = gzip.encode(data);
final unpacked = gzip.decode(packed);
const raw = DeflateCodec(level: 1); // fastest
final stream = raw.encode(data); // no header, no checksum
Levels
| Level | What it does |
|---|---|
| 0 | Stores the data uncompressed, in valid blocks. |
| 1-3 | Fast: takes the first good match it finds. |
| 4-9 | Lazy matching: checks whether the next position starts a longer match. Higher levels search further. |
| 6 | The default, zlib's balance of size and speed. |
A level outside 0-9 throws a RangeError from encode.
Checksums
crc32('123456789'.codeUnits); // 0xCBF43926
adler32('Wikipedia'.codeUnits); // 0x11E60398
// Data in pieces: pass the running value back in.
var crc = crc32(firstPart);
crc = crc32(secondPart, crc);
Notes
- zlib streams that need a preset dictionary (
FDICT) are refused. - Bytes after the end of a stream are ignored. In gzip data, anything after the last member that does not start another member is ignored.
encodewrites gzip headers with no file name, comment or time, and the operating system set to "unknown", so the output depends only on the data and the level.- Everything is in memory:
encodeanddecodetake the whole input and return the whole output. There is no streaming API.
License
BSD 3-Clause. See LICENSE.
Libraries
- just_deflate
- Pure Dart DEFLATE (RFC 1951) compression and decompression, with the zlib (RFC 1950) and gzip (RFC 1952) formats around it.