@rhyster/wow-casc-dbc 2.7.6 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -36,6 +36,22 @@ interface EncodingData {
36
36
  eKey2FileSize: Map<string, number>;
37
37
  }
38
38
 
39
+ interface InstallTag {
40
+ name: string;
41
+ type: number;
42
+ files: boolean[];
43
+ }
44
+ interface InstallFile {
45
+ name: string;
46
+ hash: string;
47
+ size: number;
48
+ tags: InstallTag[];
49
+ }
50
+ interface InstallData {
51
+ tags: InstallTag[];
52
+ files: InstallFile[];
53
+ }
54
+
39
55
  interface Version {
40
56
  Region: string;
41
57
  BuildConfig: string;
@@ -61,6 +77,7 @@ interface ClientPreloadData {
61
77
  archives: Map<string, ArchiveIndex>;
62
78
  encoding: EncodingData;
63
79
  rootFile: RootData;
80
+ install: InstallData;
64
81
  }
65
82
  interface FileFetchResultFull {
66
83
  type: 'full';
@@ -129,6 +146,7 @@ declare class CASCClient {
129
146
  loadBroadcastTACTKeys(adb: ADBReader): void;
130
147
  getFileDataIDByName(name: string): number | undefined;
131
148
  getContentKeysByFileDataID(fileDataID: number): FileInfo[] | undefined;
149
+ getContentKeysFromInstall(name: string): InstallFile[] | undefined;
132
150
  getFileByContentKey(cKey: string, allowMissingKey?: false): Promise<FileFetchResultFull>;
133
151
  getFileByContentKey(cKey: string, allowMissingKey: true): Promise<FileFetchResult>;
134
152
  }
@@ -258,4 +276,4 @@ declare class DBDParser {
258
276
  getRowData(id: number): Record<string, ColumnData> | undefined;
259
277
  }
260
278
 
261
- export { ADBReader, type ArchiveIndex, type BasicColumnData, CASCClient, type ClientPreloadData, type Column, type ColumnData, DBDParser, type EncodingData, type FieldStorageInfo, type FieldStorageInfoCompressionBitpacked, type FieldStorageInfoCompressionBitpackedIndexed, type FieldStorageInfoCompressionBitpackedIndexedArray, type FieldStorageInfoCompressionBitpackedSigned, type FieldStorageInfoCompressionCommonData, type FieldStorageInfoCompressionNone, type FieldStructure, type FileFetchResult, type FileFetchResultFull, type FileFetchResultPartial, type FileInfo, type Hotfix, type HotfixDelete, type HotfixEntry, type HotfixModify, type MissingKeyBlock, type ParsedField, type ParsedFieldBitpacked, type ParsedFieldBitpackedArray, type ParsedFieldCommonData, type ParsedFieldNone, type RootData, type SparseRow, type Version, WDCReader };
279
+ export { ADBReader, type ArchiveIndex, type BasicColumnData, CASCClient, type ClientPreloadData, type Column, type ColumnData, DBDParser, type EncodingData, type FieldStorageInfo, type FieldStorageInfoCompressionBitpacked, type FieldStorageInfoCompressionBitpackedIndexed, type FieldStorageInfoCompressionBitpackedIndexedArray, type FieldStorageInfoCompressionBitpackedSigned, type FieldStorageInfoCompressionCommonData, type FieldStorageInfoCompressionNone, type FieldStructure, type FileFetchResult, type FileFetchResultFull, type FileFetchResultPartial, type FileInfo, type Hotfix, type HotfixDelete, type HotfixEntry, type HotfixModify, type InstallData, type InstallFile, type MissingKeyBlock, type ParsedField, type ParsedFieldBitpacked, type ParsedFieldBitpackedArray, type ParsedFieldCommonData, type ParsedFieldNone, type RootData, type SparseRow, type Version, WDCReader };
package/dist/index.d.mts CHANGED
@@ -36,6 +36,22 @@ interface EncodingData {
36
36
  eKey2FileSize: Map<string, number>;
37
37
  }
38
38
 
39
+ interface InstallTag {
40
+ name: string;
41
+ type: number;
42
+ files: boolean[];
43
+ }
44
+ interface InstallFile {
45
+ name: string;
46
+ hash: string;
47
+ size: number;
48
+ tags: InstallTag[];
49
+ }
50
+ interface InstallData {
51
+ tags: InstallTag[];
52
+ files: InstallFile[];
53
+ }
54
+
39
55
  interface Version {
40
56
  Region: string;
41
57
  BuildConfig: string;
@@ -61,6 +77,7 @@ interface ClientPreloadData {
61
77
  archives: Map<string, ArchiveIndex>;
62
78
  encoding: EncodingData;
63
79
  rootFile: RootData;
80
+ install: InstallData;
64
81
  }
65
82
  interface FileFetchResultFull {
66
83
  type: 'full';
@@ -129,6 +146,7 @@ declare class CASCClient {
129
146
  loadBroadcastTACTKeys(adb: ADBReader): void;
130
147
  getFileDataIDByName(name: string): number | undefined;
131
148
  getContentKeysByFileDataID(fileDataID: number): FileInfo[] | undefined;
149
+ getContentKeysFromInstall(name: string): InstallFile[] | undefined;
132
150
  getFileByContentKey(cKey: string, allowMissingKey?: false): Promise<FileFetchResultFull>;
133
151
  getFileByContentKey(cKey: string, allowMissingKey: true): Promise<FileFetchResult>;
134
152
  }
@@ -258,4 +276,4 @@ declare class DBDParser {
258
276
  getRowData(id: number): Record<string, ColumnData> | undefined;
259
277
  }
260
278
 
261
- export { ADBReader, type ArchiveIndex, type BasicColumnData, CASCClient, type ClientPreloadData, type Column, type ColumnData, DBDParser, type EncodingData, type FieldStorageInfo, type FieldStorageInfoCompressionBitpacked, type FieldStorageInfoCompressionBitpackedIndexed, type FieldStorageInfoCompressionBitpackedIndexedArray, type FieldStorageInfoCompressionBitpackedSigned, type FieldStorageInfoCompressionCommonData, type FieldStorageInfoCompressionNone, type FieldStructure, type FileFetchResult, type FileFetchResultFull, type FileFetchResultPartial, type FileInfo, type Hotfix, type HotfixDelete, type HotfixEntry, type HotfixModify, type MissingKeyBlock, type ParsedField, type ParsedFieldBitpacked, type ParsedFieldBitpackedArray, type ParsedFieldCommonData, type ParsedFieldNone, type RootData, type SparseRow, type Version, WDCReader };
279
+ export { ADBReader, type ArchiveIndex, type BasicColumnData, CASCClient, type ClientPreloadData, type Column, type ColumnData, DBDParser, type EncodingData, type FieldStorageInfo, type FieldStorageInfoCompressionBitpacked, type FieldStorageInfoCompressionBitpackedIndexed, type FieldStorageInfoCompressionBitpackedIndexedArray, type FieldStorageInfoCompressionBitpackedSigned, type FieldStorageInfoCompressionCommonData, type FieldStorageInfoCompressionNone, type FieldStructure, type FileFetchResult, type FileFetchResultFull, type FileFetchResultPartial, type FileInfo, type Hotfix, type HotfixDelete, type HotfixEntry, type HotfixModify, type InstallData, type InstallFile, type MissingKeyBlock, type ParsedField, type ParsedFieldBitpacked, type ParsedFieldBitpackedArray, type ParsedFieldCommonData, type ParsedFieldNone, type RootData, type SparseRow, type Version, WDCReader };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { default as CASCClient } from './client.ts';
3
3
  export { default as DBDParser } from './dbd.ts';
4
4
  export { default as WDCReader } from './wdc.ts';
5
5
  export type { HotfixEntry } from './adb.ts';
6
- export type { Version, ClientPreloadData, ArchiveIndex, EncodingData, RootData, FileInfo, FileFetchResultFull, FileFetchResultPartial, FileFetchResult, MissingKeyBlock, } from './client.ts';
6
+ export type { Version, ClientPreloadData, ArchiveIndex, EncodingData, InstallFile, InstallData, RootData, FileInfo, FileFetchResultFull, FileFetchResultPartial, FileFetchResult, MissingKeyBlock, } from './client.ts';
7
7
  export type { Column, ColumnData, BasicColumnData, } from './dbd.ts';
8
8
  export type { FieldStructure, FieldStorageInfo, FieldStorageInfoCompressionNone, FieldStorageInfoCompressionBitpacked, FieldStorageInfoCompressionCommonData, FieldStorageInfoCompressionBitpackedIndexed, FieldStorageInfoCompressionBitpackedIndexedArray, FieldStorageInfoCompressionBitpackedSigned, ParsedField, ParsedFieldNone, ParsedFieldCommonData, ParsedFieldBitpacked, ParsedFieldBitpackedArray, SparseRow, Hotfix, HotfixModify, HotfixDelete, } from './wdc.ts';
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AAEhD,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EACR,OAAO,EACP,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,eAAe,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACR,MAAM,EACN,UAAU,EACV,eAAe,GAClB,MAAM,UAAU,CAAC;AAClB,YAAY,EACR,cAAc,EACd,gBAAgB,EAChB,+BAA+B,EAC/B,oCAAoC,EACpC,qCAAqC,EACrC,2CAA2C,EAC3C,gDAAgD,EAChD,0CAA0C,EAC1C,WAAW,EACX,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,SAAS,EACT,MAAM,EACN,YAAY,EACZ,YAAY,GACf,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AAEhD,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EACR,OAAO,EACP,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,eAAe,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACR,MAAM,EACN,UAAU,EACV,eAAe,GAClB,MAAM,UAAU,CAAC;AAClB,YAAY,EACR,cAAc,EACd,gBAAgB,EAChB,+BAA+B,EAC/B,oCAAoC,EACpC,qCAAqC,EACrC,2CAA2C,EAC3C,gDAAgD,EAChD,0CAA0C,EAC1C,WAAW,EACX,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,SAAS,EACT,MAAM,EACN,YAAY,EACZ,YAAY,GACf,MAAM,UAAU,CAAC"}
package/dist/index.mjs CHANGED
@@ -680,8 +680,8 @@ const parseCDNConfig = (text) => parseConfig(text);
680
680
  const parseBuildConfig = (text) => parseConfig(text);
681
681
 
682
682
  const ENC_MAGIC = 17742;
683
- const MAGIC_OFFSET = 0;
684
- const VERSION_OFFSET = 2;
683
+ const MAGIC_OFFSET$1 = 0;
684
+ const VERSION_OFFSET$1 = 2;
685
685
  const HASH_SIZE_CKEY_OFFSET = 3;
686
686
  const HASH_SIZE_EKEY_OFFSET = 4;
687
687
  const CKEY_PAGE_SIZE_OFFSET = 5;
@@ -696,9 +696,9 @@ const parseEncodingFile = (inputBuffer, eKey, cKey) => {
696
696
  const { buffer } = reader;
697
697
  const encodingHash = crypto.createHash("md5").update(buffer).digest("hex");
698
698
  assert(encodingHash === cKey, `Invalid encoding hash: expected ${cKey}, got ${encodingHash}`);
699
- const magic = buffer.readUInt16BE(MAGIC_OFFSET);
699
+ const magic = buffer.readUInt16BE(MAGIC_OFFSET$1);
700
700
  assert(magic === ENC_MAGIC, `Invalid encoding magic: ${magic.toString(16).padStart(4, "0")}`);
701
- const version = buffer.readUInt8(VERSION_OFFSET);
701
+ const version = buffer.readUInt8(VERSION_OFFSET$1);
702
702
  const hashSizeCKey = buffer.readUInt8(HASH_SIZE_CKEY_OFFSET);
703
703
  const hashSizeEKey = buffer.readUInt8(HASH_SIZE_EKEY_OFFSET);
704
704
  const cKeyPageSizeKB = buffer.readUInt16BE(CKEY_PAGE_SIZE_OFFSET);
@@ -796,6 +796,71 @@ const parseEncodingFile = (inputBuffer, eKey, cKey) => {
796
796
  };
797
797
  };
798
798
 
799
+ const INSTALL_MAGIC = 18766;
800
+ const MAGIC_OFFSET = 0;
801
+ const VERSION_OFFSET = 2;
802
+ const HASH_SIZE_OFFSET = 3;
803
+ const NUM_TAGS_OFFSET = 4;
804
+ const NUM_ENTRIES_OFFSET = 6;
805
+ const TAGS_OFFSET = 10;
806
+ const parseInstallFile = (inputBuffer, eKey, cKey) => {
807
+ const reader = new BLTEReader(inputBuffer, eKey);
808
+ reader.processBytes();
809
+ const { buffer } = reader;
810
+ const installHash = crypto.createHash("md5").update(buffer).digest("hex");
811
+ assert(installHash === cKey, `Invalid root hash: expected ${cKey}, got ${installHash}`);
812
+ const magic = buffer.readUInt16BE(MAGIC_OFFSET);
813
+ assert(magic === INSTALL_MAGIC, `Invalid install magic: ${magic.toString(16).padStart(4, "0")}`);
814
+ const version = buffer.readUInt8(VERSION_OFFSET);
815
+ const hashSize = buffer.readUInt8(HASH_SIZE_OFFSET);
816
+ const numTags = buffer.readUInt16BE(NUM_TAGS_OFFSET);
817
+ const numEntries = buffer.readUInt32BE(NUM_ENTRIES_OFFSET);
818
+ assert(version === 1, `Invalid install version: ${version.toString()}`);
819
+ let pointer = TAGS_OFFSET;
820
+ const tags = [];
821
+ for (let i = 0; i < numTags; i += 1) {
822
+ const startOffset = pointer;
823
+ while (buffer[pointer] !== 0) {
824
+ pointer += 1;
825
+ }
826
+ const name = buffer.toString("utf-8", startOffset, pointer);
827
+ pointer += 1;
828
+ const type = buffer.readUInt16BE(pointer);
829
+ pointer += 2;
830
+ const files2 = [];
831
+ const finalOffset = pointer + Math.ceil(numEntries / 8);
832
+ while (pointer < finalOffset) {
833
+ const byte = buffer.readUInt8(pointer);
834
+ pointer += 1;
835
+ for (let j = 7; j >= 0; j -= 1) {
836
+ files2.push((byte & 1 << j) > 0);
837
+ }
838
+ }
839
+ tags.push({ name, type, files: files2 });
840
+ }
841
+ const files = [];
842
+ for (let i = 0; i < numEntries; i += 1) {
843
+ const startOffset = pointer;
844
+ while (buffer[pointer] !== 0) {
845
+ pointer += 1;
846
+ }
847
+ const name = buffer.toString("utf-8", startOffset, pointer);
848
+ pointer += 1;
849
+ const hash = buffer.toString("hex", pointer, pointer + hashSize);
850
+ pointer += hashSize;
851
+ const size = buffer.readUInt32BE(pointer);
852
+ pointer += 4;
853
+ const fileTags = tags.filter((tag) => tag.files[i]);
854
+ files.push({
855
+ name,
856
+ hash,
857
+ size,
858
+ tags: fileTags
859
+ });
860
+ }
861
+ return { tags, files };
862
+ };
863
+
799
864
  const parseProductConfig = (text) => {
800
865
  const lines = text.split(/\r?\n/);
801
866
  const headers = lines[0].split("|").map((header) => header.split("!")[0].replace(" ", ""));
@@ -1594,11 +1659,19 @@ class CASCClient {
1594
1659
  this.log(2 /* info */, "Parsing encoding table...");
1595
1660
  const encoding = parseEncodingFile(encodingBuffer, encodingEKey, encodingCKey);
1596
1661
  this.log(2 /* info */, `Parsed encoding table (${encoding.cKey2EKey.size.toString()} entries)`);
1662
+ const getBuildConfigKeys = (configText) => {
1663
+ if (configText.includes(" ")) {
1664
+ const [cKey2, eKey2] = configText.split(" ");
1665
+ return [cKey2, eKey2];
1666
+ }
1667
+ const cKey = configText;
1668
+ const eKeys = encoding.cKey2EKey.get(cKey);
1669
+ assert(eKeys !== void 0, `Failing to find encoding key for ${cKey}`);
1670
+ const eKey = typeof eKeys === "string" ? eKeys : eKeys[0];
1671
+ return [cKey, eKey];
1672
+ };
1597
1673
  this.log(2 /* info */, "Loading root table...");
1598
- const rootCKey = buildConfig.root;
1599
- const rootEKeys = encoding.cKey2EKey.get(rootCKey);
1600
- assert(rootEKeys !== void 0, "Failing to find EKey for root table.");
1601
- const rootEKey = typeof rootEKeys === "string" ? rootEKeys : rootEKeys[0];
1674
+ const [rootCKey, rootEKey] = getBuildConfigKeys(buildConfig.root);
1602
1675
  const rootBuffer = await getDataFile(prefixes, rootEKey, "build", this.version.BuildConfig, {
1603
1676
  name: "root",
1604
1677
  showProgress: this.logLevel >= 2 /* info */,
@@ -1608,11 +1681,23 @@ class CASCClient {
1608
1681
  this.log(2 /* info */, "Parsing root file...");
1609
1682
  const rootFile = parseRootFile(rootBuffer, rootEKey, rootCKey);
1610
1683
  this.log(2 /* info */, `Parsed root file (${rootFile.fileDataID2CKey.size.toString()} entries, ${rootFile.nameHash2FileDataID.size.toString()} hashes)`);
1684
+ this.log(2 /* info */, "Loading install manifest...");
1685
+ const [installCKey, installEKey] = getBuildConfigKeys(buildConfig.install);
1686
+ const installBuffer = await getDataFile(prefixes, installEKey, "build", this.version.BuildConfig, {
1687
+ name: "install",
1688
+ showProgress: this.logLevel >= 2 /* info */,
1689
+ showAttemptFail: this.logLevel >= 1 /* warn */
1690
+ });
1691
+ this.log(2 /* info */, `Loaded install manifest (${formatFileSize(installBuffer.byteLength)})`);
1692
+ this.log(2 /* info */, "Parsing install manifest...");
1693
+ const install = parseInstallFile(installBuffer, installEKey, installCKey);
1694
+ this.log(2 /* info */, `Parsed install manifest (${install.tags.length.toString()} tags, ${install.files.length.toString()} files)`);
1611
1695
  this.preload = {
1612
1696
  prefixes,
1613
1697
  archives,
1614
1698
  encoding,
1615
- rootFile
1699
+ rootFile,
1700
+ install
1616
1701
  };
1617
1702
  }
1618
1703
  async loadRemoteListFile() {
@@ -1700,6 +1785,11 @@ class CASCClient {
1700
1785
  const { rootFile } = this.preload;
1701
1786
  return rootFile.fileDataID2CKey.get(fileDataID);
1702
1787
  }
1788
+ getContentKeysFromInstall(name) {
1789
+ assert(this.preload, "Client not initialized");
1790
+ const { install } = this.preload;
1791
+ return install.files.filter((file) => file.name === name);
1792
+ }
1703
1793
  async getFileByContentKey(cKey, allowMissingKey = false) {
1704
1794
  assert(this.preload, "Client not initialized");
1705
1795
  const { prefixes, encoding, archives } = this.preload;
@@ -1825,8 +1915,8 @@ class DBDParser {
1825
1915
  const versionChunk = chunks.find((chunk) => chunk.find((line) => {
1826
1916
  const layoutsMatch = PATTERN_LAYOUT.exec(line);
1827
1917
  const layouts = layoutsMatch?.[1].split(",").map((v) => v.trim().toLowerCase());
1828
- return layouts?.includes(layoutHashHex);
1829
- }));
1918
+ return layouts?.includes(layoutHashHex) === true;
1919
+ }) !== void 0);
1830
1920
  assert(versionChunk, `No version definition found for layout hash ${layoutHashHex}`);
1831
1921
  versionChunk.forEach((line) => {
1832
1922
  if (line.startsWith("LAYOUT") || line.startsWith("BUILD") || line.startsWith("COMMENT")) {