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