JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 82
  • Score
    100M100P100Q109422F
  • License MIT

A JavaScript implementation of the QFS compression and decompression algorithm

Package Exports

  • qfs-compression

Readme

qfs-compression

This library provides a JS implementation of the QFS compression algorithm. This algorithm is based on LZ77 and is commonly found in files used by EA games.

It is basically a port of an original C implementation made by @wouanagaine. More information on it can be found on the SC4 devotion wiki.

Installation

npm install qfs-compression

Usage

The module exports two functions: compress() and decompress(). Both accept either a Node.js Buffer or a Uint8Array. If the Buffer global is available - such as on Node - a Buffer is returned, otherwise a bare Uint8Array is returned. This is useful in the browser as it does not require a Buffer polyfill this way.

import { compress, decompress } from 'qfs-compression';

let input = Buffer.from([...]);
let input = new Uint8Array([...]);

let compressed = compress(input);
let original = decompress(compressed);

Documentation

compress(input[, options])

  • input <Buffer> | <Uint8Array> An uncompressed buffer of binary data that needs compression.
  • options <Object>:
    • windowBits: The amount of bits used for the sliding window. Defaults to 17, which means a sliding window of 128 kB.

decompress(input)

  • input <Buffer> | <Uint8Array> A buffer with binary data that was previously compressed using QFS compression.

Caveats

  • The limit of data that can be compressed is 16MB. This is because the uncompressed size is stored in the header using 3 bytes, which means a maximum size of 0xffffff bytes can be properly written away in the header.

  • In some games (for example SimCity 4), a compressed buffer is prefixed by 4 bytes containing the size of the entire buffer. The library does not detect this automatically, so if you are dealing with such games, you need to manually truncate the bytes as

    decompress(input.slice(4))

Performance

Obviously a pure C implementation is faster than a JS implementation. However, v8 is able to produce really good optimized code for the library, so if the compression function gets hot, it will match the performance of a C implementation, and may even be faster than linking a C implementation using native Node addons.