1 /*	SCCS Id: @(#)exesmurf.c	 3.1	 91/01/29			  */
2 /* Copyright (c) Pierre Martineau and Stephen Spackman 1991, 1992, 1993.  */
3 /* NetHack may be freely redistributed.  See license for details.	  */
4 
5 /******************************************************************************
6 *                                                                             *
7 *                         EXE header list and modify                          *
8 *                                                                             *
9 *                        by Pierre Martineau, 91/01/29                        *
10 *                                                                             *
11 *                                Version 1.2                                  *
12 *                                                                             *
13 >*****************************************************************************<
14 * Modified (stephen@estragon.uchicago.edu):                                   *
15 * 1990oct23 sps Overlay splitter-outer first cut                              *
16 *        31     Error handling; some #defines                                 *
17 *     nov01     /l                                                            *
18 *   91jan29     Changed default overlay file names to conform to ovlmgr 30a0  *
19 ******************************************************************************/
20 
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <math.h>
25 
26 /** parameters ***************************************************************/
27 #define MAXFILENAME 128   /* Probably overkill - theoretical limit is 80     */
28 #define NPARTS	    36	  /* Maximum # of overlay files (excluding root .EXE)*/
29 #define COPYBUFSIZE 32768 /* Fair sized buffer for file copy                 */
30 #define BAKEXT      ".BAK"/* Extension for .exe backups                      */
31 #define OVLEXT      ".OVL"/* Default extension for overlay files             */
32 /* #define MANYZEROES */  /* Old style default: foo00001.ovl, not foo0.ovl   */
33 /*****************************************************************************/
34 
35 #define BOOLEAN int
36 #define TRUE    1
37 #define FALSE   0
38 
sstrccnt(register char const * s,register char c)39 int sstrccnt(register char const *s, register char c)
40   { int n = 0;
41 
42     while (*s) if (*s++ == c) n++;
43     return n;
44   }
45 
46 FILE *wrkfile, *outfile;
47 long min, max, stk;
48 BOOLEAN listflg = FALSE;
49 BOOLEAN verbose = FALSE;
50 BOOLEAN minflg = FALSE;
51 BOOLEAN maxflg = FALSE;
52 BOOLEAN stkflg = FALSE;
53 
54 int column = 0;
55 
56 struct exehdr {
57 unsigned signature;
58 unsigned mod512;
59 unsigned pages;
60 unsigned relocitems;
61 unsigned headerparas;
62 unsigned minalloc;
63 unsigned maxalloc;
64 unsigned ss;
65 unsigned sp;
66 unsigned checksum;
67 unsigned ip;
68 unsigned cs;
69 unsigned relocptr;
70 unsigned ovlnum;
71 } exehdr_area;
72 
main(argc,argv)73 main(argc, argv)
74 int argc;
75 char *argv[];
76 {
77 char *dot, *slash;
78 char fname[MAXFILENAME], oname[MAXFILENAME], zname[MAXFILENAME];
79 char *jname = NULL;
80 char *args;
81 int i;
82 long offset, oldstk;
83 unsigned nparts = 0, part = 0, partstart[NPARTS + 2];
84 
85     printf("EXE list and modify V1.1s, by Pierre Martineau, 90/05/20.\n");
86     printf("This program may be freely distributed.\n");
87 
88 	if ((argc < 2) || (argc > NPARTS + 2)) {
89         usage();
90         return;
91     }
92 
93 /*  Process any remaining arguments  */
94 
95     if (argc == 2) {
96         listflg = TRUE;
97         verbose = TRUE; /* ??? */
98     }
99     else {
100         i = 2;
101         while (argc-- > 2) {
102             args = argv[i];
103 	    if ('0' <= args[0] && args[0] <= '9') { /* File split request */
104 			if (nparts >= NPARTS) {
105 			printf("\nToo many .OVL files requested (max. %d)\n", NPARTS);
106 		    usage();
107 		    return;
108 		}
109 		else if (!atoi(args)) {
110 		    printf("\nCan't relocate the root overlay (#0)\n");
111 		    usage();
112 		    return;
113 		}
114 		else if (nparts && partstart[nparts - 1] >= atoi(args)) {
115 		    printf("\nOverlay starts must be in ascending order\n");
116 		    usage();
117 		    return;
118 		}
119 		partstart[nparts++] = atoi(args);
120 	    } else {
121 		if ((args[0] != '-') && (args[0] != '/')) {
122 		    printf("\nInvalid switch in paramater %s!\n", argv[i]);
123 			usage();
124 			return;
125 		}
126 		args++;
127 		if (strnicmp(args, "min", 3) == 0) {
128 		    args += 3;
129 		    min = atol(args);
130 		    minflg = TRUE;
131 		}
132 		else if (strnicmp(args, "max", 3) == 0) {
133 		    args += 3;
134 		    max = atol(args);
135 		    maxflg = TRUE;
136 		}
137 		else if (strnicmp(args, "stk", 3) == 0) {
138 		    args += 3;
139 		    stk = atol(args);
140 		    stkflg = TRUE;
141 		}
142 		else if (strnicmp(args, "v", 1) == 0) {
143 		    listflg = TRUE;
144                     verbose = TRUE;
145                 }
146                 else if (strnicmp(args, "l", 1) == 0)
147                     listflg = TRUE;
148                 else if (strnicmp(args, "p", 1) == 0) {
149                     args++;
150                     jname = args;
151                 }
152 		else {
153 		    printf("\nInvalid paramater %s!\n", argv[i]);
154 		    usage();
155 		    return;
156 		}
157             }
158             i++;
159         }
160     }
161 
162 /*  Extract filename from first argumemt  */
163 
164     strcpy(fname, argv[1]);
165     dot = strrchr(fname, '.');
166     slash = strrchr(fname, '\\');
167     if ((dot == NULL) || (slash > dot))
168         strcat(fname, ".exe");
169 
170     if (nparts) {
171 	strcpy(oname,fname);
172 	*strrchr(fname, '.') = '\0';
173 	strcat(fname,BAKEXT);
174 	if (!stricmp(oname,fname)) {
175 	    printf(
176                 "\nI refuse to split a file with extension "BAKEXT": %s\n",
177                 oname
178             );
179 	    return;
180 	}
181         if (!jname || nparts > 1 && !sstrccnt(jname, '?')) {
182             char ext[5];
183             char *t;
184 
185             if (!jname) {
186                 strcpy(zname, oname);
187                 *strrchr(zname, '.') = '\0';
188                 strcpy(ext, OVLEXT);
189             } else {
190                 if (strrchr(jname, '.') &&
191                      (!strrchr(jname, '\\') ||
192                          strrchr(jname, '.') > strrchr(jname, '\\')
193                      )
194                 ) {
195                     strncpy(ext, strrchr(jname, '.'), sizeof(ext));
196                     ext[sizeof(ext) - 1] = '\0';
197                     strncpy(zname, jname, strrchr(jname, '.') - jname);
198                     zname[strrchr(jname, '.') - jname] = '\0';
199                 } else {
200                     strcpy(zname, jname);
201                     strcpy(ext, OVLEXT);
202                 }
203             }
204             t = strrchr(zname, '\\') ? strrchr(zname, '\\') + 1:
205                 strrchr(zname, ':') ? strrchr(zname, ':') + 1:
206                 zname;
207             if (strlen(t) >= 8)
208                 t[7] = '\0';
209 #if defined(MANYZEROES)
210 	    while (strlen(t) < 8)
211 #endif
212 	      strcat(t, "?");
213             strcat(zname, ext);
214             jname = zname;
215         }
216 	if (rename(oname,fname)) { /* This assumes oldname, newname.
217 				      There's some confusion. OK for TC2.0 */
218 	    printf("\nCouldn't rename (original) %s to %s\n", oname, fname);
219 	    return;
220 	}
221 	if ((outfile = fopen(oname, "wb")) == NULL) {
222             printf("\nCouldn't create file %s\n",oname);
223             return;
224         }
225     }
226 
227     if ((wrkfile = fopen(fname, "r+b")) == NULL) {
228         printf("\nCouldn't open file %s\n", fname);
229         return;
230     }
231 
232     fread(&exehdr_area, sizeof (struct exehdr), 1, wrkfile);
233     if (exehdr_area.signature != 0x5a4d) {
234         printf("\nNot an EXE file!\n");
235         return;
236     }
237 
238     while(!feof(wrkfile)) {
239         if (nparts) {
240 	    if (exehdr_area.ovlnum == partstart[part]) {
241 	         fclose(outfile);
242                  {
243                      int p = part + 1;
244                      strcpy(oname, jname);
245                      while (sstrccnt(oname, '?') > 1) {
246                          *strrchr(oname, '?') = '0' + p % 10;
247                          p /= 10;
248                      }
249                      *strchr(oname, '?') = (p > 9 ? 'a' - 10 : '0') + p;
250                  }
251                  part++;
252 		 if ((outfile = fopen(oname, "wb")) == NULL) {
253                      printf("\nCan't open file %s\n", oname);
254                      return;
255                  }
256 	    }
257             fwrite(&exehdr_area, sizeof (struct exehdr), 1, outfile);
258             if (ferror(outfile)) {
259                 printf("\nWrite error while moving overlay header in %s\n", oname);
260                 return;
261             }
262 	}
263         if (listflg)
264             show_hdr();
265         else if (nparts)
266             printf("[overlay %d]\r", exehdr_area.ovlnum); /* Keep talking... */
267         if ((minflg || maxflg || stkflg) && (exehdr_area.ovlnum == 0) && (exehdr_area.signature == 0x5a4d)) {
268             if (minflg)
269                 exehdr_area.minalloc = min;
270             if (maxflg)
271                 exehdr_area.maxalloc = max;
272             if (stkflg) {
273                 oldstk = exehdr_area.sp;
274                 exehdr_area.sp = stk;
275                 if (!minflg) {
276                     exehdr_area.minalloc += ((stk - oldstk) / 16);
277                     printf("\nAdjusting size of minalloc!\n");
278                 }
279             }
280             fseek(nparts ? outfile : wrkfile, ftell(wrkfile) - sizeof (struct exehdr), SEEK_SET);
281             fwrite(&exehdr_area, sizeof (struct exehdr), 1, nparts ? outfile : wrkfile);
282             if (ferror(nparts ? outfile : wrkfile)) {
283                 printf("Write error while trying to update header!\n");
284                 fclose(nparts ? outfile : wrkfile);
285                 return;
286             }
287         }
288         offset = exehdr_area.pages;
289         offset *= 512L;
290         offset -= sizeof(struct exehdr);
291         if (nparts) { /* Copy the stuff across */
292 	    static char buffer[COPYBUFSIZE];
293 	    while (offset > sizeof(buffer)) {
294 	         fread(buffer, sizeof(buffer), 1, wrkfile);
295                  if (ferror(wrkfile)) {
296                      printf("\nRead error in overlay body\n");
297                      return;
298                  }
299 		 fwrite(buffer, sizeof(buffer), 1, outfile);
300                  if (ferror(outfile)) {
301                      printf("\nWrite error moving overlay body, file %s\n", oname);
302                      return;
303                  }
304 		 offset -= sizeof(buffer);
305 	    }
306 	    fread(buffer, (unsigned)offset, 1, wrkfile);
307             if (ferror(wrkfile)) {
308                 printf("\nRead error in overlay body\n");
309                 return;
310             }
311             fwrite(buffer, (unsigned)offset, 1, outfile);
312             if (ferror(outfile)) {
313                 printf("\nWrite error moving overlay body, file %s\n", oname);
314                 return;
315             }
316         } else fseek(wrkfile, offset, SEEK_CUR);
317         fread(&exehdr_area, sizeof (struct exehdr), 1, wrkfile);
318         if (ferror(wrkfile)) {
319             printf("Read error while trying to get a header!\n");
320             fclose(wrkfile);
321             return;
322         }
323     }
324     if (nparts) {
325         fclose(outfile);
326         if (!listflg) printf("                    \r");
327     }
328     fclose(wrkfile);
329     if (listflg && !verbose && column % 4) printf("\n");
330 }
331 
show_hdr()332 show_hdr()
333 {
334 long lsize;
335 
336     lsize = exehdr_area.pages;
337     if (exehdr_area.mod512 != 0)
338         lsize--;
339     lsize *= 512L;
340     lsize += exehdr_area.minalloc * 16;
341     lsize += exehdr_area.mod512;
342     lsize -= exehdr_area.headerparas * 16;
343 
344     if (verbose) {
345         printf("\nOverlay: %d\n", exehdr_area.ovlnum);
346         printf("Size (512 byte pages)\t-%6x\t\t%6u\n", exehdr_area.pages, exehdr_area.pages);
347         printf("Remainder (last page)\t-%6x\t\t%6u\n", exehdr_area.mod512, exehdr_area.mod512);
348         printf("Header size (in paras)\t-%6x\t\t%6u\n", exehdr_area.headerparas, exehdr_area.headerparas);
349         printf("Minalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.minalloc, exehdr_area.minalloc);
350         printf("Maxalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.maxalloc, exehdr_area.maxalloc);
351         printf("Load size (in bytes)\t-%6lx\t\t%6lu\n", lsize, lsize);
352         printf("Relocation items\t-%6x\t\t%6u\n", exehdr_area.relocitems, exehdr_area.relocitems);
353         printf("Relocation table offset\t-%6x\t\t%6u\n", exehdr_area.relocptr, exehdr_area.relocptr);
354         printf("Checksum\t\t-%6x\t\t%6u\n", exehdr_area.checksum, exehdr_area.checksum);
355         printf("Initial CS:IP\t\t-  %04x:%04x\n", exehdr_area.cs, exehdr_area.ip);
356         printf("Initial SS:SP\t\t-  %04x:%04x\n", exehdr_area.ss, exehdr_area.sp);
357     } else {
358         if (!exehdr_area.ovlnum) {
359             printf("\nOverlay: %d\n", exehdr_area.ovlnum);
360             printf("Minalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.minalloc, exehdr_area.minalloc);
361             printf("Maxalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.maxalloc, exehdr_area.maxalloc);
362             printf("Stored size (in bytes)\t-%6lx\t\t%6lu\n", exehdr_area.pages * 512L, exehdr_area.pages * 512L);
363             printf("Load size (in bytes)\t-%6lx\t\t%6lu\n", lsize, lsize);
364             printf("Initial CS:IP, SS:SP\t-  %04x:%04x\t  %04x:%04x\n", exehdr_area.cs, exehdr_area.ip, exehdr_area.ss, exehdr_area.sp);
365 	} else {
366 	    static bis = 0;
367 	    if (!bis++)
368                 printf("\nOvl StrdSz LoadSz | Ovl StrdSz LoadSz | Ovl StrdSz LoadSz | Ovl StrdSz LoadSz\n");
369             printf("%3d:%6lu %6lu%s", exehdr_area.ovlnum, exehdr_area.pages * 512L, lsize, ++column % 4 ? " | " : "\n");
370         }
371     }
372 }
373 
usage()374 usage()
375 {
376     printf("\nUsage: exesmurf exe_file [/l] [/v] [/min#####] [/max#####] [/stk#####]\n");
377     printf("                [n1 n2...nn] [/p????????.???]\n");
378     printf("       where: min   = minalloc\n");
379     printf("              max   = maxalloc\n");
380     printf("              stk   = stack size\n");
381     printf("              ##### = decimal number of paragraphs\n");
382     printf("              ni    = overlay starting each new .OVL file, n1 < n2 <...< nn\n");
383     printf("              p     = DOS filename, maybe with ?s, for overlay files.\n");
384 }
385