static int ApplyMpqPatch(
    TMPQFile * hf,
    TPatchHeader * pPatchHeader)
{
    unsigned char md5_digest[MD5_DIGEST_SIZE];
    hash_state md5_state;
    int nError = ERROR_SUCCESS;

    // Verify the original file before patching
    if(pPatchHeader->dwSizeBeforePatch != 0)
    {
        md5_init(&md5_state);
        md5_process(&md5_state, hf->pbFileData, hf->cbFileData);
        md5_done(&md5_state, md5_digest);
        if(memcmp(pPatchHeader->md5_before_patch, md5_digest, MD5_DIGEST_SIZE))
            nError = ERROR_FILE_CORRUPT;
    }

    // Apply the patch
    if(nError == ERROR_SUCCESS)
    {
        switch(pPatchHeader->dwPatchType)
        {
            case 0x59504f43:    // 'COPY'
                nError = ApplyMpqPatch_COPY(hf, pPatchHeader);
                break;

            case 0x30445342:    // 'BSD0'
                nError = ApplyMpqPatch_BSD0(hf, pPatchHeader);
                break;

            default:
                nError = ERROR_FILE_CORRUPT;
                break;
        }
    }

    // Verify MD5 after patch
    if(nError == ERROR_SUCCESS && pPatchHeader->dwSizeAfterPatch != 0)
    {
        // Verify the patched file
        md5_init(&md5_state);
        md5_process(&md5_state, hf->pbFileData, hf->cbFileData);
        md5_done(&md5_state, md5_digest);
        if(memcmp(pPatchHeader->md5_after_patch, md5_digest, MD5_DIGEST_SIZE))
            nError = ERROR_FILE_CORRUPT;
    }

    return nError;
}
static int ApplyMpqPatch(
    TMPQFile * hf,
    TPatchHeader * pPatchHeader)
{
    int nError = ERROR_SUCCESS;

    // Verify the original file before patching
    if(pPatchHeader->dwSizeBeforePatch != 0)
    {
        if(!VerifyDataBlockHash(hf->pbFileData, hf->cbFileData, pPatchHeader->md5_before_patch))
            nError = ERROR_FILE_CORRUPT;
    }

    // Apply the patch
    if(nError == ERROR_SUCCESS)
    {
        switch(pPatchHeader->dwPatchType)
        {
            case 0x59504f43:    // 'COPY'
                nError = ApplyMpqPatch_COPY(hf, pPatchHeader);
                break;

            case 0x30445342:    // 'BSD0'
                nError = ApplyMpqPatch_BSD0(hf, pPatchHeader);
                break;

            default:
                nError = ERROR_FILE_CORRUPT;
                break;
        }
    }

    // Verify MD5 after patch
    if(nError == ERROR_SUCCESS && pPatchHeader->dwSizeAfterPatch != 0)
    {
        // Verify the patched file
        if(!VerifyDataBlockHash(hf->pbFileData, hf->cbFileData, pPatchHeader->md5_after_patch))
            nError = ERROR_FILE_CORRUPT;
    }

    return nError;
}