@rhyster/wow-casc-dbc 2.5.0 → 2.6.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/dist/index.cjs CHANGED
@@ -4,20 +4,20 @@ const assert = require('node:assert');
4
4
  const crypto = require('node:crypto');
5
5
  const async = require('async');
6
6
  const cliProgress = require('cli-progress');
7
+ const zlib = require('node:zlib');
7
8
  const fs = require('node:fs/promises');
8
- const path = require('node:path');
9
9
  const http = require('node:http');
10
- const zlib = require('node:zlib');
10
+ const path = require('node:path');
11
11
 
12
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
13
13
 
14
14
  const assert__default = /*#__PURE__*/_interopDefaultCompat(assert);
15
15
  const crypto__default = /*#__PURE__*/_interopDefaultCompat(crypto);
16
16
  const cliProgress__default = /*#__PURE__*/_interopDefaultCompat(cliProgress);
17
+ const zlib__default = /*#__PURE__*/_interopDefaultCompat(zlib);
17
18
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
18
- const path__default = /*#__PURE__*/_interopDefaultCompat(path);
19
19
  const http__default = /*#__PURE__*/_interopDefaultCompat(http);
20
- const zlib__default = /*#__PURE__*/_interopDefaultCompat(zlib);
20
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
21
21
 
22
22
  var __defProp$6 = Object.defineProperty;
23
23
  var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -25,121 +25,448 @@ var __publicField$6 = (obj, key, value) => {
25
25
  __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
26
26
  return value;
27
27
  };
