stormlib-js 0.1.0 → 0.1.1

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/dist/index.d.ts CHANGED
@@ -1,163 +1,29 @@
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
- }
1
+ import { F as FileEntry, O as OpenArchiveOptions, a as FileFindData, M as MpqHeader } from './storm-buffer-nHXHoPVG.js';
2
+ export { A as ATTRIBUTES_NAME, B as BetTableHeader, H as HetTableHeader, I as ID_MPQ, b as ID_MPQ_USERDATA, L as LISTFILE_NAME, c as MPQ_COMPRESSION_ADPCM_MONO, d as MPQ_COMPRESSION_ADPCM_STEREO, e as MPQ_COMPRESSION_BZIP2, f as MPQ_COMPRESSION_HUFFMANN, g as MPQ_COMPRESSION_LZMA, h as MPQ_COMPRESSION_PKWARE, i as MPQ_COMPRESSION_SPARSE, j as MPQ_COMPRESSION_ZLIB, k as MPQ_FILE_COMPRESS, l as MPQ_FILE_ENCRYPTED, m as MPQ_FILE_EXISTS, n as MPQ_FILE_IMPLODE, o as MPQ_FILE_KEY_V2, p as MPQ_FILE_SINGLE_UNIT, q as MPQ_FORMAT_VERSION_1, r as MPQ_FORMAT_VERSION_2, s as MPQ_FORMAT_VERSION_3, t as MPQ_FORMAT_VERSION_4, u as MpqBlockEntry, v as MpqCompressionError, w as MpqCorruptError, x as MpqEncryptionError, y as MpqError, z as MpqHashEntry, C as MpqNotFoundError, D as MpqUnsupportedError, E as MpqUserData, S as SIGNATURE_NAME, G as decryptBlock, J as decryptFileKey, K as encryptBlock, N as getStormBuffer, P as hashFileKey, Q as hashNameA, R as hashNameB, T as hashString, U as hashTableIndex, V as jenkinsHash } from './storm-buffer-nHXHoPVG.js';
147
3
 
148
4
  /**
149
5
  * File stream abstraction for reading MPQ archives from disk.
150
6
  * Uses Node.js fs module for synchronous positioned reads.
151
7
  */
