Browse Source

prepare v0.8.0

101arrowz 2 years ago
parent
commit
52da76efb5

+ 7 - 0
CHANGELOG.md

@@ -1,3 +1,10 @@
+## 0.8.0
+- BREAKING: synchronous decompression functions now take an options object rather than an output buffer as a second parameter
+  - `inflateSync(compressed, outBuf)` is now `inflateSync(compressed, { out: outBuf })`
+- Support dictionaries in compression and decompression
+- Support multi-member files in GZIP streaming decompression
+- Dramatically improved streaming performance
+- Fixed missing error on certain malformed GZIP files
 ## 0.7.3
 - Fix folder creation for certain operating system
   - Create 0-length "files" for each directory specified with "object" syntax"

+ 21 - 18
README.md

@@ -4,20 +4,21 @@ High performance (de)compression in an 8kB package
 ## Why fflate?
 `fflate` (short for fast flate) is the **fastest, smallest, and most versatile** pure JavaScript compression and decompression library in existence, handily beating [`pako`](https://npmjs.com/package/pako), [`tiny-inflate`](https://npmjs.com/package/tiny-inflate), and [`UZIP.js`](https://github.com/photopea/UZIP.js) in performance benchmarks while being multiple times more lightweight. Its compression ratios are often better than even the original Zlib C library. It includes support for DEFLATE, GZIP, and Zlib data. Data compressed by `fflate` can be decompressed by other tools, and vice versa.
 
-In addition to the base decompression and compression APIs, `fflate` supports high-speed ZIP file archiving for an extra 3 kB. In fact, the compressor, in synchronous mode, compresses both more quickly and with a higher compression ratio than most compression software (even Info-ZIP, a C program), and in asynchronous mode it can utilize multiple threads to achieve over 3x the performance of any other utility.
+In addition to the base decompression and compression APIs, `fflate` supports high-speed ZIP file archiving for an extra 3 kB. In fact, the compressor, in synchronous mode, compresses both more quickly and with a higher compression ratio than most compression software (even Info-ZIP, a C program), and in asynchronous mode it can utilize multiple threads to achieve over 3x the performance of virtually any other utility.
 
 |                             | `pako` | `tiny-inflate`         | `UZIP.js`             | `fflate`                       |
 |-----------------------------|--------|------------------------|-----------------------|--------------------------------|
 | Decompression performance   | 1x     | Up to 40% slower       | **Up to 40% faster**  | **Up to 40% faster**           |
-| Compression performance     | 1x     | N/A                    | Up to 5% faster       | **Up to 50% faster**           |
+| Compression performance     | 1x     | N/A                    | Up to 25% faster      | **Up to 50% faster**           |
 | Base bundle size (minified) | 45.6kB | **3kB (inflate only)** | 14.2kB                | 8kB **(3kB for inflate only)** |
+| Decompression support       | ✅     | ✅                      | ✅                    | ✅                             |
 | Compression support         | ✅     | ❌                      | ✅                    | ✅                             |
-| Thread/Worker safe          | ✅     | ✅                      | ❌                    | ✅                             |
 | ZIP support                 | ❌     | ❌                      | ✅                    | ✅                             |
 | Streaming support           | ✅     | ❌                      | ❌                    | ✅                             |
-| GZIP/Zlib support           | ✅     | ❌                      | ❌                    | ✅                             |
+| GZIP support                | ✅     | ❌                      | ❌                    | ✅                             |
 | Supports files up to 4GB    | ✅     | ❌                      | ❌                    | ✅                             |
 | Doesn't hang on error       | ✅     | ❌                      | ❌                    | ✅                             |
+| Dictionary support          | ✅     | ❌                      | ❌                    | ✅                             |
 | Multi-thread/Asynchronous   | ❌     | ❌                      | ❌                    | ✅                             |
 | Streaming ZIP support       | ❌     | ❌                      | ❌                    | ✅                             |
 | Uses ES Modules             | ❌     | ❌                      | ❌                    | ✅                             |
@@ -506,20 +507,22 @@ See the [documentation](https://github.com/101arrowz/fflate/blob/master/docs/REA
 
 ## Bundle size estimates
 
-Since `fflate` uses ES Modules, this table should give you a general idea of `fflate`'s bundle size for the features you need. The maximum bundle size that is possible with `fflate` is about 30kB if you use every single feature, but feature parity with `pako` is only around 10kB (as opposed to 45kB from `pako`). If your bundle size increases dramatically after adding `fflate`, please [create an issue](https://github.com/101arrowz/fflate/issues/new).
-
-| Feature                 | Bundle size (minified)         | Nearest competitor     |
-|-------------------------|--------------------------------|------------------------|
-| Decompression           | 3kB                            | `tiny-inflate`         |
-| Compression             | 5kB                            | `UZIP.js`, 184% larger |
-| Async decompression     | 4kB (1kB + raw decompression)  | N/A                    |
-| Async compression       | 6kB (1kB + raw compression)    | N/A                    |
-| ZIP decompression       | 5kB (2kB + raw decompression)  | `UZIP.js`, 184% larger |
-| ZIP compression         | 7kB (2kB + raw compression)    | `UZIP.js`, 103% larger |
-| GZIP/Zlib decompression | 4kB (1kB + raw decompression)  | `pako`, 1040% larger   |
-| GZIP/Zlib compression   | 5kB (1kB + raw compression)    | `pako`, 812% larger    |
-| Streaming decompression | 4kB (1kB + raw decompression)  | `pako`, 1040% larger   |
-| Streaming compression   | 5kB (1kB + raw compression)    | `pako`, 812% larger    |
+The bundle size measurements for `fflate` on sites like Bundlephobia include every feature of the library and should be seen as an upper bound. As long as you are using tree shaking or dead code elimination, this table should give you a general idea of `fflate`'s bundle size for the features you need.
+
+The maximum bundle size that is possible with `fflate` is about 31kB if you use every single feature, but feature parity with `pako` is only around 10kB (as opposed to 45kB from `pako`). If your bundle size increases dramatically after adding `fflate`, please [create an issue](https://github.com/101arrowz/fflate/issues/new).
+
+| Feature                 | Bundle size (minified)         | Nearest competitor      |
+|-------------------------|--------------------------------|-------------------------|
+| Decompression           | 3kB                            | `tiny-inflate`          |
+| Compression             | 5kB                            | `UZIP.js`, 2.84x larger |
+| Async decompression     | 4kB (1kB + raw decompression)  | N/A                     |
+| Async compression       | 6kB (1kB + raw compression)    | N/A                     |
+| ZIP decompression       | 5kB (2kB + raw decompression)  | `UZIP.js`, 2.84x larger |
+| ZIP compression         | 7kB (2kB + raw compression)    | `UZIP.js`, 2.03x larger |
+| GZIP/Zlib decompression | 4kB (1kB + raw decompression)  | `pako`, 11.4x larger    |
+| GZIP/Zlib compression   | 5kB (1kB + raw compression)    | `pako`, 9.12x larger    |
+| Streaming decompression | 4kB (1kB + raw decompression)  | `pako`, 11.4x larger    |
+| Streaming compression   | 5kB (1kB + raw compression)    | `pako`, 9.12x larger    |
 
 ## What makes `fflate` so fast?
 Many JavaScript compression/decompression libraries exist. However, the most popular one, [`pako`](https://npmjs.com/package/pako), is merely a clone of Zlib rewritten nearly line-for-line in JavaScript. Although it is by no means poorly made, `pako` doesn't recognize the many differences between JavaScript and C, and therefore is suboptimal for performance. Moreover, even when minified, the library is 45 kB; it may not seem like much, but for anyone concerned with optimizing bundle size (especially library authors), it's more weight than necessary.

+ 19 - 13
docs/README.md

@@ -43,13 +43,19 @@
 * [AsyncZlibOptions](interfaces/asynczliboptions.md)
 * [DeflateOptions](interfaces/deflateoptions.md)
 * [FlateError](interfaces/flateerror.md)
+* [GunzipOptions](interfaces/gunzipoptions.md)
+* [GunzipStreamOptions](interfaces/gunzipstreamoptions.md)
 * [GzipOptions](interfaces/gzipoptions.md)
+* [InflateOptions](interfaces/inflateoptions.md)
+* [InflateStreamOptions](interfaces/inflatestreamoptions.md)
 * [UnzipDecoder](interfaces/unzipdecoder.md)
 * [UnzipDecoderConstructor](interfaces/unzipdecoderconstructor.md)
 * [UnzipFile](interfaces/unzipfile.md)
 * [UnzipFileInfo](interfaces/unzipfileinfo.md)
 * [UnzipOptions](interfaces/unzipoptions.md)
 * [Unzipped](interfaces/unzipped.md)
+* [UnzlibOptions](interfaces/unzliboptions.md)
+* [UnzlibStreamOptions](interfaces/unzlibstreamoptions.md)
 * [ZipAttributes](interfaces/zipattributes.md)
 * [ZipInputFile](interfaces/zipinputfile.md)
 * [ZipOptions](interfaces/zipoptions.md)
@@ -258,7 +264,7 @@ ___
 
 ### decompressSync
 
-▸ **decompressSync**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
+▸ **decompressSync**(`data`: Uint8Array, `opts?`: [AsyncInflateOptions](interfaces/asyncinflateoptions.md)): Uint8Array
 
 Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format
 
@@ -267,7 +273,7 @@ Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the
 Name | Type | Description |
 ------ | ------ | ------ |
 `data` | Uint8Array | The data to decompress |
-`out?` | Uint8Array | Where to write the data. Saves memory if you know the decompressed size and provide an output buffer of that length. |
+`opts?` | [AsyncInflateOptions](interfaces/asyncinflateoptions.md) | The decompression options |
 
 **Returns:** Uint8Array
 
@@ -325,7 +331,7 @@ ___
 
 ▸ **gunzip**(`data`: Uint8Array, `opts`: [AsyncGunzipOptions](interfaces/asyncgunzipoptions.md), `cb`: [FlateCallback](README.md#flatecallback)): [AsyncTerminable](interfaces/asyncterminable.md)
 
-Asynchronously expands single-member GZIP data
+Asynchronously expands GZIP data
 
 #### Parameters:
 
@@ -339,7 +345,7 @@ Name | Type | Description |
 
 ▸ **gunzip**(`data`: Uint8Array, `cb`: [FlateCallback](README.md#flatecallback)): [AsyncTerminable](interfaces/asyncterminable.md)
 
-Asynchronously expands single-member GZIP data
+Asynchronously expands GZIP data
 
 #### Parameters:
 
@@ -354,16 +360,16 @@ ___
 
 ### gunzipSync
 
-▸ **gunzipSync**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
+▸ **gunzipSync**(`data`: Uint8Array, `opts?`: [GunzipOptions](interfaces/gunzipoptions.md)): Uint8Array
 
-Expands single-member GZIP data
+Expands GZIP data
 
 #### Parameters:
 
 Name | Type | Description |
 ------ | ------ | ------ |
 `data` | Uint8Array | The data to decompress |
-`out?` | Uint8Array | Where to write the data. GZIP already encodes the output size, so providing this doesn't save memory. |
+`opts?` | [GunzipOptions](interfaces/gunzipoptions.md) | The decompression options |
 
 **Returns:** Uint8Array
 
@@ -477,7 +483,7 @@ ___
 
 ### inflateSync
 
-▸ **inflateSync**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
+▸ **inflateSync**(`data`: Uint8Array, `opts?`: [InflateOptions](interfaces/inflateoptions.md)): Uint8Array
 
 Expands DEFLATE data with no wrapper
 
@@ -486,7 +492,7 @@ Expands DEFLATE data with no wrapper
 Name | Type | Description |
 ------ | ------ | ------ |
 `data` | Uint8Array | The data to decompress |
-`out?` | Uint8Array | Where to write the data. Saves memory if you know the decompressed size and provide an output buffer of that length. |
+`opts?` | [InflateOptions](interfaces/inflateoptions.md) | The decompression options |
 
 **Returns:** Uint8Array
 
@@ -577,7 +583,7 @@ ___
 
 ### unzlib
 
-▸ **unzlib**(`data`: Uint8Array, `opts`: [AsyncGunzipOptions](interfaces/asyncgunzipoptions.md), `cb`: [FlateCallback](README.md#flatecallback)): [AsyncTerminable](interfaces/asyncterminable.md)
+▸ **unzlib**(`data`: Uint8Array, `opts`: [AsyncUnzlibOptions](interfaces/asyncunzliboptions.md), `cb`: [FlateCallback](README.md#flatecallback)): [AsyncTerminable](interfaces/asyncterminable.md)
 
 Asynchronously expands Zlib data
 
@@ -586,7 +592,7 @@ Asynchronously expands Zlib data
 Name | Type | Description |
 ------ | ------ | ------ |
 `data` | Uint8Array | The data to decompress |
-`opts` | [AsyncGunzipOptions](interfaces/asyncgunzipoptions.md) | The decompression options |
+`opts` | [AsyncUnzlibOptions](interfaces/asyncunzliboptions.md) | The decompression options |
 `cb` | [FlateCallback](README.md#flatecallback) | The function to be called upon decompression completion |
 
 **Returns:** [AsyncTerminable](interfaces/asyncterminable.md)
@@ -608,7 +614,7 @@ ___
 
 ### unzlibSync
 
-▸ **unzlibSync**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
+▸ **unzlibSync**(`data`: Uint8Array, `opts?`: [UnzlibOptions](interfaces/unzliboptions.md)): Uint8Array
 
 Expands Zlib data
 
@@ -617,7 +623,7 @@ Expands Zlib data
 Name | Type | Description |
 ------ | ------ | ------ |
 `data` | Uint8Array | The data to decompress |
-`out?` | Uint8Array | Where to write the data. Saves memory if you know the decompressed size and provide an output buffer of that length. |
+`opts?` | [UnzlibOptions](interfaces/unzliboptions.md) | The decompression options |
 
 **Returns:** Uint8Array
 

+ 1 - 1
docs/classes/asyncgunzip.md

@@ -1,6 +1,6 @@
 # Class: AsyncGunzip
 
-Asynchronous streaming GZIP decompression
+Asynchronous streaming single or multi-member GZIP decompression
 
 ## Hierarchy
 

+ 14 - 1
docs/classes/gunzip.md

@@ -1,6 +1,6 @@
 # Class: Gunzip
 
-Streaming GZIP decompression
+Streaming single or multi-member GZIP decompression
 
 ## Hierarchy
 
@@ -24,6 +24,19 @@ Streaming GZIP decompression
 
 ### constructor
 
+\+ **new Gunzip**(`opts`: [GunzipStreamOptions](../interfaces/gunzipstreamoptions.md), `cb?`: [FlateStreamHandler](../README.md#flatestreamhandler)): [Gunzip](gunzip.md)
+
+Creates a GUNZIP stream
+
+#### Parameters:
+
+Name | Type | Description |
+------ | ------ | ------ |
+`opts` | [GunzipStreamOptions](../interfaces/gunzipstreamoptions.md) | The decompression options |
+`cb?` | [FlateStreamHandler](../README.md#flatestreamhandler) | The callback to call whenever data is inflated  |
+
+**Returns:** [Gunzip](gunzip.md)
+
 \+ **new Gunzip**(`cb?`: [FlateStreamHandler](../README.md#flatestreamhandler)): [Gunzip](gunzip.md)
 
 Creates a GUNZIP stream

+ 14 - 1
docs/classes/inflate.md

@@ -24,9 +24,22 @@ Streaming DEFLATE decompression
 
 ### constructor
 
+\+ **new Inflate**(`opts`: [InflateStreamOptions](../interfaces/inflatestreamoptions.md), `cb?`: [FlateStreamHandler](../README.md#flatestreamhandler)): [Inflate](inflate.md)
+
+Creates a DEFLATE decompression stream
+
+#### Parameters:
+
+Name | Type | Description |
+------ | ------ | ------ |
+`opts` | [InflateStreamOptions](../interfaces/inflatestreamoptions.md) | The decompression options |
+`cb?` | [FlateStreamHandler](../README.md#flatestreamhandler) | The callback to call whenever data is inflated  |
+
+**Returns:** [Inflate](inflate.md)
+
 \+ **new Inflate**(`cb?`: [FlateStreamHandler](../README.md#flatestreamhandler)): [Inflate](inflate.md)
 
-Creates an inflation stream
+Creates a DEFLATE decompression stream
 
 #### Parameters:
 

+ 13 - 0
docs/classes/unzlib.md

@@ -24,6 +24,19 @@ Streaming Zlib decompression
 
 ### constructor
 
+\+ **new Unzlib**(`opts`: [UnzlibStreamOptions](../interfaces/unzlibstreamoptions.md), `cb?`: [FlateStreamHandler](../README.md#flatestreamhandler)): [Unzlib](unzlib.md)
+
+Creates a Zlib decompression stream
+
+#### Parameters:
+
+Name | Type | Description |
+------ | ------ | ------ |
+`opts` | [UnzlibStreamOptions](../interfaces/unzlibstreamoptions.md) | The decompression options |
+`cb?` | [FlateStreamHandler](../README.md#flatestreamhandler) | The callback to call whenever data is inflated  |
+
+**Returns:** [Unzlib](unzlib.md)
+
 \+ **new Unzlib**(`cb?`: [FlateStreamHandler](../README.md#flatestreamhandler)): [Unzlib](unzlib.md)
 
 Creates a Zlib decompression stream

+ 18 - 0
docs/interfaces/asyncdeflateoptions.md

@@ -17,6 +17,7 @@ Options for compressing data asynchronously into a DEFLATE format
 ### Properties
 
 * [consume](asyncdeflateoptions.md#consume)
+* [dictionary](asyncdeflateoptions.md#dictionary)
 * [level](asyncdeflateoptions.md#level)
 * [mem](asyncdeflateoptions.md#mem)
 
@@ -33,6 +34,23 @@ unusable but will increase performance and reduce memory usage.
 
 ___
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [DeflateOptions](deflateoptions.md).[dictionary](deflateoptions.md#dictionary)*
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### level
 
 • `Optional` **level**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9

+ 15 - 0
docs/interfaces/asyncgunzipoptions.md

@@ -6,6 +6,8 @@ Options for decompressing GZIP data asynchronously
 
 * AsyncOptions
 
+* [InflateStreamOptions](inflatestreamoptions.md)
+
   ↳ **AsyncGunzipOptions**
 
 ## Index
@@ -13,6 +15,7 @@ Options for decompressing GZIP data asynchronously
 ### Properties
 
 * [consume](asyncgunzipoptions.md#consume)
+* [dictionary](asyncgunzipoptions.md#dictionary)
 
 ## Properties
 
@@ -24,3 +27,15 @@ Options for decompressing GZIP data asynchronously
 
 Whether or not to "consume" the source data. This will make the typed array/buffer you pass in
 unusable but will increase performance and reduce memory usage.
+
+___
+
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.

+ 18 - 0
docs/interfaces/asyncgzipoptions.md

@@ -15,6 +15,7 @@ Options for compressing data asynchronously into a GZIP format
 ### Properties
 
 * [consume](asyncgzipoptions.md#consume)
+* [dictionary](asyncgzipoptions.md#dictionary)
 * [filename](asyncgzipoptions.md#filename)
 * [level](asyncgzipoptions.md#level)
 * [mem](asyncgzipoptions.md#mem)
@@ -33,6 +34,23 @@ unusable but will increase performance and reduce memory usage.
 
 ___
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [DeflateOptions](deflateoptions.md).[dictionary](deflateoptions.md#dictionary)*
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### filename
 
 • `Optional` **filename**: string

+ 15 - 0
docs/interfaces/asyncinflateoptions.md

@@ -6,6 +6,8 @@ Options for decompressing DEFLATE data asynchronously
 
 * AsyncOptions
 
+* [InflateStreamOptions](inflatestreamoptions.md)
+
   ↳ **AsyncInflateOptions**
 
   ↳↳ [AsyncUnzlibOptions](asyncunzliboptions.md)
@@ -15,6 +17,7 @@ Options for decompressing DEFLATE data asynchronously
 ### Properties
 
 * [consume](asyncinflateoptions.md#consume)
+* [dictionary](asyncinflateoptions.md#dictionary)
 * [size](asyncinflateoptions.md#size)
 
 ## Properties
@@ -30,6 +33,18 @@ unusable but will increase performance and reduce memory usage.
 
 ___
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.
+
+___
+
 ### size
 
 • `Optional` **size**: number

+ 13 - 0
docs/interfaces/asyncunzliboptions.md

@@ -13,6 +13,7 @@ Options for decompressing Zlib data asynchronously
 ### Properties
 
 * [consume](asyncunzliboptions.md#consume)
+* [dictionary](asyncunzliboptions.md#dictionary)
 * [size](asyncunzliboptions.md#size)
 
 ## Properties
@@ -28,6 +29,18 @@ unusable but will increase performance and reduce memory usage.
 
 ___
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.
+
+___
+
 ### size
 
 • `Optional` **size**: number

+ 18 - 0
docs/interfaces/asynczipoptions.md

@@ -17,6 +17,7 @@ Options for asynchronously creating a ZIP archive
 * [attrs](asynczipoptions.md#attrs)
 * [comment](asynczipoptions.md#comment)
 * [consume](asynczipoptions.md#consume)
+* [dictionary](asynczipoptions.md#dictionary)
 * [extra](asynczipoptions.md#extra)
 * [level](asynczipoptions.md#level)
 * [mem](asynczipoptions.md#mem)
@@ -76,6 +77,23 @@ unusable but will increase performance and reduce memory usage.
 
 ___
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [DeflateOptions](deflateoptions.md).[dictionary](deflateoptions.md#dictionary)*
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### extra
 
 • `Optional` **extra**: Record\<number, Uint8Array>

+ 18 - 0
docs/interfaces/asynczliboptions.md

@@ -15,6 +15,7 @@ Options for compressing data asynchronously into a Zlib format
 ### Properties
 
 * [consume](asynczliboptions.md#consume)
+* [dictionary](asynczliboptions.md#dictionary)
 * [level](asynczliboptions.md#level)
 * [mem](asynczliboptions.md#mem)
 
@@ -31,6 +32,23 @@ unusable but will increase performance and reduce memory usage.
 
 ___
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [DeflateOptions](deflateoptions.md).[dictionary](deflateoptions.md#dictionary)*
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### level
 
 • `Optional` **level**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9

+ 16 - 0
docs/interfaces/deflateoptions.md

@@ -18,11 +18,27 @@ Options for compressing data into a DEFLATE format
 
 ### Properties
 
+* [dictionary](deflateoptions.md#dictionary)
 * [level](deflateoptions.md#level)
 * [mem](deflateoptions.md#mem)
 
 ## Properties
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### level
 
 • `Optional` **level**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9

+ 36 - 0
docs/interfaces/gunzipoptions.md

@@ -0,0 +1,36 @@
+# Interface: GunzipOptions
+
+Options for decompressing GZIP data
+
+## Hierarchy
+
+* [InflateStreamOptions](inflatestreamoptions.md)
+
+  ↳ **GunzipOptions**
+
+## Index
+
+### Properties
+
+* [dictionary](gunzipoptions.md#dictionary)
+* [out](gunzipoptions.md#out)
+
+## Properties
+
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.
+
+___
+
+### out
+
+• `Optional` **out**: Uint8Array
+
+The buffer into which to write the decompressed data. GZIP already encodes the output size, so providing this doesn't save memory.

+ 27 - 0
docs/interfaces/gunzipstreamoptions.md

@@ -0,0 +1,27 @@
+# Interface: GunzipStreamOptions
+
+Options for decompressing a GZIP stream
+
+## Hierarchy
+
+* [InflateStreamOptions](inflatestreamoptions.md)
+
+  ↳ **GunzipStreamOptions**
+
+## Index
+
+### Properties
+
+* [dictionary](gunzipstreamoptions.md#dictionary)
+
+## Properties
+
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.

+ 18 - 0
docs/interfaces/gzipoptions.md

@@ -14,6 +14,7 @@ Options for compressing data into a GZIP format
 
 ### Properties
 
+* [dictionary](gzipoptions.md#dictionary)
 * [filename](gzipoptions.md#filename)
 * [level](gzipoptions.md#level)
 * [mem](gzipoptions.md#mem)
@@ -21,6 +22,23 @@ Options for compressing data into a GZIP format
 
 ## Properties
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [DeflateOptions](deflateoptions.md).[dictionary](deflateoptions.md#dictionary)*
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### filename
 
 • `Optional` **filename**: string

+ 38 - 0
docs/interfaces/inflateoptions.md

@@ -0,0 +1,38 @@
+# Interface: InflateOptions
+
+Options for decompressing DEFLATE data
+
+## Hierarchy
+
+* [InflateStreamOptions](inflatestreamoptions.md)
+
+  ↳ **InflateOptions**
+
+  ↳↳ [UnzlibOptions](unzliboptions.md)
+
+## Index
+
+### Properties
+
+* [dictionary](inflateoptions.md#dictionary)
+* [out](inflateoptions.md#out)
+
+## Properties
+
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.
+
+___
+
+### out
+
+• `Optional` **out**: Uint8Array
+
+The buffer into which to write the decompressed data. Saves memory if you know the decompressed size in advance.

+ 35 - 0
docs/interfaces/inflatestreamoptions.md

@@ -0,0 +1,35 @@
+# Interface: InflateStreamOptions
+
+Options for decompressing a DEFLATE stream
+
+## Hierarchy
+
+* **InflateStreamOptions**
+
+  ↳ [InflateOptions](inflateoptions.md)
+
+  ↳ [GunzipStreamOptions](gunzipstreamoptions.md)
+
+  ↳ [GunzipOptions](gunzipoptions.md)
+
+  ↳ [UnzlibStreamOptions](unzlibstreamoptions.md)
+
+  ↳ [AsyncInflateOptions](asyncinflateoptions.md)
+
+  ↳ [AsyncGunzipOptions](asyncgunzipoptions.md)
+
+## Index
+
+### Properties
+
+* [dictionary](inflatestreamoptions.md#dictionary)
+
+## Properties
+
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.

+ 38 - 0
docs/interfaces/unzliboptions.md

@@ -0,0 +1,38 @@
+# Interface: UnzlibOptions
+
+Options for decompressing Zlib data
+
+## Hierarchy
+
+* [InflateOptions](inflateoptions.md)
+
+  ↳ **UnzlibOptions**
+
+## Index
+
+### Properties
+
+* [dictionary](unzliboptions.md#dictionary)
+* [out](unzliboptions.md#out)
+
+## Properties
+
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.
+
+___
+
+### out
+
+• `Optional` **out**: Uint8Array
+
+*Inherited from [InflateOptions](inflateoptions.md).[out](inflateoptions.md#out)*
+
+The buffer into which to write the decompressed data. Saves memory if you know the decompressed size in advance.

+ 27 - 0
docs/interfaces/unzlibstreamoptions.md

@@ -0,0 +1,27 @@
+# Interface: UnzlibStreamOptions
+
+Options for decompressing a Zlib stream
+
+## Hierarchy
+
+* [InflateStreamOptions](inflatestreamoptions.md)
+
+  ↳ **UnzlibStreamOptions**
+
+## Index
+
+### Properties
+
+* [dictionary](unzlibstreamoptions.md#dictionary)
+
+## Properties
+
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [InflateStreamOptions](inflatestreamoptions.md).[dictionary](inflatestreamoptions.md#dictionary)*
+
+The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect.
+
+Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error.

+ 18 - 0
docs/interfaces/zipoptions.md

@@ -16,6 +16,7 @@ Options for creating a ZIP archive
 
 * [attrs](zipoptions.md#attrs)
 * [comment](zipoptions.md#comment)
+* [dictionary](zipoptions.md#dictionary)
 * [extra](zipoptions.md#extra)
 * [level](zipoptions.md#level)
 * [mem](zipoptions.md#mem)
@@ -64,6 +65,23 @@ field is not read by consumer software.
 
 ___
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [DeflateOptions](deflateoptions.md).[dictionary](deflateoptions.md#dictionary)*
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### extra
 
 • `Optional` **extra**: Record\<number, Uint8Array>

+ 18 - 0
docs/interfaces/zliboptions.md

@@ -14,11 +14,29 @@ Options for compressing data into a Zlib format
 
 ### Properties
 
+* [dictionary](zliboptions.md#dictionary)
 * [level](zliboptions.md#level)
 * [mem](zliboptions.md#mem)
 
 ## Properties
 
+### dictionary
+
+• `Optional` **dictionary**: Uint8Array
+
+*Inherited from [DeflateOptions](deflateoptions.md).[dictionary](deflateoptions.md#dictionary)*
+
+A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios.
+
+Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input.
+The decompressor must supply the same dictionary as the compressor to extract the original data.
+
+Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise.
+
+Avoid using dictionaries with GZIP and ZIP to maximize software compatibility.
+
+___
+
 ### level
 
 • `Optional` **level**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "fflate",
-  "version": "0.7.4",
+  "version": "0.8.0",
   "description": "High performance (de)compression in an 8kB package",
   "main": "./lib/index.cjs",
   "module": "./esm/browser.js",

+ 17 - 16
src/index.ts

@@ -236,7 +236,7 @@ const err = (ind: number, msg?: string | 0, nt?: 1) => {
 // expands raw DEFLATE data
 const inflt = (dat: Uint8Array, st: InflateState, buf?: Uint8Array, dict?: Uint8Array) => {
   // source length       dict length
-  const sl = dat.length, dl = dict && dict.length;
+  const sl = dat.length, dl = dict ? dict.length : 0;
   if (!sl || st.f && !st.l) return buf || new u8(0);
   // have to estimate size
   const noBuf = !buf || st.i != 2;
@@ -375,8 +375,8 @@ const inflt = (dat: Uint8Array, st: InflateState, buf?: Uint8Array, dict?: Uint8
         if (noBuf) cbuf(bt + 131072);
         const end = bt + add;
         if (bt < dt) {
-          if (!dict) err(3);
           const shift = dl - dt, dend = Math.min(dt, end);
+          if (shift + bt < 0) err(3);
           for (; bt < dend; ++bt) buf[bt] = dict[shift + bt];
         }
         for (; bt < end; bt += 4) {
@@ -1427,9 +1427,11 @@ export class Inflate {
   private e(c: Uint8Array) {
     if (!this.ondata) err(5);
     if (this.d) err(4);
-    const l = this.p.length;
-    const n = new u8(l + c.length);
-    n.set(this.p), n.set(c, l), this.p = n;
+    if (!this.p.length) this.p = c;
+    else if (c.length) {
+      const n = new u8(this.p.length + c.length);
+      n.set(this.p), n.set(c, this.p.length), this.p = n;
+    } 
   }
 
   private c(final: boolean) {
@@ -1663,6 +1665,7 @@ export function gzipSync(data: Uint8Array, opts?: GzipOptions) {
  */
 export class Gunzip {
   private v = 1;
+  private o: Uint8Array;
   private p: Uint8Array;
   private s: InflateState;
   /**
@@ -1698,19 +1701,17 @@ export class Gunzip {
       if (s >= p.length && !final) return;
       this.p = p.subarray(s), this.v = 0;
     }
-    if (final) {
-      if (this.p.length < 8) err(6, 'invalid gzip data');
-      this.p = this.p.subarray(0, -8);
-    }
     // necessary to prevent TS from using the closure value
     // This allows for workerization to function correctly
     (Inflate.prototype as unknown as { c: typeof Inflate.prototype['c'] }).c.call(this, final);
     // process concatenated GZIP
-    if (this.s.f && !this.s.l && !final) {
-      this.s = { i: 0 };
+    if (this.s.f && !this.s.l) {
       const need = shft(this.s.p) + 8;
+      this.s = { i: 0 };
       this.v = Math.max(need - this.p.length, 0) + 1;
       this.p = this.p.subarray(need);
+      this.o = new u8(0);
+      if (this.p.length) this.push(new u8(0), final);
     }
   }
 }
@@ -1756,7 +1757,7 @@ export class AsyncGunzip {
 }
 
 /**
- * Asynchronously expands single-member GZIP data
+ * Asynchronously expands GZIP data
  * @param data The data to decompress
  * @param opts The decompression options
  * @param cb The function to be called upon decompression completion
@@ -1764,7 +1765,7 @@ export class AsyncGunzip {
  */
 export function gunzip(data: Uint8Array, opts: AsyncGunzipOptions, cb: FlateCallback): AsyncTerminable;
 /**
- * Asynchronously expands single-member GZIP data
+ * Asynchronously expands GZIP data
  * @param data The data to decompress
  * @param cb The function to be called upon decompression completion
  * @returns A function that can be used to immediately terminate the decompression
@@ -1781,14 +1782,14 @@ export function gunzip(data: Uint8Array, opts: AsyncGunzipOptions | FlateCallbac
 }
 
 /**
- * Expands single-member GZIP data
+ * Expands GZIP data
  * @param data The data to decompress
  * @param opts The decompression options
  * @returns The decompressed version of the data
  */
 export function gunzipSync(data: Uint8Array, opts?: GunzipOptions) {
   const st = gzs(data);
-  if (st + 8 < data.length) err(6, 'invalid gzip data');
+  if (st + 8 > data.length) err(6, 'invalid gzip data');
   return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);
 }
 
@@ -2038,7 +2039,7 @@ export function unzlib(data: Uint8Array, opts: AsyncUnzlibOptions | FlateCallbac
 /**
  * Expands Zlib data
  * @param data The data to decompress
- * @param out Where to write the data. Saves memory if you know the decompressed size and provide an output buffer of that length.
+ * @param opts The decompression options
  * @returns The decompressed version of the data
  */
 export function unzlibSync(data: Uint8Array, opts?: UnzlibOptions) {