@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/README.md +1 -1
- package/dist/index.cjs +777 -729
- package/dist/index.d.cts +66 -67
- package/dist/index.d.mts +66 -67
- package/dist/index.d.ts +66 -67
- package/dist/index.mjs +804 -756
- package/package.json +12 -18
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
|
|
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
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
__publicField$6(this, "
|
|
32
|
-
__publicField$6(this, "
|
|
33
|
-
this
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
184
|
+
result[i] = input[i] ^ this.block[this.position];
|
|
185
|
+
this.position += 1;
|
|
138
186
|
}
|
|
187
|
+
return result;
|
|
139
188
|
}
|
|
140
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
-
|
|
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
|
|
421
|
-
const
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1001
|
+
if (isNegative)
|
|
1002
|
+
result[0] = -result[0];
|
|
1003
|
+
return result.join(" ");
|
|
891
1004
|
};
|
|
892
|
-
const
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
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$
|
|
899
|
-
var __defNormalProp$
|
|
900
|
-
var __publicField$
|
|
901
|
-
__defNormalProp$
|
|
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$
|
|
925
|
-
__publicField$
|
|
926
|
-
__publicField$
|
|
927
|
-
__publicField$
|
|
928
|
-
__publicField$
|
|
929
|
-
__publicField$
|
|
930
|
-
__publicField$
|
|
931
|
-
__publicField$
|
|
932
|
-
__publicField$
|
|
933
|
-
__publicField$
|
|
934
|
-
__publicField$
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
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 = [
|
|
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$
|
|
1454
|
-
__publicField$
|
|
1455
|
-
__publicField$
|
|
1456
|
-
__publicField$
|
|
1457
|
-
__publicField$
|
|
1458
|
-
__publicField$
|
|
1459
|
-
__publicField$
|
|
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.
|
|
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
|
|
1609
|
-
assert__default(Array.isArray(keyRow) && keyRow
|
|
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
|
-
|
|
1699
|
-
__publicField$
|
|
1700
|
-
|
|
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
|
|
1703
|
-
var __defNormalProp
|
|
1704
|
-
var __publicField
|
|
1705
|
-
__defNormalProp
|
|
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
|
|
1751
|
-
__publicField
|
|
1752
|
-
__publicField
|
|
1753
|
-
__publicField
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1883
|
+
const match = PATTERN_FIELD.exec(line);
|
|
1795
1884
|
if (match) {
|
|
1796
|
-
const [
|
|
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()) :
|
|
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
|
|
1803
|
-
const isInline = !annotations
|
|
1804
|
-
const isRelation = !!annotations
|
|
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(
|
|
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;
|