@@ -35,6 +35,19 @@ typedef enum _ROOT_FORMAT
3535 RootFormatWoW_v2, // Since build 30080 (WoW 8.2.0)
3636} ROOT_FORMAT, *PROOT_FORMAT;
3737
38+ // The last byte of the structure causes wrong alignment with default compiler options
39+ #pragma pack(push, 1)
40+ typedef struct _FILE_ROOT_GROUP_HEADER_58221 // Since build 58221 (11.1.0.58221)
41+ {
42+ DWORD NumberOfFiles; // Number of entries
43+ DWORD LocaleFlags; // File locale mask (CASC_LOCALE_XXX)
44+ DWORD ContentFlags1;
45+ DWORD ContentFlags2;
46+ BYTE ContentFlags3;
47+
48+ } FILE_ROOT_GROUPHEADER_58221, *PFILE_ROOT_GROUPHEADER_58221;
49+ #pragma pack(pop)
50+
3851// ROOT file header since build 50893 (10.1.7)
3952typedef struct _FILE_ROOT_HEADER_50893
4053{
@@ -43,7 +56,7 @@ typedef struct _FILE_ROOT_HEADER_50893
4356 DWORD Version; // Must be 1
4457 DWORD TotalFiles;
4558 DWORD FilesWithNameHash;
46- } FILE_ROOT_HEADER_50893, * PFILE_ROOT_HEADER_50893;
59+ } FILE_ROOT_HEADER_50893, *PFILE_ROOT_HEADER_50893;
4760
4861// ROOT file header since build 30080 (8.2.0)
4962typedef struct _FILE_ROOT_HEADER_30080
@@ -97,7 +110,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
97110{
98111 public:
99112
100- typedef LPBYTE (*CAPTURE_ROOT_HEADER)(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless);
113+ typedef LPBYTE (*CAPTURE_ROOT_HEADER)(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version );
101114
102115 TRootHandler_WoW (ROOT_FORMAT aRootFormat, DWORD aFileCounterHashless, LPCTSTR szDumpFile = NULL ) : TFileTreeRoot(FTREE_FLAGS_WOW)
103116 {
@@ -155,7 +168,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
155168#endif
156169
157170 // Check for the new format (World of Warcraft 10.1.7, build 50893)
158- static LPBYTE CaptureRootHeader_50893 (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
171+ static LPBYTE CaptureRootHeader_50893 (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version )
159172 {
160173 FILE_ROOT_HEADER_50893 RootHeader;
161174
@@ -167,7 +180,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
167180 // Verify the root file header
168181 if (RootHeader.Signature != CASC_WOW_ROOT_SIGNATURE)
169182 return NULL ;
170- if (RootHeader.Version != 1 )
183+ if (RootHeader.Version != 1 && RootHeader. Version != 2 )
171184 return NULL ;
172185 if (RootHeader.FilesWithNameHash > RootHeader.TotalFiles )
173186 return NULL ;
@@ -177,11 +190,12 @@ struct TRootHandler_WoW : public TFileTreeRoot
177190
178191 *RootFormat = RootFormatWoW_v2;
179192 *FileCounterHashless = RootHeader.TotalFiles - RootHeader.FilesWithNameHash ;
193+ *Version = RootHeader.Version ;
180194 return pbRootPtr + RootHeader.SizeOfHeader ;
181195 }
182196
183197 // Check for the root format for build 30080+ (WoW 8.2.0)
184- static LPBYTE CaptureRootHeader_30080 (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
198+ static LPBYTE CaptureRootHeader_30080 (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version )
185199 {
186200 FILE_ROOT_HEADER_30080 RootHeader;
187201
@@ -198,11 +212,12 @@ struct TRootHandler_WoW : public TFileTreeRoot
198212
199213 *RootFormat = RootFormatWoW_v2;
200214 *FileCounterHashless = RootHeader.TotalFiles - RootHeader.FilesWithNameHash ;
215+ *Version = 0 ;
201216 return pbRootPtr + sizeof (FILE_ROOT_HEADER_30080);
202217 }
203218
204219 // Check for the root format for build 18125+ (WoW 6.0.1)
205- static LPBYTE CaptureRootHeader_18125 (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
220+ static LPBYTE CaptureRootHeader_18125 (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version )
206221 {
207222 size_t DataLength;
208223
@@ -218,10 +233,11 @@ struct TRootHandler_WoW : public TFileTreeRoot
218233
219234 *RootFormat = RootFormatWoW_v1;
220235 *FileCounterHashless = 0 ;
236+ *Version = 0 ;
221237 return pbRootPtr;
222238 }
223239
224- static LPBYTE CaptureRootHeader (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
240+ static LPBYTE CaptureRootHeader (LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version )
225241 {
226242 CAPTURE_ROOT_HEADER PfnCaptureRootHeader[] =
227243 {
@@ -234,24 +250,42 @@ struct TRootHandler_WoW : public TFileTreeRoot
234250 {
235251 LPBYTE pbCapturedPtr;
236252
237- if ((pbCapturedPtr = PfnCaptureRootHeader[i](pbRootPtr, pbRootEnd, RootFormat, FileCounterHashless)) != NULL )
253+ if ((pbCapturedPtr = PfnCaptureRootHeader[i](pbRootPtr, pbRootEnd, RootFormat, FileCounterHashless, Version )) != NULL )
238254 {
239255 return pbCapturedPtr;
240256 }
241257 }
242258 return NULL ;
243259 }
244260
245- LPBYTE CaptureRootGroup (FILE_ROOT_GROUP & RootGroup, LPBYTE pbRootPtr, LPBYTE pbRootEnd)
261+ LPBYTE CaptureRootGroup (FILE_ROOT_GROUP & RootGroup, LPBYTE pbRootPtr, LPBYTE pbRootEnd, DWORD dwRootVersion )
246262 {
247263 // Reset the entire root group structure
248264 memset (&RootGroup, 0 , sizeof (FILE_ROOT_GROUP));
249265
250- // Validate the locale block header
251- if ((pbRootPtr + sizeof (FILE_ROOT_GROUP_HEADER)) >= pbRootEnd)
252- return NULL ;
253- memcpy (&RootGroup.Header , pbRootPtr, sizeof (FILE_ROOT_GROUP_HEADER));
254- pbRootPtr = pbRootPtr + sizeof (FILE_ROOT_GROUP_HEADER);
266+ if (dwRootVersion == 0 || dwRootVersion == 1 )
267+ {
268+ // Validate the locale block header
269+ if ((pbRootPtr + sizeof (FILE_ROOT_GROUP_HEADER)) >= pbRootEnd)
270+ return NULL ;
271+ memcpy (&RootGroup.Header , pbRootPtr, sizeof (FILE_ROOT_GROUP_HEADER));
272+ pbRootPtr = pbRootPtr + sizeof (FILE_ROOT_GROUP_HEADER);
273+ }
274+ else if (dwRootVersion == 2 )
275+ {
276+ PFILE_ROOT_GROUPHEADER_58221 pRootGroupHeader;
277+
278+ // Get pointer to the root group header
279+ if ((pbRootPtr + sizeof (FILE_ROOT_GROUPHEADER_58221)) >= pbRootEnd)
280+ return NULL ;
281+ pRootGroupHeader = (PFILE_ROOT_GROUPHEADER_58221)pbRootPtr;
282+ pbRootPtr = pbRootPtr + sizeof (FILE_ROOT_GROUPHEADER_58221);
283+
284+ // Convert to old ContentFlags for now...
285+ RootGroup.Header .NumberOfFiles = pRootGroupHeader->NumberOfFiles ;
286+ RootGroup.Header .ContentFlags = pRootGroupHeader->ContentFlags1 | pRootGroupHeader->ContentFlags2 | (DWORD)(pRootGroupHeader->ContentFlags3 << 17 );
287+ RootGroup.Header .LocaleFlags = pRootGroupHeader->LocaleFlags ;
288+ }
255289
256290 // Validate the array of file data IDs
257291 if ((pbRootPtr + (sizeof (DWORD) * RootGroup.Header .NumberOfFiles )) >= pbRootEnd)
@@ -380,7 +414,8 @@ struct TRootHandler_WoW : public TFileTreeRoot
380414 LPBYTE pbRootEnd,
381415 DWORD dwLocaleMask,
382416 BYTE bOverrideLowViolence,
383- BYTE bAudioLocale)
417+ BYTE bAudioLocale,
418+ DWORD dwRootVersion)
384419 {
385420 FILE_ROOT_GROUP RootBlock;
386421
@@ -395,7 +430,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
395430 // OutputDebugStringA(szMessage);
396431
397432 // Validate the file locale block
398- pbRootPtr = CaptureRootGroup (RootBlock, pbRootPtr, pbRootEnd);
433+ pbRootPtr = CaptureRootGroup (RootBlock, pbRootPtr, pbRootEnd, dwRootVersion );
399434 if (pbRootPtr == NULL )
400435 return ERROR_BAD_FORMAT;
401436
@@ -481,33 +516,34 @@ struct TRootHandler_WoW : public TFileTreeRoot
481516 LPBYTE pbRootPtr,
482517 LPBYTE pbRootEnd,
483518 DWORD dwLocaleMask,
484- BYTE bAudioLocale)
519+ BYTE bAudioLocale,
520+ DWORD dwRootVersion)
485521 {
486522 DWORD dwErrCode;
487523
488524 // Load the locale as-is
489- dwErrCode = ParseWowRootFile_Level2 (hs, pbRootPtr, pbRootEnd, dwLocaleMask, false , bAudioLocale);
525+ dwErrCode = ParseWowRootFile_Level2 (hs, pbRootPtr, pbRootEnd, dwLocaleMask, false , bAudioLocale, dwRootVersion );
490526 if (dwErrCode != ERROR_SUCCESS)
491527 return dwErrCode;
492528
493529 // If we wanted enGB, we also load enUS for the missing files
494530 if (dwLocaleMask == CASC_LOCALE_ENGB)
495- ParseWowRootFile_Level2 (hs, pbRootPtr, pbRootEnd, CASC_LOCALE_ENUS, false , bAudioLocale);
531+ ParseWowRootFile_Level2 (hs, pbRootPtr, pbRootEnd, CASC_LOCALE_ENUS, false , bAudioLocale, dwRootVersion );
496532
497533 if (dwLocaleMask == CASC_LOCALE_PTPT)
498- ParseWowRootFile_Level2 (hs, pbRootPtr, pbRootEnd, CASC_LOCALE_PTBR, false , bAudioLocale);
534+ ParseWowRootFile_Level2 (hs, pbRootPtr, pbRootEnd, CASC_LOCALE_PTBR, false , bAudioLocale, dwRootVersion );
499535
500536 return ERROR_SUCCESS;
501537 }
502538
503539 // WoW.exe: 004146C7 (BuildManifest::Load)
504- DWORD Load (TCascStorage * hs, LPBYTE pbRootPtr, LPBYTE pbRootEnd, DWORD dwLocaleMask)
540+ DWORD Load (TCascStorage * hs, LPBYTE pbRootPtr, LPBYTE pbRootEnd, DWORD dwLocaleMask, DWORD dwRootVersion )
505541 {
506542 DWORD dwErrCode;
507543
508- dwErrCode = ParseWowRootFile_Level1 (hs, pbRootPtr, pbRootEnd, dwLocaleMask, 0 );
544+ dwErrCode = ParseWowRootFile_Level1 (hs, pbRootPtr, pbRootEnd, dwLocaleMask, 0 , dwRootVersion );
509545 if (dwErrCode == ERROR_SUCCESS)
510- dwErrCode = ParseWowRootFile_Level1 (hs, pbRootPtr, pbRootEnd, dwLocaleMask, 1 );
546+ dwErrCode = ParseWowRootFile_Level1 (hs, pbRootPtr, pbRootEnd, dwLocaleMask, 1 , dwRootVersion );
511547
512548#ifdef CASCLIB_DEBUG
513549 // Dump the array of the file data IDs
@@ -618,10 +654,11 @@ DWORD RootHandler_CreateWoW(TCascStorage * hs, CASC_BLOB & RootFile, DWORD dwLoc
618654 LPBYTE pbRootEnd = RootFile.End ();
619655 LPBYTE pbRootPtr;
620656 DWORD FileCounterHashless = 0 ;
657+ DWORD RootVersion = 0 ;
621658 DWORD dwErrCode = ERROR_BAD_FORMAT;
622659
623660 // Verify the root header
624- if ((pbRootPtr = TRootHandler_WoW::CaptureRootHeader (pbRootFile, pbRootEnd, &RootFormat, &FileCounterHashless)) == NULL )
661+ if ((pbRootPtr = TRootHandler_WoW::CaptureRootHeader (pbRootFile, pbRootEnd, &RootFormat, &FileCounterHashless, &RootVersion )) == NULL )
625662 return ERROR_BAD_FORMAT;
626663
627664#ifdef CASCLIB_WRITE_VERIFIED_FILENAMES
@@ -639,7 +676,7 @@ DWORD RootHandler_CreateWoW(TCascStorage * hs, CASC_BLOB & RootFile, DWORD dwLoc
639676 // fp = fopen("E:\\file-data-ids2.txt", "wt");
640677
641678 // Load the root directory. If load failed, we free the object
642- dwErrCode = pRootHandler->Load (hs, pbRootPtr, pbRootEnd, dwLocaleMask);
679+ dwErrCode = pRootHandler->Load (hs, pbRootPtr, pbRootEnd, dwLocaleMask, RootVersion );
643680 if (dwErrCode != ERROR_SUCCESS)
644681 {
645682 delete pRootHandler;
0 commit comments