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 
extract2(char * filename,const unsigned char * data,size_t len)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, (DWORD)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 
extract(char * filename,const bin_file * bin)158 BOOL extract(char* filename, const bin_file* bin)
159 {
160     return extract2(filename, bin->data, bin->len);
161 }
162 
open_file(char * filename,BOOL bWrite)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 
compare_file_(char * filename,const unsigned char * data,size_t len,const char * test_name,int line)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, (DWORD)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 
validate_signature(const char * casename,const char * fieldname,const bin_file * bin,const char * expected)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 
crc32(unsigned int seed,unsigned char * msg,unsigned int msglen)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 
validate_patch(patch_data * current)332 static void validate_patch(patch_data* current)
333 {
334     UINT crc;
335 
336     crc = crc32(~0, current->patch.data, (UINT)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, (UINT)current->patch_header.len);
340     ok(crc == 0, "Invalid patch_header crc 0x%x for %s\n", crc, current->name);
341 }
342 
apply_patch(patch_data * current)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 
test_one(patch_data * current)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 
START_TEST(mspatcha)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 }
520