stormlib-js 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,254 @@
1
+ # stormlib-js
2
+
3
+ Pure TypeScript implementation of [StormLib](https://github.com/ladislav-zezula/StormLib) for reading MPQ (Mo'PaQ) archives. No native bindings, no WASM — just TypeScript.
4
+
5
+ MPQ is the archive format used by Blizzard Entertainment games including Diablo, StarCraft, Warcraft III, and World of Warcraft.
6
+
7
+ ## Features
8
+
9
+ - **Read-only** MPQ archive support
10
+ - **MPQ V1 through V4** format support
11
+ - **Pure TypeScript** — no native addons or WASM compilation required
12
+ - **Synchronous API** — simple, straightforward file extraction
13
+ - **Single runtime dependency** — only [pako](https://github.com/nickolaskgas/pako) for zlib
14
+ - **Dual module output** — ships both CommonJS and ESM builds with full type declarations
15
+
16
+ ### Compression algorithms
17
+
18
+ | Algorithm | Status |
19
+ |---|---|
20
+ | zlib (Deflate) | Supported |
21
+ | PKWARE DCL (Implode) | Supported |
22
+ | Blizzard Huffman | Supported |
23
+ | ADPCM Mono / Stereo | Supported |
24
+ | Sparse (RLE) | Supported |
25
+ | BZIP2 | Not supported |
26
+ | LZMA | Not supported |
27
+
28
+ > BZIP2 and LZMA are rarely used in practice (only some SC2/HotS archives). If you need them, contributions are welcome.
29
+
30
+ ### Table formats
31
+
32
+ | Table | Status |
33
+ |---|---|
34
+ | Classic Hash Table | Supported |
35
+ | Classic Block Table | Supported |
36
+ | Hi-Block Table (V2+) | Supported |
37
+ | HET Table (V3+) | Supported |
38
+ | BET Table (V3+) | Supported |
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install stormlib-js
44
+ ```
45
+
46
+ ## Quick start
47
+
48
+ ```typescript
49
+ import { MpqArchive } from 'stormlib-js';
50
+
51
+ // Open an archive
52
+ const archive = MpqArchive.open('game.mpq');
53
+
54
+ // List known files (from internal listfile)
55
+ const files = archive.getFileList();
56
+ console.log(files);
57
+
58
+ // Extract a file
59
+ const data = archive.extractFile('war3map.j');
60
+ console.log(data.toString('utf-8'));
61
+
62
+ // Search with wildcards
63
+ const results = archive.findFiles('*.blp');
64
+ for (const entry of results) {
65
+ console.log(entry.fileName, entry.fileSize);
66
+ }
67
+
68
+ // Clean up
69
+ archive.close();
70
+ ```
71
+
72
+ ## API
73
+
74
+ ### `MpqArchive`
75
+
76
+ The main class for working with MPQ archives.
77
+
78
+ #### `MpqArchive.open(path, options?)`
79
+
80
+ Opens an MPQ archive from a file path.
81
+
82
+ ```typescript
83
+ const archive = MpqArchive.open('archive.mpq');
84
+
85
+ // With options
86
+ const archive = MpqArchive.open('archive.mpq', {
87
+ noListfile: false, // Skip loading internal (listfile)
88
+ noAttributes: false, // Skip loading internal (attributes)
89
+ noHeaderSearch: false, // Don't search for MPQ header (assume offset 0)
90
+ forceMpqV1: false, // Force reading as MPQ V1
91
+ });
92
+ ```
93
+
94
+ #### `archive.hasFile(name)`
95
+
96
+ Returns `true` if the file exists in the archive.
97
+
98
+ ```typescript
99
+ if (archive.hasFile('war3map.j')) {
100
+ // ...
101
+ }
102
+ ```
103
+
104
+ #### `archive.extractFile(name)`
105
+
106
+ Extracts a file and returns its contents as a `Buffer`.
107
+
108
+ ```typescript
109
+ const buf = archive.extractFile('war3map.w3i');
110
+ ```
111
+
112
+ #### `archive.openFile(name)`
113
+
114
+ Opens a file handle for more control over reading.
115
+
116
+ ```typescript
117
+ const file = archive.openFile('units.doo');
118
+ console.log(file.size, file.compressedSize, file.flags);
119
+ const data = file.read();
120
+ file.close();
121
+ ```
122
+
123
+ #### `archive.getFileList()`
124
+
125
+ Returns an array of known file names (populated from the internal listfile).
126
+
127
+ ```typescript
128
+ const names = archive.getFileList();
129
+ // ['war3map.j', 'war3map.w3e', ...]
130
+ ```
131
+
132
+ #### `archive.findFiles(mask?)`
133
+
134
+ Searches for files matching a wildcard pattern. Supports `*` and `?`.
135
+
136
+ ```typescript
137
+ const textures = archive.findFiles('*.blp');
138
+ for (const f of textures) {
139
+ console.log(f.fileName, f.fileSize, f.compSize);
140
+ }
141
+ ```
142
+
143
+ #### `archive.enumerateFiles()`
144
+
145
+ Lists all file entries including unnamed ones. Unnamed entries are given synthetic names like `File00000001.xxx`.
146
+
147
+ ```typescript
148
+ const all = archive.enumerateFiles();
149
+ console.log(`Total: ${all.length} files`);
150
+ ```
151
+
152
+ #### `archive.addListfile(names)`
153
+
154
+ Applies an external list of file names to resolve unnamed entries. Useful for archives without an internal `(listfile)`.
155
+
156
+ ```typescript
157
+ const resolved = archive.addListfile([
158
+ 'war3map.j', 'war3map.w3e', 'war3map.w3i',
159
+ ]);
160
+ console.log(`${resolved} new names resolved`);
161
+ ```
162
+
163
+ #### `archive.getHeader()`
164
+
165
+ Returns the parsed MPQ header.
166
+
167
+ ```typescript
168
+ const header = archive.getHeader();
169
+ console.log(`Format: V${header.wFormatVersion + 1}`);
170
+ console.log(`Sector size: ${512 << header.wSectorSize}`);
171
+ ```
172
+
173
+ #### `archive.close()`
174
+
175
+ Closes the archive and releases the underlying file handle.
176
+
177
+ ### Error classes
178
+
179
+ All errors extend `MpqError`:
180
+
181
+ | Class | Description |
182
+ |---|---|
183
+ | `MpqNotFoundError` | File not found in the archive |
184
+ | `MpqCorruptError` | Archive data is corrupt |
185
+ | `MpqUnsupportedError` | Unsupported feature (e.g. BZIP2) |
186
+ | `MpqEncryptionError` | Decryption failure |
187
+ | `MpqCompressionError` | Decompression failure |
188
+
189
+ ```typescript
190
+ import { MpqNotFoundError } from 'stormlib-js';
191
+
192
+ try {
193
+ archive.extractFile('nonexistent.txt');
194
+ } catch (err) {
195
+ if (err instanceof MpqNotFoundError) {
196
+ console.log('File does not exist');
197
+ }
198
+ }
199
+ ```
200
+
201
+ ## Supported games
202
+
203
+ This library can read MPQ archives from:
204
+
205
+ - **Diablo** / **Diablo II** (V1, Huffman/PKWARE compression)
206
+ - **StarCraft** / **Brood War** (V1, Huffman/PKWARE compression)
207
+ - **Warcraft III** / **The Frozen Throne** (V1, zlib compression)
208
+ - **World of Warcraft** (V2, 64-bit offsets)
209
+ - **StarCraft II** (V3/V4, HET/BET tables)
210
+
211
+ ## Advanced usage
212
+
213
+ Low-level crypto and hashing functions are exported for specialized use cases:
214
+
215
+ ```typescript
216
+ import {
217
+ hashString, jenkinsHash,
218
+ decryptBlock, encryptBlock,
219
+ getStormBuffer,
220
+ MPQ_HASH_TABLE_INDEX,
221
+ MPQ_HASH_NAME_A,
222
+ } from 'stormlib-js';
223
+
224
+ // Compute MPQ hash
225
+ const idx = hashString('(listfile)', MPQ_HASH_TABLE_INDEX);
226
+
227
+ // Jenkins hash for HET tables
228
+ const hash = jenkinsHash('war3map.j');
229
+ ```
230
+
231
+ ## Development
232
+
233
+ ```bash
234
+ # Install dependencies
235
+ npm install
236
+
237
+ # Run tests
238
+ npm test
239
+
240
+ # Type check
241
+ npm run typecheck
242
+
243
+ # Build
244
+ npm run build
245
+ ```
246
+
247
+ ## Acknowledgments
248
+
249
+ - [Ladislav Zezula](https://github.com/ladislav-zezula) for the original [StormLib](https://github.com/ladislav-zezula/StormLib) C/C++ library and the comprehensive MPQ format documentation
250
+ - [The StormLib documentation](http://www.zezula.net/en/mpq/stormlib.html) for format specifications
251
+
252
+ ## License
253
+
254
+ MIT
@@ -0,0 +1,420 @@
1
+ /** Raw MPQ header as parsed from disk (normalized to V4 superset) */
2
+ interface MpqHeader {
3
+ /** 'MPQ\x1A' signature */
4
+ dwID: number;
5
+ /** Size of the header */
6
+ dwHeaderSize: number;
7
+ /** 32-bit archive size (V1) */
8
+ dwArchiveSize: number;
9
+ /** Format version: 0=V1, 1=V2, 2=V3, 3=V4 */
10
+ wFormatVersion: number;
11
+ /** Sector size shift (sector size = 512 << wSectorSize) */
12
+ wSectorSize: number;
13
+ /** Hash table offset (relative to archive start) */
14
+ dwHashTablePos: number;
15
+ /** Block table offset (relative to archive start) */
16
+ dwBlockTablePos: number;
17
+ /** Number of hash table entries */
18
+ dwHashTableSize: number;
19
+ /** Number of block table entries */
20
+ dwBlockTableSize: number;
21
+ /** 64-bit hi-block table offset */
22
+ hiBlockTablePos64: bigint;
23
+ /** High 16 bits of hash table offset */
24
+ wHashTablePosHi: number;
25
+ /** High 16 bits of block table offset */
26
+ wBlockTablePosHi: number;
27
+ /** 64-bit archive size */
28
+ archiveSize64: bigint;
29
+ /** 64-bit BET table position */
30
+ betTablePos64: bigint;
31
+ /** 64-bit HET table position */
32
+ hetTablePos64: bigint;
33
+ /** Compressed hash table size */
34
+ hashTableSize64: bigint;
35
+ /** Compressed block table size */
36
+ blockTableSize64: bigint;
37
+ /** Compressed hi-block table size */
38
+ hiBlockTableSize64: bigint;
39
+ /** Compressed HET table size */
40
+ hetTableSize64: bigint;
41
+ /** Compressed BET table size */
42
+ betTableSize64: bigint;
43
+ /** Raw chunk size for MD5 */
44
+ dwRawChunkSize: number;
45
+ /** MD5 checksums (V4) */
46
+ md5BlockTable: Uint8Array;
47
+ md5HashTable: Uint8Array;
48
+ md5HiBlockTable: Uint8Array;
49
+ md5BetTable: Uint8Array;
50
+ md5HetTable: Uint8Array;
51
+ md5MpqHeader: Uint8Array;
52
+ }
53
+ /** User data header that may precede the MPQ header */
54
+ interface MpqUserData {
55
+ dwID: number;
56
+ cbUserDataSize: number;
57
+ dwHeaderOffs: number;
58
+ cbUserDataHeader: number;
59
+ }
60
+ /** Hash table entry (16 bytes on disk) */
61
+ interface MpqHashEntry {
62
+ /** Hash of file path (method A) */
63
+ dwName1: number;
64
+ /** Hash of file path (method B) */
65
+ dwName2: number;
66
+ /** Windows LANGID locale */
67
+ lcLocale: number;
68
+ /** Platform (always 0) */
69
+ platform: number;
70
+ /** Index into block table (0xFFFFFFFF=free, 0xFFFFFFFE=deleted) */
71
+ dwBlockIndex: number;
72
+ }
73
+ /** Block table entry (16 bytes on disk) */
74
+ interface MpqBlockEntry {
75
+ /** File data offset relative to archive start */
76
+ dwFilePos: number;
77
+ /** Compressed file size */
78
+ dwCSize: number;
79
+ /** Uncompressed file size */
80
+ dwFSize: number;
81
+ /** File flags */
82
+ dwFlags: number;
83
+ }
84
+ /** Unified file entry (in-memory representation) */
85
+ interface FileEntry {
86
+ /** Jenkins hash (for BET table) */
87
+ fileNameHash: bigint;
88
+ /** File data offset relative to MPQ header */
89
+ byteOffset: bigint;
90
+ /** File time (FILETIME) from attributes */
91
+ fileTime: bigint;
92
+ /** Decompressed size */
93
+ fileSize: number;
94
+ /** Compressed size */
95
+ cmpSize: number;
96
+ /** File flags */
97
+ flags: number;
98
+ /** CRC32 from attributes */
99
+ crc32: number;
100
+ /** MD5 from attributes */
101
+ md5: Uint8Array;
102
+ /** File name (empty if unknown) */
103
+ fileName: string;
104
+ }
105
+ /** HET table header */
106
+ interface HetTableHeader {
107
+ signature: number;
108
+ version: number;
109
+ dataSize: number;
110
+ tableSize: number;
111
+ maxFileCount: number;
112
+ hashTableSize: number;
113
+ hashEntrySize: number;
114
+ totalIndexSize: number;
115
+ indexSizeExtra: number;
116
+ indexSize: number;
117
+ blockTableSize: number;
118
+ }
119
+ /** BET table header */
120
+ interface BetTableHeader {
121
+ signature: number;
122
+ version: number;
123
+ dataSize: number;
124
+ tableSize: number;
125
+ maxFileCount: number;
126
+ flagCount: number;
127
+ }
128
+ /** File search result */
129
+ interface FileFindData {
130
+ fileName: string;
131
+ plainName: string;
132
+ hashIndex: number;
133
+ blockIndex: number;
134
+ fileSize: number;
135
+ compSize: number;
136
+ fileFlags: number;
137
+ locale: number;
138
+ }
139
+ /** Open archive flags */
140
+ interface OpenArchiveOptions {
141
+ noListfile?: boolean;
142
+ noAttributes?: boolean;
143
+ noHeaderSearch?: boolean;
144
+ forceMpqV1?: boolean;
145
+ checkSectorCrc?: boolean;
146
+ }
147
+
148
+ /**
149
+ * File stream abstraction for reading MPQ archives from disk.
150
+ * Uses Node.js fs module for synchronous positioned reads.
151
+ */
152
+ declare class FileStream {
153
+ private fd;
154
+ private fileSize;
155
+ private filePath;
156
+ private constructor();
157
+ /**
158
+ * Open a file for reading.
159
+ */
160
+ static open(path: string): FileStream;
161
+ /**
162
+ * Read bytes at a given offset.
163
+ *
164
+ * @param offset - Byte offset from the beginning of the file
165
+ * @param length - Number of bytes to read
166
+ * @returns Buffer containing the read data
167
+ */
168
+ read(offset: bigint, length: number): Buffer;
169
+ /**
170
+ * Read bytes into an existing buffer.
171
+ */
172
+ readInto(offset: bigint, buffer: Buffer, bufOffset: number, length: number): number;
173
+ /**
174
+ * Get the total file size.
175
+ */
176
+ getSize(): bigint;
177
+ /**
178
+ * Get the file path.
179
+ */
180
+ getPath(): string;
181
+ /**
182
+ * Close the file stream.
183
+ */
184
+ close(): void;
185
+ }
186
+
187
+ /**
188
+ * MpqFile represents an open file handle within an MPQ archive.
189
+ * It provides methods to read file data.
190
+ */
191
+
192
+ declare class MpqFile {
193
+ private stream;
194
+ private archiveOffset;
195
+ private entry;
196
+ private sectorSize;
197
+ private fileKey;
198
+ private closed;
199
+ constructor(stream: FileStream, archiveOffset: bigint, entry: FileEntry, sectorSize: number);
200
+ /** Uncompressed file size */
201
+ get size(): number;
202
+ /** Compressed file size */
203
+ get compressedSize(): number;
204
+ /** File flags */
205
+ get flags(): number;
206
+ /** File name */
207
+ get name(): string;
208
+ /** The underlying file entry */
209
+ get fileEntry(): FileEntry;
210
+ /**
211
+ * Read the entire file contents.
212
+ *
213
+ * @returns Buffer containing the decompressed file data
214
+ */
215
+ read(): Buffer;
216
+ /**
217
+ * Close the file handle.
218
+ */
219
+ close(): void;
220
+ }
221
+
222
+ /**
223
+ * MpqArchive - Main class for reading MPQ archives.
224
+ *
225
+ * This is the primary public API for opening and reading MPQ files.
226
+ */
227
+
228
+ declare class MpqArchive {
229
+ private stream;
230
+ private header;
231
+ private archiveOffset;
232
+ private sectorSize;
233
+ private hashTable;
234
+ private blockTable;
235
+ private hiBlockTable;
236
+ private hetTable;
237
+ private betTable;
238
+ private fileEntries;
239
+ private attributes;
240
+ private closed;
241
+ private constructor();
242
+ /**
243
+ * Open an MPQ archive from a file path.
244
+ *
245
+ * @param path - Path to the MPQ file
246
+ * @param options - Open options
247
+ * @returns MpqArchive instance
248
+ */
249
+ static open(path: string, options?: OpenArchiveOptions): MpqArchive;
250
+ /**
251
+ * Load all archive tables (hash, block, HET, BET).
252
+ */
253
+ private loadTables;
254
+ /**
255
+ * Load and parse the (listfile) to populate file names.
256
+ */
257
+ private loadListfile;
258
+ /**
259
+ * Load and parse the (attributes) file.
260
+ */
261
+ private loadAttributes;
262
+ /**
263
+ * Internal: extract a file by name without relying on the listfile.
264
+ * Used for bootstrapping (listfile) and (attributes) loading.
265
+ */
266
+ private extractFileByName;
267
+ /**
268
+ * Check if a file exists in the archive.
269
+ */
270
+ hasFile(name: string): boolean;
271
+ /**
272
+ * Open a file within the archive for reading.
273
+ *
274
+ * @param name - File path within the archive
275
+ * @returns MpqFile handle
276
+ */
277
+ openFile(name: string): MpqFile;
278
+ /**
279
+ * Extract a file's contents directly.
280
+ *
281
+ * @param name - File path within the archive
282
+ * @returns Buffer with the file contents
283
+ */
284
+ extractFile(name: string): Buffer;
285
+ /**
286
+ * Get the list of all known file names (from listfile).
287
+ */
288
+ getFileList(): string[];
289
+ /**
290
+ * Find files matching a wildcard pattern.
291
+ *
292
+ * @param mask - Wildcard pattern (supports '*' and '?')
293
+ * @returns Array of matching file entries
294
+ */
295
+ findFiles(mask?: string): FileFindData[];
296
+ /**
297
+ * Apply an external list of file names to resolve unnamed entries.
298
+ * Equivalent to providing an external listfile to SFileFindFirstFile.
299
+ *
300
+ * @param names - Array of file names to try
301
+ * @returns Number of newly resolved names
302
+ */
303
+ addListfile(names: string[]): number;
304
+ /**
305
+ * Enumerate all existing file entries, including those without names.
306
+ * Unnamed entries get a synthetic name like "File00001234.xxx".
307
+ */
308
+ enumerateFiles(): FileFindData[];
309
+ /** Get the archive header */
310
+ getHeader(): Readonly<MpqHeader>;
311
+ /** Get the number of file entries */
312
+ get fileCount(): number;
313
+ /** Get the sector size */
314
+ getSectorSize(): number;
315
+ /**
316
+ * Close the archive and release resources.
317
+ */
318
+ close(): void;
319
+ /**
320
+ * Resolve a file name to its FileEntry.
321
+ */
322
+ private resolveFile;
323
+ private ensureOpen;
324
+ }
325
+
326
+ declare class MpqError extends Error {
327
+ constructor(message: string);
328
+ }
329
+ declare class MpqNotFoundError extends MpqError {
330
+ constructor(message?: string);
331
+ }
332
+ declare class MpqCorruptError extends MpqError {
333
+ constructor(message?: string);
334
+ }
335
+ declare class MpqUnsupportedError extends MpqError {
336
+ constructor(message?: string);
337
+ }
338
+ declare class MpqEncryptionError extends MpqError {
339
+ constructor(message?: string);
340
+ }
341
+ declare class MpqCompressionError extends MpqError {
342
+ constructor(message?: string);
343
+ }
344
+
345
+ declare const ID_MPQ = 441536589;
346
+ declare const ID_MPQ_USERDATA = 458313805;
347
+ declare const MPQ_FORMAT_VERSION_1 = 0;
348
+ declare const MPQ_FORMAT_VERSION_2 = 1;
349
+ declare const MPQ_FORMAT_VERSION_3 = 2;
350
+ declare const MPQ_FORMAT_VERSION_4 = 3;
351
+ declare const MPQ_FILE_IMPLODE = 256;
352
+ declare const MPQ_FILE_COMPRESS = 512;
353
+ declare const MPQ_FILE_ENCRYPTED = 65536;
354
+ declare const MPQ_FILE_KEY_V2 = 131072;
355
+ declare const MPQ_FILE_SINGLE_UNIT = 16777216;
356
+ declare const MPQ_FILE_EXISTS = 2147483648;
357
+ declare const MPQ_COMPRESSION_HUFFMANN = 1;
358
+ declare const MPQ_COMPRESSION_ZLIB = 2;
359
+ declare const MPQ_COMPRESSION_PKWARE = 8;
360
+ declare const MPQ_COMPRESSION_BZIP2 = 16;
361
+ declare const MPQ_COMPRESSION_LZMA = 18;
362
+ declare const MPQ_COMPRESSION_SPARSE = 32;
363
+ declare const MPQ_COMPRESSION_ADPCM_MONO = 64;
364
+ declare const MPQ_COMPRESSION_ADPCM_STEREO = 128;
365
+ declare const LISTFILE_NAME = "(listfile)";
366
+ declare const SIGNATURE_NAME = "(signature)";
367
+ declare const ATTRIBUTES_NAME = "(attributes)";
368
+
369
+ /**
370
+ * Compute MPQ hash of a string. The hashType selects which section of the
371
+ * StormBuffer to use:
372
+ * - MPQ_HASH_TABLE_INDEX (0x000): hash table slot
373
+ * - MPQ_HASH_NAME_A (0x100): file name verification hash 1
374
+ * - MPQ_HASH_NAME_B (0x200): file name verification hash 2
375
+ * - MPQ_HASH_FILE_KEY (0x300): encryption key derivation
376
+ */
377
+ declare function hashString(str: string, hashType: number): number;
378
+ /** Convenience: compute hash table index */
379
+ declare function hashTableIndex(fileName: string): number;
380
+ /** Convenience: compute name hash A */
381
+ declare function hashNameA(fileName: string): number;
382
+ /** Convenience: compute name hash B */
383
+ declare function hashNameB(fileName: string): number;
384
+ /** Convenience: compute file encryption key hash */
385
+ declare function hashFileKey(fileName: string): number;
386
+ /**
387
+ * Jenkins hashlittle2 - used for HET/BET tables (64-bit hash).
388
+ * Produces a 64-bit hash as a BigInt.
389
+ */
390
+ declare function jenkinsHash(str: string): bigint;
391
+
392
+ /**
393
+ * Decrypt an MPQ data block in-place.
394
+ * The buffer must be DWORD-aligned (length must be a multiple of 4).
395
+ *
396
+ * @param data - Buffer to decrypt (modified in place)
397
+ * @param key - Primary encryption key (DWORD)
398
+ */
399
+ declare function decryptBlock(data: Buffer, key: number): void;
400
+ /**
401
+ * Encrypt an MPQ data block in-place.
402
+ *
403
+ * @param data - Buffer to encrypt (modified in place)
404
+ * @param key - Primary encryption key (DWORD)
405
+ */
406
+ declare function encryptBlock(data: Buffer, key: number): void;
407
+ /**
408
+ * Calculate the decryption key for a file within an MPQ archive.
409
+ *
410
+ * @param fileName - Full path of the file within the archive
411
+ * @param byteOffset - File's offset within the archive (lower 32 bits)
412
+ * @param fileSize - Uncompressed file size
413
+ * @param flags - File flags from block table
414
+ * @returns The file decryption key
415
+ */
416
+ declare function decryptFileKey(fileName: string, byteOffset: bigint, fileSize: number, flags: number): number;
417
+
418
+ declare function getStormBuffer(): Uint32Array;
419
+
420
+ export { ATTRIBUTES_NAME, type BetTableHeader, type FileEntry, type FileFindData, type HetTableHeader, ID_MPQ, ID_MPQ_USERDATA, LISTFILE_NAME, MPQ_COMPRESSION_ADPCM_MONO, MPQ_COMPRESSION_ADPCM_STEREO, MPQ_COMPRESSION_BZIP2, MPQ_COMPRESSION_HUFFMANN, MPQ_COMPRESSION_LZMA, MPQ_COMPRESSION_PKWARE, MPQ_COMPRESSION_SPARSE, MPQ_COMPRESSION_ZLIB, MPQ_FILE_COMPRESS, MPQ_FILE_ENCRYPTED, MPQ_FILE_EXISTS, MPQ_FILE_IMPLODE, MPQ_FILE_KEY_V2, MPQ_FILE_SINGLE_UNIT, MPQ_FORMAT_VERSION_1, MPQ_FORMAT_VERSION_2, MPQ_FORMAT_VERSION_3, MPQ_FORMAT_VERSION_4, MpqArchive, type MpqBlockEntry, MpqCompressionError, MpqCorruptError, MpqEncryptionError, MpqError, MpqFile, type MpqHashEntry, type MpqHeader, MpqNotFoundError, MpqUnsupportedError, type MpqUserData, type OpenArchiveOptions, SIGNATURE_NAME, decryptBlock, decryptFileKey, encryptBlock, getStormBuffer, hashFileKey, hashNameA, hashNameB, hashString, hashTableIndex, jenkinsHash };