Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1516 lines
48 KiB

  1. #ifndef _WIN32_WINNT
  2. #define _WIN32_WINNT 0x0400
  3. #endif
  4. #ifndef WIN32
  5. #define WIN32 0x0400
  6. #endif
  7. #pragma warning( disable: 4001 4035 4115 4200 4201 4204 4209 4214 4514 4699 )
  8. #include <windows.h>
  9. #include <wincrypt.h>
  10. #pragma warning( disable: 4201 )
  11. #include <imagehlp.h>
  12. #pragma warning( disable: 4001 4035 4115 4200 4201 4204 4209 4214 4514 4699 )
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include "patchapi.h"
  17. #include "patchprv.h"
  18. #include <ntverp.h>
  19. #include <common.ver>
  20. typedef
  21. BOOL
  22. PATCHAPI
  23. FN_CreatePatchFileA(
  24. IN LPCSTR OldFileName,
  25. IN LPCSTR NewFileName,
  26. OUT LPCSTR PatchFileName,
  27. IN ULONG OptionFlags,
  28. IN PPATCH_OPTION_DATA OptionData // optional
  29. );
  30. typedef FN_CreatePatchFileA *PFN_CreatePatchFileA;
  31. FN_CreatePatchFileA CreatePatchFileA; // assert typedef correctness
  32. typedef
  33. BOOL
  34. PATCHAPI
  35. FN_CreatePatchFileExA(
  36. IN ULONG OldFileCount, // maximum 255
  37. IN PPATCH_OLD_FILE_INFO_A OldFileInfoArray,
  38. IN LPCSTR NewFileName,
  39. OUT LPCSTR PatchFileName,
  40. IN ULONG OptionFlags,
  41. IN PPATCH_OPTION_DATA OptionData, // optional
  42. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  43. IN PVOID CallbackContext
  44. );
  45. typedef FN_CreatePatchFileExA *PFN_CreatePatchFileExA;
  46. FN_CreatePatchFileExA CreatePatchFileExA; // assert typedef correctness
  47. void CopyRight( void ) {
  48. printf(
  49. "\n"
  50. "MPATCH " VER_PRODUCTVERSION_STR " Patch Creation Utility\n"
  51. VER_LEGALCOPYRIGHT_STR
  52. "\n\n"
  53. );
  54. }
  55. void Usage( void ) {
  56. printf(
  57. "Usage: MPATCH [options] OldFile[;OldFile2[;OldFile3]] NewFile TargetPatchFile\n"
  58. "\n"
  59. " Options:\n"
  60. "\n"
  61. " -NOBINDFIX Turn off automatic compensation for bound imports in\n"
  62. " the the old file. The default is to ignore binding\n"
  63. " data in the old file during patch creation which will\n"
  64. " cause the application of the patch to succeed whether\n"
  65. " or not the old file on the target machine is bound, not\n"
  66. " bound, or even bound to different import addresses.\n"
  67. " If the files are not Win32 binaries, this option is\n"
  68. " ignored and has no effect.\n"
  69. "\n"
  70. " -NOLOCKFIX Turn off automatic compensation for smashed lock prefix\n"
  71. " instructions. If the files are not Win32 binaries,\n"
  72. " this option is ignored and has no effect.\n"
  73. "\n"
  74. " -NOREBASE Turn off automatic internal rebasing of old file to new\n"
  75. " file's image base address. If the files are not Win32\n"
  76. " binaries, this option is ignored and has no effect.\n"
  77. "\n"
  78. " -NORESTIME Turn off automatic fixup of resource section timestamps\n"
  79. " (ignored if not Win32 binaries).\n"
  80. "\n"
  81. " -NOSTORETIME Don't store the timestamp of the new file in the patch\n"
  82. " file. Instead, set the timestamp of the patch file to\n"
  83. " the timestamp of the new file.\n"
  84. "\n"
  85. " -IGNORE:Offset,Length[,FileNumber]\n"
  86. "\n"
  87. " Ignore a range of bytes in the OldFile because those\n"
  88. " bytes might be different in the old file being patched\n"
  89. " on the target machine.\n"
  90. "\n"
  91. " -RETAIN:Offset,Length[,OffsetInNewFile[,FileNumber]]\n"
  92. "\n"
  93. " When applying the patch, preserve the range of bytes in\n"
  94. " the old file and copy them to the new file at the given\n"
  95. " OffsetInNewFile.\n"
  96. "\n"
  97. #if 0
  98. " -RIFTINFO:FileName[,FileNumber]\n"
  99. "\n"
  100. " Use rift table information from FileName (produced from\n"
  101. " riftinfo.exe).\n"
  102. "\n"
  103. #endif
  104. " -FAILBIGGER If patch file is bigger than simple compressed file,\n"
  105. " don't create the patch file (takes longer).\n"
  106. "\n"
  107. " -FAILIFSAME If old and new files are the same (ignoring binding\n"
  108. " differences, etc), don't create the patch file.\n"
  109. "\n"
  110. " -NOCOMPARE Don't compare patch compression against ordinary non-\n"
  111. " patch compression (saves time).\n"
  112. "\n"
  113. " -NOPROGRESS Don't display percent complete while building patch.\n"
  114. "\n"
  115. " -NEWSYMPATH:PathName[;PathName]\n"
  116. "\n"
  117. " For NewFile, search for symbol file(s) in these path\n"
  118. " locations (recursive search each path until found).\n"
  119. " The default is to search for symbol files(s) starting\n"
  120. " in the same directory as the NewFile.\n"
  121. "\n"
  122. " -OLDSYMPATH:PathName[;PathName][,FileNumber]\n"
  123. "\n"
  124. " For OldFile, search for symbol file(s) in these path\n"
  125. " locations (recursive search each path until found).\n"
  126. " The default is to search for symbol files(s) starting\n"
  127. " in the same directory as the OldFile.\n"
  128. "\n"
  129. " -UNDECORATED After matching decorated symbol names, match remaining\n"
  130. " symbols using undecorated names.\n"
  131. "\n"
  132. " -NOSYMS Don't use debug symbol files when creating the patch.\n"
  133. "\n"
  134. " -NOSYMFAIL Don't fail to create patch if symbols cannot be loaded.\n"
  135. "\n"
  136. " -NOSYMWARN Don't warn if symbols can't be found or don't match the\n"
  137. " corresponding file (symbol checksum mismatch).\n"
  138. "\n"
  139. " -USEBADSYMS Rather than ignoring symbols if the checksums don't\n"
  140. " match the corresponding files, use the bad symbols.\n"
  141. "\n"
  142. " -E8 Force E8 call translation for x86 binaries.\n"
  143. "\n"
  144. " -NOE8 Force no E8 call translation for x86 binaries.\n"
  145. "\n"
  146. " If neither -E8 or -NOE8 are specified, and the files\n"
  147. " are x86 binaries, the patch will be built internally\n"
  148. " twice and the smaller will be chosen for output.\n"
  149. "\n"
  150. " -MSPATCH194COMPAT Assure the patch file can be used with version\n"
  151. " 1.94 of MSPATCH*.DLL. May increase size of patch\n"
  152. " file if old or new file is larger than 4Mb.\n"
  153. "\n"
  154. " MPATCH will also look for environment variables named \"MPATCH\"\n"
  155. " followed by an underscore and the name of the option. Command line\n"
  156. " specified options override environment variable options. Examples:\n"
  157. "\n"
  158. " MPATCH_NOCOMPARE=1\n"
  159. " MPATCH_NEWSYMPATH=c:\\winnt\\symbols;\\\\server\\share\\symbols\n"
  160. "\n"
  161. );
  162. exit( 1 );
  163. }
  164. BOOL bNoProgress;
  165. BOOL bNoSymWarn;
  166. BOOL bUseBadSyms;
  167. DWORDLONG
  168. GetFileSizeByName(
  169. IN LPCSTR FileName
  170. )
  171. {
  172. DWORDLONG FileSizeReturn;
  173. ULONG FileSizeHigh;
  174. ULONG FileSizeLow;
  175. HANDLE hFile;
  176. FileSizeReturn = 0xFFFFFFFFFFFFFFFF;
  177. hFile = CreateFile(
  178. FileName,
  179. GENERIC_READ,
  180. FILE_SHARE_READ | FILE_SHARE_WRITE,
  181. NULL,
  182. OPEN_EXISTING,
  183. 0,
  184. NULL
  185. );
  186. if ( hFile != INVALID_HANDLE_VALUE ) {
  187. FileSizeLow = GetFileSize( hFile, &FileSizeHigh );
  188. if (( FileSizeLow != 0xFFFFFFFF ) || ( GetLastError() == NO_ERROR )) {
  189. FileSizeReturn = ((DWORDLONG)FileSizeHigh << 32 ) | FileSizeLow;
  190. }
  191. CloseHandle( hFile );
  192. }
  193. return FileSizeReturn;
  194. }
  195. BOOL
  196. GetMpatchEnvironString(
  197. IN LPCSTR VarName,
  198. OUT LPSTR Buffer,
  199. IN DWORD BufferSize
  200. )
  201. {
  202. CHAR EnvironName[ 256 ];
  203. sprintf( EnvironName, "mpatch_%s", VarName );
  204. if ( GetEnvironmentVariable( EnvironName, Buffer, BufferSize )) {
  205. return TRUE;
  206. }
  207. return FALSE;
  208. }
  209. BOOL
  210. GetMpatchEnvironValue(
  211. IN LPCSTR VarName
  212. )
  213. {
  214. CHAR LocalBuffer[ 256 ];
  215. if ( GetMpatchEnvironString( VarName, LocalBuffer, sizeof( LocalBuffer ))) {
  216. if (( *LocalBuffer == '0' ) && ( strtoul( LocalBuffer, NULL, 0 ) == 0 )) {
  217. return FALSE;
  218. }
  219. return TRUE;
  220. }
  221. return FALSE;
  222. }
  223. BOOL
  224. CALLBACK
  225. MyProgressCallback(
  226. PVOID CallbackContext,
  227. ULONG CurrentPosition,
  228. ULONG MaximumPosition
  229. )
  230. {
  231. UNREFERENCED_PARAMETER( CallbackContext );
  232. if ( MaximumPosition != 0 ) {
  233. fprintf( stderr, "\r%3.1f%% complete", ( CurrentPosition * 100.0 ) / MaximumPosition );
  234. }
  235. return TRUE;
  236. }
  237. BOOL
  238. CALLBACK
  239. MySymLoadCallback(
  240. IN ULONG WhichFile,
  241. IN LPCSTR SymbolFileName,
  242. IN ULONG SymType,
  243. IN ULONG SymbolFileCheckSum,
  244. IN ULONG SymbolFileTimeDate,
  245. IN ULONG ImageFileCheckSum,
  246. IN ULONG ImageFileTimeDate,
  247. IN PVOID CallbackContext
  248. )
  249. {
  250. LPCSTR *FileNameArray = CallbackContext;
  251. LPCSTR SymTypeText;
  252. if (( SymType == SymNone ) || ( SymType == SymExport )) {
  253. //
  254. // Symbols could not be found.
  255. //
  256. if ( ! bNoSymWarn ) {
  257. printf(
  258. "\n"
  259. "WARNING: no debug symbols for %s\n\n",
  260. FileNameArray[ WhichFile ]
  261. );
  262. }
  263. return TRUE;
  264. }
  265. //
  266. // Note that the Old file checksum is the checksum AFTER normalization,
  267. // so if the original .dbg file was updated with bound checksum, the
  268. // old file's checksum will not match the symbol file's checksum. But,
  269. // binding a file does not change its TimeDateStamp, so that should be
  270. // a valid comparison. But, .sym files don't have a TimeDateStamp, so
  271. // the SymbolFileTimeDate may be zero. If either the checksums match
  272. // or the timedate stamps match, we'll say its valid.
  273. //
  274. if (( ImageFileCheckSum == SymbolFileCheckSum ) ||
  275. ( ImageFileTimeDate == SymbolFileTimeDate )) {
  276. return TRUE;
  277. }
  278. if ( ! bNoSymWarn ) {
  279. switch ( SymType ) {
  280. case SymNone: SymTypeText = "No"; break;
  281. case SymCoff: SymTypeText = "Coff"; break;
  282. case SymCv: SymTypeText = "CodeView"; break;
  283. case SymPdb: SymTypeText = "Pdb"; break;
  284. case SymExport: SymTypeText = "Export"; break;
  285. case SymDeferred: SymTypeText = "Deferred"; break;
  286. case SymSym: SymTypeText = "Sym"; break;
  287. default: SymTypeText = "Unknown"; break;
  288. }
  289. printf(
  290. "\n"
  291. "WARNING: %s symbols %s don't match %s:\n"
  292. " symbol file checksum (%08X) does not match image (%08X), and\n"
  293. " symbol file timedate (%08X) does not match image (%08X).\n\n",
  294. SymTypeText,
  295. SymbolFileName,
  296. FileNameArray[ WhichFile ],
  297. SymbolFileCheckSum,
  298. ImageFileCheckSum,
  299. SymbolFileTimeDate,
  300. ImageFileTimeDate
  301. );
  302. }
  303. return bUseBadSyms;
  304. }
  305. PRIFT_TABLE RiftTableArray[ 256 ];
  306. PATCH_OLD_FILE_INFO_A OldFileInfo[ 256 ];
  307. LPSTR OldFileSymPathArray[ 256 ];
  308. LPSTR NewFileSymPath;
  309. LPSTR FileNameArray[ 257 ];
  310. PATCH_OPTION_DATA OptionData = { sizeof( PATCH_OPTION_DATA ) };
  311. CHAR TextBuffer[ 65000 ];
  312. void __cdecl main( int argc, char *argv[] ) {
  313. LPSTR OldFileName = NULL;
  314. LPSTR NewFileName = NULL;
  315. LPSTR PatchFileName = NULL;
  316. LPSTR DllFileName = NULL;
  317. ULONG OptionFlags = PATCH_OPTION_USE_LZX_BEST | PATCH_OPTION_USE_LZX_LARGE;
  318. BOOL Success;
  319. LPSTR arg;
  320. LPSTR p, q;
  321. LPSTR FileName;
  322. int i, j, n;
  323. ULONG OldOffset;
  324. ULONG NewOffset;
  325. ULONG Length;
  326. ULONG FileNum;
  327. ULONG OldFileCount;
  328. ULONG ErrorCode;
  329. ULONG NewFileSize;
  330. ULONG PatchFileSize;
  331. ULONG OldFileRva;
  332. ULONG NewFileRva;
  333. BOOL bNoCompare = FALSE;
  334. FILE *RiftFile;
  335. LPSTR FileNamePart;
  336. CHAR LoadedFileName[ MAX_PATH + 1 ];
  337. HMODULE hLib;
  338. PFN_CreatePatchFileA pCreatePatchFileA = CreatePatchFileA;
  339. PFN_CreatePatchFileExA pCreatePatchFileExA = CreatePatchFileExA;
  340. SetErrorMode( SEM_FAILCRITICALERRORS );
  341. #ifndef DEBUG
  342. SetErrorMode( SEM_NOALIGNMENTFAULTEXCEPT | SEM_FAILCRITICALERRORS );
  343. #endif
  344. #ifdef TESTCODE
  345. bNoCompare = TRUE;
  346. #endif
  347. CopyRight();
  348. for ( i = 1; i < argc; i++ ) {
  349. arg = argv[ i ];
  350. if ( strchr( arg, '?' )) {
  351. Usage();
  352. }
  353. }
  354. //
  355. // First get environment arguments because command-line args will
  356. // override them.
  357. //
  358. if ( GetMpatchEnvironValue( "e8" )) {
  359. OptionFlags &= ~PATCH_OPTION_USE_LZX_A;
  360. }
  361. if ( GetMpatchEnvironValue( "noe8" )) {
  362. OptionFlags &= ~PATCH_OPTION_USE_LZX_B;
  363. }
  364. if ( GetMpatchEnvironValue( "mspatch194compat" )) {
  365. OptionFlags &= ~PATCH_OPTION_USE_LZX_LARGE;
  366. }
  367. if ( GetMpatchEnvironValue( "nobindfix" )) {
  368. OptionFlags |= PATCH_OPTION_NO_BINDFIX;
  369. }
  370. if ( GetMpatchEnvironValue( "nolockfix" )) {
  371. OptionFlags |= PATCH_OPTION_NO_LOCKFIX;
  372. }
  373. if ( GetMpatchEnvironValue( "norebase" )) {
  374. OptionFlags |= PATCH_OPTION_NO_REBASE;
  375. }
  376. if ( GetMpatchEnvironValue( "norestime" )) {
  377. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  378. }
  379. if ( GetMpatchEnvironValue( "nostoretime" )) {
  380. OptionFlags |= PATCH_OPTION_NO_TIMESTAMP;
  381. }
  382. if ( GetMpatchEnvironValue( "failbigger" )) {
  383. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  384. }
  385. if ( GetMpatchEnvironValue( "failifbigger" )) {
  386. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  387. }
  388. if ( GetMpatchEnvironValue( "failsame" )) {
  389. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  390. }
  391. if ( GetMpatchEnvironValue( "failifsame" )) {
  392. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  393. }
  394. if ( GetMpatchEnvironValue( "nocompare" )) {
  395. bNoCompare = TRUE;
  396. }
  397. if ( GetMpatchEnvironValue( "noprogress" )) {
  398. bNoProgress = TRUE;
  399. }
  400. if ( GetMpatchEnvironValue( "undecorated" )) {
  401. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_UNDECORATED_TOO;
  402. }
  403. if ( GetMpatchEnvironValue( "nosyms" )) {
  404. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_IMAGEHLP;
  405. }
  406. if ( GetMpatchEnvironValue( "nosymfail" )) {
  407. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_FAILURES;
  408. }
  409. if ( GetMpatchEnvironValue( "nosymwarn" )) {
  410. bNoSymWarn = TRUE;
  411. }
  412. if ( GetMpatchEnvironValue( "usebadsyms" )) {
  413. bUseBadSyms = TRUE;
  414. }
  415. if ( GetMpatchEnvironString( "ignore", TextBuffer, sizeof( TextBuffer ))) {
  416. p = TextBuffer;
  417. q = strchr( p, ',' );
  418. if ( q != NULL ) {
  419. *q = 0;
  420. OldOffset = strtoul( p, NULL, 0 );
  421. p = q + 1;
  422. q = strchr( p, ',' );
  423. if ( q ) {
  424. *q = 0;
  425. }
  426. Length = strtoul( p, NULL, 0 );
  427. FileNum = 1;
  428. if ( q ) {
  429. p = q + 1;
  430. FileNum = strtoul( p, NULL, 0 );
  431. if ( FileNum == 0 ) {
  432. FileNum = 1;
  433. }
  434. }
  435. if ( FileNum <= 255 ) {
  436. void *pv = realloc(
  437. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray,
  438. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount * sizeof( PATCH_IGNORE_RANGE ) + sizeof( PATCH_IGNORE_RANGE )
  439. );
  440. if (pv) {
  441. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray = pv;
  442. } else {
  443. printf( "Out of memory\n" );
  444. exit( 1 );
  445. }
  446. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].OffsetInOldFile = OldOffset;
  447. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].LengthInBytes = Length;
  448. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount++;
  449. }
  450. }
  451. }
  452. if ( GetMpatchEnvironString( "retain", TextBuffer, sizeof( TextBuffer ))) {
  453. p = TextBuffer;
  454. q = strchr( p, ',' );
  455. if ( q != NULL ) {
  456. *q = 0;
  457. OldOffset = strtoul( p, NULL, 0 );
  458. p = q + 1;
  459. q = strchr( p, ',' );
  460. if ( q ) {
  461. *q = 0;
  462. }
  463. Length = strtoul( p, NULL, 0 );
  464. NewOffset = OldOffset;
  465. FileNum = 1;
  466. if ( q ) {
  467. p = q + 1;
  468. q = strchr( p, ',' );
  469. if ( q ) {
  470. *q = 0;
  471. }
  472. NewOffset = strtoul( p, NULL, 0 );
  473. if ( q ) {
  474. p = q + 1;
  475. FileNum = strtoul( p, NULL, 0 );
  476. if ( FileNum == 0 ) {
  477. FileNum = 1;
  478. }
  479. }
  480. }
  481. if ( FileNum <= 255 ) {
  482. void *pv = realloc(
  483. OldFileInfo[ FileNum - 1 ].RetainRangeArray,
  484. OldFileInfo[ FileNum - 1 ].RetainRangeCount * sizeof( PATCH_RETAIN_RANGE ) + sizeof( PATCH_RETAIN_RANGE )
  485. );
  486. if (pv) {
  487. OldFileInfo[ FileNum - 1 ].RetainRangeArray = pv;
  488. } else {
  489. printf( "Out of memory\n" );
  490. exit( 1 );
  491. }
  492. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInOldFile = OldOffset;
  493. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInNewFile = NewOffset;
  494. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].LengthInBytes = Length;
  495. OldFileInfo[ FileNum - 1 ].RetainRangeCount++;
  496. }
  497. }
  498. }
  499. if ( GetMpatchEnvironString( "riftinfo", TextBuffer, sizeof( TextBuffer ))) {
  500. p = TextBuffer;
  501. q = strchr( p, ',' );
  502. if ( q ) {
  503. *q = 0;
  504. }
  505. FileName = p;
  506. FileNum = 1;
  507. if ( q ) {
  508. p = q + 1;
  509. FileNum = strtoul( p, NULL, 0 );
  510. if ( FileNum == 0 ) {
  511. FileNum = 1;
  512. }
  513. }
  514. if ( FileNum <= 255 ) {
  515. RiftTableArray[ FileNum - 1 ] = malloc( sizeof( RIFT_TABLE ));
  516. if ( RiftTableArray[ FileNum - 1 ] == NULL ) {
  517. printf( "Out of memory\n" );
  518. exit( 1 );
  519. }
  520. RiftTableArray[ FileNum - 1 ]->RiftEntryCount = 0;
  521. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = 0;
  522. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = NULL;
  523. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = NULL;
  524. RiftFile = fopen( FileName, "rt" );
  525. if ( RiftFile == NULL ) {
  526. printf( "Could not open %s\n", FileName );
  527. exit( 1 );
  528. }
  529. while ( fgets( TextBuffer, sizeof( TextBuffer ), RiftFile )) {
  530. //
  531. // Line looks like "00001456 00002345" where each number
  532. // is an RVA in hexadecimal and the first column is the
  533. // OldFileRva and the second column is the NewFileRva.
  534. // Any text beyond column 17 is considered a comment, and
  535. // any line that does not begin with a digit is ignored.
  536. //
  537. if (( isxdigit( *TextBuffer )) && ( strlen( TextBuffer ) >= 17 )) {
  538. OldFileRva = strtoul( TextBuffer, NULL, 16 );
  539. NewFileRva = strtoul( TextBuffer + 9, NULL, 16 );
  540. if (( OldFileRva + NewFileRva ) != 0 ) {
  541. void *pv = realloc (
  542. RiftTableArray[ FileNum - 1 ]->RiftEntryArray,
  543. RiftTableArray[ FileNum - 1 ]->RiftEntryCount * sizeof( RIFT_ENTRY ) + sizeof( RIFT_ENTRY )
  544. );
  545. if (pv) {
  546. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = pv;
  547. } else {
  548. printf( "Out of memory\n" );
  549. exit( 1 );
  550. }
  551. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].OldFileRva = OldFileRva;
  552. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].NewFileRva = NewFileRva;
  553. RiftTableArray[ FileNum - 1 ]->RiftEntryCount++;
  554. }
  555. }
  556. }
  557. fclose( RiftFile );
  558. if ( RiftTableArray[ FileNum - 1 ]->RiftEntryCount ) {
  559. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = RiftTableArray[ FileNum - 1 ]->RiftEntryCount;
  560. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = malloc( RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  561. if ( RiftTableArray[ FileNum - 1 ]->RiftUsageArray == NULL ) {
  562. printf( "Out of memory\n" );
  563. exit( 1 );
  564. }
  565. ZeroMemory( RiftTableArray[ FileNum - 1 ]->RiftUsageArray, RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  566. }
  567. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_EXTERNAL_RIFT;
  568. }
  569. }
  570. if ( GetMpatchEnvironString( "oldsympath", TextBuffer, sizeof( TextBuffer ))) {
  571. p = TextBuffer;
  572. q = strchr( p, ',' );
  573. if ( q ) {
  574. *q = 0;
  575. }
  576. FileName = p;
  577. FileNum = 1;
  578. if ( q ) {
  579. p = q + 1;
  580. FileNum = strtoul( p, NULL, 0 );
  581. if ( FileNum == 0 ) {
  582. FileNum = 1;
  583. }
  584. }
  585. if ( FileNum <= 255 ) {
  586. OldFileSymPathArray[ FileNum - 1 ] = _strdup( FileName );
  587. }
  588. }
  589. if ( GetMpatchEnvironString( "newsympath", TextBuffer, sizeof( TextBuffer ))) {
  590. p = TextBuffer;
  591. q = strchr( p, ',' );
  592. if ( q ) {
  593. *q = 0;
  594. }
  595. FileName = p;
  596. FileNum = 1;
  597. if ( q ) {
  598. p = q + 1;
  599. FileNum = strtoul( p, NULL, 0 );
  600. if ( FileNum == 0 ) {
  601. FileNum = 1;
  602. }
  603. }
  604. if ( FileNum == 1 ) {
  605. NewFileSymPath = _strdup( FileName );
  606. }
  607. }
  608. //
  609. // Now process commandline args
  610. //
  611. for ( i = 1; i < argc; i++ ) {
  612. arg = argv[ i ];
  613. if ( strchr( arg, '?' )) {
  614. Usage();
  615. }
  616. if (( *arg == '-' ) || ( *arg == '/' )) {
  617. _strlwr( ++arg );
  618. if ( strcmp( arg, "e8" ) == 0 ) {
  619. OptionFlags &= ~PATCH_OPTION_USE_LZX_A;
  620. }
  621. else if ( strcmp( arg, "noe8" ) == 0 ) {
  622. OptionFlags &= ~PATCH_OPTION_USE_LZX_B;
  623. }
  624. else if ( strcmp( arg, "mspatch194compat" ) == 0 ) {
  625. OptionFlags &= ~PATCH_OPTION_USE_LZX_LARGE;
  626. }
  627. else if ( strcmp( arg, "nobindfix" ) == 0 ) {
  628. OptionFlags |= PATCH_OPTION_NO_BINDFIX;
  629. }
  630. else if ( strcmp( arg, "bindfix" ) == 0 ) {
  631. OptionFlags &= ~PATCH_OPTION_NO_BINDFIX;
  632. }
  633. else if ( strcmp( arg, "nolockfix" ) == 0 ) {
  634. OptionFlags |= PATCH_OPTION_NO_LOCKFIX;
  635. }
  636. else if ( strcmp( arg, "lockfix" ) == 0 ) {
  637. OptionFlags &= ~PATCH_OPTION_NO_LOCKFIX;
  638. }
  639. else if ( strcmp( arg, "norebase" ) == 0 ) {
  640. OptionFlags |= PATCH_OPTION_NO_REBASE;
  641. }
  642. else if ( strcmp( arg, "rebase" ) == 0 ) {
  643. OptionFlags &= ~PATCH_OPTION_NO_REBASE;
  644. }
  645. else if ( strcmp( arg, "norestime" ) == 0 ) {
  646. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  647. }
  648. else if ( strcmp( arg, "norestimefix" ) == 0 ) {
  649. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  650. }
  651. else if ( strcmp( arg, "restime" ) == 0 ) {
  652. OptionFlags &= ~PATCH_OPTION_NO_RESTIMEFIX;
  653. }
  654. else if ( strcmp( arg, "restimefix" ) == 0 ) {
  655. OptionFlags &= ~PATCH_OPTION_NO_RESTIMEFIX;
  656. }
  657. else if ( strcmp( arg, "nostoretime" ) == 0 ) {
  658. OptionFlags |= PATCH_OPTION_NO_TIMESTAMP;
  659. }
  660. else if ( strcmp( arg, "storetime" ) == 0 ) {
  661. OptionFlags &= ~PATCH_OPTION_NO_TIMESTAMP;
  662. }
  663. else if ( strcmp( arg, "failbigger" ) == 0 ) {
  664. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  665. }
  666. else if ( strcmp( arg, "nofailbigger" ) == 0 ) {
  667. OptionFlags &= ~PATCH_OPTION_FAIL_IF_BIGGER;
  668. }
  669. else if ( strcmp( arg, "failifbigger" ) == 0 ) {
  670. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  671. }
  672. else if ( strcmp( arg, "nofailifbigger" ) == 0 ) {
  673. OptionFlags &= ~PATCH_OPTION_FAIL_IF_BIGGER;
  674. }
  675. else if ( strcmp( arg, "failifsame" ) == 0 ) {
  676. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  677. }
  678. else if ( strcmp( arg, "failsame" ) == 0 ) {
  679. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  680. }
  681. else if ( strcmp( arg, "nofailifsame" ) == 0 ) {
  682. OptionFlags &= ~PATCH_OPTION_FAIL_IF_SAME_FILE;
  683. }
  684. else if ( strcmp( arg, "nofailsame" ) == 0 ) {
  685. OptionFlags &= ~PATCH_OPTION_FAIL_IF_SAME_FILE;
  686. }
  687. else if ( strcmp( arg, "nocompare" ) == 0 ) {
  688. bNoCompare = TRUE;
  689. }
  690. else if ( strcmp( arg, "compare" ) == 0 ) {
  691. bNoCompare = FALSE;
  692. }
  693. else if ( strcmp( arg, "noprogress" ) == 0 ) {
  694. bNoProgress = TRUE;
  695. }
  696. else if ( strcmp( arg, "progress" ) == 0 ) {
  697. bNoProgress = FALSE;
  698. }
  699. else if ( strcmp( arg, "decorated" ) == 0 ) {
  700. OptionData.SymbolOptionFlags &= ~PATCH_SYMBOL_UNDECORATED_TOO;
  701. }
  702. else if ( strcmp( arg, "undecorated" ) == 0 ) {
  703. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_UNDECORATED_TOO;
  704. }
  705. else if ( strcmp( arg, "nosyms" ) == 0 ) {
  706. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_IMAGEHLP;
  707. }
  708. else if ( strcmp( arg, "syms" ) == 0 ) {
  709. OptionData.SymbolOptionFlags &= ~PATCH_SYMBOL_NO_IMAGEHLP;
  710. }
  711. else if ( strcmp( arg, "nosymfail" ) == 0 ) {
  712. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_FAILURES;
  713. }
  714. else if ( strcmp( arg, "symfail" ) == 0 ) {
  715. OptionData.SymbolOptionFlags &= ~PATCH_SYMBOL_NO_FAILURES;
  716. }
  717. else if ( strcmp( arg, "nosymwarn" ) == 0 ) {
  718. bNoSymWarn = TRUE;
  719. }
  720. else if ( strcmp( arg, "symwarn" ) == 0 ) {
  721. bNoSymWarn = FALSE;
  722. }
  723. else if ( strcmp( arg, "usebadsyms" ) == 0 ) {
  724. bUseBadSyms = TRUE;
  725. }
  726. else if ( strcmp( arg, "nousebadsyms" ) == 0 ) {
  727. bUseBadSyms = FALSE;
  728. }
  729. else if ( strcmp( arg, "nobadsyms" ) == 0 ) {
  730. bUseBadSyms = FALSE;
  731. }
  732. else if ( memcmp( arg, "ignore:", 7 ) == 0 ) {
  733. p = strchr( arg, ':' ) + 1;
  734. q = strchr( p, ',' );
  735. if ( q == NULL ) {
  736. Usage();
  737. }
  738. *q = 0;
  739. OldOffset = strtoul( p, NULL, 0 );
  740. p = q + 1;
  741. q = strchr( p, ',' );
  742. if ( q ) {
  743. *q = 0;
  744. }
  745. Length = strtoul( p, NULL, 0 );
  746. FileNum = 1;
  747. if ( q ) {
  748. p = q + 1;
  749. FileNum = strtoul( p, NULL, 0 );
  750. if ( FileNum == 0 ) {
  751. FileNum = 1;
  752. }
  753. }
  754. if ( FileNum > 255 ) {
  755. Usage();
  756. }
  757. {
  758. void *pv = realloc(
  759. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray,
  760. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount * sizeof( PATCH_IGNORE_RANGE ) + sizeof( PATCH_IGNORE_RANGE )
  761. );
  762. if (pv) {
  763. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray = pv;
  764. } else {
  765. printf( "Out of memory\n" );
  766. exit( 1 );
  767. }
  768. }
  769. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].OffsetInOldFile = OldOffset;
  770. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].LengthInBytes = Length;
  771. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount++;
  772. }
  773. else if ( memcmp( arg, "retain:", 7 ) == 0 ) {
  774. p = strchr( arg, ':' ) + 1;
  775. q = strchr( p, ',' );
  776. if ( q == NULL ) {
  777. Usage();
  778. }
  779. *q = 0;
  780. OldOffset = strtoul( p, NULL, 0 );
  781. p = q + 1;
  782. q = strchr( p, ',' );
  783. if ( q ) {
  784. *q = 0;
  785. }
  786. Length = strtoul( p, NULL, 0 );
  787. NewOffset = OldOffset;
  788. FileNum = 1;
  789. if ( q ) {
  790. p = q + 1;
  791. q = strchr( p, ',' );
  792. if ( q ) {
  793. *q = 0;
  794. }
  795. NewOffset = strtoul( p, NULL, 0 );
  796. if ( q ) {
  797. p = q + 1;
  798. FileNum = strtoul( p, NULL, 0 );
  799. if ( FileNum == 0 ) {
  800. FileNum = 1;
  801. }
  802. }
  803. }
  804. if ( FileNum > 255 ) {
  805. Usage();
  806. }
  807. {
  808. void *pv = realloc(
  809. OldFileInfo[ FileNum - 1 ].RetainRangeArray,
  810. OldFileInfo[ FileNum - 1 ].RetainRangeCount * sizeof( PATCH_RETAIN_RANGE ) + sizeof( PATCH_RETAIN_RANGE )
  811. );
  812. if (pv) {
  813. OldFileInfo[ FileNum - 1 ].RetainRangeArray = pv;
  814. } else {
  815. printf( "Out of memory\n" );
  816. exit( 1 );
  817. }
  818. }
  819. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInOldFile = OldOffset;
  820. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInNewFile = NewOffset;
  821. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].LengthInBytes = Length;
  822. OldFileInfo[ FileNum - 1 ].RetainRangeCount++;
  823. }
  824. else if ( memcmp( arg, "riftinfo:", 9 ) == 0 ) {
  825. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_EXTERNAL_RIFT;
  826. p = strchr( arg, ':' ) + 1;
  827. q = strchr( p, ',' );
  828. if ( q ) {
  829. *q = 0;
  830. }
  831. FileName = p;
  832. FileNum = 1;
  833. if ( q ) {
  834. p = q + 1;
  835. FileNum = strtoul( p, NULL, 0 );
  836. if ( FileNum == 0 ) {
  837. FileNum = 1;
  838. }
  839. }
  840. if ( FileNum > 255 ) {
  841. Usage();
  842. }
  843. RiftTableArray[ FileNum - 1 ] = malloc( sizeof( RIFT_TABLE ));
  844. if ( RiftTableArray[ FileNum - 1 ] == NULL ) {
  845. printf( "Out of memory\n" );
  846. exit( 1 );
  847. }
  848. RiftTableArray[ FileNum - 1 ]->RiftEntryCount = 0;
  849. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = 0;
  850. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = NULL;
  851. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = NULL;
  852. RiftFile = fopen( FileName, "rt" );
  853. if ( RiftFile == NULL ) {
  854. printf( "Could not open %s\n", FileName );
  855. exit( 1 );
  856. }
  857. while ( fgets( TextBuffer, sizeof( TextBuffer ), RiftFile )) {
  858. //
  859. // Line looks like "00001456 00002345" where each number
  860. // is an RVA in hexadecimal and the first column is the
  861. // OldFileRva and the second column is the NewFileRva.
  862. // Any text beyond column 17 is considered a comment, and
  863. // any line that does not begin with a digit is ignored.
  864. //
  865. if (( isxdigit( *TextBuffer )) && ( strlen( TextBuffer ) >= 17 )) {
  866. OldFileRva = strtoul( TextBuffer, NULL, 16 );
  867. NewFileRva = strtoul( TextBuffer + 9, NULL, 16 );
  868. if (( OldFileRva + NewFileRva ) != 0 ) {
  869. void *pv = realloc(
  870. RiftTableArray[ FileNum - 1 ]->RiftEntryArray,
  871. RiftTableArray[ FileNum - 1 ]->RiftEntryCount * sizeof( RIFT_ENTRY ) + sizeof( RIFT_ENTRY )
  872. );
  873. if (pv) {
  874. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = pv;
  875. } else {
  876. printf( "Out of memory\n" );
  877. exit( 1 );
  878. }
  879. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].OldFileRva = OldFileRva;
  880. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].NewFileRva = NewFileRva;
  881. RiftTableArray[ FileNum - 1 ]->RiftEntryCount++;
  882. }
  883. }
  884. }
  885. fclose( RiftFile );
  886. if ( RiftTableArray[ FileNum - 1 ]->RiftEntryCount ) {
  887. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = RiftTableArray[ FileNum - 1 ]->RiftEntryCount;
  888. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = malloc( RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  889. if ( RiftTableArray[ FileNum - 1 ]->RiftUsageArray == NULL ) {
  890. printf( "Out of memory\n" );
  891. exit( 1 );
  892. }
  893. ZeroMemory( RiftTableArray[ FileNum - 1 ]->RiftUsageArray, RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  894. }
  895. }
  896. else if ( memcmp( arg, "oldsympath:", 11 ) == 0 ) {
  897. p = strchr( arg, ':' ) + 1;
  898. q = strchr( p, ',' );
  899. if ( q ) {
  900. *q = 0;
  901. }
  902. FileName = p;
  903. FileNum = 1;
  904. if ( q ) {
  905. p = q + 1;
  906. FileNum = strtoul( p, NULL, 0 );
  907. if ( FileNum == 0 ) {
  908. FileNum = 1;
  909. }
  910. }
  911. if ( FileNum > 255 ) {
  912. Usage();
  913. }
  914. OldFileSymPathArray[ FileNum - 1 ] = _strdup( FileName );
  915. }
  916. else if ( memcmp( arg, "newsympath:", 11 ) == 0 ) {
  917. p = strchr( arg, ':' ) + 1;
  918. q = strchr( p, ',' );
  919. if ( q ) {
  920. *q = 0;
  921. }
  922. FileName = p;
  923. FileNum = 1;
  924. if ( q ) {
  925. p = q + 1;
  926. FileNum = strtoul( p, NULL, 0 );
  927. if ( FileNum == 0 ) {
  928. FileNum = 1;
  929. }
  930. }
  931. if ( FileNum != 1 ) {
  932. Usage();
  933. }
  934. NewFileSymPath = _strdup( FileName );
  935. }
  936. else if ( strncmp( arg, "dll:", 4 ) == 0 ) {
  937. DllFileName = arg + 4;
  938. }
  939. else {
  940. Usage();
  941. }
  942. }
  943. else if ( OldFileName == NULL ) {
  944. OldFileName = arg;
  945. }
  946. else if ( NewFileName == NULL ) {
  947. NewFileName = arg;
  948. }
  949. else if ( PatchFileName == NULL ) {
  950. PatchFileName = arg;
  951. }
  952. else {
  953. Usage();
  954. }
  955. }
  956. if (( OldFileName == NULL ) || ( NewFileName == NULL ) || ( PatchFileName == NULL )) {
  957. Usage();
  958. }
  959. if ( DllFileName != NULL ) {
  960. hLib = LoadLibrary( DllFileName );
  961. if ( hLib == NULL ) {
  962. printf( "Unable to load DLL '%s'\n", DllFileName );
  963. exit( 1 );
  964. }
  965. if ( GetModuleFileName( hLib, LoadedFileName, sizeof( LoadedFileName ))) {
  966. printf( "Loaded DLL '%s'\n", LoadedFileName );
  967. }
  968. pCreatePatchFileA = (PFN_CreatePatchFileA) GetProcAddress( hLib, "CreatePatchFileA" );
  969. pCreatePatchFileExA = (PFN_CreatePatchFileExA) GetProcAddress( hLib, "CreatePatchFileExA" );
  970. if (( pCreatePatchFileExA == NULL ) || ( pCreatePatchFileExA == NULL )) {
  971. printf( "Unable to import CreatePatchFileA and CreatePatchFileExA from DLL\n" );
  972. exit( 1 );
  973. }
  974. }
  975. OldFileCount = 0;
  976. p = OldFileName;
  977. q = strchr( OldFileName, ';' );
  978. while ( q ) {
  979. *q = 0;
  980. if ( *p ) {
  981. OldFileInfo[ OldFileCount ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_A );
  982. OldFileInfo[ OldFileCount ].OldFileName = p;
  983. OldFileCount++;
  984. }
  985. p = q + 1;
  986. q = strchr( p, ';' );
  987. }
  988. if ( *p ) {
  989. OldFileInfo[ OldFileCount ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_A );
  990. OldFileInfo[ OldFileCount ].OldFileName = p;
  991. OldFileCount++;
  992. }
  993. //
  994. // Make sure rift tables are ascending and don't contain duplicate
  995. // OldRva values (ambiguous).
  996. //
  997. for ( i = 0; i < (int)OldFileCount; i++ ) {
  998. if (( RiftTableArray[ i ] ) && ( RiftTableArray[ i ]->RiftEntryCount > 1 )) {
  999. n = RiftTableArray[ i ]->RiftEntryCount - 1;
  1000. RiftQsort( &RiftTableArray[ i ]->RiftEntryArray[ 0 ], &RiftTableArray[ i ]->RiftEntryArray[ n ] );
  1001. #ifdef TESTCODE
  1002. for ( j = 0; j < n; j++ ) {
  1003. if ( RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva >
  1004. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].OldFileRva ) {
  1005. printf( "\nRift sort failed at index %d of %d\n", j, n + 1 );
  1006. for ( j = 0; j <= n; j++ ) {
  1007. printf( "%08X\n", RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva );
  1008. }
  1009. exit( 1 );
  1010. break;
  1011. }
  1012. }
  1013. #endif // TESTCODE
  1014. for ( j = 0; j < n; j++ ) {
  1015. while (( j < n ) &&
  1016. ( RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva ==
  1017. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].OldFileRva )) {
  1018. if ( RiftTableArray[ i ]->RiftEntryArray[ j ].NewFileRva !=
  1019. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].NewFileRva ) {
  1020. //
  1021. // This is an ambiguous entry since the OldRva values
  1022. // match but the NewRva values do not. Report and
  1023. // discard the former.
  1024. //
  1025. printf(
  1026. "RiftInfo for %s contains ambiguous entries:\n"
  1027. " OldRva:%08X NewRva:%08X (discarded)\n"
  1028. " OldRva:%08X NewRva:%08X (kept)\n\n",
  1029. OldFileInfo[ i ].OldFileName,
  1030. RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva,
  1031. RiftTableArray[ i ]->RiftEntryArray[ j ].NewFileRva,
  1032. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].OldFileRva,
  1033. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].NewFileRva
  1034. );
  1035. }
  1036. else {
  1037. //
  1038. // This is a completely duplicate entry, so just
  1039. // silently remove it.
  1040. //
  1041. }
  1042. MoveMemory(
  1043. &RiftTableArray[ i ]->RiftEntryArray[ j ],
  1044. &RiftTableArray[ i ]->RiftEntryArray[ j + 1 ],
  1045. ( n - j ) * sizeof( RIFT_ENTRY )
  1046. );
  1047. --n;
  1048. }
  1049. }
  1050. RiftTableArray[ i ]->RiftEntryCount = n + 1;
  1051. }
  1052. }
  1053. for ( i = 0; i < (int)OldFileCount; i++ ) {
  1054. if ( OldFileSymPathArray[ i ] == NULL ) {
  1055. GetFullPathName( OldFileInfo[ i ].OldFileName, sizeof( TextBuffer ), TextBuffer, &FileNamePart );
  1056. if (( FileNamePart > TextBuffer ) && ( *( FileNamePart - 1 ) == '\\' )) {
  1057. *( FileNamePart - 1 ) = 0;
  1058. }
  1059. OldFileSymPathArray[ i ] = _strdup( TextBuffer );
  1060. }
  1061. }
  1062. if ( NewFileSymPath == NULL ) {
  1063. GetFullPathName( NewFileName, sizeof( TextBuffer ), TextBuffer, &FileNamePart );
  1064. if (( FileNamePart > TextBuffer ) && ( *( FileNamePart - 1 ) == '\\' )) {
  1065. *( FileNamePart - 1 ) = 0;
  1066. }
  1067. NewFileSymPath = _strdup( TextBuffer );
  1068. }
  1069. OptionData.NewFileSymbolPath = NewFileSymPath;
  1070. OptionData.OldFileSymbolPathArray = OldFileSymPathArray;
  1071. if ( OptionData.SymbolOptionFlags & PATCH_SYMBOL_EXTERNAL_RIFT ) {
  1072. OptionData.OldFileSymbolPathArray = (PVOID)RiftTableArray;
  1073. }
  1074. OptionData.SymLoadCallback = MySymLoadCallback;
  1075. OptionData.SymLoadContext = FileNameArray;
  1076. FileNameArray[ 0 ] = (LPSTR)NewFileName;
  1077. for ( i = 0; i < (int)OldFileCount; i++ ) {
  1078. FileNameArray[ i + 1 ] = (LPSTR)OldFileInfo[ i ].OldFileName;
  1079. }
  1080. Success = pCreatePatchFileExA(
  1081. OldFileCount,
  1082. OldFileInfo,
  1083. NewFileName,
  1084. PatchFileName,
  1085. OptionFlags,
  1086. &OptionData,
  1087. bNoProgress ? NULL : MyProgressCallback,
  1088. NULL
  1089. );
  1090. ErrorCode = GetLastError();
  1091. printf( "\n\n" );
  1092. if ( ! Success ) {
  1093. CHAR ErrorText[ 16 ];
  1094. sprintf( ErrorText, ( ErrorCode < 0x10000000 ) ? "%d" : "%X", ErrorCode );
  1095. printf( "Failed to create patch (%s)\n", ErrorText );
  1096. exit( 1 );
  1097. }
  1098. NewFileSize = (ULONG) GetFileSizeByName( NewFileName );
  1099. PatchFileSize = (ULONG) GetFileSizeByName( PatchFileName );
  1100. if (( NewFileSize != 0xFFFFFFFF ) && ( NewFileSize != 0 ) && ( PatchFileSize != 0xFFFFFFFF )) {
  1101. printf( "%d bytes (%3.1f%% compression, %.1f:1)\n",
  1102. PatchFileSize,
  1103. ((((LONG)NewFileSize - (LONG)PatchFileSize ) * 100.0 ) / NewFileSize ),
  1104. ((double)NewFileSize / PatchFileSize )
  1105. );
  1106. if ( ! bNoCompare ) {
  1107. CHAR TempFile1[ MAX_PATH ];
  1108. CHAR TempFile2[ MAX_PATH ];
  1109. HANDLE hFile;
  1110. GetTempPath( MAX_PATH, TempFile1 );
  1111. GetTempPath( MAX_PATH, TempFile2 );
  1112. strcat( TempFile1, "\\tt$$src.$$$" );
  1113. strcat( TempFile2, "\\tt$$pat.$$$" );
  1114. hFile = CreateFile(
  1115. TempFile1,
  1116. GENERIC_READ | GENERIC_WRITE,
  1117. FILE_SHARE_READ,
  1118. NULL,
  1119. CREATE_ALWAYS,
  1120. FILE_ATTRIBUTE_TEMPORARY,
  1121. NULL
  1122. );
  1123. if ( hFile != INVALID_HANDLE_VALUE ) {
  1124. CloseHandle( hFile );
  1125. Success = pCreatePatchFileA(
  1126. TempFile1,
  1127. NewFileName,
  1128. TempFile2,
  1129. OptionFlags & ~PATCH_OPTION_FAIL_IF_BIGGER,
  1130. NULL
  1131. );
  1132. if ( Success ) {
  1133. ULONG CompFileSize = (ULONG) GetFileSizeByName( TempFile2 );
  1134. if (( CompFileSize != 0xFFFFFFFF ) && ( CompFileSize != 0 )) {
  1135. if ( CompFileSize <= PatchFileSize ) {
  1136. printf( "\nWARNING: Simply compressing %s would be %d bytes smaller (%3.1f%%)\n",
  1137. NewFileName,
  1138. PatchFileSize - CompFileSize,
  1139. ((((LONG)PatchFileSize - (LONG)CompFileSize ) * 100.0 ) / CompFileSize )
  1140. );
  1141. }
  1142. else if ( NewFileSize != 0 ) {
  1143. printf( "\n%d bytes saved (%3.1f%%) over non-patching compression\n",
  1144. CompFileSize - PatchFileSize,
  1145. ((((LONG)CompFileSize - (LONG)PatchFileSize ) * 100.0 ) / NewFileSize )
  1146. );
  1147. }
  1148. }
  1149. }
  1150. }
  1151. DeleteFile( TempFile1 );
  1152. DeleteFile( TempFile2 );
  1153. }
  1154. }
  1155. else {
  1156. printf( "OK\n" );
  1157. }
  1158. exit( 0 );
  1159. }