XZ Decompression Library
npm install xz-compatXZ Decompression Library
xz-compat is a complete pure JavaScript implementation of XZ decompression with support for LZMA2 compression, BCJ filters (Branch Conversion for various CPU architectures), and Delta filtering. Compatible with Node.js 0.8+.
- ✅ XZ Format Support: Full XZ container format decoding
- ✅ LZMA2 Decoder: Complete LZMA2 decompression implementation
- ✅ High-Level 7z API: Streamlined decoding for 7z files with automatic native acceleration
- ✅ BCJ Filters: Branch conversion for improved compression on executables
- x86 (32-bit)
- ARM (32-bit)
- ARM64 / AArch64
- ARM Thumb
- PowerPC
- SPARC
- IA64 / Itanium
- ✅ Delta Filter: Byte-level delta encoding
- ✅ Streaming & Sync: Both streaming transforms and synchronous decoding
- ✅ Node 0.8+: Works on legacy Node.js versions
- ✅ Native Acceleration: Optional lzma-native on Node.js 10+ for 3-5x performance boost
``bash`
npm install xz-compat
For Node.js 10+, install lzma-native for automatic performance boost:
`bash`
npm install lzma-native
This provides 3-5x faster decompression. The library automatically detects and uses native bindings when available, falling back to pure JavaScript on older Node versions, when installation fails, or when disabled via LZMA_NATIVE_DISABLE=1.
`javascript
import { readFileSync } from 'fs';
import { decodeXZ } from 'xz-compat';
const compressedData = readFileSync('file.xz');
const decompressedData = decodeXZ(compressedData);
console.log('Decompressed:', decompressedData.toString());
`
`javascript
import { createReadStream } from 'fs';
import { createXZDecoder } from 'xz-compat';
const input = createReadStream('file.xz');
const decoder = createXZDecoder();
input.pipe(decoder);
decoder.on('data', (chunk) => {
console.log('Decompressed chunk:', chunk);
});
`
`javascript
import { decode7zLzma2, decode7zLzma } from 'xz-compat';
// Decompress LZMA2 from a 7z file (properties extracted separately)
const lzma2Data = readFileSync('data.7z');
const lzma2Properties = / from 7z folder structure /;
const decompressed = decode7zLzma2(lzma2Data, lzma2Properties);
`
`javascript
import { decodeLzma2 } from 'xz-compat';
import { writeFileSync } from 'fs';
const lzma2Data = readFileSync('data.lzma2');
const chunks = [];
decodeLzma2(lzma2Data, lzma2Properties, expectedSize, {
write: (chunk) => {
chunks.push(chunk);
}
});
const decompressed = Buffer.concat(chunks);
writeFileSync('output.bin', decompressed);
`
`javascript
import { decodeBcj, decodeBcjArm } from 'xz-compat';
// Decode x86 BCJ filtered data
const x86Data = readFileSync('filtered-x86.bin');
const unfiltered = decodeBcj(x86Data);
// Decode ARM BCJ filtered data
const armData = readFileSync('filtered-arm.bin');
const unfilteredArm = decodeBcjArm(armData);
`
#### XZ Decompression
#### decodeXZ(buffer: Buffer): Buffer
Synchronously decompresses XZ format data.
- Automatic native acceleration: Uses lzma-native when available on Node 10+
- Self-describing: Properties embedded in XZ format
#### createXZDecoder(): Transform
Creates a streaming Transform for XZ decompression.
- Automatically uses native acceleration when available
#### 7z LZMA/LZMA2 Decompression
#### decode7zLzma2(data: Buffer, properties: Buffer, unpackSize?: number): Buffer
Decompresses LZMA2 data from a 7z file.
- Accepts properties separately (matching 7z format)
- Tries native acceleration via lzma-native automatically
- Falls back to pure JavaScript if native unavailable
#### decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number): Buffer
Decompresses LZMA1 data from a 7z file.
- Accepts 5-byte properties separately
- Tries native acceleration automatically
#### LZMA Decompression
#### decodeLzma(buffer: Buffer, properties: Buffer, outSize: number, sink?: OutputSink): Buffer
Synchronously decodes LZMA1 compressed data.
- Low-level API for raw LZMA data
- Requires separate properties and output size
#### createLzmaDecoder(properties: Buffer, outSize: number): Transform
Creates a streaming Transform for LZMA1 decompression.
#### LZMA2 Decompression
#### decodeLzma2(buffer: Buffer, properties: Buffer, unpackSize: number, sink?: OutputSink): Buffer
Synchronously decodes LZMA2 compressed data.
#### createLzma2Decoder(properties: Buffer, unpackSize?: number): Transform
Creates a streaming Transform for LZMA2 decompression.
Branch Conversion (BCJ) filters improve compression of executables by converting relative branch addresses to absolute addresses, creating more repetitive patterns.
All BCJ filters follow the same interface:
- decodeBcj*(buffer: Buffer, properties?: Buffer, unpackSize?: number): BuffercreateBcj*Decoder(properties?: Buffer, unpackSize?: number): Transform
-
Supported BCJ filters:
- decodeBcj / createBcjDecoder - x86 (32-bit)decodeBcjArm
- / createBcjArmDecoder - ARM (32-bit)decodeBcjArm64
- / createBcjArm64Decoder - ARM64 / AArch64decodeBcjArmt
- / createBcjArmtDecoder - ARM ThumbdecodeBcjPpc
- / createBcjPpcDecoder - PowerPCdecodeBcjSparc
- / createBcjSparcDecoder - SPARCdecodeBcjIa64
- / createBcjIa64Decoder - IA64 / Itanium
#### decodeDelta(buffer: Buffer, distance?: Buffer): Buffer
Decodes Delta filtered data (inter-byte differences).
`javascript
import { createReadStream } from 'fs';
import { createXZDecoder } from 'xz-compat';
import { pipeline } from 'stream/promises';
async function decompressXZ(inputPath, outputPath) {
await pipeline(
createReadStream(inputPath),
createXZDecoder(),
createWriteStream(outputPath)
);
}
`
`javascript
import { decodeLzma2 } from 'xz-compat';
// Decompress raw LZMA2 stream
const data = readFileSync('data.lzma2');
const chunks = [];
decodeLzma2(data, propertiesBuffer, uncompressedSize, {
write: (chunk) => chunks.push(chunk)
});
const result = Buffer.concat(chunks);
`
`javascript
import { decodeXZ } from 'xz-compat';
function processXZFiles(filePaths) {
return filePaths.map(file => {
const compressed = readFileSync(file);
const decompressed = decodeXZ(compressed);
// Process decompressed data
return processData(decompressed);
});
}
`
XZ is a container format that wraps LZMA2 compressed data:
1. Stream Header
2. One or more Blocks (each with Block Header + Compressed Data)
3. Index (records block positions)
4. Stream Footer
Each Block can contain:
- A chain of preprocessing filters (Delta, BCJ)
- LZMA2 compression
BCJ filters convert branch instructions in executable code:
x86 Example:
- Original: E8 xx xx xx xx (CALL with relative offset)E8 aa aa aa aa
- Converted: (CALL with absolute address)
This creates more repetitive patterns for better LZMA2 compression.
This implementation is based on the reference XZ Utils (XZ Embedded) codebase:
- XZ Utils GitHub
- Filter algorithms match the xz embedded reference implementations
- Node.js: 0.8 and above
- Browser: Not tested (designed for Node.js)
- Dependencies: None (pure JavaScript)
This is a decompression-only implementation focused on compatibility and ease of use:
- No compression support (only decompression)
- Simplified streaming interface
- Pure JavaScript (no native bindings)
- Optimized for readability and maintainability
Performance characteristics:
- Synchronous: Suitable for small to medium files
- Streaming: Memory-efficient for large files
- Trade-off: Pure JavaScript may be slower than native implementations
- BCJ Decoding: Optimized reference algorithm implementations
MIT
Contributions welcome! Please ensure tests pass:
`bash``
npm test