bool IsPatchData(const void * pvData, DWORD cbData, LPDWORD pdwPatchedFileSize) { TPatchHeader * pPatchHeader = (TPatchHeader *)pvData; BLIZZARD_BSDIFF40_FILE DiffFile; DWORD dwPatchType; if(cbData >= sizeof(TPatchHeader) + sizeof(BLIZZARD_BSDIFF40_FILE)) { dwPatchType = BSWAP_INT32_UNSIGNED(pPatchHeader->dwPatchType); if(dwPatchType == 0x30445342) { // Give the caller the patch file size if(pdwPatchedFileSize != NULL) { Decompress_RLE((LPBYTE)&DiffFile, sizeof(BLIZZARD_BSDIFF40_FILE), (LPBYTE)(pPatchHeader + 1), sizeof(BLIZZARD_BSDIFF40_FILE)); DiffFile.NewFileSize = BSWAP_INT64_UNSIGNED(DiffFile.NewFileSize); *pdwPatchedFileSize = (DWORD)DiffFile.NewFileSize; return true; } } } return false; }
static int ApplyFilePatch_BSD0( TMPQPatcher * pPatcher, PMPQ_PATCH_HEADER pFullPatch, LPBYTE pbTarget, LPBYTE pbSource) { PBLIZZARD_BSDIFF40_FILE pBsdiff; PBSDIFF_CTRL_BLOCK pCtrlBlock; LPBYTE pbPatchData = (LPBYTE)(pFullPatch + 1); LPBYTE pDataBlock; LPBYTE pExtraBlock; LPBYTE pbOldData = pbSource; LPBYTE pbNewData = pbTarget; DWORD dwCombineSize; DWORD dwNewOffset = 0; // Current position to patch DWORD dwOldOffset = 0; // Current source position DWORD dwNewSize; // Patched file size DWORD dwOldSize = pPatcher->cbFileData; // File size before patch // Get pointer to the patch header // Format of BSDIFF header corresponds to original BSDIFF, which is: // 0000 8 bytes signature "BSDIFF40" // 0008 8 bytes size of the control block // 0010 8 bytes size of the data block // 0018 8 bytes new size of the patched file pBsdiff = (PBLIZZARD_BSDIFF40_FILE)pbPatchData; pbPatchData += sizeof(BLIZZARD_BSDIFF40_FILE); // Get pointer to the 32-bit BSDIFF control block // The control block follows immediately after the BSDIFF header // and consists of three 32-bit integers // 0000 4 bytes Length to copy from the BSDIFF data block the new file // 0004 4 bytes Length to copy from the BSDIFF extra block // 0008 4 bytes Size to increment source file offset pCtrlBlock = (PBSDIFF_CTRL_BLOCK)pbPatchData; pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->CtrlBlockSize); // Get the pointer to the data block pDataBlock = (LPBYTE)pbPatchData; pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->DataBlockSize); // Get the pointer to the extra block pExtraBlock = (LPBYTE)pbPatchData; dwNewSize = (DWORD)BSWAP_INT64_UNSIGNED(pBsdiff->NewFileSize); // Now patch the file while(dwNewOffset < dwNewSize) { DWORD dwAddDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwAddDataLength); DWORD dwMovDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwMovDataLength); DWORD dwOldMoveLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwOldMoveLength); DWORD i; // Sanity check if((dwNewOffset + dwAddDataLength) > dwNewSize) return ERROR_FILE_CORRUPT; // Read the diff string to the target buffer memcpy(pbNewData + dwNewOffset, pDataBlock, dwAddDataLength); pDataBlock += dwAddDataLength; // Get the longest block that we can combine dwCombineSize = ((dwOldOffset + dwAddDataLength) >= dwOldSize) ? (dwOldSize - dwOldOffset) : dwAddDataLength; if((dwNewOffset + dwCombineSize) > dwNewSize || (dwNewOffset + dwCombineSize) < dwNewOffset) return ERROR_FILE_CORRUPT; // Now combine the patch data with the original file for(i = 0; i < dwCombineSize; i++) pbNewData[dwNewOffset + i] = pbNewData[dwNewOffset + i] + pbOldData[dwOldOffset + i]; // Move the offsets dwNewOffset += dwAddDataLength; dwOldOffset += dwAddDataLength; // Sanity check if((dwNewOffset + dwMovDataLength) > dwNewSize) return ERROR_FILE_CORRUPT; // Copy the data from the extra block in BSDIFF patch memcpy(pbNewData + dwNewOffset, pExtraBlock, dwMovDataLength); pExtraBlock += dwMovDataLength; dwNewOffset += dwMovDataLength; // Move the old offset if(dwOldMoveLength & 0x80000000) dwOldMoveLength = 0x80000000 - dwOldMoveLength; dwOldOffset += dwOldMoveLength; pCtrlBlock++; } // The size after patch must match if(dwNewOffset != pFullPatch->dwSizeAfterPatch) return ERROR_FILE_CORRUPT; // Update the new data size pPatcher->cbFileData = dwNewOffset; return ERROR_SUCCESS; }
static int ApplyMpqPatch_BSD0( TMPQFile * hf, TPatchHeader * pPatchHeader) { PBLIZZARD_BSDIFF40_FILE pBsdiff; LPDWORD pCtrlBlock; LPBYTE pbPatchData = (LPBYTE)pPatchHeader + sizeof(TPatchHeader); LPBYTE pDataBlock; LPBYTE pExtraBlock; LPBYTE pbNewData = NULL; LPBYTE pbOldData = (LPBYTE)hf->pbFileData; DWORD dwNewOffset = 0; // Current position to patch DWORD dwOldOffset = 0; // Current source position DWORD dwNewSize; // Patched file size DWORD dwOldSize = hf->cbFileData; // File size before patch // Get pointer to the patch header // Format of BSDIFF header corresponds to original BSDIFF, which is: // 0000 8 bytes signature "BSDIFF40" // 0008 8 bytes size of the control block // 0010 8 bytes size of the data block // 0018 8 bytes new size of the patched file pBsdiff = (PBLIZZARD_BSDIFF40_FILE)pbPatchData; pbPatchData += sizeof(BLIZZARD_BSDIFF40_FILE); // Get pointer to the 32-bit BSDIFF control block // The control block follows immediately after the BSDIFF header // and consists of three 32-bit integers // 0000 4 bytes Length to copy from the BSDIFF data block the new file // 0004 4 bytes Length to copy from the BSDIFF extra block // 0008 4 bytes Size to increment source file offset pCtrlBlock = (LPDWORD)pbPatchData; pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->CtrlBlockSize); // Get the pointer to the data block pDataBlock = (LPBYTE)pbPatchData; pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->DataBlockSize); // Get the pointer to the extra block pExtraBlock = (LPBYTE)pbPatchData; dwNewSize = (DWORD)BSWAP_INT64_UNSIGNED(pBsdiff->NewFileSize); // Allocate new buffer pbNewData = ALLOCMEM(BYTE, dwNewSize); if(pbNewData == NULL) return ERROR_NOT_ENOUGH_MEMORY; // Now patch the file while(dwNewOffset < dwNewSize) { DWORD dwAddDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock[0]); DWORD dwMovDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock[1]); DWORD dwOldMoveLength = BSWAP_INT32_UNSIGNED(pCtrlBlock[2]); DWORD i; // Sanity check if((dwNewOffset + dwAddDataLength) > dwNewSize) { FREEMEM(pbNewData); return ERROR_FILE_CORRUPT; } // Read the diff string to the target buffer memcpy(pbNewData + dwNewOffset, pDataBlock, dwAddDataLength); pDataBlock += dwAddDataLength; // Now combine the patch data with the original file for(i = 0; i < dwAddDataLength; i++) { if(dwOldOffset < dwOldSize) pbNewData[dwNewOffset] = pbNewData[dwNewOffset] + pbOldData[dwOldOffset]; dwNewOffset++; dwOldOffset++; } // Sanity check if((dwNewOffset + dwMovDataLength) > dwNewSize) { FREEMEM(pbNewData); return ERROR_FILE_CORRUPT; } // Copy the data from the extra block in BSDIFF patch memcpy(pbNewData + dwNewOffset, pExtraBlock, dwMovDataLength); pExtraBlock += dwMovDataLength; dwNewOffset += dwMovDataLength; // Move the old offset if(dwOldMoveLength & 0x80000000) dwOldMoveLength = 0x80000000 - dwOldMoveLength; dwOldOffset += dwOldMoveLength; pCtrlBlock += 3; } // Free the old file data FREEMEM(hf->pbFileData); // Put the new data to the fil structure hf->pbFileData = pbNewData; hf->cbFileData = dwNewSize; return ERROR_SUCCESS; }
static int ApplyFilePatch_BSD0( TMPQPatcher * pPatcher, PMPQ_PATCH_HEADER pFullPatch, unsigned char * pbTarget, unsigned char * pbSource) { PBLIZZARD_BSDIFF40_FILE pBsdiff; PBSDIFF_CTRL_BLOCK pCtrlBlock; unsigned char * pbPatchData = (unsigned char *)(pFullPatch + 1); unsigned char * pDataBlock; unsigned char * pExtraBlock; unsigned char * pbOldData = pbSource; unsigned char * pbNewData = pbTarget; uint32_t dwCombineSize; uint32_t dwNewOffset = 0; /* Current position to patch */ uint32_t dwOldOffset = 0; /* Current source position */ uint32_t dwNewSize; /* Patched file size */ uint32_t dwOldSize = pPatcher->cbFileData; /* File size before patch */ /* Get pointer to the patch header */ /* Format of BSDIFF header corresponds to original BSDIFF, which is: */ /* 0000 8 bytes signature "BSDIFF40" */ /* 0008 8 bytes size of the control block */ /* 0010 8 bytes size of the data block */ /* 0018 8 bytes new size of the patched file */ pBsdiff = (PBLIZZARD_BSDIFF40_FILE)pbPatchData; pbPatchData += sizeof(BLIZZARD_BSDIFF40_FILE); /* Get pointer to the 32-bit BSDIFF control block */ /* The control block follows immediately after the BSDIFF header */ /* and consists of three 32-bit integers */ /* 0000 4 bytes Length to copy from the BSDIFF data block the new file */ /* 0004 4 bytes Length to copy from the BSDIFF extra block */ /* 0008 4 bytes Size to increment source file offset */ pCtrlBlock = (PBSDIFF_CTRL_BLOCK)pbPatchData; pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->CtrlBlockSize); /* Get the pointer to the data block */ pDataBlock = (unsigned char *)pbPatchData; pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->DataBlockSize); /* Get the pointer to the extra block */ pExtraBlock = (unsigned char *)pbPatchData; dwNewSize = (uint32_t)BSWAP_INT64_UNSIGNED(pBsdiff->NewFileSize); /* Now patch the file */ while(dwNewOffset < dwNewSize) { uint32_t dwAddDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwAddDataLength); uint32_t dwMovDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwMovDataLength); uint32_t dwOldMoveLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwOldMoveLength); uint32_t i; /* Sanity check */ if((dwNewOffset + dwAddDataLength) > dwNewSize) return ERROR_FILE_CORRUPT; /* Read the diff string to the target buffer */ memcpy(pbNewData + dwNewOffset, pDataBlock, dwAddDataLength); pDataBlock += dwAddDataLength; /* Get the longest block that we can combine */ dwCombineSize = ((dwOldOffset + dwAddDataLength) >= dwOldSize) ? (dwOldSize - dwOldOffset) : dwAddDataLength; /* Now combine the patch data with the original file */ for(i = 0; i < dwCombineSize; i++) pbNewData[dwNewOffset + i] = pbNewData[dwNewOffset + i] + pbOldData[dwOldOffset + i]; /* Move the offsets */ dwNewOffset += dwAddDataLength; dwOldOffset += dwAddDataLength; /* Sanity check */ if((dwNewOffset + dwMovDataLength) > dwNewSize) return ERROR_FILE_CORRUPT; /* Copy the data from the extra block in BSDIFF patch */ memcpy(pbNewData + dwNewOffset, pExtraBlock, dwMovDataLength); pExtraBlock += dwMovDataLength; dwNewOffset += dwMovDataLength; /* Move the old offset */ if(dwOldMoveLength & 0x80000000) dwOldMoveLength = 0x80000000 - dwOldMoveLength; dwOldOffset += dwOldMoveLength; pCtrlBlock++; } /* The size after patch must match */ if(dwNewOffset != pFullPatch->dwSizeAfterPatch) return ERROR_FILE_CORRUPT; /* Update the new data size */ pPatcher->cbFileData = dwNewOffset; return ERROR_SUCCESS; }