void LoadLocaleMPQFiles(int const locale) { char filename[512]; //Locale-xxXX.MPQ sprintf(filename,"%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &localeMPQ[0])) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); if (!SFileOpenPatchArchive(localeMPQ[0], filename, langs[locale], MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if (!SFileIsPatchedArchive(localeMPQ[0])) assert(false && "An error occured"); //Others for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &localeMPQ[i+1])) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ failed"); } for(int j = i; j < PATCH_REV_COUNT; ++j) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[j]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); if (!SFileOpenPatchArchive(localeMPQ[i+1], filename, langs[locale], MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if (!SFileIsPatchedArchive(localeMPQ[i+1])) assert(false && "An error occured"); } }
void LoadMapMPQFiles() { char filename[512]; //Locale-xxXX.MPQ sprintf(filename,"%s/Data/world.MPQ", input_path); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMPQ)) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); printf(" -%i\n", patchRev[i]); if (!SFileOpenPatchArchive(WorldMPQ, filename, "base", MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if (!SFileIsPatchedArchive(WorldMPQ)) assert(false && "An error occured"); for(int j = 0; j < 3; j++) { sprintf(filename, "%s/Data/expansion%u.MPQ", input_path, j+1); printf("Loading %s\n", filename); if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &ExpansionsMPQ[j])) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } if (!IsValidMpqHandle((TMPQArchive*)ExpansionsMPQ[j])) { printf("Load of Expansion%u.MPQ Failed!\n", j+1); printf("\nPlease verify you downloaded all the MPQs. You should replace\n'SET accountType \"xx\"'\nin your WTF/config.wtf and WTF/launcher.wtf by\n'SET accountType \"CT\"'\nand then restart your launcher\n"); exit(1); } for(int i = 0; i < PATCH_REV_COUNT; ++i) { char ext[7] = ""; sprintf(ext, "-%i", patchRev[i]); sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext); printf(" -%i\n", patchRev[i]); if (!SFileOpenPatchArchive(ExpansionsMPQ[j], filename, "base", MPQ_OPEN_READ_ONLY)) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } } }
void LoadLocaleMPQFiles(int const locale) { char filename[512]; //Locale-xxXX.MPQ sprintf(filename,"%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); printf("Loading %s\n", filename); if(!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &localeMPQ[0])) { printf("%i\n", GetLastError()); assert(false && "\nLoad of MPQ failed"); } for(int i = 0; i < PATCH_REV_COUNT; ++i) { bool result; if(patchRev[i] >= 13914) { GetMPQFileName(filename, patchRev[i], input_path, langs[locale]); result = SFileOpenPatchArchive(localeMPQ[0], filename, NULL, MPQ_OPEN_READ_ONLY); } else { GetMPQFileName(filename, patchRev[i], input_path); result = SFileOpenPatchArchive(localeMPQ[0], filename, langs[locale], MPQ_OPEN_READ_ONLY); } if(!result) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if(!SFileIsPatchedArchive(localeMPQ[0])) assert(false && "An error occured"); //Others for(int i = 0; i < PATCH_REV_COUNT; ++i) { GetMPQFileName(filename, patchRev[i], input_path, langs[locale]); printf("Loading %s\n", filename); if(!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &localeMPQ[i+1])) { printf("%i\n", GetLastError()); assert(false && "Load of MPQ failed"); } for(int j = i + 1; j < PATCH_REV_COUNT; ++j) { bool result; if(patchRev[j] >= 13914) { GetMPQFileName(filename, patchRev[j], input_path, langs[locale]); result = SFileOpenPatchArchive(localeMPQ[i+1], filename, NULL, MPQ_OPEN_READ_ONLY); } else { GetMPQFileName(filename, patchRev[j], input_path); result = SFileOpenPatchArchive(localeMPQ[i+1], filename, langs[locale], MPQ_OPEN_READ_ONLY); } if(!result) { printf("%j\n", GetLastError()); assert(false && "Load of MPQ patch failed"); } } if(!SFileIsPatchedArchive(localeMPQ[i+1]) && i != PATCH_REV_COUNT - 1) assert(false && "An error occured"); } }
static DWORD VerifyFile( HANDLE hMpq, const char * szFileName, LPDWORD pdwCrc32, char * pMD5, DWORD dwFlags) { hash_state md5_state; unsigned char * pFileMd5; unsigned char md5[MD5_DIGEST_SIZE]; TFileEntry * pFileEntry; TMPQFile * hf; BYTE Buffer[0x1000]; HANDLE hFile = NULL; DWORD dwVerifyResult = 0; DWORD dwSearchScope = SFILE_OPEN_FROM_MPQ; DWORD dwTotalBytes = 0; DWORD dwBytesRead; DWORD dwCrc32 = 0; // Fix the open type for patched archives if(SFileIsPatchedArchive(hMpq)) dwSearchScope = SFILE_OPEN_PATCHED_FILE; // Attempt to open the file if(SFileOpenFileEx(hMpq, szFileName, dwSearchScope, &hFile)) { // Get the file size hf = (TMPQFile *)hFile; pFileEntry = hf->pFileEntry; dwTotalBytes = SFileGetFileSize(hFile, NULL); // Initialize the CRC32 and MD5 contexts md5_init(&md5_state); dwCrc32 = crc32(0, Z_NULL, 0); // If we have to verify raw data MD5, do it if(dwFlags & SFILE_VERIFY_RAW_MD5) { if(hf->ha->pHeader->dwRawChunkSize != 0) { // Note: we have to open the file from the MPQ where it was open from if(VerifyRawMpqData(hf->ha, pFileEntry->ByteOffset, pFileEntry->dwCmpSize) != ERROR_SUCCESS) dwVerifyResult |= VERIFY_FILE_RAW_MD5_ERROR; dwVerifyResult |= VERIFY_FILE_HAS_RAW_MD5; } } // Also turn on sector checksum verification if(dwFlags & SFILE_VERIFY_SECTOR_CRC) hf->bCheckSectorCRCs = true; // Go through entire file and update both CRC32 and MD5 for(;;) { // Read data from file SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); if(dwBytesRead == 0) { if(GetLastError() == ERROR_CHECKSUM_ERROR) dwVerifyResult |= VERIFY_FILE_SECTOR_CRC_ERROR; break; } // Update CRC32 value if(dwFlags & SFILE_VERIFY_FILE_CRC) dwCrc32 = crc32(dwCrc32, Buffer, dwBytesRead); // Update MD5 value if(dwFlags & SFILE_VERIFY_FILE_MD5) md5_process(&md5_state, Buffer, dwBytesRead); // Decrement the total size dwTotalBytes -= dwBytesRead; } // If the file has sector checksums, indicate it in the flags if(dwFlags & SFILE_VERIFY_SECTOR_CRC) { if((hf->pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->SectorChksums != NULL && hf->SectorChksums[0] != 0) dwVerifyResult |= VERIFY_FILE_HAS_SECTOR_CRC; } // Check if the entire file has been read // No point in checking CRC32 and MD5 if not // Skip checksum checks if the file has patches if(dwTotalBytes == 0) { // Check CRC32 and MD5 only if there is no patches if(hf->hfPatchFile == NULL) { // Check if the CRC32 matches. if(dwFlags & SFILE_VERIFY_FILE_CRC) { // Only check the CRC32 if it is valid if(pFileEntry->dwCrc32 != 0) { dwVerifyResult |= VERIFY_FILE_HAS_CHECKSUM; if(dwCrc32 != pFileEntry->dwCrc32) dwVerifyResult |= VERIFY_FILE_CHECKSUM_ERROR; } } // Check if MD5 matches if(dwFlags & SFILE_VERIFY_FILE_MD5) { // Patch files have their MD5 saved in the patch info pFileMd5 = (hf->pPatchInfo != NULL) ? hf->pPatchInfo->md5 : pFileEntry->md5; md5_done(&md5_state, md5); // Only check the MD5 if it is valid if(is_valid_md5(pFileMd5)) { dwVerifyResult |= VERIFY_FILE_HAS_MD5; if(memcmp(md5, pFileMd5, MD5_DIGEST_SIZE)) dwVerifyResult |= VERIFY_FILE_MD5_ERROR; } } } else { // Patched files are MD5-checked automatically dwVerifyResult |= VERIFY_FILE_HAS_MD5; } } else { dwVerifyResult |= VERIFY_READ_ERROR; } SFileCloseFile(hFile); } else { // Remember that the file couldn't be open dwVerifyResult |= VERIFY_OPEN_ERROR; } // If the caller required CRC32 and/or MD5, give it to him if(pdwCrc32 != NULL) *pdwCrc32 = dwCrc32; if(pMD5 != NULL) memcpy(pMD5, md5, MD5_DIGEST_SIZE); return dwVerifyResult; }
DWORD WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags) { hash_state md5_state; unsigned char md5[MD5_DIGEST_SIZE]; TFileEntry * pFileEntry; TMPQFile * hf; BYTE Buffer[0x1000]; HANDLE hFile = NULL; DWORD dwVerifyResult = 0; DWORD dwSearchScope = SFILE_OPEN_FROM_MPQ; DWORD dwTotalBytes = 0; DWORD dwBytesRead; DWORD dwCrc32; // Fix the open type for patched archives if (SFileIsPatchedArchive(hMpq)) dwSearchScope = SFILE_OPEN_PATCHED_FILE; // Attempt to open the file if (SFileOpenFileEx(hMpq, szFileName, dwSearchScope, &hFile)) { // Get the file size hf = (TMPQFile *)hFile; pFileEntry = hf->pFileEntry; dwTotalBytes = SFileGetFileSize(hFile, NULL); // Initialize the CRC32 and MD5 contexts md5_init(&md5_state); dwCrc32 = crc32(0, Z_NULL, 0); // Also turn on sector checksum verification hf->bCheckSectorCRCs = true; // Go through entire file and update both CRC32 and MD5 for (;;) { // Read data from file SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); if (dwBytesRead == 0) { if (GetLastError() == ERROR_CHECKSUM_ERROR) dwVerifyResult |= VERIFY_SECTOR_CHECKSUM_ERROR; break; } // Update CRC32 value if (dwFlags & MPQ_ATTRIBUTE_CRC32) dwCrc32 = crc32(dwCrc32, Buffer, dwBytesRead); // Update MD5 value if (dwFlags & MPQ_ATTRIBUTE_MD5) md5_process(&md5_state, Buffer, dwBytesRead); // Decrement the total size dwTotalBytes -= dwBytesRead; } // If the file has sector checksums, indicate it in the flags if ((hf->pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->SectorChksums != NULL && hf->SectorChksums[0] != 0) dwVerifyResult |= VERIFY_SECTORS_HAVE_CHECKSUM; // Check if the entire file has been read // No point in checking CRC32 and MD5 if not // Skip checksum checks if the file has patches if (dwTotalBytes == 0) { // Check CRC32 and MD5 only if there is no patches if (hf->hfPatchFile == NULL) { // Check if the CRC32 matches. if (dwFlags & MPQ_ATTRIBUTE_CRC32) { // Some files may have their CRC zeroed if (pFileEntry->dwCrc32 != 0) { dwVerifyResult |= VERIFY_FILE_HAS_CHECKSUM; if (dwCrc32 != pFileEntry->dwCrc32) dwVerifyResult |= VERIFY_FILE_CHECKSUM_ERROR; } } // Check if MD5 matches if (dwFlags & MPQ_ATTRIBUTE_MD5) { md5_done(&md5_state, md5); // Some files have the MD5 zeroed. Don't check MD5 in that case if (is_valid_md5(pFileEntry->md5)) { dwVerifyResult |= VERIFY_FILE_HAS_MD5; if (memcmp(md5, pFileEntry->md5, MD5_DIGEST_SIZE)) dwVerifyResult |= VERIFY_FILE_MD5_ERROR; } } } else { // Patched files are MD5-checked automatically dwVerifyResult |= VERIFY_FILE_HAS_MD5; } } else { dwVerifyResult |= VERIFY_READ_ERROR; } SFileCloseFile(hFile); } else { // Remember that the file couldn't be open dwVerifyResult |= VERIFY_OPEN_ERROR; } return dwVerifyResult; }