home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / tools / exe2bin / exe2com / exe2com.c next >
Text File  |  1987-11-21  |  9KB  |  315 lines

  1. /*
  2.     exe2com 1.02 - an exe2bin replacement
  3.           by Chris Dunford/The Cove Software Group.
  4.     see exe2com.doc for more info.
  5.  
  6.     usage: exe2com file [file]
  7.     usage is the same as exe2bin except:
  8.         1. Output defaults to COM rather than BIN
  9.         2. Binary fixup option not supported
  10.         3. Checksum not verified
  11.         4. Provides more useful error messages, and a warning if a
  12.            COM file is being created with initial IP != 0x100.
  13.  
  14.     Compiler notes:
  15.         The original executable of this file was produced with the
  16.         Computer Innovations C86 compiler (v2.2).
  17.  
  18.     This program was knocked together in about an hour in response to
  19.     the removal of EXE2BIN from the standard DOS distribution disks.
  20.     Improvements/corrections are encouraged.
  21.  
  22.     Program donated to the public domain by the author.
  23.  
  24.     cjd 4/17/87
  25.  
  26.     Modified to run under Turbo C by Roger Schlafly, Borland.
  27.     (It may not run on C86 any more.)
  28.     Compile with
  29.       tcc -Id:\c -Ld:\c -mt -w -O -Z -p exe2com
  30.       exe2com exe2com
  31.     or
  32.       tcc -Id:\c -Ld:\c -M -mt -w -DDEBUG=1 -O -Z -p exe2com
  33.       exe2com exe2com
  34.  
  35.     rss 6/26/87
  36.  
  37.     Fix for even 512-byte boundary file losing last 512 bytes.
  38.     Also corrected signon per request of Chris Dunford ( his name
  39.     was lost in the translation to Turbo C ).
  40.     Version updated to 1.02 to indicate change.
  41.  
  42.     Chris Blum   CompuServe 76625,1041
  43.  
  44.     CJB 11/22/87
  45. */
  46.  
  47. #include <stdio.h>
  48.  
  49. #include <string.h>
  50. /* for unlink */
  51. #include <dos.h>
  52. /* for exit */
  53. #include <stdlib.h>
  54. /* for tolower */
  55. #include <ctype.h>
  56.  
  57. /* Conversion error codes */
  58. #define BADREAD  1
  59. #define BADWRITE 2
  60. #define BADSIG   3
  61. #define HASRELO  4
  62. #define HAS_SS   5
  63. #define HAS_CS   6
  64. #define BAD_IP   7
  65. #define TOO_BIG  8
  66.  
  67. /*
  68. **  Define structure of fixed-format part of EXE file header
  69. */
  70. struct exe_header {
  71.         char exe_sig[2];    /* EXE file signature: "MZ" */
  72.     unsigned excess,        /* Image size mod 512 (valid bytes in last page) */
  73.              pages,         /* # 512-byte pages in image */
  74.              relo_ct,       /* Count of relocation table entries */
  75.              hdr_size,      /* Size of header, in paragraphs */
  76.              min_mem,       /* Min required memory */
  77.              max_mem,       /* Max required memory */
  78.              ss,            /* Stack seg offset in load module */
  79.              sp,            /* Initial value of SP */
  80.              cksum,         /* File checksum */
  81.              ip,            /* Initial value of IP */
  82.              cs,            /* CS offset in load module */
  83.              relo_start,    /* Offset of first relo item */
  84.              ovl_num;       /* Overlay number */
  85. } xh;
  86.  
  87. FILE *fi,                   /* Input file stream */
  88.      *fo;                   /* Output file stream */
  89.  
  90. char fin[129],              /* Input file name */
  91.      fon[129];              /* Output file name */
  92.  
  93.  
  94. unsigned long code_start,   /* Offset of program image in EXE file */
  95.               code_size;    /* Size of program image, in bytes */
  96.  
  97.  
  98. void err_xit (unsigned code);
  99. void convert (void);
  100. void read_hdr(void);
  101. void init (unsigned argc, char *argv[]);
  102.  
  103. char *lower (char *cp)
  104. {
  105. char *cp0;
  106.    for (cp0=cp; (*cp=tolower (*cp)) != 0; ++cp)
  107.            ;
  108.    return cp0;
  109. }
  110.  
  111. void cdecl main(unsigned argc, char *argv[])
  112. {
  113.     init (argc, argv);
  114.     read_hdr ();
  115.     convert ();
  116. }
  117.  
  118.  
  119. /*
  120. **  Initialize - get filenames and open/create files
  121. */
  122. void init (unsigned argc, char *argv[])
  123. {
  124. char *cp;
  125.  
  126.     printf ("exe2com 1.02 by Chris Dunford/The Cove Software Group\n");
  127.  
  128.     /* Check arg count */
  129.     if (argc < 2 || argc > 3) {
  130.         fprintf (stderr, "usage: exe2com file [file]\n");
  131.         exit (1);
  132.     }
  133.  
  134.     /* If argv[1] (the input file) has no extension, add .EXE */
  135.     strcpy (fin, lower (argv[1]));
  136.     if (!strchr (fin, '.'))
  137.         strcat (fin, ".exe");
  138.  
  139.     /* Get or construct output file name */
  140.     if (argc == 3)
  141.         strcpy (fon, lower (argv[2]));
  142.     else
  143.         strcpy (fon, fin);
  144.  
  145.     /* Check output extension--change EXE to COM, or add COM */
  146.     if (!(cp = strchr (fon, '.')))
  147.         strcat (fon, ".com");
  148.     else if (strcmp (cp, ".exe") == 0)
  149.         strcpy (cp, ".com");
  150.  
  151. #ifdef DEBUG
  152.     printf ("input=%s, output=%s\n", fin, fon);
  153. #endif
  154.  
  155.     /* Try to open input file */
  156.     if (!(fi = fopen (fin, "rb"))) {
  157.         fprintf (stderr, "exe2com: can't find input file %s\n", fin);
  158.         exit (1);
  159.     }
  160.  
  161.     /* Try to create output file */
  162.     if (!(fo = fopen (fon, "wb"))) {
  163.         fprintf (stderr, "exe2com: can't open output file %s\n", fin);
  164.         exit (1);
  165.     }
  166. }
  167.  
  168.  
  169. /*
  170. **  Read and check the EXE file header
  171. */
  172. void read_hdr(void)
  173. {
  174.  
  175.     /* Read the formatted portion of the header */
  176.     if (!fread (&xh, sizeof (struct exe_header), 1, fi))
  177.         err_xit (BADREAD);
  178.  
  179. #ifdef DEBUG
  180.     printf ("EXE file header:\n");
  181.     printf ("  signature      %c%c\n", xh.exe_sig[0], xh.exe_sig[1]);
  182.     printf ("  bytes last pg  %04x\n", xh.excess);
  183.     printf ("  pages          %04x\n", xh.pages);
  184.     printf ("  relo count     %04x\n", xh.relo_ct);
  185.     printf ("  header size    %04x\n", xh.hdr_size);
  186.     printf ("  min mem        %04x\n", xh.min_mem);
  187.     printf ("  max mem        %04x\n", xh.max_mem);
  188.     printf ("  ss             %04x\n", xh.ss);
  189.     printf ("  sp             %04x\n", xh.sp);
  190.     printf ("  checksum       %04x\n", xh.cksum);
  191.     printf ("  ip             %04x\n", xh.ip);
  192.     printf ("  cs             %04x\n", xh.cs);
  193.     printf ("  relo tbl start %04x\n", xh.relo_start);
  194.     printf ("  overlay nbr    %04x\n", xh.ovl_num);
  195. #endif
  196.  
  197.     /* Check header; to be convertible, must have:
  198.     **      -- first two bytes == "MZ"
  199.     **      -- no relocatable items
  200.     **      -- no stack segment
  201.     **      -- no code segment
  202.     **      -- IP == 0 or 100
  203.     */
  204.     if (strncmp (xh.exe_sig, "MZ", 2))
  205.         err_xit (BADSIG);
  206.     if (xh.relo_ct)
  207.         err_xit (HASRELO);
  208.     if (xh.ss || xh.sp)
  209.         err_xit (HAS_SS);
  210.     if (xh.ip != 0 && xh.ip != 0x100)
  211.         err_xit (BAD_IP);
  212.  
  213.     /* Compute offset of program image in module, and program size.
  214.     **
  215.     ** The program size is computed as follows; it cannot exceed 64K bytes:
  216.     **     512 * (# EXE pages - 1)
  217.     **   + valid bytes in last EXE page
  218.     **   - offset of program image in EXE file
  219.     **
  220.     ** Note that if the IP is nonzero, we will skip the first
  221.     ** IP bytes of the program image, and copy IP bytes fewer
  222.     ** than the actual size.
  223.     */
  224.     code_start = ((unsigned long) xh.hdr_size) << 4;
  225.     code_size = (unsigned long) (xh.pages-1) * 512
  226.         + (xh.excess ? xh.excess : 512)    /* fixed 11/19/87 - CJB */
  227.         - code_start;
  228.     if (code_size >= 65536L)
  229.         err_xit (TOO_BIG);
  230.  
  231.     /* Issue a warning if COM file and IP != 0x100 */
  232.     if (!strcmp (strchr (fon, '.'), ".com") && xh.ip != 0x100)
  233.         fprintf (stderr, "exe2com warning: COM file, initial IP not 100H\n");
  234.  
  235. }
  236.  
  237.  
  238.  
  239. /*
  240. **  Convert the file.  Nothing to do, really, other than
  241. **  reading the image (which follows the header), and
  242. **  dumping it back out to disk.
  243. */
  244. void convert (void)
  245. {
  246. char buffer[512];
  247. unsigned wsize;
  248.  
  249.     /* Seek to start of program image, skipping IP bytes */
  250.     if (fseek (fi, code_start+xh.ip, 0) != 0)
  251.         err_xit (BADREAD);
  252.  
  253.     /* Reduce the "remaining" byte count by IP bytes */
  254.     code_size -= xh.ip;
  255.  
  256.     /* Read blocks and copy to output */
  257.     while (code_size) {
  258.  
  259.         /* Read block */
  260.         if (!fread (buffer, 1, 512, fi))
  261.             err_xit (BADREAD);
  262.  
  263.         /* Set count of bytes to write, write block */
  264.         wsize = (unsigned) (code_size > 512 ? 512 : code_size);
  265.         if (!fwrite (buffer, wsize, 1, fo))
  266.             err_xit (BADWRITE);
  267.  
  268.         /* Subtract bytes written from remaining byte count */
  269.         code_size -= wsize;
  270.     }
  271.  
  272.     /* All done, close the two files */
  273.     fclose (fi);
  274.     fclose (fo);
  275. }
  276.  
  277.  
  278. /*
  279. **  Display an error message, delete output file, exit.
  280. */
  281. void err_xit (unsigned code)
  282. {
  283. char msg[64];
  284.  
  285.     switch (code) {
  286.         case BADREAD:   strcpy (msg, "error reading EXE header");
  287.                         break;
  288.         case BADWRITE:  strcpy (msg, "error writing output file");
  289.                         break;
  290.         case BADSIG:    strcpy (msg, "invalid EXE file signature");
  291.                         break;
  292.         case HASRELO:   strcpy (msg, "EXE has relocatable items");
  293.                         break;
  294.         case HAS_SS:    strcpy (msg, "EXE has stack segment");
  295.                         break;
  296.         case HAS_CS:    strcpy (msg, "EXE has nonzero CS");
  297.                         break;
  298.         case BAD_IP:    strcpy (msg, "IP not 0 or 100H");
  299.                         break;
  300.         case TOO_BIG:   strcpy (msg, "program exceeds 64K");
  301.                         break;
  302.         default:        strcpy (msg, "unknown error");
  303.     }
  304.  
  305.     fprintf (stderr, "exe2com: %s, can't convert\n", msg);
  306.  
  307.     /* Close two files and delete partial output */
  308.     fclose (fi);
  309.     fclose (fo);
  310.     unlink (fon);
  311.  
  312.     /* Exit with errorlevel 1 */
  313.     exit (1);
  314. }
  315.