# Reforger PAK Unpacker (Node.js) Node.js library to extract files from Arma Reforger `.pak` archive files. ## Features - Extract all files from PAK archives - Extract specific files by name - List all files in an archive - Support for Zlib compressed files - Async and sync APIs - Easy integration into Express.js or other Node.js applications ## Installation ```bash npm install ``` ## Usage ### Basic Example - Extract All Files ```javascript const { PakUnpacker } = require('./PakUnpacker'); async function extractPak() { const unpacker = new PakUnpacker('path/to/file.pak'); await unpacker.load(); console.log(`Found ${unpacker.entries.length} files`); await unpacker.extract('./output'); console.log('Extraction complete!'); } extractPak(); ``` ### List Files in Archive ```javascript const { PakUnpacker } = require('./PakUnpacker'); async function listFiles() { const unpacker = new PakUnpacker('path/to/file.pak'); await unpacker.load(); const files = unpacker.listFiles(); files.forEach(file => { console.log(`${file.name} - ${file.size} bytes (${file.compressed ? 'Compressed' : 'Uncompressed'})`); }); } listFiles(); ``` ### Extract a Specific File ```javascript const { PakUnpacker } = require('./PakUnpacker'); async function extractFile() { const unpacker = new PakUnpacker('path/to/file.pak'); await unpacker.load(); const fileData = await unpacker.getFile('config.json'); if (fileData) { console.log('File content:', fileData.toString('utf8')); } else { console.log('File not found'); } } extractFile(); ``` ### Synchronous API ```javascript const { PakUnpacker } = require('./PakUnpacker'); function extractPakSync() { const unpacker = new PakUnpacker('path/to/file.pak'); unpacker.loadSync(); console.log(`Found ${unpacker.entries.length} files`); unpacker.extractSync('./output'); console.log('Extraction complete!'); } extractPakSync(); ``` ## API Integration Example ### Express.js REST API ```javascript const express = require('express'); const { PakUnpacker } = require('./PakUnpacker'); const app = express(); // List all files in a PAK archive app.get('/api/pak/:pakName/files', async (req, res) => { try { const unpacker = new PakUnpacker(`./paks/${req.params.pakName}.pak`); await unpacker.load(); const files = unpacker.listFiles(); res.json({ success: true, files }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // Extract a specific file app.get('/api/pak/:pakName/extract/:fileName(*)', async (req, res) => { try { const unpacker = new PakUnpacker(`./paks/${req.params.pakName}.pak`); await unpacker.load(); const fileData = await unpacker.getFile(req.params.fileName); if (fileData) { res.setHeader('Content-Type', 'application/octet-stream'); res.send(fileData); } else { res.status(404).json({ success: false, error: 'File not found' }); } } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); app.listen(3000, () => { console.log('Server running on port 3000'); }); ``` ## PAK File Format Reforger PAK files have the following structure: 1. **FORM Block**: Header with size (Big Endian Int32) 2. **HEAD Block**: 32 bytes header data 3. **DATA Block**: Size + data block 4. **Entries Block**: Directory and file entries ### Entry Types - **Type 0**: Directory (with child count) - **Type 1**: File (with offset, size, original size, compression info) ### Compression - **None** (0x00): No compression - **Zlib** (0x106): Deflate compression with 2-byte Zlib header ## API Reference ### Class: PakUnpacker #### Constructor ```javascript new PakUnpacker(filePath) ``` - `filePath` (string): Path to the .pak file #### Methods ##### async load() Load and parse the PAK file asynchronously. ##### loadSync() Load and parse the PAK file synchronously (blocking). ##### async extract(dstDir) Extract all files to the destination directory. - `dstDir` (string): Destination directory path ##### extractSync(dstDir) Extract all files synchronously. - `dstDir` (string): Destination directory path ##### async getFile(fileName) Get a specific file's data by name. - `fileName` (string): Name or partial name of the file - Returns: `Promise` ##### getFileSync(fileName) Get a specific file's data synchronously. - `fileName` (string): Name or partial name of the file - Returns: `Buffer|null` ##### listFiles() List all files in the PAK archive. - Returns: Array of objects with `{name, size, originalSize, compressed}` properties #### Properties - `entries` (Array): Array of PakEntryFile objects - `formSize` (number): Size of the FORM block - `dataSize` (number): Size of the DATA block - `entriesSize` (number): Size of the entries block ## Requirements - Node.js >= 14.0.0 - No external dependencies (uses built-in modules only) ## License MIT ## Credits Converted from the original C# implementation.