home *** CD-ROM | disk | FTP | other *** search
- /* binpatch.c Simple non-interactive binary patch utility
- * DWF 7/19/94 First version and hopefully the last. Just say NO to
- * creeping features!
- *
- * Usage: binpatch infile outfile < patch
- *
- * This program is written so that it should work under Messy-DOS, i.e.,
- * it uses temporary files instead of reading the entire binary into memory.
- * I have successfully compiled it with an old version of Turbo C, but I had
- * to add an #ifdef to the includes.
- *
- * Here is an example patch file. Comments, with # in the first column,
- * are ignored; the other lines alternate between search-string and
- * replace-string in hexadecimal.
- *
- * # Patches for shareware doom.exe 1.5 beta posted to alt.games.doom by
- * # ep104@cus.cam.ac.uk (Elias 'CaveMan' Papavassilopoulos)
- * #
- * # Fix crash & burn on idkfa + shotgun
- * B9 09 00 00 00 C7 40 B0 02 00 00 00
- * B9 08 00 00 00 C7 40 B0 02 00 00 00
- * #
- * # Enable cheat codes in Nightmare mode
- * 0F 85 29 03 00 00 83 3D 70 82 02 00 04
- * 0F 85 29 03 00 00 83 3D 70 82 02 00 45
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #ifndef __TURBOC__
- #include <unistd.h>
- #endif
-
- /* Names for temporary files */
- #define temp1 "temp1"
- #define temp2 "temp2"
-
- /* Maximum length of text lines on input */
- /*#define maxlen 80*/
- #define maxlen 256
-
- void
- usage ()
- {
- puts ("Usage: binpatch infile outfile < patch");
- exit (0);
- }
-
- void
- bail ()
- {
- unlink (temp1);
- unlink (temp2);
- exit (-1);
- }
-
- void
- dont_clobber (char *fname)
- {
- FILE *inf;
- if ((inf = fopen (fname, "r"))) {
- printf ("Will not overwrite existing file %s -- rename or delete it\n",
- fname);
- exit (-1);
- }
- }
-
- int
- get_line (unsigned char line[maxlen], int *len)
- {
- char txtlin[maxlen];
- int t, tt;
- *len = 0;
- do t = (int) fgets (txtlin, maxlen, stdin); while ((txtlin[0] == '#') && t);
- if (!t)
- return 0;
- if (strlen (txtlin) >= maxlen-1) {
- printf ("Line in patch file >= %d characters: too long\n", maxlen-1);
- bail ();
- }
- t = 0;
- while (sscanf (txtlin+t, "%x", &tt) == 1) {
- line[(*len)++] = (unsigned char)tt;
- while (isalnum (txtlin[t])) t++;
- while (isspace (txtlin[t])) t++;
- }
- return *len;
- }
-
- void
- search_and_destroy (FILE *inf, FILE *otf, unsigned char srch[maxlen],
- int srchlen, unsigned char repl[maxlen], int *matches)
- {
- int matchnum=0, fchar, t;
- while ((fchar = fgetc (inf)) != EOF) {
- if (fchar == (int)srch[matchnum]) {
- matchnum++;
- if (matchnum == srchlen) {
- for (t=0;t<matchnum;t++)
- fputc ((int)repl[t], otf);
- matchnum = 0;
- (*matches)++;
- }
- } else {
- for (t=0;t<matchnum;t++)
- fputc ((int)srch[t], otf);
- matchnum = 0;
- fputc (fchar, otf);
- }
- }
- for (t=0;t<matchnum;t++)
- fputc ((int)srch[t], otf);
- }
-
- int
- main (int argc, char **argv)
- {
- FILE *inf=NULL, *otf=NULL;
- int matches, whichtemp=0, srchlen, repllen, pnum=0;
- unsigned char srch[maxlen], repl[maxlen];
- if (argc != 3)
- usage ();
-
- dont_clobber (temp1);
- dont_clobber (temp2);
- dont_clobber (argv[2]);
-
- /* Open initial input file */
- if (!(inf = fopen (argv[1], "rb"))) {
- perror ("fopen");
- usage ();
- }
-
- while (get_line (srch, &srchlen)) {
- pnum++;
- if (!(get_line (repl, &repllen))) {
- printf ("Unexpected EOF in patch file\n");
- bail ();
- }
- if (srchlen != repllen) {
- printf ("Search-string length != replace-string length in patch file\n");
- bail ();
- }
-
- /* Open files */
- if (whichtemp) {
- if (!(otf = fopen (temp1, "wb"))) {
- perror ("fopen");
- bail ();
- }
- if (!inf)
- if (!(inf = fopen (temp2, "rb"))) {
- perror ("fopen");
- bail ();
- }
- } else {
- if (!(otf = fopen (temp2, "wb"))) {
- perror ("fopen");
- bail ();
- }
- if (!inf)
- if (!(inf = fopen (temp1, "rb"))) {
- perror ("fopen");
- bail ();
- }
- }
- whichtemp = 1 - whichtemp;
-
- matches = 0;
- search_and_destroy (inf, otf, srch, srchlen, repl, &matches);
- printf ("Chunk #%d: ", pnum);
- switch (matches) {
- case 0:
- puts ("Error -- no strings matched.");
- break;
- case 1:
- puts ("Replaced 1 string.");
- break;
- default:
- printf ("Replaced %d strings.\n", matches);
- }
-
- fclose (inf);
- fclose (otf);
- inf = otf = NULL;
- }
-
- unlink (argv[2]);
- if (whichtemp) {
- unlink (temp1);
- if (rename (temp2, argv[2])) {
- perror ("rename");
- bail ();
- }
- } else {
- unlink (temp2);
- if (rename (temp1, argv[2])) {
- perror ("rename");
- bail ();
- }
- }
-
- exit (0);
- }
-
-