static void DumpIndexKey( FILE * fp, TCascStorage * hs, LPBYTE pbIndexKey, int nDumpLevel) { PCASC_INDEX_ENTRY pIndexEntry; TCascFile * hf; QUERY_KEY QueryKey; HANDLE hFile; BYTE HeaderArea[MAX_HEADER_AREA_SIZE]; char szBuffer[0x20]; QueryKey.pbData = pbIndexKey; QueryKey.cbData = MD5_HASH_SIZE; pIndexEntry = FindIndexEntry(hs, &QueryKey); if(pIndexEntry != NULL) { ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E); DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); // Mask the file offset FileOffset &= 0x3FFFFFFF; fprintf(fp, " data.%03u at 0x%08x (0x%lx bytes)\n", ArchIndex, (DWORD)FileOffset, FileSize); if(nDumpLevel > 2) { QueryKey.pbData = pIndexEntry->IndexKey; QueryKey.cbData = MD5_HASH_SIZE; if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile)) { // Make sure that the data file is open and frame header loaded CascGetFileSize(hFile, NULL); hf = IsValidFileHandle(hFile); assert(hf->pStream != NULL); // Read the header area FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA; FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)); CascCloseFile(hFile); // Dump the header area fprintf(fp, " FileSize: %X Rest: %s\n", ConvertBytesToInteger_4_LE(&HeaderArea[0x10]), StringFromBinary(&HeaderArea[0x14], 10, szBuffer)); } } }
static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexEntry) { ULONGLONG FileOffsMask = ((ULONGLONG)1 << hs->KeyMapping[0].SegmentBits) - 1; ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); TCascFile * hf; // Allocate the CASC file structure hf = (TCascFile *)CASC_ALLOC(TCascFile, 1); if(hf != NULL) { // Initialize the structure memset(hf, 0, sizeof(TCascFile)); hf->ArchiveIndex = (DWORD)(FileOffset >> hs->KeyMapping[0].SegmentBits); hf->HeaderOffset = (DWORD)(FileOffset & FileOffsMask); hf->szClassName = "TCascFile"; // Copy the file size. Note that for all files except ENCODING, // this is the compressed file size hf->CompressedSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); // For now, we set the file size to be equal to compressed size // This is used when loading the ENCODING file, which does not // have entry in the encoding table hf->FileSize = hf->CompressedSize; // Increment the number of references to the archive hs->dwRefCount++; hf->hs = hs; }
static TCascFile * CreateFileHandle(TCascStorage * hs, PQUERY_KEY pCKey, PQUERY_KEY pEKey, PCASC_EKEY_ENTRY pEKeyEntry, DWORD dwOpenFlags, DWORD dwContentSize) { ULONGLONG StorageOffset = ConvertBytesToInteger_5(pEKeyEntry->StorageOffset); ULONGLONG FileOffsMask = ((ULONGLONG)1 << hs->IndexFile[0].FileOffsetBits) - 1; TCascFile * hf; // Allocate the CASC file structure hf = (TCascFile *)CASC_ALLOC(TCascFile, 1); if(hf != NULL) { // Initialize the structure memset(hf, 0, sizeof(TCascFile)); hf->ArchiveIndex = (DWORD)(StorageOffset >> hs->IndexFile[0].FileOffsetBits); hf->ArchiveOffset = (DWORD)(StorageOffset & FileOffsMask); hf->szClassName = "TCascFile"; hf->OpenFlags = dwOpenFlags; // Supply the content key, if available if(pCKey != NULL) { assert(pCKey->pbData != NULL && pCKey->cbData == MD5_HASH_SIZE); memcpy(hf->CKey.Value, pCKey->pbData, pCKey->cbData); } // Supply the encoded key, if available if(pEKey != NULL) { assert(pEKey->pbData != NULL && CASC_EKEY_SIZE <= pEKey->cbData && pEKey->cbData <= MD5_HASH_SIZE); memcpy(hf->EKey.Value, pEKey->pbData, pEKey->cbData); } // Copy the encoded file size if(pEKeyEntry != NULL) { hf->EncodedSize = ConvertBytesToInteger_4_LE(pEKeyEntry->EncodedSize); } // Set the content size hf->ContentSize = dwContentSize; // Increment the number of references to the archive hs->dwRefCount++; hf->hs = hs; }
void CascDumpIndexEntry( TCascStorage * /* hs */, TDumpContext * dc, PCASC_INDEX_ENTRY pIndexEntry, int /* nDumpLevel */) { if(pIndexEntry != NULL) { ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E); DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); // Mask the file offset FileOffset &= 0x3FFFFFFF; dump_print(dc, " data.%03u at 0x%08x (0x%lx bytes)\n", ArchIndex, (DWORD)FileOffset, FileSize); //if(nDumpLevel > 2) //{ // QueryKey.pbData = pIndexEntry->IndexKey; // QueryKey.cbData = MD5_HASH_SIZE; // if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile)) // { // // Make sure that the data file is open and frame header loaded // CascGetFileSize(hFile, NULL); // hf = IsValidFileHandle(hFile); // assert(hf->pStream != NULL); // // Read the header area // FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA; // FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)); // CascCloseFile(hFile); // // Dump the header area // dump_print(dc, " FileSize: %X Rest: %s\n", // ConvertBytesToInteger_4_LE(&HeaderArea[0x10]), // StringFromBinary(&HeaderArea[0x14], 10, szBuffer)); // } //} }
static int EnsureHeaderAreaIsLoaded(TCascFile * hf) { TCascStorage * hs = hf->hs; ULONGLONG FileOffset = hf->HeaderOffset; LPBYTE pbHeaderArea; DWORD FileSignature; DWORD FileSize; BYTE HeaderArea[MAX_HEADER_AREA_SIZE]; int nError; // We need the data file to be open nError = EnsureDataStreamIsOpen(hf); if(nError != ERROR_SUCCESS) return nError; // Make sure that we already know the shift // to the begin of file data. // Note that older builds of Heroes of the Storm have entries pointing // to the beginning of the header area. // Newer versions of HOTS have encoding entries pointing directly to // the BLTE header if(hs->dwFileBeginDelta == 0xFFFFFFFF) { FileSignature = 0; FileOffset = hf->HeaderOffset; if(!FileStream_Read(hf->pStream, &FileOffset, &FileSignature, sizeof(DWORD))) return ERROR_FILE_CORRUPT; hs->dwFileBeginDelta = (FileSignature == BLTE_HEADER_SIGNATURE) ? BLTE_HEADER_DELTA : 0; } // If the file size is not loaded yet, do it if(hf->FrameCount == 0) { // Load the part before BLTE header + header itself FileOffset = hf->HeaderOffset - hs->dwFileBeginDelta; if(!FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea))) return ERROR_FILE_CORRUPT; // Copy the MD5 hash of the frame array memcpy(hf->FrameArrayHash, HeaderArea, MD5_HASH_SIZE); pbHeaderArea = HeaderArea + MD5_HASH_SIZE; // Copy the file size FileSize = ConvertBytesToInteger_4_LE(pbHeaderArea); pbHeaderArea += 0x0E; // Verify the BLTE signature if(ConvertBytesToInteger_4_LE(pbHeaderArea) != BLTE_HEADER_SIGNATURE) return ERROR_BAD_FORMAT; pbHeaderArea += sizeof(DWORD); // Load the size of the frame headers hf->HeaderSize = ConvertBytesToInteger_4(pbHeaderArea); if(hf->HeaderSize & 0x80000000) return ERROR_BAD_FORMAT; pbHeaderArea += sizeof(DWORD); // Read the header size assert(hs->dwFileBeginDelta <= BLTE_HEADER_DELTA); hf->HeaderOffset += (BLTE_HEADER_DELTA - hs->dwFileBeginDelta); hf->FrameCount = 1; // Retrieve the frame count, if different from 1 if(hf->HeaderSize != 0) { // The next byte must be 0x0F if(pbHeaderArea[0] != 0x0F) return ERROR_BAD_FORMAT; pbHeaderArea++; // Next three bytes form number of frames hf->FrameCount = ConvertBytesToInteger_3(pbHeaderArea); } #ifdef CASCLIB_TEST hf->FileSize_HdrArea = FileSize; #endif } return ERROR_SUCCESS; }