8
+ type BinaryInput$1 = Buffer | Uint8Array | ArrayBuffer;
152
9
  declare class FileStream {
153
10
  private fd;
154
11
  private fileSize;
155
12
  private filePath;
13
+ private memoryData;
14
+ private static fsModule;
156
15
  private constructor();
157
16
  /**
158
17
  * Open a file for reading.
159
18
  */
160
19
  static open(path: string): FileStream;
20
+ /**
21
+ * Create an in-memory stream from binary data.
22
+ */
23
+ static fromBuffer(data: BinaryInput$1, filePath?: string): FileStream;
24
+ private static normalizeBuffer;
25
+ private static getRequire;
26
+ private static getFs;
161
27
  /**
162
28
  * Read bytes at a given offset.
163
29
  *
@@ -225,6 +91,7 @@ declare class MpqFile {
225
91
  * This is the primary public API for opening and reading MPQ files.
226
92
  */
227
93
 
94
+ type BinaryInput = Buffer | Uint8Array | ArrayBuffer;
228
95
  declare class MpqArchive {
229
96
  private stream;
230
97
  private header;
@@ -247,6 +114,17 @@ declare class MpqArchive {
247
114
  * @returns MpqArchive instance
248
115
  */
249
116
  static open(path: string, options?: OpenArchiveOptions): MpqArchive;
117
+ /**
118
+ * Open an MPQ archive from in-memory binary data.
119
+ *
120
+ * This API works in both Node.js and browser runtimes.
121
+ *
122
+ * @param data - MPQ binary contents
123
+ * @param options - Open options
124
+ * @returns MpqArchive instance
125
+ */
126
+ static openFromBuffer(data: BinaryInput, options?: OpenArchiveOptions): MpqArchive;
127
+ private static openFromStream;
250
128
  /**
251
129
  * Load all archive tables (hash, block, HET, BET).
252
130
  */
@@ -323,98 +201,4 @@ declare class MpqArchive {
323
201
  private ensureOpen;
324
202
  }
325
203
 
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 };
204
+ export { FileEntry, FileFindData, MpqArchive, MpqFile, MpqHeader, OpenArchiveOptions };
package/dist/index.js CHANGED
@@ -719,21 +719,66 @@ var MpqCompressionError = class extends MpqError {
719
719
  };
720
720
 
721
721
  // src/stream/file-stream.ts
722
- var fs = __toESM(require("fs"));
723
- var FileStream = class _FileStream {
724
- constructor(fd, fileSize, filePath) {
722
+ var _FileStream = class _FileStream {
723
+ constructor(fd, fileSize, filePath, memoryData = null) {
725
724
  this.fd = fd;
726
725
  this.fileSize = fileSize;
727
726
  this.filePath = filePath;
727
+ this.memoryData = memoryData;
728
728
  }
729
729
  /**
730
730
  * Open a file for reading.
731
731
  */
732
732
  static open(path) {
733
+ const fs = _FileStream.getFs();
733
734
  const fd = fs.openSync(path, "r");
734
735
  const stat = fs.fstatSync(fd);
735
736
  return new _FileStream(fd, BigInt(stat.size), path);
736
737
  }
738
+ /**
739
+ * Create an in-memory stream from binary data.
740
+ */
741
+ static fromBuffer(data, filePath = "[buffer]") {
742
+ const buffer = _FileStream.normalizeBuffer(data);
743
+ return new _FileStream(-1, BigInt(buffer.length), filePath, buffer);
744
+ }
745
+ static normalizeBuffer(data) {
746
+ if (Buffer.isBuffer(data)) {
747
+ return data;
748
+ }
749
+ if (data instanceof Uint8Array) {
750
+ return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
751
+ }
752
+ return Buffer.from(data);
753
+ }
754
+ static getRequire() {
755
+ try {
756
+ if (typeof require === "function") {
757
+ return require;
758
+ }
759
+ } catch {
760
+ }
761
+ try {
762
+ return Function('return typeof require === "function" ? require : null;')();
763
+ } catch {
764
+ return null;
765
+ }
766
+ }
767
+ static getFs() {
768
+ if (_FileStream.fsModule) {
769
+ return _FileStream.fsModule;
770
+ }
771
+ const req = _FileStream.getRequire();
772
+ if (!req) {
773
+ throw new Error("Node.js fs module is not available in this runtime. Use MpqArchive.openFromBuffer().");
774
+ }
775
+ const fs = req("fs");
776
+ if (!fs) {
777
+ throw new Error("Failed to load Node.js fs module.");
778
+ }
779
+ _FileStream.fsModule = fs;
780
+ return _FileStream.fsModule;
781
+ }
737
782
  /**
738
783
  * Read bytes at a given offset.
739
784
  *
@@ -742,6 +787,15 @@ var FileStream = class _FileStream {
742
787
  * @returns Buffer containing the read data
743
788
  */
744
789
  read(offset, length) {
790
+ if (this.memoryData) {
791
+ const start = Number(offset);
792
+ if (start >= this.memoryData.length || length <= 0) {
793
+ return Buffer.alloc(0);
794
+ }
795
+ const end = Math.min(start + length, this.memoryData.length);
796
+ return this.memoryData.subarray(start, end);
797
+ }
798
+ const fs = _FileStream.getFs();
745
799
  const buffer = Buffer.alloc(length);
746
800
  const bytesRead = fs.readSync(this.fd, buffer, 0, length, Number(offset));
747
801
  if (bytesRead < length) {
@@ -753,6 +807,15 @@ var FileStream = class _FileStream {
753
807
  * Read bytes into an existing buffer.
754
808
  */
755
809
  readInto(offset, buffer, bufOffset, length) {
810
+ if (this.memoryData) {
811
+ const start = Number(offset);
812
+ if (start >= this.memoryData.length || length <= 0) {
813
+ return 0;
814
+ }
815
+ const end = Math.min(start + length, this.memoryData.length);
816
+ return this.memoryData.copy(buffer, bufOffset, start, end);
817
+ }
818
+ const fs = _FileStream.getFs();
756
819
  return fs.readSync(this.fd, buffer, bufOffset, length, Number(offset));
757
820
  }
758
821
  /**
@@ -771,12 +834,16 @@ var FileStream = class _FileStream {
771
834
  * Close the file stream.
772
835
  */
773
836
  close() {
774
- if (this.fd >= 0) {
837
+ if (this.fd >= 0 && !this.memoryData) {
838
+ const fs = _FileStream.getFs();
775
839
  fs.closeSync(this.fd);
776
840
  this.fd = -1;
777
841
  }
842
+ this.memoryData = null;
778
843
  }
779
844
  };
845
+ _FileStream.fsModule = null;
846
+ var FileStream = _FileStream;
780
847
 
781
848
  // src/archive/header.ts
782
849
  function createDefaultHeader() {
@@ -2639,6 +2706,22 @@ var MpqArchive = class _MpqArchive {
2639
2706
  */
2640
2707
  static open(path, options) {
2641
2708
  const stream = FileStream.open(path);
2709
+ return _MpqArchive.openFromStream(stream, options);
2710
+ }
2711
+ /**
2712
+ * Open an MPQ archive from in-memory binary data.
2713
+ *
2714
+ * This API works in both Node.js and browser runtimes.
2715
+ *
2716
+ * @param data - MPQ binary contents
2717
+ * @param options - Open options
2718
+ * @returns MpqArchive instance
2719
+ */
2720
+ static openFromBuffer(data, options) {
2721
+ const stream = FileStream.fromBuffer(data);
2722
+ return _MpqArchive.openFromStream(stream, options);
2723
+ }
2724
+ static openFromStream(stream, options) {
2642
2725
  try {
2643
2726
  const noHeaderSearch = options?.noHeaderSearch ?? false;
2644
2727
  const { header, headerOffset } = findHeader(stream, noHeaderSearch);