This commit is contained in:
Shauren
2017-08-17 17:31:02 +02:00
parent 43d268d75c
commit 3f39913628
11 changed files with 290 additions and 38 deletions

View File

@@ -32,6 +32,7 @@ set(SRC_FILES
src/CascRootFile_Diablo3.cpp
src/CascRootFile_Mndx.cpp
src/CascRootFile_Ovr.cpp
src/CascRootFile_SC1.cpp
src/CascRootFile_WoW6.cpp
)

View File

@@ -45,6 +45,7 @@
#define CASC_GAME_DIABLO3 0x00030000 // Diablo 3 since PTR 2.2.0
#define CASC_GAME_OVERWATCH 0x00040000 // Overwatch since PTR 24919
#define CASC_GAME_STARCRAFT2 0x00050000 // Starcraft II - Legacy of the Void, since build 38996
#define CASC_GAME_STARCRAFT1 0x00060000 // Starcraft 1 (remastered)
#define CASC_GAME_MASK 0xFFFF0000 // Mask for getting game ID
#define CASC_INDEX_COUNT 0x10
@@ -345,6 +346,7 @@ int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFil
int RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
int RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
int RootHandler_CreateWoW6(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask);
int RootHandler_CreateSC1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
//-----------------------------------------------------------------------------
// Dumping CASC data structures

View File

