static int WowHandler_Insert( TRootHandler_WoW6 * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey) { PCASC_FILE_ENTRY pFileEntry; DWORD FileDataId = 0; // Don't let the number of items to overflow if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) return ERROR_NOT_ENOUGH_MEMORY; // Insert the item to the linear file list pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); if(pFileEntry != NULL) { // Get the file data ID of the previous item (0 if this is the first one) if(pRootHandler->FileTable.ItemCount > 1) FileDataId = pFileEntry[-1].FileDataId; // Fill-in the new entry pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey; pFileEntry->FileNameHash = CalcFileNameHash(szFileName); pFileEntry->FileDataId = FileDataId + 1; pFileEntry->Locales = CASC_LOCALE_ALL; // Verify collisions (debug version only) assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); // Insert the entry to the map Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); } return ERROR_SUCCESS; }
static int ParseDirEntries_FileId2( TRootHandler_Diablo3 * pRootHandler, LPBYTE pbFileEntries, DWORD dwFileEntries, DWORD dwRootDirIndex) { PDIABLO3_FILEID2_ENTRY pEntry = (PDIABLO3_FILEID2_ENTRY)pbFileEntries; PCASC_FILE_ENTRY pFileEntry; // Overflow test if((pRootHandler->FileTable.ItemCount + dwFileEntries) >= pRootHandler->FileTable.ItemCountMax) { assert(false); return ERROR_NOT_ENOUGH_MEMORY; } // Parse the all ID1 entries in the file for(DWORD i = 0; i < dwFileEntries; i++, pEntry++) { // Insert the file entry to the global list pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); assert(pFileEntry != NULL); // Fill the index entry pFileEntry->EncodingKey = pEntry->EncodingKey; pFileEntry->FileNameHash = MAKE_INDEX64(dwRootDirIndex, pEntry->FileIndex, pEntry->SubIndex); pFileEntry->dwFlags = CASC_ENTRY_SHORT_NAME | CASC_ENTRY_HAS_SUBINDEX; } return ERROR_SUCCESS; }
static void ResolveFullFileNames( TRootHandler_Diablo3 * pRootHandler, PDIABLO3_CORE_TOC_ENTRY pCoreTocEntries, PCASC_MAP pPackageMap, LPBYTE pbCoreTocFile, DWORD dwFileIndexes) { PCASC_FILE_ENTRY pFileEntry; char * szPlainName; char * szNamePtr; size_t nLength; DWORD dwRootIndex; DWORD dwFileIndex; DWORD dwSubIndex; char szShortName[MAX_PATH+1]; char szFullName[MAX_PATH+1]; // Keep compiler happy CASCLIB_UNUSED(dwFileIndexes); // Parse the entire file table for(size_t i = 0; i < pRootHandler->FileTable.ItemCount; i++) { // Retrieve the file entry at n-th position pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, i); // Skip the items that already have full name if(pFileEntry->dwFlags & CASC_ENTRY_SHORT_NAME) { // Retrieve the file index of that file dwRootIndex = INDEX64_ROOT_INDEX(pFileEntry->FileNameHash); dwFileIndex = INDEX64_FILE_INDEX(pFileEntry->FileNameHash); dwSubIndex = (pFileEntry->dwFlags & CASC_ENTRY_HAS_SUBINDEX) ? INDEX64_SUB_INDEX(pFileEntry->FileNameHash) : DIABLO3_INVALID_INDEX; assert(dwFileIndex < dwFileIndexes); // Get the plain name of the file szPlainName = (char *)(pbCoreTocFile + pCoreTocEntries[dwFileIndex].NameOffset); // Create the short file name nLength = CreateShortName(pPackageMap, dwRootIndex, pCoreTocEntries[dwFileIndex].AssetIndex, szPlainName, dwSubIndex, szShortName); // Insert the short name to the list of the names szNamePtr = (char *)Array_Insert(&pRootHandler->FileNames, szShortName, nLength + 1); pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szNamePtr); // Create the full file name nLength = CreateFileName(pRootHandler, szShortName, szFullName); pFileEntry->FileNameHash = CalcFileNameHash(szFullName); // Insert the entry to the name map. Use the mapping of FullName -> FileHash Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); } } }
static int ParseRoot_AddRootEntries( TRootHandler_WoW6 * pRootHandler, PCASC_ROOT_BLOCK pRootBlock) { PCASC_FILE_ENTRY pFileEntry; DWORD dwFileDataId = 0; // Sanity checks assert(pRootHandler->FileTable.ItemArray != NULL); assert(pRootHandler->FileTable.ItemCountMax != 0); assert(pRootHandler->FileDataIdLookupTable.ItemArray != NULL); assert(pRootHandler->FileDataIdLookupTable.ItemCountMax != 0); // WoW.exe (build 19116): Blocks with zero files are skipped for(DWORD i = 0; i < pRootBlock->pLocaleBlockHdr->NumberOfFiles; i++) { // Create new entry, with overflow check if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) return ERROR_INSUFFICIENT_BUFFER; pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); if (pRootHandler->FileDataIdLookupTable.ItemCount >= pRootHandler->FileDataIdLookupTable.ItemCountMax) return ERROR_INSUFFICIENT_BUFFER; Array_Insert(&pRootHandler->FileDataIdLookupTable, &pFileEntry, 1); // (004147A3) Prepare the CASC_FILE_ENTRY structure pFileEntry->FileNameHash = pRootBlock->pRootEntries[i].FileNameHash; pFileEntry->FileDataId = dwFileDataId + pRootBlock->FileDataIds[i]; pFileEntry->Locales = pRootBlock->pLocaleBlockHdr->Locales; pFileEntry->EncodingKey = pRootBlock->pRootEntries[i].EncodingKey; // Also, insert the entry to the map Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); // Update the local File Data Id assert((pFileEntry->FileDataId + 1) > pFileEntry->FileDataId); dwFileDataId = pFileEntry->FileDataId + 1; // Move to the next root entry pFileEntry++; } return ERROR_SUCCESS; }
// Insert an entry with file name as-is static int InsertFileEntry( TRootHandler_Diablo3 * pRootHandler, ENCODING_KEY & EncodingKey, const char * szFileName, size_t cchFileName) { PCASC_FILE_ENTRY pFileEntry; // We must not allow the file name array to be reallocated. // Reallocating the array would cause pointers in TRootHandler_Diablo3::pRootMap // become invalid if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) { assert(false); return ERROR_NOT_ENOUGH_MEMORY; } // Insert the plain name to the root handler's global name list szFileName = (const char *)Array_Insert(&pRootHandler->FileNames, szFileName, cchFileName); if(szFileName == NULL) return ERROR_NOT_ENOUGH_MEMORY; // Make sure that we don't exceed the file limit at this phase pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); assert(pFileEntry != NULL); // Store the info into the file entry pFileEntry->EncodingKey = EncodingKey; pFileEntry->FileNameHash = CalcFileNameHash(szFileName); pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName); pFileEntry->dwFlags = 0; // Verify collisions (debug version only) assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); // Calculate the file name hash Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); // Success return ERROR_SUCCESS; }