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, (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 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, (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 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, (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 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, ¤t->patch)) 359 return; 360 if (!extract(targetname, ¤t->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, ¤t->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, ¤t->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, ¤t->patch)) 426 return; 427 if (!extract(targetname, ¤t->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, ¤t->patch)) 448 return; 449 if (!extract(targetname, ¤t->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", ¤t->input, current->input_signature); 470 validate_signature(current->name, "output", ¤t->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 } 520