28
- class Store {
29
- constructor(dataFile) {
30
- __publicField$6(this, "data");
31
- __publicField$6(this, "dataFile");
32
- __publicField$6(this, "promise");
33
- this.dataFile = dataFile;
34
- this.data = {};
35
- this.promise = new Promise((resolve) => {
36
- fs__default.readFile(dataFile, "utf-8").then((file) => {
37
- this.data = JSON.parse(file);
38
- resolve();
39
- }).catch(() => {
40
- resolve();
41
- });
42
- });
43
- }
44
- async get(key) {
45
- await this.promise;
46
- return this.data[key];
47
- }
48
- async set(key, value) {
49
- await this.promise;
50
- this.data[key] = value;
51
- await fs__default.writeFile(this.dataFile, JSON.stringify(this.data), "utf-8");
28
+ const ADB_MAGIC = 1481004104;
29
+ class ADBReader {
30
+ constructor(buffer) {
31
+ __publicField$6(this, "build");
32
+ __publicField$6(this, "entries", []);
33
+ __publicField$6(this, "tableEntries", /* @__PURE__ */ new Map());
34
+ const magic = buffer.readUInt32BE(0);
35
+ assert__default(magic === ADB_MAGIC, `[ADB]: Invalid magic: ${magic.toString(16).padStart(8, "0")}`);
36
+ const version = buffer.readUInt32LE(4);
37
+ assert__default(version === 9, `[ADB]: Invalid version: ${version.toString()}`);
38
+ const build = buffer.readUInt32LE(8);
39
+ this.build = build;
40
+ let pointer = 44;
41
+ while (pointer < buffer.byteLength) {
42
+ const offset = pointer;
43
+ const entryMagic = buffer.readUInt32BE(offset);
44
+ assert__default(entryMagic === ADB_MAGIC, `[ADB]: Invalid entry magic: ${magic.toString(16).padStart(8, "0")}`);
45
+ const regionID = buffer.readInt32LE(offset + 4);
46
+ const pushID = buffer.readInt32LE(offset + 8);
47
+ const uniqueID = buffer.readUInt32LE(offset + 12);
48
+ const tableHash = buffer.readUInt32LE(offset + 16);
49
+ const recordID = buffer.readUInt32LE(offset + 20);
50
+ const dataSize = buffer.readUInt32LE(offset + 24);
51
+ const recordState = buffer.readUInt32LE(offset + 28);
52
+ const data = buffer.subarray(offset + 32, offset + 32 + dataSize);
53
+ const entry = {
54
+ regionID,
55
+ pushID,
56
+ uniqueID,
57
+ tableHash,
58
+ recordID,
59
+ dataSize,
60
+ recordState,
61
+ data
62
+ };
63
+ this.entries.push(entry);
64
+ if (!this.tableEntries.has(tableHash)) {
65
+ this.tableEntries.set(tableHash, []);
66
+ }
67
+ this.tableEntries.get(tableHash)?.push(entry);
68
+ pointer += 32 + dataSize;
69
+ }
52
70
  }
53
71
  }
54
72
 
55
- const USER_AGENT = "node-wow-casc-dbc";
56
- const CACHE_ROOT = path__default.resolve("cache");
57
- const CACHE_DIRS = {
58
- build: "builds",
59
- indexes: "indices",
60
- data: "data",
61
- dbd: "dbd"
73
+ var __defProp$5 = Object.defineProperty;
74
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
75
+ var __publicField$5 = (obj, key, value) => {
76
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
77
+ return value;
62
78
  };
63
- const CACHE_INTEGRITY_FILE = path__default.resolve(CACHE_ROOT, "integrity.json");
64
- const cacheIntegrity = new Store(CACHE_INTEGRITY_FILE);
65
- const formatCDNKey = (key) => `${key.substring(0, 2)}/${key.substring(2, 4)}/${key}`;
66
- const requestData = async (url, {
67
- partialOffset,
68
- partialLength,
69
- showProgress
70
- } = {}) => new Promise((resolve, reject) => {
71
- const options = {
72
- headers: {
73
- "User-Agent": USER_AGENT,
74
- Range: partialOffset && partialLength ? `bytes=${partialOffset.toString()}-${(partialOffset + partialLength - 1).toString()}` : "bytes=0-"
75
- }
76
- };
77
- http__default.get(url, options, (res) => {
78
- if (res.statusCode === 301 || res.statusCode === 302) {
79
- if (res.headers.location) {
80
- requestData(res.headers.location, { partialOffset, partialLength, showProgress }).then(resolve).catch((err) => {
81
- throw err;
82
- });
83
- } else {
84
- reject(new Error(`Failed to request ${url}, Status Code: ${res.statusCode.toString()}`));
79
+ class Salsa20 {
80
+ constructor(key, nonce) {
81
+ __publicField$5(this, "fixed");
82
+ __publicField$5(this, "key");
83
+ __publicField$5(this, "nonce");
84
+ __publicField$5(this, "counter", new Uint32Array([0, 0]));
85
+ __publicField$5(this, "state", new Uint32Array(16));
86
+ __publicField$5(this, "block", new Uint8Array(64));
87
+ __publicField$5(this, "position", 0);
88
+ assert__default(key.length === 32 || key.length === 16, "Salsa20 requires 128-bit or 256-bit key");
89
+ assert__default(nonce.length === 8, "Salsa20 requires 64-bit nonce");
90
+ this.key = new Uint32Array(8);
91
+ const keyView = new DataView(key.buffer);
92
+ if (key.length === 32) {
93
+ for (let i = 0; i < 8; i += 1) {
94
+ this.key[i] = keyView.getUint32(i * 4, true);
85
95
  }
86
- return;
96
+ this.fixed = new Uint32Array([
97
+ 1634760805,
98
+ 857760878,
99
+ 2036477234,
100
+ 1797285236
101
+ ]);
102
+ } else {
103
+ for (let i = 0; i < 4; i += 1) {
104
+ const word = keyView.getUint32(i * 4, true);
105
+ this.key[i] = word;
106
+ this.key[i + 4] = word;
107
+ }
108
+ this.fixed = new Uint32Array([
109
+ 1634760805,
110
+ 824206446,
111
+ 2036477238,
112
+ 1797285236
113
+ ]);
87
114
  }
88
- if (!res.statusCode || res.statusCode < 200 || res.statusCode > 302) {
89
- reject(new Error(`Failed to request ${url}, Status Code: ${res.statusCode?.toString() ?? "undefined"}`));
90
- return;
115
+ this.nonce = new Uint32Array(2);
116
+ const nonceView = new DataView(nonce.buffer);
117
+ for (let i = 0; i < 2; i += 1) {
118
+ this.nonce[i] = nonceView.getUint32(i * 4, true);
91
119
  }
92
- const lengthText = res.headers["content-length"];
93
- const length = lengthText ? parseInt(lengthText, 10) : 0;
94
- const bar = showProgress && !Number.isNaN(length) && length >= 10485760 ? new cliProgress__default.SingleBar({ etaBuffer: 10240 }, cliProgress__default.Presets.shades_classic) : void 0;
95
- bar?.start(length, 0);
96
- const chunks = [];
97
- res.on("data", (chunk) => {
98
- bar?.increment(chunk.length);
99
- chunks.push(chunk);
100
- });
101
- res.on("end", () => {
102
- bar?.stop();
103
- resolve(Buffer.concat(chunks));
104
- });
105
- res.on("error", (err) => {
106
- bar?.stop();
107
- reject(err);
108
- });
109
- }).on("error", reject).end();
110
- });
111
- const downloadFile = (prefixes, type, key, {
112
- partialOffset,
113
- partialLength,
114
- showProgress,
115
- showAttemptFail
116
- } = {}) => {
117
- const urls = prefixes.map((prefix) => `${prefix}/${type}/${formatCDNKey(key)}`);
118
- return urls.reduce(
119
- (prev, url, index) => prev.catch((err) => {
120
- if (showAttemptFail && index > 0 && err instanceof Error) {
121
- console.warn(`${( new Date()).toISOString()} [WARN]:`, err.message);
122
- }
123
- return requestData(url, { partialOffset, partialLength, showProgress });
124
- }),
125
- Promise.reject(new Error(""))
126
- );
127
- };
128
- const getFileCache = async (file) => {
129
- const integrity = await cacheIntegrity.get(file);
130
- if (integrity) {
131
- try {
132
- const buffer = await fs__default.readFile(path__default.resolve(CACHE_ROOT, file));
133
- const hash = crypto__default.createHash("sha256").update(buffer).digest("hex");
134
- if (hash === integrity) {
135
- return buffer;
120
+ this.generateBlock();
121
+ }
122
+ // eslint-disable-next-line @typescript-eslint/naming-convention
123
+ QR(a, b, c, d) {
124
+ let t;
125
+ t = this.state[a] + this.state[d] & 4294967295;
126
+ this.state[b] ^= t << 7 | t >>> 25;
127
+ t = this.state[b] + this.state[a] & 4294967295;
128
+ this.state[c] ^= t << 9 | t >>> 23;
129
+ t = this.state[c] + this.state[b] & 4294967295;
130
+ this.state[d] ^= t << 13 | t >>> 19;
131
+ t = this.state[d] + this.state[c] & 4294967295;
132
+ this.state[a] ^= t << 18 | t >>> 14;
133
+ }
134
+ generateBlock() {
135
+ const init = new Uint32Array([
136
+ this.fixed[0],
137
+ this.key[0],
138
+ this.key[1],
139
+ this.key[2],
140
+ this.key[3],
141
+ this.fixed[1],
142
+ this.nonce[0],
143
+ this.nonce[1],
144
+ this.counter[0],
145
+ this.counter[1],
146
+ this.fixed[2],
147
+ this.key[4],
148
+ this.key[5],
149
+ this.key[6],
150
+ this.key[7],
151
+ this.fixed[3]
152
+ ]);
153
+ this.state = new Uint32Array(init);
154
+ for (let i = 0; i < 20; i += 2) {
155
+ this.QR(0, 4, 8, 12);
156
+ this.QR(5, 9, 13, 1);
157
+ this.QR(10, 14, 2, 6);
158
+ this.QR(15, 3, 7, 11);
159
+ this.QR(0, 1, 2, 3);
160
+ this.QR(5, 6, 7, 4);
161
+ this.QR(10, 11, 8, 9);
162
+ this.QR(15, 12, 13, 14);
163
+ }
164
+ for (let i = 0; i < 16; i += 1) {
165
+ const word = this.state[i] + init[i] & 4294967295;
166
+ this.block[i * 4] = word & 255;
167
+ this.block[i * 4 + 1] = word >>> 8 & 255;
168
+ this.block[i * 4 + 2] = word >>> 16 & 255;
169
+ this.block[i * 4 + 3] = word >>> 24 & 255;
170
+ }
171
+ this.counter[0] = this.counter[0] + 1 & 4294967295;
172
+ if (this.counter[0] === 0) {
173
+ this.counter[1] = this.counter[1] + 1 & 4294967295;
174
+ }
175
+ }
176
+ process(input) {
177
+ const { length } = input;
178
+ const result = new Uint8Array(length);
179
+ for (let i = 0; i < length; i += 1) {
180
+ if (this.position === 64) {
181
+ this.generateBlock();
182
+ this.position = 0;
136
183
  }
137
- } catch {
184
+ result[i] = input[i] ^ this.block[this.position];
185
+ this.position += 1;
138
186
  }
187
+ return result;
139
188
  }
140
- return void 0;
189
+ }
190
+
191
+ var __defProp$4 = Object.defineProperty;
192
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
193
+ var __publicField$4 = (obj, key, value) => {
194
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
195
+ return value;
141
196
  };
142
- const getDataFile = async (prefixes, key, type, buildCKey, {
197
+ const BLTE_MAGIC = 1112298565;
198
+ const ENC_TYPE_SALSA20 = 83;
199
+ const EMPTY_HASH = "00000000000000000000000000000000";
200
+ class BLTEReader {
201
+ constructor(buffer, eKey, keys = /* @__PURE__ */ new Map()) {
202
+ __publicField$4(this, "buffer");
203
+ __publicField$4(this, "blte");
204
+ __publicField$4(this, "blocks", []);
205
+ __publicField$4(this, "keys");
206
+ __publicField$4(this, "processedBlock", 0);
207
+ __publicField$4(this, "processedOffset", 0);
208
+ this.blte = buffer;
209
+ this.buffer = Buffer.alloc(0);
210
+ this.keys = keys;
211
+ const size = buffer.byteLength;
212
+ assert__default(size >= 8, `[BLTE]: Invalid size: ${size.toString()} < 8`);
213
+ const magic = buffer.readUInt32BE(0);
214
+ assert__default(magic === BLTE_MAGIC, `[BLTE]: Invalid magic: ${magic.toString(16).padStart(8, "0")}`);
215
+ const headerSize = buffer.readUInt32BE(4);
216
+ if (headerSize === 0) {
217
+ const blteHash2 = crypto__default.createHash("md5").update(buffer).digest("hex");
218
+ assert__default(blteHash2 === eKey, `[BLTE]: Invalid hash: expected ${eKey}, got ${blteHash2}`);
219
+ this.blocks.push({
220
+ compressedSize: size - 8,
221
+ decompressedSize: size - 9,
222
+ hash: EMPTY_HASH
223
+ });
224
+ this.processedOffset = 8;
225
+ return;
226
+ }
227
+ const blteHash = crypto__default.createHash("md5").update(buffer.subarray(0, headerSize)).digest("hex");
228
+ assert__default(blteHash === eKey, `[BLTE]: Invalid hash: expected ${eKey}, got ${blteHash}`);
229
+ assert__default(size >= 12, `[BLTE]: Invalid size: ${size.toString()} < 12`);
230
+ const flag = buffer.readUInt8(8);
231
+ const numBlocks = buffer.readIntBE(9, 3);
232
+ assert__default(numBlocks > 0, `[BLTE]: Invalid number of blocks: ${numBlocks.toString()}`);
233
+ assert__default(flag === 15, `[BLTE]: Invalid flag: ${flag.toString(16).padStart(2, "0")}`);
234
+ const blockHeaderSize = numBlocks * 24;
235
+ assert__default(headerSize === blockHeaderSize + 12, `[BLTE]: Invalid header size: header size ${headerSize.toString()} != block header size ${blockHeaderSize.toString()} + 12`);
236
+ assert__default(size >= headerSize, `[BLTE]: Invalid size: ${size.toString()} < ${headerSize.toString()}`);
237
+ for (let i = 0; i < numBlocks; i += 1) {
238
+ const offset = 12 + i * 24;
239
+ const compressedSize = buffer.readUInt32BE(offset);
240
+ const decompressedSize = buffer.readUInt32BE(offset + 4);
241
+ const hash = buffer.toString("hex", offset + 8, offset + 24);
242
+ this.blocks.push({
243
+ compressedSize,
244
+ decompressedSize,
245
+ hash
246
+ });
247
+ }
248
+ this.processedOffset = headerSize;
249
+ }
250
+ processBlock(buffer, index, allowMissingKey) {
251
+ const flag = buffer.readUInt8(0);
252
+ switch (flag) {
253
+ case 69: {
254
+ let offset = 1;
255
+ const keyNameLength = buffer.readUInt8(offset);
256
+ offset += 1;
257
+ const keyNameBE = buffer.toString("hex", offset, offset + keyNameLength);
258
+ offset += keyNameLength;
259
+ const ivLength = buffer.readUInt8(offset);
260
+ offset += 1;
261
+ const ivBuffer = buffer.subarray(offset, offset + ivLength);
262
+ offset += ivLength;
263
+ const encryptType = buffer.readUInt8(offset);
264
+ offset += 1;
265
+ assert__default(encryptType === ENC_TYPE_SALSA20, `[BLTE]: Invalid encrypt type: ${encryptType.toString(16).padStart(2, "0")} at block ${index.toString()}`);
266
+ const keyName = [...keyNameBE.matchAll(/.{2}/g)].map((v) => v[0]).reverse().join("").toLowerCase();
267
+ const key = this.keys.get(keyName);
268
+ if (!key) {
269
+ if (allowMissingKey) {
270
+ return keyName;
271
+ }
272
+ throw new Error(`[BLTE]: Missing key: ${keyName} at block ${index.toString()}`);
273
+ }
274
+ const iv = new Uint8Array(8);
275
+ for (let i = 0; i < 8; i += 1) {
276
+ if (i < ivLength) {
277
+ iv[i] = ivBuffer.readUInt8(i) ^ index >>> 8 * i & 255;
278
+ } else {
279
+ iv[i] = 0;
280
+ }
281
+ }
282
+ const handler = new Salsa20(key, iv);
283
+ const decrypted = handler.process(buffer.subarray(offset));
284
+ if (allowMissingKey) {
285
+ return this.processBlock(Buffer.from(decrypted.buffer), index, true);
286
+ }
287
+ return this.processBlock(Buffer.from(decrypted.buffer), index, false);
288
+ }
289
+ case 70:
290
+ throw new Error(`[BLTE]: Frame (Recursive) block not supported at block ${index.toString()}`);
291
+ case 78:
292
+ return buffer.subarray(1);
293
+ case 90:
294
+ return zlib__default.inflateSync(buffer.subarray(1));
295
+ default:
296
+ throw new Error(`[BLTE]: Invalid block flag: ${flag.toString(16).padStart(2, "0")} at block ${index.toString()}`);
297
+ }
298
+ }
299
+ processBytes(allowMissingKey = false, size = Infinity) {
300
+ const missingKeyBlocks = [];
301
+ while (this.processedBlock < this.blocks.length && size > this.buffer.byteLength) {
302
+ const blockIndex = this.processedBlock;
303
+ const block = this.blocks[blockIndex];
304
+ const blockBuffer = this.blte.subarray(
305
+ this.processedOffset,
306
+ this.processedOffset + block.compressedSize
307
+ );
308
+ if (block.hash !== EMPTY_HASH) {
309
+ const blockHash = crypto__default.createHash("md5").update(blockBuffer).digest("hex");
310
+ assert__default(blockHash === block.hash, `[BLTE]: Invalid block hash: expected ${block.hash}, got ${blockHash}`);
311
+ }
312
+ if (allowMissingKey) {
313
+ const buffer = this.processBlock(blockBuffer, blockIndex, allowMissingKey);
314
+ if (buffer instanceof Buffer) {
315
+ assert__default(
316
+ buffer.byteLength === block.decompressedSize,
317
+ `[BLTE]: Invalid decompressed size: expected ${block.decompressedSize.toString()}, got ${buffer.byteLength.toString()}`
318
+ );
319
+ this.buffer = Buffer.concat([this.buffer, buffer]);
320
+ } else {
321
+ missingKeyBlocks.push({
322
+ offset: this.buffer.byteLength,
323
+ size: block.decompressedSize,
324
+ blockIndex,
325
+ keyName: buffer
326
+ });
327
+ this.buffer = Buffer.concat([
328
+ this.buffer,
329
+ Buffer.alloc(block.decompressedSize)
330
+ ]);
331
+ }
332
+ } else {
333
+ const buffer = this.processBlock(blockBuffer, blockIndex, allowMissingKey);
334
+ assert__default(
335
+ buffer.byteLength === block.decompressedSize,
336
+ `[BLTE]: Invalid decompressed size: expected ${block.decompressedSize.toString()}, got ${buffer.byteLength.toString()}`
337
+ );
338
+ this.buffer = Buffer.concat([this.buffer, buffer]);
339
+ }
340
+ this.processedBlock += 1;
341
+ this.processedOffset += block.compressedSize;
342
+ }
343
+ return allowMissingKey ? missingKeyBlocks : void 0;
344
+ }
345
+ }
346
+
347
+ var __defProp$3 = Object.defineProperty;
348
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
349
+ var __publicField$3 = (obj, key, value) => {
350
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
351
+ return value;
352
+ };
353
+ class Store {
354
+ constructor(dataFile) {
355
+ __publicField$3(this, "data");
356
+ __publicField$3(this, "dataFile");
357
+ __publicField$3(this, "promise");
358
+ this.dataFile = dataFile;
359
+ this.data = {};
360
+ this.promise = new Promise((resolve) => {
361
+ fs__default.readFile(dataFile, "utf-8").then((file) => {
362
+ this.data = JSON.parse(file);
363
+ resolve();
364
+ }).catch(() => {
365
+ resolve();
366
+ });
367
+ });
368
+ }
369
+ async get(key) {
370
+ await this.promise;
371
+ return this.data[key];
372
+ }
373
+ async set(key, value) {
374
+ await this.promise;
375
+ this.data[key] = value;
376
+ await fs__default.writeFile(this.dataFile, JSON.stringify(this.data), "utf-8");
377
+ }
378
+ }
379
+
380
+ const USER_AGENT = "node-wow-casc-dbc";
381
+ const CACHE_ROOT = path__default.resolve("cache");
382
+ const CACHE_DIRS = {
383
+ build: "builds",
384
+ indexes: "indices",
385
+ data: "data",
386
+ dbd: "dbd"
387
+ };
388
+ const CACHE_INTEGRITY_FILE = path__default.resolve(CACHE_ROOT, "integrity.json");
389
+ const cacheIntegrity = new Store(CACHE_INTEGRITY_FILE);
390
+ const formatCDNKey = (key) => `${key.substring(0, 2)}/${key.substring(2, 4)}/${key}`;
391
+ const requestData = async (url, {
392
+ partialOffset,
393
+ partialLength,
394
+ showProgress
395
+ } = {}) => new Promise((resolve, reject) => {
396
+ const options = {
397
+ headers: {
398
+ // eslint-disable-next-line @typescript-eslint/naming-convention
399
+ "User-Agent": USER_AGENT,
400
+ // eslint-disable-next-line @typescript-eslint/naming-convention
401
+ Range: partialOffset !== void 0 && partialLength !== void 0 ? `bytes=${partialOffset.toString()}-${(partialOffset + partialLength - 1).toString()}` : "bytes=0-"
402
+ }
403
+ };
404
+ http__default.get(url, options, (res) => {
405
+ if (res.statusCode === 301 || res.statusCode === 302) {
406
+ if (res.headers.location !== void 0) {
407
+ requestData(res.headers.location, { partialOffset, partialLength, showProgress }).then(resolve).catch((err) => {
408
+ throw err;
409
+ });
410
+ } else {
411
+ reject(new Error(`Failed to request ${url}, Status Code: ${res.statusCode.toString()}`));
412
+ }
413
+ return;
414
+ }
415
+ if (res.statusCode === void 0 || res.statusCode < 200 || res.statusCode > 302) {
416
+ reject(new Error(`Failed to request ${url}, Status Code: ${res.statusCode?.toString() ?? "undefined"}`));
417
+ return;
418
+ }
419
+ const lengthText = res.headers["content-length"];
420
+ const length = lengthText !== void 0 ? parseInt(lengthText, 10) : 0;
421
+ const bar = showProgress === true && !Number.isNaN(length) && length >= 10485760 ? new cliProgress__default.SingleBar({ etaBuffer: 10240 }, cliProgress__default.Presets.shades_classic) : void 0;
422
+ bar?.start(length, 0);
423
+ const chunks = [];
424
+ res.on("data", (chunk) => {
425
+ bar?.increment(chunk.length);
426
+ chunks.push(chunk);
427
+ });
428
+ res.on("end", () => {
429
+ bar?.stop();
430
+ resolve(Buffer.concat(chunks));
431
+ });
432
+ res.on("error", (err) => {
433
+ bar?.stop();
434
+ reject(err);
435
+ });
436
+ }).on("error", reject).end();
437
+ });
438
+ const downloadFile = (prefixes, type, key, {
439
+ partialOffset,
440
+ partialLength,
441
+ showProgress,
442
+ showAttemptFail
443
+ } = {}) => {
444
+ const urls = prefixes.map((prefix) => `${prefix}/${type}/${formatCDNKey(key)}`);
445
+ return urls.reduce(
446
+ (prev, url, index) => prev.catch((err) => {
447
+ if (showAttemptFail === true && index > 0 && err instanceof Error) {
448
+ console.warn(`${( new Date()).toISOString()} [WARN]:`, err.message);
449
+ }
450
+ return requestData(url, { partialOffset, partialLength, showProgress });
451
+ }),
452
+ Promise.reject(new Error(""))
453
+ );
454
+ };
455
+ const getFileCache = async (file) => {
456
+ const integrity = await cacheIntegrity.get(file);
457
+ if (integrity !== void 0) {
458
+ try {
459
+ const buffer = await fs__default.readFile(path__default.resolve(CACHE_ROOT, file));
460
+ const hash = crypto__default.createHash("sha256").update(buffer).digest("hex");
461
+ if (hash === integrity) {
462
+ return buffer;
463
+ }
464
+ } catch {
465
+ }
466
+ }
467
+ return void 0;
468
+ };
469
+ const getDataFile = async (prefixes, key, type, buildCKey, {
143
470
  name,
144
471
  partialOffset,
145
472
  partialLength,
@@ -147,7 +474,7 @@ const getDataFile = async (prefixes, key, type, buildCKey, {
147
474
  showAttemptFail
148
475
  } = {}) => {
149
476
  const dir = type === "build" ? path__default.join(CACHE_DIRS[type], buildCKey) : CACHE_DIRS[type];
150
- const file = name ? path__default.join(dir, name) : path__default.join(dir, key);
477
+ const file = name !== void 0 ? path__default.join(dir, name) : path__default.join(dir, key);
151
478
  const cacheBuffer = await getFileCache(file);
152
479
  if (cacheBuffer) {
153
480
  if (name === void 0 && partialOffset !== void 0 && partialLength !== void 0) {
@@ -161,7 +488,7 @@ const getDataFile = async (prefixes, key, type, buildCKey, {
161
488
  showProgress,
162
489
  showAttemptFail
163
490
  });
164
- if (partialOffset === void 0 && partialLength === void 0 || name) {
491
+ if (partialOffset === void 0 && partialLength === void 0 || name !== void 0) {
165
492
  await fs__default.mkdir(path__default.resolve(CACHE_ROOT, dir), { recursive: true });
166
493
  await fs__default.writeFile(path__default.resolve(CACHE_ROOT, file), downloadBuffer);
167
494
  const hash = crypto__default.createHash("sha256").update(downloadBuffer).digest("hex");
@@ -178,391 +505,204 @@ const getConfigFile = async (prefixes, key, {
178
505
  };
179
506
  const getProductVersions = async (region, product) => {
180
507
  const url = `http://${region}.patch.battle.net:1119/${product}/versions`;
181
- const headers = {
182
- "User-Agent": USER_AGENT
183
- };
508
+ const headers = new Headers();
509
+ headers.set("User-Agent", USER_AGENT);
184
510
  const res = await fetch(url, { headers });
185
511
  return res.text();
186
512
  };
187
513
  const getProductCDNs = async (region, product) => {
188
514
  const url = `http://${region}.patch.battle.net:1119/${product}/cdns`;
189
- const headers = {
190
- "User-Agent": USER_AGENT
191
- };
515
+ const headers = new Headers();
516
+ headers.set("User-Agent", USER_AGENT);
192
517
  const res = await fetch(url, { headers });
193
518
  return res.text();
194
519
  };
195
520
 
196
- const parseProductConfig = (text) => {
197
- const lines = text.split(/\r?\n/);
198
- const headers = lines[0].split("|").map((header) => header.split("!")[0].replace(" ", ""));
199
- const entries = lines.filter((line, index) => index > 0 && line.trim().length !== 0 && !line.startsWith("#")).map((line) => {
200
- const node = {};
201
- const entryFields = line.split("|");
202
- for (let i = 0, n = entryFields.length; i < n; i += 1) {
203
- node[headers[i]] = entryFields[i];
204
- }
205
- return node;
206
- });
207
- return entries;
208
- };
209
- const parseProductVersions = (text) => parseProductConfig(text);
210
- const parseProductCDNs = (text) => parseProductConfig(text);
211
-
212
- const normalizeKey = (key) => key.split("-").map((part, index) => index === 0 ? part : `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("");
213
- const parseConfig = (text) => {
214
- const entries = {};
215
- text.split(/\r?\n/).filter((line) => line.trim().length !== 0 && !line.startsWith("#")).forEach((line) => {
216
- const match = line.match(/([^\s]+)\s?=\s?(.*)/);
217
- assert__default(match !== null, "Invalid token encountered parsing CDN config");
218
- const [key, value] = match.slice(1);
219
- entries[normalizeKey(key)] = value;
220
- });
221
- return entries;
222
- };
223
- const parseCDNConfig = (text) => parseConfig(text);
224
- const parseBuildConfig = (text) => parseConfig(text);
225
-
226
- const VERSION_SUB_OFFSET = -12;
227
- const CHECKSUM_SIZE_SUB_OFFSET = -5;
228
- const BLOCK_SIZE_OFFSET = 3;
229
- const OFFSET_BYTES_OFFSET = 4;
230
- const SIZE_BYTES_OFFSET = 5;
231
- const KEY_SIZE_OFFSET = 6;
232
- const NUM_ELEMENTS_OFFSET = 8;
233
- const CHECKSUM_OFFSET = 12;
234
- const CHECKSUM_TRIES = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
235
- const tryArchiveIndexChecksumSize = (buffer, cKey) => {
236
- const res = CHECKSUM_TRIES.filter(
237
- (index) => buffer.readUInt8(buffer.byteLength - index + CHECKSUM_SIZE_SUB_OFFSET) === index && buffer.readUInt8(buffer.byteLength - index + VERSION_SUB_OFFSET) === 1
238
- );
239
- if (res.length === 1) {
240
- return res[0];
241
- }
242
- throw new Error(`Invalid checksum size: ${res.join(", ")} in ${cKey}`);
243
- };
244
- const parseArchiveIndex = (buffer, cKey) => {
245
- const checksumSize = tryArchiveIndexChecksumSize(buffer, cKey);
246
- const versionOffset = buffer.byteLength - checksumSize + VERSION_SUB_OFFSET;
247
- const footerOffset = versionOffset - checksumSize;
248
- const tocChecksum = buffer.toString("hex", footerOffset, versionOffset);
249
- const version = buffer.readUInt8(versionOffset);
250
- const blockSizeKB = buffer.readUInt8(versionOffset + BLOCK_SIZE_OFFSET);
251
- const offsetBytes = buffer.readUInt8(versionOffset + OFFSET_BYTES_OFFSET);
252
- const sizeBytes = buffer.readUInt8(versionOffset + SIZE_BYTES_OFFSET);
253
- const keySize = buffer.readUInt8(versionOffset + KEY_SIZE_OFFSET);
254
- const numElements = buffer.readUInt32LE(versionOffset + NUM_ELEMENTS_OFFSET);
255
- const footerChecksum = buffer.toString("hex", versionOffset + CHECKSUM_OFFSET);
256
- assert__default(version === 1, `Invalid version: ${version.toString()} in ${cKey}`);
257
- const entrySize = keySize + offsetBytes + sizeBytes;
258
- const blockSize = blockSizeKB * 1024;
259
- const numBlocks = footerOffset / (blockSize + keySize + checksumSize);
260
- const tocSize = (keySize + checksumSize) * numBlocks;
261
- const toc = buffer.subarray(footerOffset - tocSize, footerOffset);
262
- const footer = buffer.subarray(footerOffset);
263
- const footerCheckBuffer = Buffer.concat([
264
- buffer.subarray(versionOffset, buffer.byteLength - checksumSize),
265
- Buffer.alloc(checksumSize)
266
- ]);
267
- const hash = crypto__default.createHash("md5").update(footer).digest("hex");
268
- assert__default(hash === cKey, `Invalid footer hash in ${cKey}: expected ${cKey}, got ${hash}`);
269
- const footerHash = crypto__default.createHash("md5").update(footerCheckBuffer).digest("hex").slice(0, checksumSize * 2);
270
- assert__default(footerHash === footerChecksum, `Invalid footer checksum in ${cKey}: expected ${footerChecksum}, got ${footerHash}`);
271
- const tocHash = crypto__default.createHash("md5").update(toc).digest("hex").slice(0, checksumSize * 2);
272
- assert__default(tocHash === tocChecksum, `Invalid toc checksum in ${cKey}: expected ${tocChecksum}, got ${tocHash}`);
273
- const result = /* @__PURE__ */ new Map();
274
- for (let i = 0; i < numBlocks; i += 1) {
275
- const lastEkey = toc.toString("hex", i * keySize, (i + 1) * keySize);
276
- const blockChecksum = toc.toString("hex", numBlocks * keySize + i * checksumSize, numBlocks * keySize + (i + 1) * checksumSize);
277
- const blockOffset = i * blockSize;
278
- const blockHash = crypto__default.createHash("md5").update(buffer.subarray(i * blockSize, (i + 1) * blockSize)).digest("hex").slice(0, checksumSize * 2);
279
- assert__default(blockChecksum === blockHash, `Invalid block hash in ${cKey} at ${i.toString()}: expected ${blockChecksum}, got ${blockHash}`);
280
- let length = 0;
281
- while (length < blockSize) {
282
- const entryOffset = blockOffset + length * entrySize;
283
- const eKey = buffer.toString("hex", entryOffset, entryOffset + keySize);
284
- const size = buffer.readUIntBE(entryOffset + keySize, sizeBytes);
285
- const offset = buffer.readUIntBE(entryOffset + keySize + sizeBytes, offsetBytes);
286
- result.set(eKey, { key: cKey, size, offset });
287
- length += 1;
288
- if (eKey === lastEkey) {
289
- break;
290
- }
291
- }
292
- }
293
- assert__default(result.size === numElements, `Invalid number of elements: ${result.size.toString()} != ${numElements.toString()} in ${cKey}`);
294
- return result;
295
- };
296
-
297
- var __defProp$5 = Object.defineProperty;
298
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
299
- var __publicField$5 = (obj, key, value) => {
300
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
301
- return value;
302
- };
303
- class Salsa20 {
304
- constructor(key, nonce) {
305
- __publicField$5(this, "fixed");
306
- __publicField$5(this, "key");
307
- __publicField$5(this, "nonce");
308
- __publicField$5(this, "counter", new Uint32Array([0, 0]));
309
- __publicField$5(this, "state", new Uint32Array(16));
310
- __publicField$5(this, "block", new Uint8Array(64));
311
- __publicField$5(this, "position", 0);
312
- assert__default(key.length === 32 || key.length === 16, "Salsa20 requires 128-bit or 256-bit key");
313
- assert__default(nonce.length === 8, "Salsa20 requires 64-bit nonce");
314
- this.key = new Uint32Array(8);
315
- const keyView = new DataView(key.buffer);
316
- if (key.length === 32) {
317
- for (let i = 0; i < 8; i += 1) {
318
- this.key[i] = keyView.getUint32(i * 4, true);
319
- }
320
- this.fixed = new Uint32Array([
321
- 1634760805,
322
- 857760878,
323
- 2036477234,
324
- 1797285236
325
- ]);
326
- } else {
327
- for (let i = 0; i < 4; i += 1) {
328
- const word = keyView.getUint32(i * 4, true);
329
- this.key[i] = word;
330
- this.key[i + 4] = word;
331
- }
332
- this.fixed = new Uint32Array([
333
- 1634760805,
334
- 824206446,
335
- 2036477238,
336
- 1797285236
337
- ]);
338
- }
339
- this.nonce = new Uint32Array(2);
340
- const nonceView = new DataView(nonce.buffer);
341
- for (let i = 0; i < 2; i += 1) {
342
- this.nonce[i] = nonceView.getUint32(i * 4, true);
343
- }
344
- this.generateBlock();
345
- }
346
- QR(a, b, c, d) {
347
- let t;
348
- t = this.state[a] + this.state[d] & 4294967295;
349
- this.state[b] ^= t << 7 | t >>> 25;
350
- t = this.state[b] + this.state[a] & 4294967295;
351
- this.state[c] ^= t << 9 | t >>> 23;
352
- t = this.state[c] + this.state[b] & 4294967295;
353
- this.state[d] ^= t << 13 | t >>> 19;
354
- t = this.state[d] + this.state[c] & 4294967295;
355
- this.state[a] ^= t << 18 | t >>> 14;
356
- }
357
- generateBlock() {
358
- const init = new Uint32Array([
359
- this.fixed[0],
360
- this.key[0],
361
- this.key[1],
362
- this.key[2],
363
- this.key[3],
364
- this.fixed[1],
365
- this.nonce[0],
366
- this.nonce[1],
367
- this.counter[0],
368
- this.counter[1],
369
- this.fixed[2],
370
- this.key[4],
371
- this.key[5],
372
- this.key[6],
373
- this.key[7],
374
- this.fixed[3]
375
- ]);
376
- this.state = new Uint32Array(init);
377
- for (let i = 0; i < 20; i += 2) {
378
- this.QR(0, 4, 8, 12);
379
- this.QR(5, 9, 13, 1);
380
- this.QR(10, 14, 2, 6);
381
- this.QR(15, 3, 7, 11);
382
- this.QR(0, 1, 2, 3);
383
- this.QR(5, 6, 7, 4);
384
- this.QR(10, 11, 8, 9);
385
- this.QR(15, 12, 13, 14);
386
- }
387
- for (let i = 0; i < 16; i += 1) {
388
- const word = this.state[i] + init[i] & 4294967295;
389
- this.block[i * 4] = word & 255;
390
- this.block[i * 4 + 1] = word >>> 8 & 255;
391
- this.block[i * 4 + 2] = word >>> 16 & 255;
392
- this.block[i * 4 + 3] = word >>> 24 & 255;
393
- }
394
- this.counter[0] = this.counter[0] + 1 & 4294967295;
395
- if (this.counter[0] === 0) {
396
- this.counter[1] = this.counter[1] + 1 & 4294967295;
397
- }
521
+ const hashlittle2 = (key, pc = 0, pb = 0) => {
522
+ const { length } = key;
523
+ let offset = 0;
524
+ let a = 3735928559 + length + pc | 0;
525
+ let b = 3735928559 + length + pc | 0;
526
+ let c = 3735928559 + length + pc + pb | 0;
527
+ while (length - offset > 12) {
528
+ a += key.charCodeAt(offset + 0);
529
+ a += key.charCodeAt(offset + 1) << 8;
530
+ a += key.charCodeAt(offset + 2) << 16;
531
+ a += key.charCodeAt(offset + 3) << 24;
532
+ b += key.charCodeAt(offset + 4);
533
+ b += key.charCodeAt(offset + 5) << 8;
534
+ b += key.charCodeAt(offset + 6) << 16;
535
+ b += key.charCodeAt(offset + 7) << 24;
536
+ c += key.charCodeAt(offset + 8);
537
+ c += key.charCodeAt(offset + 9) << 8;
538
+ c += key.charCodeAt(offset + 10) << 16;
539
+ c += key.charCodeAt(offset + 11) << 24;
540
+ a -= c;
541
+ a ^= c << 4 | c >>> 28;
542
+ c = c + b | 0;
543
+ b -= a;
544
+ b ^= a << 6 | a >>> 26;
545
+ a = a + c | 0;
546
+ c -= b;
547
+ c ^= b << 8 | b >>> 24;
548
+ b = b + a | 0;
549
+ a -= c;
550
+ a ^= c << 16 | c >>> 16;
551
+ c = c + b | 0;
552
+ b -= a;
553
+ b ^= a << 19 | a >>> 13;
554
+ a = a + c | 0;
555
+ c -= b;
556
+ c ^= b << 4 | b >>> 28;
557
+ b = b + a | 0;
558
+ offset += 12;
398
559
  }
399
- process(input) {
400
- const { length } = input;
401
- const result = new Uint8Array(length);
402
- for (let i = 0; i < length; i += 1) {
403
- if (this.position === 64) {
404
- this.generateBlock();
405
- this.position = 0;
406
- }
407
- result[i] = input[i] ^ this.block[this.position];
408
- this.position += 1;
560
+ if (length - offset > 0) {
561
+ switch (length - offset) {
562
+ case 12:
563
+ c += key.charCodeAt(offset + 11) << 24;
564
+ case 11:
565
+ c += key.charCodeAt(offset + 10) << 16;
566
+ case 10:
567
+ c += key.charCodeAt(offset + 9) << 8;
568
+ case 9:
569
+ c += key.charCodeAt(offset + 8);
570
+ case 8:
571
+ b += key.charCodeAt(offset + 7) << 24;
572
+ case 7:
573
+ b += key.charCodeAt(offset + 6) << 16;
574
+ case 6:
575
+ b += key.charCodeAt(offset + 5) << 8;
576
+ case 5:
577
+ b += key.charCodeAt(offset + 4);
578
+ case 4:
579
+ a += key.charCodeAt(offset + 3) << 24;
580
+ case 3:
581
+ a += key.charCodeAt(offset + 2) << 16;
582
+ case 2:
583
+ a += key.charCodeAt(offset + 1) << 8;
584
+ case 1:
585
+ a += key.charCodeAt(offset + 0);
409
586
  }
410
- return result;
587
+ c ^= b;
588
+ c -= b << 14 | b >>> 18;
589
+ a ^= c;
590
+ a -= c << 11 | c >>> 21;
591
+ b ^= a;
592
+ b -= a << 25 | a >>> 7;
593
+ c ^= b;
594
+ c -= b << 16 | b >>> 16;
595
+ a ^= c;
596
+ a -= c << 4 | c >>> 28;
597
+ b ^= a;
598
+ b -= a << 14 | a >>> 18;
599
+ c ^= b;
600
+ c -= b << 24 | b >>> 8;
411
601
  }
412
- }
413
-
414
- var __defProp$4 = Object.defineProperty;
415
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
416
- var __publicField$4 = (obj, key, value) => {
417
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
418
- return value;
602
+ return [c >>> 0, b >>> 0];
419
603
  };
420
- const BLTE_MAGIC = 1112298565;
421
- const ENC_TYPE_SALSA20 = 83;
422
- const EMPTY_HASH = "00000000000000000000000000000000";
423
- class BLTEReader {
424
- constructor(buffer, eKey, keys = /* @__PURE__ */ new Map()) {
425
- __publicField$4(this, "buffer");
426
- __publicField$4(this, "blte");
427
- __publicField$4(this, "blocks", []);
428
- __publicField$4(this, "keys");
429
- __publicField$4(this, "processedBlock", 0);
430
- __publicField$4(this, "processedOffset", 0);
431
- this.blte = buffer;
432
- this.buffer = Buffer.alloc(0);
433
- this.keys = keys;
434
- const size = buffer.byteLength;
435
- assert__default(size >= 8, `[BLTE]: Invalid size: ${size.toString()} < 8`);
436
- const magic = buffer.readUInt32BE(0);
437
- assert__default(magic === BLTE_MAGIC, `[BLTE]: Invalid magic: ${magic.toString(16).padStart(8, "0")}`);
438
- const headerSize = buffer.readUInt32BE(4);
439
- if (headerSize === 0) {
440
- const blteHash2 = crypto__default.createHash("md5").update(buffer).digest("hex");
441
- assert__default(blteHash2 === eKey, `[BLTE]: Invalid hash: expected ${eKey}, got ${blteHash2}`);
442
- this.blocks.push({
443
- compressedSize: size - 8,
444
- decompressedSize: size - 9,
445
- hash: EMPTY_HASH
446
- });
447
- this.processedOffset = 8;
448
- return;
449
- }
450
- const blteHash = crypto__default.createHash("md5").update(buffer.subarray(0, headerSize)).digest("hex");
451
- assert__default(blteHash === eKey, `[BLTE]: Invalid hash: expected ${eKey}, got ${blteHash}`);
452
- assert__default(size >= 12, `[BLTE]: Invalid size: ${size.toString()} < 12`);
453
- const flag = buffer.readUInt8(8);
454
- const numBlocks = buffer.readIntBE(9, 3);
455
- assert__default(numBlocks > 0, `[BLTE]: Invalid number of blocks: ${numBlocks.toString()}`);
456
- assert__default(flag === 15, `[BLTE]: Invalid flag: ${flag.toString(16).padStart(2, "0")}`);
457
- const blockHeaderSize = numBlocks * 24;
458
- assert__default(headerSize === blockHeaderSize + 12, `[BLTE]: Invalid header size: header size ${headerSize.toString()} != block header size ${blockHeaderSize.toString()} + 12`);
459
- assert__default(size >= headerSize, `[BLTE]: Invalid size: ${size.toString()} < ${headerSize.toString()}`);
460
- for (let i = 0; i < numBlocks; i += 1) {
461
- const offset = 12 + i * 24;
462
- const compressedSize = buffer.readUInt32BE(offset);
463
- const decompressedSize = buffer.readUInt32BE(offset + 4);
464
- const hash = buffer.toString("hex", offset + 8, offset + 24);
465
- this.blocks.push({
466
- compressedSize,
467
- decompressedSize,
468
- hash
469
- });
470
- }
471
- this.processedOffset = headerSize;
472
- }
473
- processBlock(buffer, index, allowMissingKey) {
474
- const flag = buffer.readUInt8(0);
475
- switch (flag) {
476
- case 69: {
477
- let offset = 1;
478
- const keyNameLength = buffer.readUInt8(offset);
479
- offset += 1;
480
- const keyNameBE = buffer.toString("hex", offset, offset + keyNameLength);
481
- offset += keyNameLength;
482
- const ivLength = buffer.readUInt8(offset);
483
- offset += 1;
484
- const ivBuffer = buffer.subarray(offset, offset + ivLength);
485
- offset += ivLength;
486
- const encryptType = buffer.readUInt8(offset);
487
- offset += 1;
488
- assert__default(encryptType === ENC_TYPE_SALSA20, `[BLTE]: Invalid encrypt type: ${encryptType.toString(16).padStart(2, "0")}`);
489
- const keyName = [...keyNameBE.matchAll(/.{2}/g)].map((v) => v[0]).reverse().join("").toLowerCase();
490
- const key = this.keys.get(keyName);
491
- if (!key) {
492
- if (allowMissingKey) {
493
- return keyName;
494
- }
495
- throw new Error(`[BLTE]: Missing key: ${keyName}`);
496
- }
497
- const iv = new Uint8Array(8);
498
- for (let i = 0; i < 8; i += 1) {
499
- const byte = ivBuffer.byteLength > i ? ivBuffer.readUInt8(i) : void 0;
500
- iv[i] = byte ? byte ^ index >> 8 * i & 255 : 0;
501
- }
502
- const handler = new Salsa20(key, iv);
503
- const decrypted = handler.process(buffer.subarray(offset));
504
- if (allowMissingKey) {
505
- return this.processBlock(Buffer.from(decrypted.buffer), index, true);
506
- }
507
- return this.processBlock(Buffer.from(decrypted.buffer), index, false);
508
- }
509
- case 70:
510
- throw new Error("[BLTE]: Frame (Recursive) block not supported");
511
- case 78:
512
- return buffer.subarray(1);
513
- case 90:
514
- return zlib__default.inflateSync(buffer.subarray(1));
515
- default:
516
- throw new Error(`[BLTE]: Invalid block flag: ${flag.toString(16).padStart(2, "0")}`);
517
- }
604
+ const getNameHash = (name) => {
605
+ const normalized = name.replace(/\//g, "\\").toUpperCase();
606
+ const [pc, pb] = hashlittle2(normalized);
607
+ return `${pc.toString(16).padStart(8, "0")}${pb.toString(16).padStart(8, "0")}`;
608
+ };
609
+
610
+ const VERSION_SUB_OFFSET = -12;
611
+ const CHECKSUM_SIZE_SUB_OFFSET = -5;
612
+ const BLOCK_SIZE_OFFSET = 3;
613
+ const OFFSET_BYTES_OFFSET = 4;
614
+ const SIZE_BYTES_OFFSET = 5;
615
+ const KEY_SIZE_OFFSET = 6;
616
+ const NUM_ELEMENTS_OFFSET = 8;
617
+ const CHECKSUM_OFFSET = 12;
618
+ const CHECKSUM_TRIES = [
619
+ 10,
620
+ 9,
621
+ 8,
622
+ 7,
623
+ 6,
624
+ 5,
625
+ 4,
626
+ 3,
627
+ 2,
628
+ 1,
629
+ 0
630
+ ];
631
+ const tryArchiveIndexChecksumSize = (buffer, cKey) => {
632
+ const res = CHECKSUM_TRIES.filter(
633
+ (index) => buffer.readUInt8(buffer.byteLength - index + CHECKSUM_SIZE_SUB_OFFSET) === index && buffer.readUInt8(buffer.byteLength - index + VERSION_SUB_OFFSET) === 1
634
+ );
635
+ if (res.length === 1) {
636
+ return res[0];
518
637
  }
519
- processBytes(allowMissingKey = false, size = Infinity) {
520
- const missingKeyBlocks = [];
521
- while (this.processedBlock < this.blocks.length && size > this.buffer.byteLength) {
522
- const blockIndex = this.processedBlock;
523
- const block = this.blocks[blockIndex];
524
- const blockBuffer = this.blte.subarray(
525
- this.processedOffset,
526
- this.processedOffset + block.compressedSize
527
- );
528
- if (block.hash !== EMPTY_HASH) {
529
- const blockHash = crypto__default.createHash("md5").update(blockBuffer).digest("hex");
530
- assert__default(blockHash === block.hash, `[BLTE]: Invalid block hash: expected ${block.hash}, got ${blockHash}`);
531
- }
532
- if (allowMissingKey) {
533
- const buffer = this.processBlock(blockBuffer, blockIndex, allowMissingKey);
534
- if (buffer instanceof Buffer) {
535
- assert__default(
536
- buffer.byteLength === block.decompressedSize,
537
- `[BLTE]: Invalid decompressed size: expected ${block.decompressedSize.toString()}, got ${buffer.byteLength.toString()}`
538
- );
539
- this.buffer = Buffer.concat([this.buffer, buffer]);
540
- } else {
541
- missingKeyBlocks.push({
542
- offset: this.buffer.byteLength,
543
- size: block.decompressedSize,
544
- blockIndex,
545
- keyName: buffer
546
- });
547
- this.buffer = Buffer.concat([
548
- this.buffer,
549
- Buffer.alloc(block.decompressedSize)
550
- ]);
551
- }
552
- } else {
553
- const buffer = this.processBlock(blockBuffer, blockIndex, allowMissingKey);
554
- assert__default(
555
- buffer.byteLength === block.decompressedSize,
556
- `[BLTE]: Invalid decompressed size: expected ${block.decompressedSize.toString()}, got ${buffer.byteLength.toString()}`
557
- );
558
- this.buffer = Buffer.concat([this.buffer, buffer]);
638
+ throw new Error(`Invalid checksum size: ${res.join(", ")} in ${cKey}`);
639
+ };
640
+ const parseArchiveIndex = (buffer, cKey) => {
641
+ const checksumSize = tryArchiveIndexChecksumSize(buffer, cKey);
642
+ const versionOffset = buffer.byteLength - checksumSize + VERSION_SUB_OFFSET;
643
+ const footerOffset = versionOffset - checksumSize;
644
+ const tocChecksum = buffer.toString("hex", footerOffset, versionOffset);
645
+ const version = buffer.readUInt8(versionOffset);
646
+ const blockSizeKB = buffer.readUInt8(versionOffset + BLOCK_SIZE_OFFSET);
647
+ const offsetBytes = buffer.readUInt8(versionOffset + OFFSET_BYTES_OFFSET);
648
+ const sizeBytes = buffer.readUInt8(versionOffset + SIZE_BYTES_OFFSET);
649
+ const keySize = buffer.readUInt8(versionOffset + KEY_SIZE_OFFSET);
650
+ const numElements = buffer.readUInt32LE(versionOffset + NUM_ELEMENTS_OFFSET);
651
+ const footerChecksum = buffer.toString("hex", versionOffset + CHECKSUM_OFFSET);
652
+ assert__default(version === 1, `Invalid version: ${version.toString()} in ${cKey}`);
653
+ const entrySize = keySize + offsetBytes + sizeBytes;
654
+ const blockSize = blockSizeKB * 1024;
655
+ const numBlocks = footerOffset / (blockSize + keySize + checksumSize);
656
+ const tocSize = (keySize + checksumSize) * numBlocks;
657
+ const toc = buffer.subarray(footerOffset - tocSize, footerOffset);
658
+ const footer = buffer.subarray(footerOffset);
659
+ const footerCheckBuffer = Buffer.concat([
660
+ buffer.subarray(versionOffset, buffer.byteLength - checksumSize),
661
+ Buffer.alloc(checksumSize)
662
+ ]);
663
+ const hash = crypto__default.createHash("md5").update(footer).digest("hex");
664
+ assert__default(hash === cKey, `Invalid footer hash in ${cKey}: expected ${cKey}, got ${hash}`);
665
+ const footerHash = crypto__default.createHash("md5").update(footerCheckBuffer).digest("hex").slice(0, checksumSize * 2);
666
+ assert__default(footerHash === footerChecksum, `Invalid footer checksum in ${cKey}: expected ${footerChecksum}, got ${footerHash}`);
667
+ const tocHash = crypto__default.createHash("md5").update(toc).digest("hex").slice(0, checksumSize * 2);
668
+ assert__default(tocHash === tocChecksum, `Invalid toc checksum in ${cKey}: expected ${tocChecksum}, got ${tocHash}`);
669
+ const result = /* @__PURE__ */ new Map();
670
+ for (let i = 0; i < numBlocks; i += 1) {
671
+ const lastEkey = toc.toString("hex", i * keySize, (i + 1) * keySize);
672
+ const blockChecksum = toc.toString("hex", numBlocks * keySize + i * checksumSize, numBlocks * keySize + (i + 1) * checksumSize);
673
+ const blockOffset = i * blockSize;
674
+ const blockHash = crypto__default.createHash("md5").update(buffer.subarray(i * blockSize, (i + 1) * blockSize)).digest("hex").slice(0, checksumSize * 2);
675
+ assert__default(blockChecksum === blockHash, `Invalid block hash in ${cKey} at ${i.toString()}: expected ${blockChecksum}, got ${blockHash}`);
676
+ let length = 0;
677
+ while (length < blockSize) {
678
+ const entryOffset = blockOffset + length * entrySize;
679
+ const eKey = buffer.toString("hex", entryOffset, entryOffset + keySize);
680
+ const size = buffer.readUIntBE(entryOffset + keySize, sizeBytes);
681
+ const offset = buffer.readUIntBE(entryOffset + keySize + sizeBytes, offsetBytes);
682
+ result.set(eKey, { key: cKey, size, offset });
683
+ length += 1;
684
+ if (eKey === lastEkey) {
685
+ break;
559
686
  }
560
- this.processedBlock += 1;
561
- this.processedOffset += block.compressedSize;
562
687
  }
563
- return allowMissingKey ? missingKeyBlocks : void 0;
564
688
  }
565
- }
689
+ assert__default(result.size === numElements, `Invalid number of elements: ${result.size.toString()} != ${numElements.toString()} in ${cKey}`);
690
+ return result;
691
+ };
692
+
693
+ const normalizeKey = (key) => key.split("-").map((part, index) => index === 0 ? part : `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("");
694
+ const parseConfig = (text) => {
695
+ const entries = {};
696
+ text.split(/\r?\n/).filter((line) => line.trim().length !== 0 && !line.startsWith("#")).forEach((line) => {
697
+ const match = /([^\s]+)\s?=\s?(.*)/.exec(line);
698
+ assert__default(match !== null, "Invalid token encountered parsing CDN config");
699
+ const [key, value] = match.slice(1);
700
+ entries[normalizeKey(key)] = value;
701
+ });
702
+ return entries;
703
+ };
704
+ const parseCDNConfig = (text) => parseConfig(text);
705
+ const parseBuildConfig = (text) => parseConfig(text);
566
706
 
567
707
  const ENC_MAGIC = 17742;
568
708
  const MAGIC_OFFSET = 0;
@@ -681,6 +821,22 @@ const parseEncodingFile = (inputBuffer, eKey, cKey) => {
681
821
  };
682
822
  };
683
823
 
824
+ const parseProductConfig = (text) => {
825
+ const lines = text.split(/\r?\n/);
826
+ const headers = lines[0].split("|").map((header) => header.split("!")[0].replace(" ", ""));
827
+ const entries = lines.filter((line, index) => index > 0 && line.trim().length !== 0 && !line.startsWith("#")).map((line) => {
828
+ const node = {};
829
+ const entryFields = line.split("|");
830
+ for (let i = 0, n = entryFields.length; i < n; i += 1) {
831
+ node[headers[i]] = entryFields[i];
832
+ }
833
+ return node;
834
+ });
835
+ return entries;
836
+ };
837
+ const parseProductVersions = (text) => parseProductConfig(text);
838
+ const parseProductCDNs = (text) => parseProductConfig(text);
839
+
684
840
  const MFST_MAGIC = 1296454484;
685
841
  const ContentFlags = {
686
842
  Install: 4,
@@ -806,99 +962,66 @@ const parseRootFile = (inputBuffer, eKey, cKey) => {
806
962
  return { fileDataID2CKey, nameHash2FileDataID };
807
963
  };
808
964
 
809
- const hashlittle2 = (key, pc = 0, pb = 0) => {
810
- const { length } = key;
811
- let offset = 0;
812
- let a = 3735928559 + length + pc | 0;
813
- let b = 3735928559 + length + pc | 0;
814
- let c = 3735928559 + length + pc + pb | 0;
815
- while (length - offset > 12) {
816
- a += key.charCodeAt(offset + 0);
817
- a += key.charCodeAt(offset + 1) << 8;
818
- a += key.charCodeAt(offset + 2) << 16;
819
- a += key.charCodeAt(offset + 3) << 24;
820
- b += key.charCodeAt(offset + 4);
821
- b += key.charCodeAt(offset + 5) << 8;
822
- b += key.charCodeAt(offset + 6) << 16;
823
- b += key.charCodeAt(offset + 7) << 24;
824
- c += key.charCodeAt(offset + 8);
825
- c += key.charCodeAt(offset + 9) << 8;
826
- c += key.charCodeAt(offset + 10) << 16;
827
- c += key.charCodeAt(offset + 11) << 24;
828
- a -= c;
829
- a ^= c << 4 | c >>> 28;
830
- c = c + b | 0;
831
- b -= a;
832
- b ^= a << 6 | a >>> 26;
833
- a = a + c | 0;
834
- c -= b;
835
- c ^= b << 8 | b >>> 24;
836
- b = b + a | 0;
837
- a -= c;
838
- a ^= c << 16 | c >>> 16;
839
- c = c + b | 0;
840
- b -= a;
841
- b ^= a << 19 | a >>> 13;
842
- a = a + c | 0;
843
- c -= b;
844
- c ^= b << 4 | b >>> 28;
845
- b = b + a | 0;
846
- offset += 12;
847
- }
848
- if (length - offset > 0) {
849
- switch (length - offset) {
850
- case 12:
851
- c += key.charCodeAt(offset + 11) << 24;
852
- case 11:
853
- c += key.charCodeAt(offset + 10) << 16;
854
- case 10:
855
- c += key.charCodeAt(offset + 9) << 8;
856
- case 9:
857
- c += key.charCodeAt(offset + 8);
858
- case 8:
859
- b += key.charCodeAt(offset + 7) << 24;
860
- case 7:
861
- b += key.charCodeAt(offset + 6) << 16;
862
- case 6:
863
- b += key.charCodeAt(offset + 5) << 8;
864
- case 5:
865
- b += key.charCodeAt(offset + 4);
866
- case 4:
867
- a += key.charCodeAt(offset + 3) << 24;
868
- case 3:
869
- a += key.charCodeAt(offset + 2) << 16;
870
- case 2:
871
- a += key.charCodeAt(offset + 1) << 8;
872
- case 1:
873
- a += key.charCodeAt(offset + 0);
965
+ const JEDEC = [
966
+ "B",
967
+ "KB",
968
+ "MB",
969
+ "GB",
970
+ "TB",
971
+ "PB",
972
+ "EB",
973
+ "ZB",
974
+ "YB"
975
+ ];
976
+ const formatFileSize = (input) => {
977
+ if (Number.isNaN(input))
978
+ return "";
979
+ let size = Number(input);
980
+ const isNegative = size < 0;
981
+ const result = [];
982
+ if (isNegative)
983
+ size = -size;
984
+ let exponent = Math.floor(Math.log(size) / Math.log(1024));
985
+ if (exponent < 0)
986
+ exponent = 0;
987
+ if (exponent > 8)
988
+ exponent = 8;
989
+ if (size === 0) {
990
+ result[0] = 0;
991
+ result[1] = JEDEC[exponent];
992
+ } else {
993
+ const val = size / 2 ** (exponent * 10);
994
+ result[0] = Number(val.toFixed(exponent > 0 ? 2 : 0));
995
+ if (result[0] === 1024 && exponent < 8) {
996
+ result[0] = 1;
997
+ exponent += 1;
874
998
  }
875
- c ^= b;
876
- c -= b << 14 | b >>> 18;
877
- a ^= c;
878
- a -= c << 11 | c >>> 21;
879
- b ^= a;
880
- b -= a << 25 | a >>> 7;
881
- c ^= b;
882
- c -= b << 16 | b >>> 16;
883
- a ^= c;
884
- a -= c << 4 | c >>> 28;
885
- b ^= a;
886
- b -= a << 14 | a >>> 18;
887
- c ^= b;
888
- c -= b << 24 | b >>> 8;
999
+ result[1] = JEDEC[exponent];
889
1000
  }
890
- return [c >>> 0, b >>> 0];
1001
+ if (isNegative)
1002
+ result[0] = -result[0];
1003
+ return result.join(" ");
891
1004
  };
892
- const getNameHash = (name) => {
893
- const normalized = name.replace(/\//g, "\\").toUpperCase();
894
- const [pc, pb] = hashlittle2(normalized);
895
- return `${pc.toString(16).padStart(8, "0")}${pb.toString(16).padStart(8, "0")}`;
1005
+ const resolveCDNHost = async (hosts, path) => {
1006
+ const latencies = await Promise.allSettled(
1007
+ hosts.map(async (host) => {
1008
+ const start = Date.now();
1009
+ await fetch(`http://${host}/`);
1010
+ const end = Date.now();
1011
+ return {
1012
+ host,
1013
+ latency: end - start
1014
+ };
1015
+ })
1016
+ );
1017
+ const resolved = latencies.filter((result) => result.status === "fulfilled").map((result) => result.value).sort((a, b) => a.latency - b.latency);
1018
+ return resolved.map((result) => `http://${result.host}/${path}`);
896
1019
  };
897
1020
 
898
- var __defProp$3 = Object.defineProperty;
899
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
900
- var __publicField$3 = (obj, key, value) => {
901
- __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
1021
+ var __defProp$2 = Object.defineProperty;
1022
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1023
+ var __publicField$2 = (obj, key, value) => {
1024
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
902
1025
  return value;
903
1026
  };
904
1027
  const WDC5_MAGIC = 1464091445;
@@ -921,17 +1044,17 @@ const readBitpackedValue = (buffer, fieldOffsetBits, fieldSizeBits, signed = fal
921
1044
  };
922
1045
  class WDCReader {
923
1046
  constructor(buffer, blocks = [], adb) {
924
- __publicField$3(this, "tableHash");
925
- __publicField$3(this, "layoutHash");
926
- __publicField$3(this, "locale");
927
- __publicField$3(this, "isNormal");
928
- __publicField$3(this, "hasRelationshipData");
929
- __publicField$3(this, "fields");
930
- __publicField$3(this, "fieldsInfo");
931
- __publicField$3(this, "rows", /* @__PURE__ */ new Map());
932
- __publicField$3(this, "relationships", /* @__PURE__ */ new Map());
933
- __publicField$3(this, "copyTable", /* @__PURE__ */ new Map());
934
- __publicField$3(this, "hotfixes", /* @__PURE__ */ new Map());
1047
+ __publicField$2(this, "tableHash");
1048
+ __publicField$2(this, "layoutHash");
1049
+ __publicField$2(this, "locale");
1050
+ __publicField$2(this, "isNormal");
1051
+ __publicField$2(this, "hasRelationshipData");
1052
+ __publicField$2(this, "fields");
1053
+ __publicField$2(this, "fieldsInfo");
1054
+ __publicField$2(this, "rows", /* @__PURE__ */ new Map());
1055
+ __publicField$2(this, "relationships", /* @__PURE__ */ new Map());
1056
+ __publicField$2(this, "copyTable", /* @__PURE__ */ new Map());
1057
+ __publicField$2(this, "hotfixes", /* @__PURE__ */ new Map());
935
1058
  const magic = buffer.readUInt32BE(0);
936
1059
  const fieldCount = buffer.readUInt32LE(140);
937
1060
  const recordSize = buffer.readUInt32LE(144);
@@ -1257,7 +1380,7 @@ class WDCReader {
1257
1380
  data: value
1258
1381
  };
1259
1382
  }
1260
- if (!recordID && fieldIndex === idIndex) {
1383
+ if (recordID === void 0 && fieldIndex === idIndex) {
1261
1384
  recordID = value;
1262
1385
  }
1263
1386
  const fieldOffset = fieldInfo.fieldOffsetBits >>> 3;
@@ -1269,7 +1392,7 @@ class WDCReader {
1269
1392
  };
1270
1393
  }
1271
1394
  case "commonData": {
1272
- const value = (recordID ? commonData.get(fieldIndex)?.get(recordID) : void 0) ?? fieldInfo.defaultValue;
1395
+ const value = (recordID !== void 0 ? commonData.get(fieldIndex)?.get(recordID) : void 0) ?? fieldInfo.defaultValue;
1273
1396
  return {
1274
1397
  type: "commonData",
1275
1398
  data: value
@@ -1304,7 +1427,7 @@ class WDCReader {
1304
1427
  assert__default(fieldPalletData, `No pallet data for field ${fieldIndex.toString()}`);
1305
1428
  value = fieldPalletData[value];
1306
1429
  }
1307
- if (!recordID && fieldIndex === idIndex) {
1430
+ if (recordID === void 0 && fieldIndex === idIndex) {
1308
1431
  recordID = value;
1309
1432
  }
1310
1433
  return {
@@ -1319,7 +1442,7 @@ class WDCReader {
1319
1442
  assert__default(recordID !== void 0, "No record ID found");
1320
1443
  this.rows.set(recordID, recordData);
1321
1444
  const foreignID = relationshipMap.get(recordIndex);
1322
- if (foreignID) {
1445
+ if (foreignID !== void 0) {
1323
1446
  this.relationships.set(recordID, foreignID);
1324
1447
  }
1325
1448
  } else {
@@ -1330,7 +1453,7 @@ class WDCReader {
1330
1453
  assert__default(recordID !== void 0, "No record ID found");
1331
1454
  this.rows.set(recordID, recordData);
1332
1455
  const foreignID = relationshipMap.get(recordIndex);
1333
- if (foreignID) {
1456
+ if (foreignID !== void 0) {
1334
1457
  this.relationships.set(recordID, foreignID);
1335
1458
  }
1336
1459
  }
@@ -1374,70 +1497,24 @@ class WDCReader {
1374
1497
  }
1375
1498
  }
1376
1499
  const dst = this.copyTable.get(id);
1377
- if (dst) {
1500
+ if (dst !== void 0) {
1378
1501
  return this.rows.get(dst);
1379
1502
  }
1380
1503
  return this.rows.get(id);
1381
1504
  }
1382
1505
  getRowRelationship(id) {
1383
1506
  const dst = this.copyTable.get(id);
1384
- if (dst) {
1507
+ if (dst !== void 0) {
1385
1508
  return this.relationships.get(dst);
1386
1509
  }
1387
1510
  return this.relationships.get(id);
1388
1511
  }
1389
1512
  }
1390
1513
 
1391
- const resolveCDNHost = async (hosts, path) => {
1392
- const latencies = await Promise.allSettled(
1393
- hosts.map(async (host) => {
1394
- const start = Date.now();
1395
- await fetch(`http://${host}/`);
1396
- const end = Date.now();
1397
- return {
1398
- host,
1399
- latency: end - start
1400
- };
1401
- })
1402
- );
1403
- const resolved = latencies.filter((result) => result.status === "fulfilled").map((result) => result.value).sort((a, b) => a.latency - b.latency);
1404
- return resolved.map((result) => `http://${result.host}/${path}`);
1405
- };
1406
- const JEDEC = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
1407
- const formatFileSize = (input) => {
1408
- if (Number.isNaN(input))
1409
- return "";
1410
- let size = Number(input);
1411
- const isNegative = size < 0;
1412
- const result = [];
1413
- if (isNegative)
1414
- size = -size;
1415
- let exponent = Math.floor(Math.log(size) / Math.log(1024));
1416
- if (exponent < 0)
1417
- exponent = 0;
1418
- if (exponent > 8)
1419
- exponent = 8;
1420
- if (size === 0) {
1421
- result[0] = 0;
1422
- result[1] = JEDEC[exponent];
1423
- } else {
1424
- const val = size / 2 ** (exponent * 10);
1425
- result[0] = Number(val.toFixed(exponent > 0 ? 2 : 0));
1426
- if (result[0] === 1024 && exponent < 8) {
1427
- result[0] = 1;
1428
- exponent += 1;
1429
- }
1430
- result[1] = JEDEC[exponent];
1431
- }
1432
- if (isNegative)
1433
- result[0] = -result[0];
1434
- return result.join(" ");
1435
- };
1436
-
1437
- var __defProp$2 = Object.defineProperty;
1438
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1439
- var __publicField$2 = (obj, key, value) => {
1440
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
1514
+ var __defProp$1 = Object.defineProperty;
1515
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1516
+ var __publicField$1 = (obj, key, value) => {
1517
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1441
1518
  return value;
1442
1519
  };
1443
1520
  var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
@@ -1447,16 +1524,21 @@ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1447
1524
  LogLevel2[LogLevel2["debug"] = 3] = "debug";
1448
1525
  return LogLevel2;
1449
1526
  })(LogLevel || {});
1450
- const textLogLevel = ["ERROR", "WARN", "INFO", "DEBUG"];
1527
+ const textLogLevel = [
1528
+ "ERROR",
1529
+ "WARN",
1530
+ "INFO",
1531
+ "DEBUG"
1532
+ ];
1451
1533
  class CASCClient {
1452
1534
  constructor(region, product, version, logLevel = 2 /* info */) {
1453
- __publicField$2(this, "region");
1454
- __publicField$2(this, "product");
1455
- __publicField$2(this, "version");
1456
- __publicField$2(this, "name2FileDataID", /* @__PURE__ */ new Map());
1457
- __publicField$2(this, "keys", /* @__PURE__ */ new Map());
1458
- __publicField$2(this, "preload");
1459
- __publicField$2(this, "logLevel");
1535
+ __publicField$1(this, "region");
1536
+ __publicField$1(this, "product");
1537
+ __publicField$1(this, "version");
1538
+ __publicField$1(this, "name2FileDataID", /* @__PURE__ */ new Map());
1539
+ __publicField$1(this, "keys", /* @__PURE__ */ new Map());
1540
+ __publicField$1(this, "preload");
1541
+ __publicField$1(this, "logLevel");
1460
1542
  this.region = region;
1461
1543
  this.product = product;
1462
1544
  this.version = version;
@@ -1472,7 +1554,7 @@ class CASCClient {
1472
1554
  if (level <= 0 /* error */) {
1473
1555
  console.error(`${( new Date()).toISOString()} [${textLogLevel[level]}]:`, message);
1474
1556
  } else {
1475
- console.log(`${( new Date()).toISOString()} [${textLogLevel[level]}]:`, message);
1557
+ console.info(`${( new Date()).toISOString()} [${textLogLevel[level]}]:`, message);
1476
1558
  }
1477
1559
  }
1478
1560
  }
@@ -1551,7 +1633,7 @@ class CASCClient {
1551
1633
  this.log(2 /* info */, "Loading root table...");
1552
1634
  const rootCKey = buildConfig.root;
1553
1635
  const rootEKeys = encoding.cKey2EKey.get(rootCKey);
1554
- assert__default(rootEKeys, "Failing to find EKey for root table.");
1636
+ assert__default(rootEKeys !== void 0, "Failing to find EKey for root table.");
1555
1637
  const rootEKey = typeof rootEKeys === "string" ? rootEKeys : rootEKeys[0];
1556
1638
  const rootBuffer = await getDataFile(prefixes, rootEKey, "build", this.version.BuildConfig, {
1557
1639
  name: "root",
@@ -1605,8 +1687,8 @@ class CASCClient {
1605
1687
  const lookupRow = lookupReader.rows.get(keyID);
1606
1688
  const keyRow = keysReader.rows.get(keyID);
1607
1689
  if (keyRow) {
1608
- assert__default(Array.isArray(lookupRow) && lookupRow[0], `Invalid TACTKeyLookup table row at id ${keyID.toString()}`);
1609
- assert__default(Array.isArray(keyRow) && keyRow[0], `Invalid TACTKey table row at id ${keyID.toString()}`);
1690
+ assert__default(Array.isArray(lookupRow) && lookupRow.length > 0, `Invalid TACTKeyLookup table row at id ${keyID.toString()}`);
1691
+ assert__default(Array.isArray(keyRow) && keyRow.length > 0, `Invalid TACTKey table row at id ${keyID.toString()}`);
1610
1692
  const keyName = lookupRow[0].data.toString(16).padStart(16, "0");
1611
1693
  const keyHexLE = keyRow[0].data.toString(16).padStart(32, "0");
1612
1694
  assert__default(keyName.length === 16, `Invalid keyName length: ${keyName.length.toString()}`);
@@ -1658,7 +1740,7 @@ class CASCClient {
1658
1740
  assert__default(this.preload, "Client not initialized");
1659
1741
  const { prefixes, encoding, archives } = this.preload;
1660
1742
  const eKeys = encoding.cKey2EKey.get(cKey);
1661
- assert__default(eKeys, `Failing to find encoding key for ${cKey}`);
1743
+ assert__default(eKeys !== void 0, `Failing to find encoding key for ${cKey}`);
1662
1744
  const eKey = typeof eKeys === "string" ? eKeys : eKeys[0];
1663
1745
  const archive = archives.get(eKey);
1664
1746
  const blte = archive ? await getDataFile(prefixes, archive.key, "data", this.version.BuildConfig, {
@@ -1674,9 +1756,12 @@ class CASCClient {
1674
1756
  const reader = new BLTEReader(blte, eKey, this.keys);
1675
1757
  if (!allowMissingKey) {
1676
1758
  reader.processBytes(allowMissingKey);
1759
+ const hash = crypto__default.createHash("md5").update(reader.buffer).digest("hex");
1760
+ assert__default(hash === cKey, `Invalid hash: expected ${cKey}, got ${hash}`);
1677
1761
  return {
1678
1762
  type: "full",
1679
- buffer: reader.buffer
1763
+ buffer: reader.buffer,
1764
+ blocks: void 0
1680
1765
  };
1681
1766
  }
1682
1767
  const blocks = reader.processBytes(allowMissingKey);
@@ -1685,7 +1770,8 @@ class CASCClient {
1685
1770
  assert__default(hash === cKey, `Invalid hash: expected ${cKey}, got ${hash}`);
1686
1771
  return {
1687
1772
  type: "full",
1688
- buffer: reader.buffer
1773
+ buffer: reader.buffer,
1774
+ blocks: void 0
1689
1775
  };
1690
1776
  }
1691
1777
  return {
@@ -1695,14 +1781,17 @@ class CASCClient {
1695
1781
  };
1696
1782
  }
1697
1783
  }
1698
- __publicField$2(CASCClient, "LocaleFlags", LocaleFlags);
1699
- __publicField$2(CASCClient, "ContentFlags", ContentFlags);
1700
- __publicField$2(CASCClient, "LogLevel", LogLevel);
1784
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1785
+ __publicField$1(CASCClient, "LocaleFlags", LocaleFlags);
1786
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1787
+ __publicField$1(CASCClient, "ContentFlags", ContentFlags);
1788
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1789
+ __publicField$1(CASCClient, "LogLevel", LogLevel);
1701
1790
 
1702
- var __defProp$1 = Object.defineProperty;
1703
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1704
- var __publicField$1 = (obj, key, value) => {
1705
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1791
+ var __defProp = Object.defineProperty;
1792
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1793
+ var __publicField = (obj, key, value) => {
1794
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1706
1795
  return value;
1707
1796
  };
1708
1797
  const PATTERN_COLUMN = /^(int|float|locstring|string)(<[^:]+::[^>]+>)?\s([^\s]+)/;
@@ -1747,10 +1836,10 @@ const getCastBuffer = (value, srcSize, dstSize) => {
1747
1836
  };
1748
1837
  class DBDParser {
1749
1838
  constructor(wdc) {
1750
- __publicField$1(this, "wdc");
1751
- __publicField$1(this, "definitions", /* @__PURE__ */ new Map());
1752
- __publicField$1(this, "columns", []);
1753
- __publicField$1(this, "cache", /* @__PURE__ */ new Map());
1839
+ __publicField(this, "wdc");
1840
+ __publicField(this, "definitions", /* @__PURE__ */ new Map());
1841
+ __publicField(this, "columns", []);
1842
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
1754
1843
  this.wdc = wdc;
1755
1844
  }
1756
1845
  async init() {
@@ -1758,7 +1847,7 @@ class DBDParser {
1758
1847
  const manifests = await (await fetch(manifestsURL)).json();
1759
1848
  const tableHashHex = this.wdc.tableHash.toString(16).padStart(8, "0").toLowerCase();
1760
1849
  const manifest = manifests.find((v) => v.tableHash.toLowerCase() === tableHashHex);
1761
- assert__default(manifest?.tableName, `No manifest found for table hash ${tableHashHex}`);
1850
+ assert__default(manifest?.tableName !== void 0, `No manifest found for table hash ${tableHashHex}`);
1762
1851
  const url = `https://raw.githubusercontent.com/wowdev/WoWDBDefs/master/definitions/${manifest.tableName}.dbd`;
1763
1852
  const text = await (await fetch(url)).text();
1764
1853
  const lines = text.split("\n").map((v) => v.trim());
@@ -1774,7 +1863,7 @@ class DBDParser {
1774
1863
  assert__default(columnsChunk?.[0] === "COLUMNS", "No column definitions found");
1775
1864
  columnsChunk.shift();
1776
1865
  columnsChunk.forEach((line) => {
1777
- const match = line.match(PATTERN_COLUMN);
1866
+ const match = PATTERN_COLUMN.exec(line);
1778
1867
  if (match) {
1779
1868
  const [, type, , name] = match;
1780
1869
  this.definitions.set(name.replace("?", ""), type);
@@ -1782,7 +1871,7 @@ class DBDParser {
1782
1871
  });
1783
1872
  const layoutHashHex = this.wdc.layoutHash.toString(16).padStart(8, "0").toLowerCase();
1784
1873
  const versionChunk = chunks.find((chunk) => chunk.find((line) => {
1785
- const layoutsMatch = line.match(PATTERN_LAYOUT);
1874
+ const layoutsMatch = PATTERN_LAYOUT.exec(line);
1786
1875
  const layouts = layoutsMatch?.[1].split(",").map((v) => v.trim().toLowerCase());
1787
1876
  return layouts?.includes(layoutHashHex);
1788
1877
  }));
@@ -1791,17 +1880,27 @@ class DBDParser {
1791
1880
  if (line.startsWith("LAYOUT") || line.startsWith("BUILD") || line.startsWith("COMMENT")) {
1792
1881
  return;
1793
1882
  }
1794
- const match = line.match(PATTERN_FIELD);
1883
+ const match = PATTERN_FIELD.exec(line);
1795
1884
  if (match) {
1796
- const [, , annotationsText, name, , unsigned, sizeText, , arraySizeText] = match;
1885
+ const [
1886
+ ,
1887
+ ,
1888
+ annotationsText,
1889
+ name,
1890
+ ,
1891
+ unsigned,
1892
+ sizeText,
1893
+ ,
1894
+ arraySizeText
1895
+ ] = match;
1797
1896
  const type = this.definitions.get(name);
1798
- assert__default(type, `No type found for column ${name}`);
1799
- const annotations = annotationsText ? annotationsText.split(",").map((v) => v.trim()) : void 0;
1897
+ assert__default(type !== void 0, `No type found for column ${name}`);
1898
+ const annotations = annotationsText ? annotationsText.split(",").map((v) => v.trim()) : [];
1800
1899
  const size = sizeText ? parseInt(sizeText, 10) : void 0;
1801
1900
  const arraySize = arraySizeText ? parseInt(arraySizeText, 10) : void 0;
1802
- const isID = !!annotations?.includes("id");
1803
- const isInline = !annotations?.includes("noninline");
1804
- const isRelation = !!annotations?.includes("relation");
1901
+ const isID = !!annotations.includes("id");
1902
+ const isInline = !annotations.includes("noninline");
1903
+ const isRelation = !!annotations.includes("relation");
1805
1904
  const isSigned = !unsigned;
1806
1905
  this.columns.push({
1807
1906
  name,
@@ -1842,18 +1941,18 @@ class DBDParser {
1842
1941
  fieldIndex += 1;
1843
1942
  }
1844
1943
  } else if (column.isInline) {
1944
+ assert__default(row.length > fieldIndex, `No value found for column ${column.name}`);
1845
1945
  const cell = row[fieldIndex];
1846
- assert__default(cell, `No value found for column ${column.name}`);
1847
1946
  const fieldInfo = this.wdc.fieldsInfo[fieldIndex];
1848
1947
  const srcSigned = fieldInfo.storageType === "bitpackedSigned";
1849
1948
  const srcSize = fieldInfo.storageType === "none" || fieldInfo.storageType === "bitpacked" || fieldInfo.storageType === "bitpackedSigned" ? Math.ceil(fieldInfo.fieldSizeBits / 8) : 4;
1850
- const dstSize = column.size ? Math.ceil(column.size / 8) : void 0;
1949
+ const dstSize = column.size !== void 0 ? Math.ceil(column.size / 8) : void 0;
1851
1950
  if (cell.type === "bitpackedArray") {
1852
1951
  data[column.name] = cell.data.map((v) => {
1853
1952
  if (column.type === "float") {
1854
1953
  return castFloat(v, srcSize, srcSigned);
1855
1954
  }
1856
- if (dstSize) {
1955
+ if (dstSize !== void 0) {
1857
1956
  return castIntegerBySize(
1858
1957
  v,
1859
1958
  srcSize,
@@ -1871,7 +1970,7 @@ class DBDParser {
1871
1970
  data[column.name] = cell.string;
1872
1971
  }
1873
1972
  } else if (column.type === "float") {
1874
- if (column.arraySize) {
1973
+ if (column.arraySize !== void 0) {
1875
1974
  const castBuffer = getCastBuffer(
1876
1975
  typeof cell.data === "number" ? BigInt(cell.data) : cell.data,
1877
1976
  srcSize,
@@ -1888,8 +1987,8 @@ class DBDParser {
1888
1987
  data[column.name] = castFloat(cell.data, srcSize, srcSigned);
1889
1988
  }
1890
1989
  } else if (column.type === "int") {
1891
- if (column.arraySize) {
1892
- assert__default(dstSize, `Missing size for int array column ${column.name}`);
1990
+ if (column.arraySize !== void 0) {
1991
+ assert__default(dstSize !== void 0, `Missing size for int array column ${column.name}`);
1893
1992
  const castBuffer = getCastBuffer(
1894
1993
  typeof cell.data === "number" ? BigInt(cell.data) : cell.data,
1895
1994
  srcSize,
@@ -1917,7 +2016,7 @@ class DBDParser {
1917
2016
  column.isSigned
1918
2017
  );
1919
2018
  } else {
1920
- assert__default(!column.size || column.size === 64, `Unexpected size ${column.size?.toString() ?? ""} for column ${column.name}`);
2019
+ assert__default(column.size === void 0 || column.size === 64, `Unexpected size ${column.size?.toString() ?? ""} for column ${column.name}`);
1921
2020
  if (srcSigned !== column.isSigned) {
1922
2021
  data[column.name] = castBigInt64(
1923
2022
  cell.data,
@@ -1971,7 +2070,7 @@ class DBDParser {
1971
2070
  if (fieldIndex + 1 < this.wdc.fields.length) {
1972
2071
  count = Math.max((nextField.position - currField.position) / size, 1);
1973
2072
  } else {
1974
- count = column.arraySize ? (buffer.byteLength - offset) / size : 1;
2073
+ count = column.arraySize !== void 0 ? (buffer.byteLength - offset) / size : 1;
1975
2074
  }
1976
2075
  for (let i = 0; i < count; i += 1) {
1977
2076
  if (column.type === "float") {
@@ -2003,57 +2102,6 @@ class DBDParser {
2003
2102
  }
2004
2103
  }
2005
2104
 
2006
- var __defProp = Object.defineProperty;
2007
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2008
- var __publicField = (obj, key, value) => {
2009
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
2010
- return value;
2011
- };
2012
- const ADB_MAGIC = 1481004104;
2013
- class ADBReader {
2014
- constructor(buffer) {
2015
- __publicField(this, "build");
2016
- __publicField(this, "entries", []);
2017
- __publicField(this, "tableEntries", /* @__PURE__ */ new Map());
2018
- const magic = buffer.readUInt32BE(0);
2019
- assert__default(magic === ADB_MAGIC, `[ADB]: Invalid magic: ${magic.toString(16).padStart(8, "0")}`);
2020
- const version = buffer.readUInt32LE(4);
2021
- assert__default(version === 9, `[ADB]: Invalid version: ${version.toString()}`);
2022
- const build = buffer.readUInt32LE(8);
2023
- this.build = build;
2024
- let pointer = 44;
2025
- while (pointer < buffer.byteLength) {
2026
- const offset = pointer;
2027
- const entryMagic = buffer.readUInt32BE(offset);
2028
- assert__default(entryMagic === ADB_MAGIC, `[ADB]: Invalid entry magic: ${magic.toString(16).padStart(8, "0")}`);
2029
- const regionID = buffer.readInt32LE(offset + 4);
2030
- const pushID = buffer.readInt32LE(offset + 8);
2031
- const uniqueID = buffer.readUInt32LE(offset + 12);
2032
- const tableHash = buffer.readUInt32LE(offset + 16);
2033
- const recordID = buffer.readUInt32LE(offset + 20);
2034
- const dataSize = buffer.readUInt32LE(offset + 24);
2035
- const recordState = buffer.readUInt32LE(offset + 28);
2036
- const data = buffer.subarray(offset + 32, offset + 32 + dataSize);
2037
- const entry = {
2038
- regionID,
2039
- pushID,
2040
- uniqueID,
2041
- tableHash,
2042
- recordID,
2043
- dataSize,
2044
- recordState,
2045
- data
2046
- };
2047
- this.entries.push(entry);
2048
- if (!this.tableEntries.has(tableHash)) {
2049
- this.tableEntries.set(tableHash, []);
2050
- }
2051
- this.tableEntries.get(tableHash)?.push(entry);
2052
- pointer += 32 + dataSize;
2053
- }
2054
- }
2055
- }
2056
-
2057
2105
  exports.ADBReader = ADBReader;
2058
2106
  exports.CASCClient = CASCClient;
2059
2107
  exports.DBDParser = DBDParser;