Commit 8695a698 authored by Conor McCarthy's avatar Conor McCarthy Committed by Alexandre Julliard

mspatcha: Partially implement ApplyPatchToFileW and related functions.

This can patch non-executables and 64-bit executable files, but patching of 32-bit executables is not supported. They are subject to special processing which alters PE relocations to match with those in the old file to improve compression. To reverse this, the meaning of the decoding data must be interpreted. Details, including where to find that data in the patch file, are included in pa19.c. Interleaved decompression of large files is also not supported. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=12501Signed-off-by: 's avatarConor McCarthy <conor.mccarthy.444@gmail.com> Signed-off-by: 's avatarHans Leidekker <hans@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 2aa49468
......@@ -2,6 +2,8 @@ MODULE = mspatcha.dll
IMPORTLIB = mspatcha
C_SRCS = \
mspatcha_main.c
lzxd_dec.c \
mspatcha_main.c \
pa19.c
RC_SRCS = version.rc
/*
* Copyright 2019 Conor McCarthy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define MAX_NORMAL_WINDOW (8U << 20)
#define MAX_LARGE_WINDOW (32U << 20)
DWORD decode_lzxd_stream(const BYTE *src, const size_t input_size,
BYTE *dst, const size_t output_size,
const size_t predef_size,
DWORD large_window,
PPATCH_PROGRESS_CALLBACK progress_fn,
PVOID progress_ctx);
1 stdcall ApplyPatchToFileA(str str str long)
2 stub ApplyPatchToFileByHandles
3 stub ApplyPatchToFileByHandlesEx
4 stub ApplyPatchToFileExA
5 stub ApplyPatchToFileExW
6 stdcall ApplyPatchToFileW(wstr wstr wstr long)
7 stdcall GetFilePatchSignatureA(str long ptr long ptr long ptr long ptr)
8 stub GetFilePatchSignatureByHandle
9 stdcall GetFilePatchSignatureW(wstr long ptr long ptr long ptr long ptr)
10 stub TestApplyPatchToFileA
11 stub TestApplyPatchToFileByHandles
12 stub TestApplyPatchToFileW
@ stdcall ApplyPatchToFileA(str str str long)
@ stdcall ApplyPatchToFileByBuffers(ptr long ptr long ptr long ptr ptr long ptr ptr)
@ stdcall ApplyPatchToFileByHandles(ptr ptr ptr long)
@ stdcall ApplyPatchToFileByHandlesEx(ptr ptr ptr long ptr ptr)
@ stdcall ApplyPatchToFileExA(str str str long ptr ptr)
@ stdcall ApplyPatchToFileExW(wstr wstr wstr long ptr ptr)
@ stdcall ApplyPatchToFileW(wstr wstr wstr long)
@ stub GetFilePatchSignatureA
@ stub GetFilePatchSignatureByBuffer
@ stub GetFilePatchSignatureByHandle
@ stub GetFilePatchSignatureW
@ stub NormalizeFileForPatchSignature
@ stdcall TestApplyPatchToFileA(str str long)
@ stdcall TestApplyPatchToFileByBuffers(ptr long ptr long ptr long)
@ stdcall TestApplyPatchToFileByHandles(ptr ptr long)
@ stdcall TestApplyPatchToFileW(wstr wstr long)
......@@ -2,6 +2,7 @@
* PatchAPI
*
* Copyright 2011 David Hedberg for CodeWeavers
* Copyright 2019 Conor McCarthy (implementations)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -16,6 +17,16 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* TODO
* - Special processing of 32-bit executables is not supported, so this
* version cannot patch 32-bit .exe and .dll files. See pa19.c for details.
* - Implement interleaved decoding when PATCH_OPTION_INTERLEAVE_FILES was
* used or the old file exceeds the lzxd window size.
* - APPLY_OPTION_FAIL_IF_CLOSE is ignored. Normalization of 32-bit PE files
* is required for checking this.
* - GetFilePatchSignature* and NormalizeFileForPatchSignature require a
* solution to the above 32-bit exe problem.
*/
#include "config.h"
......@@ -28,6 +39,8 @@
#include "patchapi.h"
#include "wine/debug.h"
#include "pa19.h"
WINE_DEFAULT_DEBUG_CHANNEL(mspatcha);
/*****************************************************
......@@ -49,79 +62,165 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return TRUE;
}
static inline WCHAR *strdupAW( const char *src )
static WCHAR *strdupAW(const char *src)
{
WCHAR *dst = NULL;
if (src)
{
int len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 );
if ((dst = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len );
int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
if ((dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
}
return dst;
}
/*****************************************************
* ApplyPatchToFileA (MSPATCHA.1)
* TestApplyPatchToFileA (MSPATCHA.@)
*/
BOOL WINAPI ApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags)
BOOL WINAPI TestApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, ULONG apply_flags)
{
BOOL ret;
WCHAR *patch_fileW, *new_fileW, *old_fileW = NULL;
WCHAR *patch_fileW, *old_fileW = NULL;
if (!(patch_fileW = strdupAW( patch_file ))) return FALSE;
if (old_file && !(old_fileW = strdupAW( old_file )))
{
HeapFree( GetProcessHeap(), 0, patch_fileW );
return FALSE;
}
if (!(new_fileW = strdupAW( new_file )))
if (!(patch_fileW = strdupAW(patch_file))) return FALSE;
if (old_file && !(old_fileW = strdupAW(old_file)))
{
HeapFree( GetProcessHeap(), 0, patch_fileW );
HeapFree( GetProcessHeap(), 0, old_fileW );
HeapFree(GetProcessHeap(), 0, patch_fileW);
return FALSE;
}
ret = ApplyPatchToFileW( patch_fileW, old_fileW, new_fileW, apply_flags );
HeapFree( GetProcessHeap(), 0, patch_fileW );
HeapFree( GetProcessHeap(), 0, old_fileW );
HeapFree( GetProcessHeap(), 0, new_fileW );
ret = apply_patch_to_file(patch_fileW, old_fileW, NULL, apply_flags, NULL, NULL, TRUE);
HeapFree(GetProcessHeap(), 0, patch_fileW);
HeapFree(GetProcessHeap(), 0, old_fileW);
return ret;
}
BOOL WINAPI TestApplyPatchToFileW(LPCWSTR patch_file_name, LPCWSTR old_file_name, ULONG apply_option_flags)
{
return apply_patch_to_file(patch_file_name, old_file_name, NULL, apply_option_flags, NULL, NULL, TRUE);
}
BOOL WINAPI TestApplyPatchToFileByHandles(HANDLE patch_file_hndl, HANDLE old_file_hndl, ULONG apply_option_flags)
{
return apply_patch_to_file_by_handles(patch_file_hndl, old_file_hndl, NULL,
apply_option_flags, NULL, NULL, TRUE);
}
BOOL WINAPI TestApplyPatchToFileByBuffers(BYTE *patch_file_buf, ULONG patch_file_size,
BYTE *old_file_buf, ULONG old_file_size,
ULONG* new_file_size,
ULONG apply_option_flags)
{
/* NOTE: windows preserves last error on success for this function, but no apps are known to depend on it */
DWORD err = apply_patch_to_file_by_buffers(patch_file_buf, patch_file_size,
old_file_buf, old_file_size,
NULL, 0, new_file_size, NULL,
apply_option_flags,
NULL, NULL,
TRUE);
SetLastError(err);
return err == ERROR_SUCCESS;
}
/*****************************************************
* ApplyPatchToFileW (MSPATCHA.6)
* ApplyPatchToFileExA (MSPATCHA.@)
*/
BOOL WINAPI ApplyPatchToFileW(LPCWSTR patch_file, LPCWSTR old_file, LPCWSTR new_file, ULONG apply_flags)
BOOL WINAPI ApplyPatchToFileExA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags,
PPATCH_PROGRESS_CALLBACK progress_fn, PVOID progress_ctx)
{
FIXME("stub - %s, %s, %s, %08x\n", debugstr_w(patch_file), debugstr_w(old_file),
debugstr_w(new_file), apply_flags);
BOOL ret = FALSE;
WCHAR *patch_fileW, *new_fileW, *old_fileW = NULL;
if (!(patch_fileW = strdupAW(patch_file))) return FALSE;
if (old_file && !(old_fileW = strdupAW(old_file)))
goto free_wstrs;
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
if (!(new_fileW = strdupAW(new_file)))
goto free_wstrs;
ret = apply_patch_to_file(patch_fileW, old_fileW, new_fileW, apply_flags, progress_fn, progress_ctx, FALSE);
HeapFree(GetProcessHeap(), 0, new_fileW);
free_wstrs:
HeapFree(GetProcessHeap(), 0, patch_fileW);
HeapFree(GetProcessHeap(), 0, old_fileW);
return ret;
}
/*****************************************************
* GetFilePatchSignatureA (MSPATCHA.7)
* ApplyPatchToFileA (MSPATCHA.@)
*/
BOOL WINAPI GetFilePatchSignatureA(LPCSTR filename, ULONG flags, PVOID data, ULONG ignore_range_count,
PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPSTR buffer)
BOOL WINAPI ApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags)
{
return ApplyPatchToFileExA(patch_file, old_file, new_file, apply_flags, NULL, NULL);
}
/*****************************************************
* ApplyPatchToFileW (MSPATCHA.@)
*/
BOOL WINAPI ApplyPatchToFileW(LPCWSTR patch_file_name, LPCWSTR old_file_name, LPCWSTR new_file_name,
ULONG apply_option_flags)
{
return apply_patch_to_file(patch_file_name, old_file_name, new_file_name, apply_option_flags,
NULL, NULL, FALSE);
}
/*****************************************************
* ApplyPatchToFileByHandles (MSPATCHA.@)
*/
BOOL WINAPI ApplyPatchToFileByHandles(HANDLE patch_file_hndl, HANDLE old_file_hndl, HANDLE new_file_hndl,
ULONG apply_option_flags)
{
return apply_patch_to_file_by_handles(patch_file_hndl, old_file_hndl, new_file_hndl,
apply_option_flags, NULL, NULL, FALSE);
}
/*****************************************************
* ApplyPatchToFileExW (MSPATCHA.@)
*/
BOOL WINAPI ApplyPatchToFileExW(LPCWSTR patch_file_name, LPCWSTR old_file_name, LPCWSTR new_file_name,
ULONG apply_option_flags,
PPATCH_PROGRESS_CALLBACK progress_fn, PVOID progress_ctx)
{
return apply_patch_to_file(patch_file_name, old_file_name, new_file_name, apply_option_flags,
progress_fn, progress_ctx, FALSE);
}
/*****************************************************
* ApplyPatchToFileByHandlesEx (MSPATCHA.@)
*/
BOOL WINAPI ApplyPatchToFileByHandlesEx(HANDLE patch_file_hndl, HANDLE old_file_hndl, HANDLE new_file_hndl,
ULONG apply_option_flags,
PPATCH_PROGRESS_CALLBACK progress_fn,
PVOID progress_ctx)
{
FIXME("stub - %s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_a(filename), flags, data,
ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
return apply_patch_to_file_by_handles(patch_file_hndl, old_file_hndl, new_file_hndl,
apply_option_flags, progress_fn, progress_ctx, FALSE);
}
/*****************************************************
* GetFilePatchSignatureW (MSPATCHA.9)
* ApplyPatchToFileByBuffers (MSPATCHA.@)
*/
BOOL WINAPI GetFilePatchSignatureW(LPCWSTR filename, ULONG flags, PVOID data, ULONG ignore_range_count,
PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPWSTR buffer)
BOOL WINAPI ApplyPatchToFileByBuffers(PBYTE patch_file_view, ULONG patch_file_size,
PBYTE old_file_view, ULONG old_file_size,
PBYTE* new_file_buf, ULONG new_file_buf_size, ULONG* new_file_size,
FILETIME* new_file_time,
ULONG apply_option_flags,
PPATCH_PROGRESS_CALLBACK progress_fn, PVOID progress_ctx)
{
FIXME("stub - %s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_w(filename), flags, data,
ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
/* NOTE: windows preserves last error on success for this function, but no apps are known to depend on it */
DWORD err = apply_patch_to_file_by_buffers(patch_file_view, patch_file_size,
old_file_view, old_file_size,
new_file_buf, new_file_buf_size, new_file_size, new_file_time,
apply_option_flags,
progress_fn, progress_ctx,
FALSE);
SetLastError(err);
return err == ERROR_SUCCESS;
}
/*
* PatchAPI PA19 file format handlers
*
* Copyright 2019 Conor McCarthy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
DWORD apply_patch_to_file_by_buffers(const BYTE *patch_file_view, const ULONG patch_file_size,
const BYTE *old_file_view, ULONG old_file_size,
BYTE **new_file_buf, const ULONG new_file_buf_size, ULONG *new_file_size,
FILETIME *new_file_time,
const ULONG apply_option_flags,
PATCH_PROGRESS_CALLBACK *progress_fn, void *progress_ctx,
const BOOL test_header_only);
BOOL apply_patch_to_file_by_handles(HANDLE patch_file_hndl, HANDLE old_file_hndl, HANDLE new_file_hndl,
const ULONG apply_option_flags,
PATCH_PROGRESS_CALLBACK *progress_fn, void *progress_ctx,
const BOOL test_header_only);
BOOL apply_patch_to_file(LPCWSTR patch_file_name, LPCWSTR old_file_name, LPCWSTR new_file_name,
const ULONG apply_option_flags,
PATCH_PROGRESS_CALLBACK *progress_fn, void *progress_ctx,
const BOOL test_header_only);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment