home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Boston 2
/
boston-2.iso
/
DOS
/
HILFEN
/
PACKER
/
EXE2COM
/
EXE2COM.C
next >
Wrap
C/C++ Source or Header
|
1993-12-01
|
9KB
|
295 lines
/*
exe2com - exe2bin replacement by Chris Dunford/Cove Software
usage: exe2com file [file]
usage is the same as exe2bin except:
1. Output defaults to COM rather than BIN
2. Binary fixup option not supported
3. Checksum not verified
4. Provides more useful error messages, and a warning if a
COM file is being created with initial IP != 0x100.
Compiler notes:
The original executable of this file was produced with the
Computer Innovations C86 compiler (v2.2), but it should work
with just about any C compiler, with the possible exception
of the lower() function. This function is part of the C86
library; it simply lowercases a string without moving it and
returns the address of the string. If your compiler doesn't
have lower() or an equivalent, add this function:
char *lower (cp)
char *cp;
{
char *cp0;
for (cp0=cp; *cp=tolower (*cp); ++cp)
;
return cp0;
}
This program was knocked together in about an hour in response to
the removal of EXE2BIN from the standard DOS distribution disks.
Improvements/corrections are encouraged.
Program donated to the public domain by the author.
cjd 4/17/87
*/
#include <stdio.h>
#define void int
/* Conversion error codes */
#define BADREAD 1
#define BADWRITE 2
#define BADSIG 3
#define HASRELO 4
#define HAS_SS 5
#define HAS_CS 6
#define BAD_IP 7
#define TOO_BIG 8
/*
** Define structure of fixed-format part of EXE file header
*/
struct exe_header {
char exe_sig[2]; /* EXE file signature: "MZ" */
unsigned excess, /* Image size mod 512 (valid bytes in last page) */
pages, /* # 512-byte pages in image */
relo_ct, /* Count of relocation table entries */
hdr_size, /* Size of header, in paragraphs */
min_mem, /* Min required memory */
max_mem, /* Max required memory */
ss, /* Stack seg offset in load module */
sp, /* Initial value of SP */
cksum, /* File checksum */
ip, /* Initial value of IP */
cs, /* CS offset in load module */
relo_start, /* Offset of first relo item */
ovl_num; /* Overlay number */
} xh;
FILE *fi, /* Input file stream */
*fo, /* Output file stream */
*fopen();
char fin[129], /* Input file name */
fon[129]; /* Output file name */
unsigned long code_start, /* Offset of program image in EXE file */
code_size; /* Size of program image, in bytes */
extern char *strcpy(), *strcat(), *index(), *lower();
main(argc, argv)
unsigned argc;
char *argv[];
{
init (argc, argv);
read_hdr ();
convert ();
}
/*
** Initialize - get filenames and open/create files
*/
void init (argc, argv)
unsigned argc;
char *argv[];
{
char *cp;
printf ("exe2com 1.00 by Chris Dunford/The Cove Software Group\n");
/* Check arg count */
if (argc < 2 || argc > 3) {
fprintf (stderr, "usage: exe2com file [file]\n");
exit (1);
}
/* If argv[1] (the input file) has no extension, add .EXE */
strcpy (fin, lower (argv[1]));
if (!index (fin, '.'))
strcat (fin, ".exe");
/* Get or construct output file name */
if (argc == 3)
strcpy (fon, lower (argv[2]));
else
strcpy (fon, fin);
/* Check output extension--change EXE to COM, or add COM */
if (!(cp = index (fon, '.')))
strcat (fon, ".com");
else if (strcmp (cp, ".exe") == 0)
strcpy (cp, ".com");
#ifdef DEBUG
printf ("input=%s, output=%s\n", fin, fon);
#endif
/* Try to open input file */
if (!(fi = fopen (fin, "rb"))) {
fprintf (stderr, "exe2com: can't find input file %s\n", fin);
exit (1);
}
/* Try to create output file */
if (!(fo = fopen (fon, "wb"))) {
fprintf (stderr, "exe2com: can't open output file %s\n", fin);
exit (1);
}
}
/*
** Read and check the EXE file header
*/
void read_hdr()
{
/* Read the formatted portion of the header */
if (!fread (&xh, sizeof (struct exe_header), 1, fi))
err_xit (BADREAD);
#ifdef DEBUG
printf ("EXE file header:\n");
printf (" signature %c%c\n", xh.exe_sig[0], xh.exe_sig[1]);
printf (" bytes last pg %04x\n", xh.excess);
printf (" pages %04x\n", xh.pages);
printf (" relo count %04x\n", xh.relo_ct);
printf (" header size %04x\n", xh.hdr_size);
printf (" min mem %04x\n", xh.min_mem);
printf (" max mem %04x\n", xh.max_mem);
printf (" ss %04x\n", xh.ss);
printf (" sp %04x\n", xh.sp);
printf (" checksum %04x\n", xh.cksum);
printf (" ip %04x\n", xh.ip);
printf (" cs %04x\n", xh.cs);
printf (" relo tbl start %04x\n", xh.relo_start);
printf (" overlay nbr %04x\n", xh.ovl_num);
#endif
/* Check header; to be convertible, must have:
** -- first two bytes == "MZ"
** -- no relocatable items
** -- no stack segment
** -- no code segment
** -- IP == 0 or 100
*/
if (strncmp (xh.exe_sig, "MZ", 2))
err_xit (BADSIG);
if (xh.relo_ct)
err_xit (HASRELO);
if (xh.ss || xh.sp)
err_xit (HAS_SS);
if (xh.ip != 0 && xh.ip != 0x100)
err_xit (BAD_IP);
/* Compute offset of program image in module, and program size.
**
** The program size is computed as follows; it cannot exceed 64K bytes:
** 512 * (# EXE pages - 1)
** + valid bytes in last EXE page
** - offset of program image in EXE file
**
** Note that if the IP is nonzero, we will skip the first
** IP bytes of the program image, and copy IP bytes fewer
** than the actual size.
*/
code_start = ((unsigned long) xh.hdr_size) << 4;
code_size = (unsigned long) (xh.pages-1) * 512 + xh.excess - code_start;
if (code_size > 65536L)
err_xit (TOO_BIG);
/* Issue a warning if COM file and IP != 0x100 */
if (!strcmp (index (fon, '.'), ".com") && xh.ip != 0x100)
fprintf (stderr, "exe2com warning: COM file, initial IP not 100H\n");
}
/*
** Convert the file. Nothing to do, really, other than
** reading the image (which follows the header), and
** dumping it back out to disk.
*/
void convert ()
{
char buffer[512];
unsigned wsize;
extern unsigned long fseek();
/* Seek to start of program image, skipping IP bytes */
if (fseek (fi, code_start+xh.ip, 0) != code_start+xh.ip)
err_xit (BADREAD);
/* Reduce the "remaining" byte count by IP bytes */
code_size -= xh.ip;
/* Read blocks and copy to output */
while (code_size) {
/* Read block */
if (!fread (buffer, 512, 1, fi))
err_xit (BADREAD);
/* Set count of bytes to write, write block */
wsize = code_size > 512 ? 512 : code_size;
if (!fwrite (buffer, wsize, 1, fo))
err_xit (BADWRITE);
/* Subtract bytes written from remaining byte count */
code_size -= wsize;
}
/* All done, close the two files */
fclose (fi);
fclose (fo);
}
/*
** Display an error message, delete output file, exit.
*/
void err_xit (code)
unsigned code;
{
char msg[64];
switch (code) {
case BADREAD: strcpy (msg, "error reading EXE header");
break;
case BADWRITE: strcpy (msg, "error writing output file");
break;
case BADSIG: strcpy (msg, "invalid EXE file signature");
break;
case HASRELO: strcpy (msg, "EXE has relocatable items");
break;
case HAS_SS: strcpy (msg, "EXE has stack segment");
break;
case HAS_CS: strcpy (msg, "EXE has nonzero CS");
break;
case BAD_IP: strcpy (msg, "IP not 0 or 100H");
break;
case TOO_BIG: strcpy (msg, "program exceeds 64K");
break;
default: strcpy (msg, "unknown error");
}
fprintf (stderr, "exe2com: %s, can't convert\n", msg);
/* Close two files and delete partial output */
fclose (fi);
fclose (fo);
unlink (fon);
/* Exit with errorlevel 1 */
exit (1);
}