[MSPTCHA_APITEST] Initial tests.
[reactos.git] / modules / rostests / apitests / mspatcha / mspatcha.c
1 /*
2 * PROJECT: mspatcha_apitest
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Tests for mspatcha
5 * COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8 #define WIN32_NO_STATUS
9 #include <windows.h>
10
11 #include "wine/test.h"
12 #include <patchapi.h>
13
14
15 /* Headers created with ExtractPatchHeaderToFileA */
16 unsigned char in1_bin[8] =
17 {
18 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, /* testdata */
19 };
20 unsigned char out1_bin[26] =
21 {
22 0x74, 0x65, 0x73, 0x74, 0x20, 0x44, 0x61, 0x74, 0x61, 0x0d, 0x0a, 0x57, 0x69, 0x74, 0x68, 0x20, /* test Data..With */
23 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, /* some extra */
24 };
25 unsigned char patch1_bin[75] =
26 {
27 0x50, 0x41, 0x31, 0x39, 0x01, 0x00, 0xc4, 0x00, 0x4e, 0x28, 0xb3, 0x5b, 0x9a, 0x08, 0xd1, 0x51, /* PA19....N(.[...Q */
28 0xf6, 0x01, 0xd2, 0x5e, 0x36, 0xe5, 0x99, 0x00, 0x00, 0x80, 0xac, 0x2a, 0x00, 0x00, 0x30, 0xa0, /* ...^6......*..0. */
29 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, /* .............tes */
30 0x74, 0x20, 0x44, 0x61, 0x74, 0x61, 0x0d, 0x0a, 0x57, 0x69, 0x74, 0x68, 0x20, 0x73, 0x6f, 0x6d, /* t Data..With som */
31 0x65, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0xa7, 0x19, 0x4a, 0x68, /* e extra..Jh */
32 };
33 unsigned char patch1_header_bin[31] =
34 {
35 0x50, 0x41, 0x31, 0x39, 0x01, 0x00, 0xc4, 0x00, 0x4e, 0x28, 0xb3, 0x5b, 0x9a, 0x08, 0xd1, 0x51, /* PA19....N(.[...Q */
36 0xf6, 0x01, 0xd2, 0x5e, 0x36, 0xe5, 0x99, 0x00, 0x00, 0x80, 0xac, 0xe9, 0xf0, 0x53, 0xf7, /* ...^6........S. */
37 };
38
39 unsigned char in2_bin[25] =
40 {
41 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xaa, /* ........"3DUfw.. */
42 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, /* ......... */
43 };
44 unsigned char out2_bin[25] =
45 {
46 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xbb, /* ........"3DUfw.. */
47 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbb, 0x00, /* ......... */
48 };
49 unsigned char patch2_bin[75] =
50 {
51 0x50, 0x41, 0x31, 0x39, 0x01, 0x00, 0xc4, 0x00, 0x62, 0x35, 0xb3, 0x5b, 0x99, 0xfa, 0xa0, 0x8a, /* PA19....b5.[.... */
52 0x02, 0x01, 0x80, 0x1d, 0xc2, 0x54, 0xfc, 0x00, 0x00, 0x80, 0xac, 0x2a, 0x00, 0x00, 0x30, 0x90, /* .....T.....*..0. */
53 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, /* ................ */
54 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xbb, 0x00, 0xbb, 0x00, /* ....."3DUfw..... */
55 0xbb, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0x00, 0x14, 0x06, 0xeb, 0x61, /* ..........a */
56 };
57 unsigned char patch2_header_bin[31] =
58 {
59 0x50, 0x41, 0x31, 0x39, 0x01, 0x00, 0xc4, 0x00, 0x62, 0x35, 0xb3, 0x5b, 0x99, 0xfa, 0xa0, 0x8a, /* PA19....b5.[.... */
60 0x02, 0x01, 0x80, 0x1d, 0xc2, 0x54, 0xfc, 0x00, 0x00, 0x80, 0xac, 0xce, 0x5d, 0x8c, 0xed, /* .....T......].. */
61 };
62
63 /* Minimum output size to trigger compression */
64 unsigned char in3_bin[138] =
65 {
66 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
67 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
68 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
69 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
70 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
71 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
72 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
73 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
74 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* .......... */
75 };
76 unsigned char out3_bin[152] =
77 {
78 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
79 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* ................ */
80 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ................ */
81 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ................ */
82 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ................ */
83 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ................ */
84 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ................ */
85 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ................ */
86 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ................ */
87 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, /* ........ */
88 };
89 unsigned char patch3_bin[88] =
90 {
91 0x50, 0x41, 0x31, 0x39, 0x01, 0x00, 0xc4, 0x00, 0xb1, 0x57, 0xb3, 0x5b, 0x18, 0x81, 0xf9, 0xd8, /* PA19.....W.[.... */
92 0x1d, 0x41, 0x01, 0xce, 0xd9, 0x52, 0x0a, 0xf1, 0x00, 0x00, 0x80, 0xb8, 0x36, 0x00, 0x00, 0x10, /* .A...R......6... */
93 0x82, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x0f, 0x22, 0xff, 0xff, 0x35, 0xd8, /* ........ .."..5. */
94 0xfb, 0x8f, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x03, 0xb7, 0x08, 0xf7, 0x7d, /* ..........!....} */
95 0x7e, 0xdf, 0x40, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x0d, 0x20, 0x7d, 0xbe, /* ~.@L......@.. }. */
96 0xf9, 0xbe, 0x68, 0xf4, 0x1f, 0x45, 0x3e, 0x35, /* ..h..E>5 */
97 };
98 unsigned char patch3_header_bin[32] =
99 {
100 0x50, 0x41, 0x31, 0x39, 0x01, 0x00, 0xc4, 0x00, 0xb1, 0x57, 0xb3, 0x5b, 0x18, 0x81, 0xf9, 0xd8, /* PA19.....W.[.... */
101 0x1d, 0x41, 0x01, 0xce, 0xd9, 0x52, 0x0a, 0xf1, 0x00, 0x00, 0x80, 0xb8, 0xbd, 0xeb, 0x70, 0xdd, /* .A...R........p. */
102 };
103
104 typedef struct _bin_file
105 {
106 unsigned char* data;
107 size_t len;
108 } bin_file;
109
110 typedef struct _patch_data
111 {
112 char* name;
113 bin_file input;
114 char* input_signature;
115 bin_file output;
116 char* output_signature;
117 bin_file patch;
118 bin_file patch_header;
119 } patch_data;
120
121 #define MAKE_BIN(data_) { data_, sizeof(data_) }
122
123 char temp_path[MAX_PATH];
124
125 BOOL extract2(char* filename, const unsigned char* data, size_t len)
126 {
127 HANDLE hFile;
128 BOOL bRet;
129 DWORD dwWritten;
130
131 if (!GetTempFileNameA(temp_path, "mpa", 0, filename))
132 {
133 ok(0, "GetTempFileNameA failed %lu\n", GetLastError());
134 return FALSE;
135 }
136
137 hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
138 if (hFile == INVALID_HANDLE_VALUE)
139 {
140 ok(0, "CreateFileA failed %lu\n", GetLastError());
141 DeleteFileA(filename);
142 return FALSE;
143 }
144
145 bRet = WriteFile(hFile, data, len, &dwWritten, NULL);
146 CloseHandle(hFile);
147 bRet = bRet && (dwWritten == len);
148
149 if (!bRet)
150 {
151 ok(0, "WriteFile failed %lu\n", GetLastError());
152 DeleteFileA(filename);
153 }
154
155 return bRet;
156 }
157
158 BOOL extract(char* filename, const bin_file* bin)
159 {
160 return extract2(filename, bin->data, bin->len);
161 }
162
163 HANDLE open_file(char* filename, BOOL bWrite)
164 {
165 DWORD dwAccess = GENERIC_READ | (bWrite ? GENERIC_WRITE : 0);
166 DWORD dwAttr = (bWrite ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY);
167 return CreateFileA(filename, dwAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING,
168 dwAttr, NULL);
169 }
170
171 void compare_file_(char* filename, const unsigned char* data, size_t len, const char* test_name, int line)
172 {
173 char* buf;
174 size_t size;
175 HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
176 FILE_ATTRIBUTE_READONLY, NULL);
177
178 if (hFile == INVALID_HANDLE_VALUE)
179 {
180 ok_(__FILE__, line)(0, "Unable to open file %s(%lu), %s\n", filename, GetLastError(), test_name);
181 return;
182 }
183 size = GetFileSize(hFile, NULL);
184 ok(size == len, "Filesize is %u instead of %u, %s\n", size, len, test_name);
185
186 buf = malloc(size);
187 if (buf)
188 {
189 DWORD dwRead;
190 if (ReadFile(hFile, buf, size, &dwRead, NULL) && dwRead == size)
191 {
192 ok(!memcmp(buf, data, min(size,len)), "Data mismatch, %s\n", test_name);
193 }
194 else
195 {
196 ok_(__FILE__, line)(0, "Unable to read %s(%lu), %s\n", filename, GetLastError(), test_name);
197 }
198
199 free(buf);
200 }
201 else
202 {
203 ok_(__FILE__, line)(0, "Unable to allocate %u, %s\n", size, test_name);
204 }
205
206 CloseHandle(hFile);
207 }
208
209 #define compare_file(filename, data, len, test_name) compare_file_(filename, data, len, test_name, __LINE__)
210
211 static void validate_signature(const char* casename, const char* fieldname, const bin_file* bin, const char* expected)
212 {
213 char filename[MAX_PATH];
214 WCHAR filenameW[MAX_PATH];
215 HANDLE hFile;
216 unsigned char data[0x100];
217 char signature[0x20] = {0};
218 WCHAR signatureW[0x20] = {0};
219 BOOL bResult;
220
221 memset(signature, 0xaa, sizeof(signature));
222 memcpy(data, bin->data, bin->len);
223
224 if (!extract(filename, bin))
225 return;
226
227 memset(signature, 0xaa, sizeof(signature)-1);
228 bResult = GetFilePatchSignatureA(filename, 0, NULL, 0, NULL, 0, NULL, sizeof(signature), signature);
229 ok(bResult, "GetFilePatchSignatureA failed %lu, %s.%s\n", GetLastError(), casename, fieldname);
230 if (bResult)
231 {
232 // Signature is crc32 of data
233 ok(!_stricmp(expected, signature), "Got %s for %s.%s\n", signature, casename, fieldname);
234 }
235
236 memset(signature, 0xaa, sizeof(signature)-1);
237 memset(signatureW, 0xaa, sizeof(signatureW)-sizeof(WCHAR));
238 // Widechar version has a widechar signature
239 MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, _countof(filenameW));
240 bResult = GetFilePatchSignatureW(filenameW, 0, NULL, 0, NULL, 0, NULL, sizeof(signatureW), signatureW);
241 ok(bResult, "GetFilePatchSignatureW failed %lu, %s.%s\n", GetLastError(), casename, fieldname);
242 if (bResult)
243 {
244 WideCharToMultiByte(CP_ACP, 0, signatureW, -1, signature, _countof(signature), NULL, NULL);
245 // Signature is crc32 of data
246 ok(!_stricmp(expected, signature), "Got %s for %s.%s\n", signature, casename, fieldname);
247 }
248
249 memset(signature, 0xaa, sizeof(signature)-1);
250 // 'Handle' version has ansi signature
251 hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
252 ok(hFile != INVALID_HANDLE_VALUE, "Unable to open file %lu\n", GetLastError());
253 if (hFile != INVALID_HANDLE_VALUE)
254 {
255 bResult = GetFilePatchSignatureByHandle(hFile, 0, NULL, 0, NULL, 0, NULL, sizeof(signature), signature);
256 ok(bResult, "GetFilePatchSignatureByHandle failed %lu, %s.%s\n", GetLastError(), casename, fieldname);
257 if (bResult)
258 {
259 // Signature is crc32 of data
260 ok(!_stricmp(expected, signature), "Got %s for %s.%s\n", signature, casename, fieldname);
261 }
262
263 CloseHandle(hFile);
264 }
265
266 DeleteFileA(filename);
267 }
268
269 /* Copyright (C) 1986 Gary S. Brown
270 * Modified by Robert Shearman. You may use the following calc_crc32 code or
271 * tables extracted from it, as desired without restriction. */
272 static const unsigned int crc_32_tab[] =
273 { /* CRC polynomial 0xedb88320 */
274 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
275 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
276 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
277 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
278 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
279 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
280 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
281 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
282 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
283 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
284 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
285 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
286 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
287 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
288 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
289 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
290 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
291 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
292 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
293 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
294 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
295 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
296 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
297 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
298 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
299 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
300 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
301 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
302 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
303 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
304 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
305 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
306 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
307 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
308 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
309 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
310 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
311 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
312 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
313 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
314 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
315 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
316 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
317 };
318
319 unsigned int crc32(unsigned int seed, unsigned char* msg, unsigned int msglen)
320 {
321 unsigned int rem = seed;
322 unsigned int i;
323
324 for (i = 0; i < msglen; i++)
325 {
326 rem = crc_32_tab[(rem ^ msg[i]) & 0xff] ^ (rem >> 8);
327 }
328
329 return rem;
330 }
331
332 static void validate_patch(patch_data* current)
333 {
334 UINT crc;
335
336 crc = crc32(~0, current->patch.data, current->patch.len);
337 ok(crc == 0, "Invalid patch crc 0x%x for %s\n", crc, current->name);
338
339 crc = crc32(~0, current->patch_header.data, current->patch_header.len);
340 ok(crc == 0, "Invalid patch_header crc 0x%x for %s\n", crc, current->name);
341 }
342
343 static void apply_patch(patch_data* current)
344 {
345 char patchname[MAX_PATH], targetname[MAX_PATH], outputname[MAX_PATH];
346 BOOL bResult;
347 DWORD dwErr;
348 HANDLE hPatch, hTarget, hFind;
349 WIN32_FIND_DATAA wfd = { sizeof(wfd) };
350
351 if (!GetTempFileNameA(temp_path, "MPO", 0, outputname))
352 {
353 ok(0, "GetTempFileNameA failed %lu, %s\n", GetLastError(), current->name);
354 return;
355 }
356 DeleteFileA(outputname);
357
358 if (!extract(patchname, &current->patch))
359 return;
360 if (!extract(targetname, &current->input))
361 {
362 DeleteFileA(patchname);
363 return;
364 }
365 // There is a bug in 2k3, where calling 'TestApplyPatchToFileA' gives an AV...
366 #if 0
367 bResult = TestApplyPatchToFileA(patchname, targetname, 0);
368 #else
369 hPatch = open_file(patchname, FALSE);
370 hTarget = open_file(targetname, FALSE);
371 bResult = TestApplyPatchToFileByHandles(hPatch, hTarget, 0);
372 CloseHandle(hPatch);
373 CloseHandle(hTarget);
374 #endif
375 ok(bResult, "TestApplyPatchToFileA failed %lu, %s\n", GetLastError(), current->name);
376 // Files are not touched
377 compare_file(patchname, current->patch.data, current->patch.len, current->name);
378 compare_file(targetname, current->input.data, current->input.len, current->name);
379 DeleteFileA(patchname);
380 DeleteFileA(targetname);
381
382
383 if (!extract2(patchname, current->patch.data, current->patch.len -1))
384 return;
385 if (!extract(targetname, &current->input))
386 {
387 DeleteFileA(patchname);
388 return;
389 }
390 hPatch = open_file(patchname, FALSE);
391 hTarget = open_file(targetname, FALSE);
392 bResult = TestApplyPatchToFileByHandles(hPatch, hTarget, 0);
393 dwErr = GetLastError();
394 CloseHandle(hPatch);
395 CloseHandle(hTarget);
396 ok(!bResult, "TestApplyPatchToFileA succeeded, %s\n", current->name);
397 ok(dwErr == ERROR_PATCH_CORRUPT, "TestApplyPatchToFileA GetLastError %lx, %s\n", dwErr, current->name);
398 // Files are not touched
399 compare_file(patchname, current->patch.data, current->patch.len - 1, current->name);
400 compare_file(targetname, current->input.data, current->input.len, current->name);
401 DeleteFileA(patchname);
402 DeleteFileA(targetname);
403
404 if (!extract(patchname, &current->patch))
405 return;
406 if (!extract2(targetname, current->input.data, current->input.len -1))
407 {
408 DeleteFileA(patchname);
409 return;
410 }
411 hPatch = open_file(patchname, FALSE);
412 hTarget = open_file(targetname, FALSE);
413 bResult = TestApplyPatchToFileByHandles(hPatch, hTarget, 0);
414 dwErr = GetLastError();
415 CloseHandle(hPatch);
416 CloseHandle(hTarget);
417 ok(!bResult, "TestApplyPatchToFileA succeeded, %s\n", current->name);
418 ok(dwErr == ERROR_PATCH_WRONG_FILE, "TestApplyPatchToFileA GetLastError %lx, %s\n", dwErr, current->name);
419 // Files are not touched
420 compare_file(patchname, current->patch.data, current->patch.len, current->name);
421 compare_file(targetname, current->input.data, current->input.len -1, current->name);
422 DeleteFileA(patchname);
423 DeleteFileA(targetname);
424
425 if (!extract(patchname, &current->patch))
426 return;
427 if (!extract(targetname, &current->input))
428 {
429 DeleteFileA(patchname);
430 return;
431 }
432 bResult = ApplyPatchToFileA(patchname, targetname, outputname, APPLY_OPTION_TEST_ONLY);
433
434 ok(bResult, "ApplyPatchToFileA failed %lu, %s\n", GetLastError(), current->name);
435 // Files are not touched
436 compare_file(patchname, current->patch.data, current->patch.len, current->name);
437 compare_file(targetname, current->input.data, current->input.len, current->name);
438 // W2k3 creates an empty file, W10 does not create a file
439 hFind = FindFirstFileA(outputname, &wfd);
440 ok(hFind == INVALID_HANDLE_VALUE || wfd.nFileSizeLow == 0, "Got a (non-empty) file, %s\n", current->name);
441 if (hFind != INVALID_HANDLE_VALUE)
442 FindClose(hFind);
443 DeleteFileA(patchname);
444 DeleteFileA(targetname);
445 DeleteFileA(outputname);
446
447 if (!extract(patchname, &current->patch))
448 return;
449 if (!extract(targetname, &current->input))
450 {
451 DeleteFileA(patchname);
452 return;
453 }
454 bResult = ApplyPatchToFileA(patchname, targetname, outputname, 0);
455 ok(bResult, "ApplyPatchToFileA failed %lu, %s\n", GetLastError(), current->name);
456 // Files are not touched
457 compare_file(patchname, current->patch.data, current->patch.len, current->name);
458 compare_file(targetname, current->input.data, current->input.len, current->name);
459 // One output file
460 compare_file(outputname, current->output.data, current->output.len, current->name);
461 DeleteFileA(patchname);
462 DeleteFileA(targetname);
463 DeleteFileA(outputname);
464 }
465
466
467 void test_one(patch_data* current)
468 {
469 validate_signature(current->name, "input", &current->input, current->input_signature);
470 validate_signature(current->name, "output", &current->output, current->output_signature);
471 apply_patch(current);
472 validate_patch(current);
473 }
474
475
476
477 static patch_data data[] =
478 {
479 {
480 "in1_text",
481 MAKE_BIN(in1_bin),
482 "99e5365e",
483 MAKE_BIN(out1_bin),
484 "f651d108",
485 MAKE_BIN(patch1_bin),
486 MAKE_BIN(patch1_header_bin),
487 },
488 {
489 "in2_binary",
490 MAKE_BIN(in2_bin),
491 "fc54c21d",
492 MAKE_BIN(out2_bin),
493 "028aa0fa",
494 MAKE_BIN(patch2_bin),
495 MAKE_BIN(patch2_header_bin),
496 },
497 {
498 "in3_compression",
499 MAKE_BIN(in3_bin),
500 "f10a52d9",
501 MAKE_BIN(out3_bin),
502 "411dd8f9",
503 MAKE_BIN(patch3_bin),
504 MAKE_BIN(patch3_header_bin),
505 },
506 };
507
508
509 START_TEST(mspatcha)
510 {
511 size_t n;
512
513 GetTempPathA(_countof(temp_path), temp_path);
514
515 for (n = 0; n < _countof(data); ++n)
516 {
517 test_one(data + n);
518 }
519 }