@@ -58,29 +58,34 @@ static CASC_ENCRYPTION_KEY CascKeys[] =
{ 0xCAE3FAC925F20402ULL, { 0x98, 0xB7, 0x8E, 0x87, 0x74, 0xBF, 0x27, 0x50, 0x93, 0xCB, 0x1B, 0x5F, 0xC7, 0x14, 0x51, 0x1B } }, // (included in game)
{ 0x061581CA8496C80CULL, { 0xDA, 0x2E, 0xF5, 0x05, 0x2D, 0xB9, 0x17, 0x38, 0x0B, 0x8A, 0xA6, 0xEF, 0x7A, 0x5F, 0x8E, 0x6A } }, //
{ 0xBE2CB0FAD3698123ULL, { 0x90, 0x2A, 0x12, 0x85, 0x83, 0x6C, 0xE6, 0xDA, 0x58, 0x95, 0x02, 0x0D, 0xD6, 0x03, 0xB0, 0x65 } }, //
{ 0x57A5A33B226B8E0AULL, { 0xFD, 0xFC, 0x35, 0xC9, 0x9B, 0x9D, 0xB1, 0x1A, 0x32, 0x62, 0x60, 0xCA, 0x24, 0x6A, 0xCB, 0x41 } }, // 1.1.0.0.30200 (Ana)
{ 0x42B9AB1AF5015920ULL, { 0xC6, 0x87, 0x78, 0x82, 0x3C, 0x96, 0x4C, 0x6F, 0x24, 0x7A, 0xCC, 0x0F, 0x4A, 0x25, 0x84, 0xF8 } }, // 1.2.0.1.30684 (Summer Games)
{ 0x57A5A33B226B8E0AULL, { 0xFD, 0xFC, 0x35, 0xC9, 0x9B, 0x9D, 0xB1, 0x1A, 0x32, 0x62, 0x60, 0xCA, 0x24, 0x6A, 0xCB, 0x41 } }, // 1.1.0.0.30200 Ana
{ 0x42B9AB1AF5015920ULL, { 0xC6, 0x87, 0x78, 0x82, 0x3C, 0x96, 0x4C, 0x6F, 0x24, 0x7A, 0xCC, 0x0F, 0x4A, 0x25, 0x84, 0xF8 } }, // 1.2.0.1.30684 Summer Games
{ 0x4F0FE18E9FA1AC1AULL, { 0x89, 0x38, 0x1C, 0x74, 0x8F, 0x65, 0x31, 0xBB, 0xFC, 0xD9, 0x77, 0x53, 0xD0, 0x6C, 0xC3, 0xCD } }, // 1.2.0.1.30684
{ 0x7758B2CF1E4E3E1BULL, { 0x3D, 0xE6, 0x0D, 0x37, 0xC6, 0x64, 0x72, 0x35, 0x95, 0xF2, 0x7C, 0x5C, 0xDB, 0xF0, 0x8B, 0xFA } }, // 1.2.0.1.30684
{ 0xE5317801B3561125ULL, { 0x7D, 0xD0, 0x51, 0x19, 0x9F, 0x84, 0x01, 0xF9, 0x5E, 0x4C, 0x03, 0xC8, 0x84, 0xDC, 0xEA, 0x33 } }, // 1.4.0.2.32143 (Halloween Terror)
{ 0x16B866D7BA3A8036ULL, { 0x13, 0x95, 0xE8, 0x82, 0xBF, 0x25, 0xB4, 0x81, 0xF6, 0x1A, 0x4D, 0x62, 0x11, 0x41, 0xDA, 0x6E } }, // 1.4.1.0.31804 (Bastion Blizzcon 2016 skin)
{ 0x11131FFDA0D18D30ULL, { 0xC3, 0x2A, 0xD1, 0xB8, 0x25, 0x28, 0xE0, 0xA4, 0x56, 0x89, 0x7B, 0x3C, 0xE1, 0xC2, 0xD2, 0x7E } }, // 1.5.0.1.32795 (Sombra)
{ 0xCAC6B95B2724144AULL, { 0x73, 0xE4, 0xBE, 0xA1, 0x45, 0xDF, 0x2B, 0x89, 0xB6, 0x5A, 0xEF, 0x02, 0xF8, 0x3F, 0xA2, 0x60 } }, // 1.5.0.1.32795 (Ecopoint: Antarctica)
{ 0xB7DBC693758A5C36ULL, { 0xBC, 0x3A, 0x92, 0xBF, 0xE3, 0x02, 0x51, 0x8D, 0x91, 0xCC, 0x30, 0x79, 0x06, 0x71, 0xBF, 0x10 } }, // 1.5.0.1.32795 (Genji Oni skin)
{ 0x90CA73B2CDE3164BULL, { 0x5C, 0xBF, 0xF1, 0x1F, 0x22, 0x72, 0x0B, 0xAC, 0xC2, 0xAE, 0x6A, 0xAD, 0x8F, 0xE5, 0x33, 0x17 } }, // 1.6.1.0.33236 (Oasis map)
{ 0xE5317801B3561125ULL, { 0x7D, 0xD0, 0x51, 0x19, 0x9F, 0x84, 0x01, 0xF9, 0x5E, 0x4C, 0x03, 0xC8, 0x84, 0xDC, 0xEA, 0x33 } }, // 1.4.0.2.32143 Halloween Terror
{ 0x16B866D7BA3A8036ULL, { 0x13, 0x95, 0xE8, 0x82, 0xBF, 0x25, 0xB4, 0x81, 0xF6, 0x1A, 0x4D, 0x62, 0x11, 0x41, 0xDA, 0x6E } }, // 1.4.1.0.31804 Bastion Blizzcon 2016 skin
{ 0x11131FFDA0D18D30ULL, { 0xC3, 0x2A, 0xD1, 0xB8, 0x25, 0x28, 0xE0, 0xA4, 0x56, 0x89, 0x7B, 0x3C, 0xE1, 0xC2, 0xD2, 0x7E } }, // 1.5.0.1.32795 Sombra
{ 0xCAC6B95B2724144AULL, { 0x73, 0xE4, 0xBE, 0xA1, 0x45, 0xDF, 0x2B, 0x89, 0xB6, 0x5A, 0xEF, 0x02, 0xF8, 0x3F, 0xA2, 0x60 } }, // 1.5.0.1.32795 Ecopoint: Antarctica
{ 0xB7DBC693758A5C36ULL, { 0xBC, 0x3A, 0x92, 0xBF, 0xE3, 0x02, 0x51, 0x8D, 0x91, 0xCC, 0x30, 0x79, 0x06, 0x71, 0xBF, 0x10 } }, // 1.5.0.1.32795 Genji Oni skin
{ 0x90CA73B2CDE3164BULL, { 0x5C, 0xBF, 0xF1, 0x1F, 0x22, 0x72, 0x0B, 0xAC, 0xC2, 0xAE, 0x6A, 0xAD, 0x8F, 0xE5, 0x33, 0x17 } }, // 1.6.1.0.33236 Oasis map
{ 0x6DD3212FB942714AULL, { 0xE0, 0x2C, 0x16, 0x43, 0x60, 0x2E, 0xC1, 0x6C, 0x3A, 0xE2, 0xA4, 0xD2, 0x54, 0xA0, 0x8F, 0xD9 } }, // 1.6.1.0.33236
{ 0x11DDB470ABCBA130ULL, { 0x66, 0x19, 0x87, 0x66, 0xB1, 0xC4, 0xAF, 0x75, 0x89, 0xEF, 0xD1, 0x3A, 0xD4, 0xDD, 0x66, 0x7A } }, // 1.6.1.0.33236 (Winter Wonderland)
{ 0x11DDB470ABCBA130ULL, { 0x66, 0x19, 0x87, 0x66, 0xB1, 0xC4, 0xAF, 0x75, 0x89, 0xEF, 0xD1, 0x3A, 0xD4, 0xDD, 0x66, 0x7A } }, // 1.6.1.0.33236 Winter Wonderland
{ 0x5BEF27EEE95E0B4BULL, { 0x36, 0xBC, 0xD2, 0xB5, 0x51, 0xFF, 0x1C, 0x84, 0xAA, 0x3A, 0x39, 0x94, 0xCC, 0xEB, 0x03, 0x3E } }, //
{ 0x9359B46E49D2DA42ULL, { 0x17, 0x3D, 0x65, 0xE7, 0xFC, 0xAE, 0x29, 0x8A, 0x93, 0x63, 0xBD, 0x6A, 0xA1, 0x89, 0xF2, 0x00 } }, // (Diablo's 20th anniversary)
{ 0x1A46302EF8896F34ULL, { 0x80, 0x29, 0xAD, 0x54, 0x51, 0xD4, 0xBC, 0x18, 0xE9, 0xD0, 0xF5, 0xAC, 0x44, 0x9D, 0xC0, 0x55 } }, // 1.7.0.2.34156 (Year of the Rooster)
{ 0x693529F7D40A064CULL, { 0xCE, 0x54, 0x87, 0x3C, 0x62, 0xDA, 0xA4, 0x8E, 0xFF, 0x27, 0xFC, 0xC0, 0x32, 0xBD, 0x07, 0xE3 } }, // 1.8.0.0.34470
{ 0x388B85AEEDCB685DULL, { 0xD9, 0x26, 0xE6, 0x59, 0xD0, 0x4A, 0x09, 0x6B, 0x24, 0xC1, 0x91, 0x51, 0x07, 0x6D, 0x37, 0x9A } }, // 1.8.0.0.34470
{ 0xE218F69AAC6C104DULL, { 0xF4, 0x3D, 0x12, 0xC9, 0x4A, 0x9A, 0x52, 0x84, 0x97, 0x97, 0x1F, 0x1C, 0xBE, 0x41, 0xAD, 0x4D } }, // 1.9.0.0.34986
{ 0xF432F0425363F250ULL, { 0xBA, 0x69, 0xF2, 0xB3, 0x3C, 0x27, 0x68, 0xF5, 0xF2, 0x9B, 0xFE, 0x78, 0xA5, 0xA1, 0xFA, 0xD5 } }, // 1.10.0.0.35455 cmf
{ 0x061D52F86830B35DULL, { 0xD7, 0x79, 0xF9, 0xC6, 0xCC, 0x9A, 0x4B, 0xE1, 0x03, 0xA4, 0xE9, 0x0A, 0x73, 0x38, 0xF7, 0x93 } }, // 1.10.0.0.35455 cmf
{ 0x9359B46E49D2DA42ULL, { 0x17, 0x3D, 0x65, 0xE7, 0xFC, 0xAE, 0x29, 0x8A, 0x93, 0x63, 0xBD, 0x6A, 0xA1, 0x89, 0xF2, 0x00 } }, // Diablo's 20th anniversary
{ 0x1A46302EF8896F34ULL, { 0x80, 0x29, 0xAD, 0x54, 0x51, 0xD4, 0xBC, 0x18, 0xE9, 0xD0, 0xF5, 0xAC, 0x44, 0x9D, 0xC0, 0x55 } }, // 1.7.0.2.34156 Year of the Rooster
{ 0x693529F7D40A064CULL, { 0xCE, 0x54, 0x87, 0x3C, 0x62, 0xDA, 0xA4, 0x8E, 0xFF, 0x27, 0xFC, 0xC0, 0x32, 0xBD, 0x07, 0xE3 } }, // 1.8.0.0.34470 CTF Maps
{ 0x388B85AEEDCB685DULL, { 0xD9, 0x26, 0xE6, 0x59, 0xD0, 0x4A, 0x09, 0x6B, 0x24, 0xC1, 0x91, 0x51, 0x07, 0x6D, 0x37, 0x9A } }, // 1.8.0.0.34470 Numbani Update (Doomfist teaser)
{ 0xE218F69AAC6C104DULL, { 0xF4, 0x3D, 0x12, 0xC9, 0x4A, 0x9A, 0x52, 0x84, 0x97, 0x97, 0x1F, 0x1C, 0xBE, 0x41, 0xAD, 0x4D } }, // 1.9.0.0.34986 Orisa
{ 0xF432F0425363F250ULL, { 0xBA, 0x69, 0xF2, 0xB3, 0x3C, 0x27, 0x68, 0xF5, 0xF2, 0x9B, 0xFE, 0x78, 0xA5, 0xA1, 0xFA, 0xD5 } }, // 1.10.0.0.35455 Uprising
{ 0x061D52F86830B35DULL, { 0xD7, 0x79, 0xF9, 0xC6, 0xCC, 0x9A, 0x4B, 0xE1, 0x03, 0xA4, 0xE9, 0x0A, 0x73, 0x38, 0xF7, 0x93 } }, // 1.10.0.0.35455 D.Va Officer Skin (HotS Nexus Challenge 2)
{ 0x1275C84CF113EF65ULL, { 0xCF, 0x58, 0xB6, 0x93, 0x3E, 0xAF, 0x98, 0xAF, 0x53, 0xE7, 0x6F, 0x84, 0x26, 0xCC, 0x7E, 0x6C } }, //
{ 0xD9C7C7AC0F14C868ULL, { 0x3A, 0xFD, 0xF6, 0x8E, 0x3A, 0x5D, 0x63, 0xBA, 0xBA, 0x1E, 0x68, 0x21, 0x88, 0x3F, 0x06, 0x7D } }, //
// {0xBD4E42661A432951ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 1.11.0.0.36376 (Unknown event)
{ 0xBD4E42661A432951ULL, { 0x6D, 0xE8, 0xE2, 0x8C, 0x85, 0x11, 0x64, 0x4D, 0x55, 0x95, 0xFC, 0x45, 0xE5, 0x35, 0x14, 0x72 } }, // 1.11.0.0.36376 Anniversary event
{ 0xC43CB14355249451ULL, { 0x0E, 0xA2, 0xB4, 0x4F, 0x96, 0xA2, 0x69, 0xA3, 0x86, 0x85, 0x6D, 0x04, 0x9A, 0x3D, 0xEC, 0x86 } }, // 1.12.0.0.37104 Horizon Lunar Colony
{ 0xE6D914F8E4744953ULL, { 0xC8, 0x47, 0x7C, 0x28, 0x9D, 0xCE, 0x66, 0xD9, 0x13, 0x65, 0x07, 0xA3, 0x3A, 0xA3, 0x33, 0x01 } }, // 1.13.0.0.37646 Doomfist
{ 0x5694C503F8C80178ULL, { 0x7F, 0x4C, 0xF1, 0xC1, 0xFB, 0xBA, 0xD9, 0x2B, 0x18, 0x43, 0x36, 0xD6, 0x77, 0xEB, 0xF9, 0x37 } }, // 1.13.0.0.37646 Doomfist
// { 0x21DBFD65F3E54269ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 1.13.0.0.37646 Summer Games 2017
// { 0x27ABA5F88DD8D078ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 1.13.0.0.37646
// Streamed WoW keys
{ 0xFA505078126ACB3EULL, { 0xBD, 0xC5, 0x18, 0x62, 0xAB, 0xED, 0x79, 0xB2, 0xDE, 0x48, 0xC8, 0xE7, 0xE6, 0x6C, 0x62, 0x00 } }, // 15 WOW-20740patch7.0.1_Beta
@@ -113,15 +118,17 @@ static CASC_ENCRYPTION_KEY CascKeys[] =
{ 0x460C92C372B2A166ULL, { 0x94, 0x6D, 0x56, 0x59, 0xF2, 0xFA, 0xF3, 0x27, 0xC0, 0xB7, 0xEC, 0x82, 0x8B, 0x74, 0x8A, 0xDB } }, // 74 WOW-21952patch7.0.3_Beta Stormheim Alliance cinematic (legion_g_a_sth)
{ 0x8165D801CCA11962ULL, { 0xCD, 0x0C, 0x0F, 0xFA, 0xAD, 0x93, 0x63, 0xEC, 0x14, 0xDD, 0x25, 0xEC, 0xDD, 0x2A, 0x5B, 0x62 } }, // 75 WOW-21952patch7.0.3_Beta Stormheim Horde cinematic (legion_g_h_sth)
{ 0xA3F1C999090ADAC9ULL, { 0xB7, 0x2F, 0xEF, 0x4A, 0x01, 0x48, 0x8A, 0x88, 0xFF, 0x02, 0x28, 0x0A, 0xA0, 0x7A, 0x92, 0xBB } }, // 81 WOW-22578patch7.1.0_PTR Firecat Mount
// {0x18AFDF5191923610ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 82 WOW-22578patch7.1.0_PTR
// {0x3C258426058FBD93ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 91 WOW-23436patch7.2.0_PTR
// {0x094E9A0474876B98ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 92 WOW-23910patch7.2.5_PTR
// {0x18AFDF5191923610ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 82 WOW-22578patch7.1.0_PTR
// {0x3C258426058FBD93ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 91 WOW-23436patch7.2.0_PTR
{ 0x094E9A0474876B98ULL, { 0xE5, 0x33, 0xBB, 0x6D, 0x65, 0x72, 0x7A, 0x58, 0x32, 0x68, 0x0D, 0x62, 0x0B, 0x0B, 0xC1, 0x0B } }, // 92 WOW-23910patch7.2.5_PTR
{ 0x3DB25CB86A40335EULL, { 0x02, 0x99, 0x0B, 0x12, 0x26, 0x0C, 0x1E, 0x9F, 0xDD, 0x73, 0xFE, 0x47, 0xCB, 0xAB, 0x70, 0x24 } }, // 93 WOW-23789patch7.2.0_PTR
{ 0x0DCD81945F4B4686ULL, { 0x1B, 0x78, 0x9B, 0x87, 0xFB, 0x3C, 0x92, 0x38, 0xD5, 0x28, 0x99, 0x7B, 0xFA, 0xB4, 0x41, 0x86 } }, // 94 WOW-23789patch7.2.0_PTR
// {0x486A2A3A2803BE89ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 95 WOW-23789patch7.2.0_PTR
{ 0x486A2A3A2803BE89ULL, { 0x32, 0x67, 0x9E, 0xA7, 0xB0, 0xF9, 0x9E, 0xBF, 0x4F, 0xA1, 0x70, 0xE8, 0x47, 0xEA, 0x43, 0x9A } }, // 95 WOW-23789patch7.2.0_PTR
// { 0x71F69446AD848E06ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 97 WOW-24473patch7.3.0_PTR
// { 0x211FCD1265A928E9ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 98 WOW-24473patch7.3.0_PTR
{ 0x0ADC9E327E42E98CULL, { 0x01, 0x7B, 0x34, 0x72, 0xC1, 0xDE, 0xE3, 0x04, 0xFA, 0x0B, 0x2F, 0xF8, 0xE5, 0x3F, 0xF7, 0xD6 } }, // 99 WOW-23910patch7.2.5_PTR
// { 0x71F69446AD848E06ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 97 WOW-24473patch7.3.0_PTR
// { 0x211FCD1265A928E9ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 98 WOW-24473patch7.3.0_PTR
// { 0xBAE9F621B60174F1ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 100 WOW-24473patch7.3.0_PTR
// { 0x34DE1EEADC97115EULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 101 WOW-24473patch7.3.0_PTR
{ 0, { 0 } }
};

View File

@@ -58,6 +58,7 @@ static const TGameIdString GameIds[] =
{"Diablo3", 0x07, CASC_GAME_DIABLO3}, // Diablo III BETA 2.2.0
{"Prometheus", 0x0A, CASC_GAME_OVERWATCH}, // Overwatch BETA since build 24919
{"SC2", 0x03, CASC_GAME_STARCRAFT2}, // Starcraft II - Legacy of the Void
{"Starcraft1", 0x0A, CASC_GAME_STARCRAFT1}, // Starcraft 1 (remake)
{NULL, 0, 0},
};

View File

@@ -108,6 +108,7 @@ typedef enum _CASC_STORAGE_INFO_CLASS
CascStorageFeatures,
CascStorageGameInfo,
CascStorageGameBuild,
CascStorageInstalledLocales,
CascStorageInfoClassMax
} CASC_STORAGE_INFO_CLASS, *PCASC_STORAGE_INFO_CLASS;
@@ -126,7 +127,7 @@ typedef struct _CASC_FIND_DATA
char * szPlainName; // Plain name of the found file
BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key
DWORD dwLocaleFlags; // Locale flags (WoW only)
DWORD dwFileDataId; // File data ID (WoW only)
DWORD dwFileDataId; // File data ID (WoW only)
DWORD dwFileSize; // Size of the file
} CASC_FIND_DATA, *PCASC_FIND_DATA;

View File

@@ -121,6 +121,29 @@ static bool IsIndexFileName_V2(const TCHAR * szFileName)
_tcsicmp(szFileName + 0x0A, _T(".idx")) == 0);
}
static bool IsRootFile_Starcraft1(LPBYTE pbFileData, DWORD cbFileData)
{
LPBYTE pbFileEnd = pbFileData + cbFileData;
LPBYTE pbHashName;
LPBYTE pbHashEnd;
// Skip the file name
while(pbFileData < pbFileEnd && pbFileData[0] != '|')
pbFileData++;
if(pbFileData[0] != '|')
return false;
// Then, a MD5 must follow
pbHashName = pbHashEnd = pbFileData + 1;
while(pbHashEnd < pbFileEnd && pbHashEnd[0] != 0x0A)
pbHashEnd++;
if(pbHashEnd[0] != 0x0A)
return false;
// The length must be exactly 32 characters
return ((pbHashEnd - pbHashName) == 32);
}
static bool IsCascIndexHeader_V1(LPBYTE pbFileData, DWORD cbFileData)
{
PFILE_INDEX_HEADER_V1 pIndexHeader = (PFILE_INDEX_HEADER_V1)pbFileData;
@@ -913,7 +936,10 @@ static int LoadRootFile(TCascStorage * hs, DWORD dwLocaleMask)
break;
default:
nError = RootHandler_CreateWoW6(hs, pbRootFile, cbRootFile, dwLocaleMask);
if(IsRootFile_Starcraft1(pbRootFile, cbRootFile))
nError = RootHandler_CreateSC1(hs, pbRootFile, cbRootFile);
else
nError = RootHandler_CreateWoW6(hs, pbRootFile, cbRootFile, dwLocaleMask);
break;
}
}
@@ -1123,6 +1149,10 @@ bool WINAPI CascGetStorageInfo(
dwInfoValue = hs->dwBuildNumber;
break;
case CascStorageInstalledLocales:
dwInfoValue = hs->dwDefaultLocale;
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return false;

View File

@@ -153,6 +153,7 @@
typedef LONG * PLONG;
typedef DWORD * PDWORD;
typedef BYTE * LPBYTE;
typedef char * LPSTR;
#ifdef PLATFORM_32BIT
#define _LZMA_UINT32_IS_ULONG

View File

@@ -494,7 +494,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
if(nError == ERROR_SUCCESS && hf->FilePointer >= hf->FileSize)
{
*pdwBytesRead = 0;
return ERROR_SUCCESS;
return true;
}
// Find the file frame where to read from

View File

@@ -90,14 +90,6 @@ typedef struct _CASC_ROOT_ENTRY_MNDX
} CASC_ROOT_ENTRY_MNDX, *PCASC_ROOT_ENTRY_MNDX;
//-----------------------------------------------------------------------------
// Testing functions prototypes
#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST)
extern "C" bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo);
#endif
//-----------------------------------------------------------------------------
// Local variables
@@ -3345,8 +3337,9 @@ int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFil
// Unit tests
#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST)
/*
extern "C" {
bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
DWORD _cdecl sub_19573D0_x86(TFileNameDatabase * pDB, DWORD arg_0, DWORD arg_4);
DWORD _cdecl sub_1957EF0_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
bool _cdecl sub_1959460_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
@@ -3390,7 +3383,7 @@ static int sub_1956CE0_x86(TFileNameDatabasePtr * pDatabasePtr, TMndxFindResult
*pbFindResult = sub_1959460_x86(pDatabasePtr->pDB, pStruct1C);
return nError;
}
/*
static void TestFileSearch_SubStrings(PMAR_FILE pMarFile, char * szFileName, size_t nLength)
{
TMndxFindResult Struct1C_1;
@@ -3437,7 +3430,6 @@ static void TestFileSearch_SubStrings(PMAR_FILE pMarFile, char * szFileName, siz
nLength--;
}
}
*/
static void TestFindPackage(PMAR_FILE pMarFile, const char * szPackageName)
{
@@ -3621,4 +3613,5 @@ void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo)
ListFile_Free(pvListFile);
}
}
*/
#endif // defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST)

View File

@@ -0,0 +1,216 @@
/*****************************************************************************/
/* CascRootFile_SC1.cpp Copyright (c) Ladislav Zezula 2017 */
/*---------------------------------------------------------------------------*/
/* Support for loading Starcraft 1 ROOT file */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 28.10.15 1.00 Lad The first version of CascRootFile_SC1.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Structure definitions for Overwatch root file
typedef struct _CASC_FILE_ENTRY
{
ENCODING_KEY EncodingKey; // Encoding key
ULONGLONG FileNameHash; // File name hash
DWORD dwFileName; // Offset of the file name in the name cache
} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY;
struct TRootHandler_SC1 : public TRootHandler
{
// Linear global list of file entries
DYNAMIC_ARRAY FileTable;
// Linear global list of names
DYNAMIC_ARRAY FileNames;
// Global map of FileName -> FileEntry
PCASC_MAP pRootMap;
};
//-----------------------------------------------------------------------------
// Local functions
static int InsertFileEntry(
TRootHandler_SC1 * pRootHandler,
const char * szFileName,
LPBYTE pbEncodingKey)
{
PCASC_FILE_ENTRY pFileEntry;
size_t nLength = strlen(szFileName);
// Attempt to insert the file name to the global buffer
szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1);
if(szFileName == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Attempt to insert the entry to the array of file entries
pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
if(pFileEntry == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Fill the file entry
pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey;
pFileEntry->FileNameHash = CalcFileNameHash(szFileName);
pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName);
// Insert the file entry to the map
assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL);
Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------
// Implementation of Overwatch root file
static int SC1Handler_Insert(
TRootHandler_SC1 * pRootHandler,
const char * szFileName,
LPBYTE pbEncodingKey)
{
return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey);
}
static LPBYTE SC1Handler_Search(TRootHandler_SC1 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */, PDWORD /* PtrFileDataId */)
{
PCASC_FILE_ENTRY pFileEntry;
// Are we still inside the root directory range?
while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount)
{
// Retrieve the file item
pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1);
// Prepare the pointer to the next search
pSearch->IndexLevel1++;
char *filename = (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName);
if (CheckWildCard(filename, pSearch->szMask)) {
strcpy(pSearch->szFileName, filename);
return pFileEntry->EncodingKey.Value;
}
}
// No more entries
return NULL;
}
static void SC1Handler_EndSearch(TRootHandler_SC1 * /* pRootHandler */, TCascSearch * /* pSearch */)
{
// Do nothing
}
static LPBYTE SC1Handler_GetKey(TRootHandler_SC1 * pRootHandler, const char * szFileName)
{
ULONGLONG FileNameHash = CalcFileNameHash(szFileName);
return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL);
}
static DWORD SC1Handler_GetFileId(TRootHandler_SC1 * /* pRootHandler */, const char * /* szFileName */)
{
// Not implemented for Overwatch
return 0;
}
static void SC1Handler_Close(TRootHandler_SC1 * pRootHandler)
{
if(pRootHandler != NULL)
{
// Free the file map
if(pRootHandler->pRootMap)
Map_Free(pRootHandler->pRootMap);
pRootHandler->pRootMap = NULL;
// Free the array of the file names and file items
Array_Free(&pRootHandler->FileTable);
Array_Free(&pRootHandler->FileNames);
// Free the root file itself
CASC_FREE(pRootHandler);
}
}
//-----------------------------------------------------------------------------
// Public functions
int RootHandler_CreateSC1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
{
TRootHandler_SC1 * pRootHandler;
ENCODING_KEY KeyBuffer;
QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE};
void * pTextFile;
size_t nLength;
char szOneLine[0x200];
char szFileName[MAX_PATH+1];
DWORD dwFileCountMax = (DWORD)hs->pEncodingMap->TableSize;
int nFileNameIndex;
int nError = ERROR_SUCCESS;
// Allocate the root handler object
hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_SC1, 1);
if(pRootHandler == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Fill-in the handler functions
memset(pRootHandler, 0, sizeof(TRootHandler_SC1));
pRootHandler->Insert = (ROOT_INSERT)SC1Handler_Insert;
pRootHandler->Search = (ROOT_SEARCH)SC1Handler_Search;
pRootHandler->EndSearch = (ROOT_ENDSEARCH)SC1Handler_EndSearch;
pRootHandler->GetKey = (ROOT_GETKEY)SC1Handler_GetKey;
pRootHandler->Close = (ROOT_CLOSE)SC1Handler_Close;
pRootHandler->GetFileId = (ROOT_GETFILEID)SC1Handler_GetFileId;
// Fill-in the flags
pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES;
// Allocate the linear array of file entries
nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000);
if(nError != ERROR_SUCCESS)
return nError;
// Allocate the buffer for the file names
nError = Array_Create(&pRootHandler->FileNames, char, 0x10000);
if(nError != ERROR_SUCCESS)
return nError;
// Create map of ROOT_ENTRY -> FileEntry
pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash));
if(pRootHandler->pRootMap == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Parse the ROOT file
pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile);
if(pTextFile != NULL)
{
// Parse the next lines
while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0)
{
LPSTR szEncodingKey;
BYTE EncodingKey[MD5_HASH_SIZE];
szEncodingKey = strchr(szOneLine, _T('|'));
if(szEncodingKey != NULL)
{
// Split the name and encoding key
*szEncodingKey++ = 0;
// Insert the entry to the map
ConvertStringToBinary(szEncodingKey, MD5_STRING_SIZE, EncodingKey);
InsertFileEntry(pRootHandler, szOneLine, EncodingKey);
}
}
// Free the listfile
ListFile_Free(pTextFile);
}
// Succeeded
return nError;
}

View File

@@ -58,7 +58,7 @@ recastnavigation (Recast is state of the art navigation mesh construction toolse
CascLib (An open-source implementation of library for reading CASC storage from Blizzard games since 2014)
https://github.com/ladislav-zezula/CascLib
Version: 16f80d1433525db73894b84d05af99e26847054d
Version: fb9442155352b36e56b74a6c0d265b3b62d20e3a
rapidjson (A fast JSON parser/generator for C++ with both SAX/DOM style API http://rapidjson.org/)
https://github.com/miloyip/rapidjson