+/*\r
+** makeobj.c\r
+**\r
+**---------------------------------------------------------------------------\r
+** Copyright 2014 Braden Obrzut\r
+** All rights reserved.\r
+**\r
+** Redistribution and use in source and binary forms, with or without\r
+** modification, are permitted provided that the following conditions\r
+** are met:\r
+**\r
+** 1. Redistributions of source code must retain the above copyright\r
+** notice, this list of conditions and the following disclaimer.\r
+** 2. Redistributions in binary form must reproduce the above copyright\r
+** notice, this list of conditions and the following disclaimer in the\r
+** documentation and/or other materials provided with the distribution.\r
+** 3. The name of the author may not be used to endorse or promote products\r
+** derived from this software without specific prior written permission.\r
+**\r
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+**---------------------------------------------------------------------------\r
+**\r
+** This is a throwaway program to create OMF object files for DOS. It also\r
+** extracts the object files. It should be compatible with MakeOBJ by John\r
+** Romero except where we calculate the checksum correctly.\r
+**\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <malloc.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <stdlib.h>\r
+\r
+#pragma pack(1)\r
+typedef struct\r
+{\r
+ unsigned char type;\r
+ unsigned short len;\r
+} SegHeader;\r
+\r
+typedef struct\r
+{\r
+ unsigned short len;\r
+ unsigned char name;\r
+ unsigned char classname;\r
+ unsigned char overlayname;\r
+} SegDef;\r
+#pragma pack()\r
+\r
+const char* ReadFile(const char* fn, int *size)\r
+{\r
+ char* out;\r
+\r
+ FILE* f = fopen(fn, "rb");\r
+ fseek(f, 0, SEEK_END);\r
+ *size = ftell(f);\r
+ out = (char*)malloc(*size);\r
+ fseek(f, 0, SEEK_SET);\r
+\r
+ fread(out, *size, 1, f);\r
+\r
+ fclose(f);\r
+\r
+ return out;\r
+}\r
+\r
+void WriteFile(const char* fn, const char *data, int size)\r
+{\r
+ FILE* f = fopen(fn, "wb");\r
+ fwrite(data, size, 1, f);\r
+ fclose(f);\r
+}\r
+\r
+void Extract(const char* infn)\r
+{\r
+ const char* in;\r
+ const char* start;\r
+ const char* p;\r
+ char outfn[16];\r
+ char str[256];\r
+ char *outdata;\r
+ int outsize;\r
+ int insize;\r
+ SegHeader head;\r
+\r
+ outdata = NULL;\r
+\r
+ start = in = ReadFile(infn, &insize);\r
+\r
+ while(in < start + insize)\r
+ {\r
+ head = *(SegHeader*)in;\r
+\r
+ switch(head.type)\r
+ {\r
+ case 0x80: /* THEADR */\r
+ memcpy(outfn, in+4, in[3]);\r
+ outfn[in[3]] = 0;\r
+ printf("Output: %s\n", outfn);\r
+ {\r
+ int i;\r
+ for(i = 0;i < 16;++i)\r
+ {\r
+ if(outfn[i] == ' ')\r
+ outfn[i] = 0;\r
+ }\r
+ }\r
+ break;\r
+ case 0x88: /* COMENT */\r
+ switch(in[3])\r
+ {\r
+ case 0:\r
+ memcpy(str, in+5, head.len-2);\r
+ str[head.len-3] = 0;\r
+ printf("Comment: %s\n", str);\r
+ break;\r
+ default:\r
+ printf("Unknown comment type %X @ %x ignored.\n", (unsigned char)in[3], (unsigned int)(in - start));\r
+ break;\r
+ }\r
+ break;\r
+ case 0x96: /* LNAMES */\r
+ p = in+3;\r
+ while(p < in+head.len+2)\r
+ {\r
+ memcpy(str, p+1, (unsigned char)*p);\r
+ str[(unsigned char)*p] = 0;\r
+ printf("Name: %s\n", str);\r
+\r
+ p += (unsigned char)*p+1;\r
+ }\r
+ break;\r
+ case 0x98: /* SEGDEF */\r
+ {\r
+ SegDef *sd;\r
+\r
+ sd = *(in+3) ? (SegDef*)(in+4) : (SegDef*)(in+7);\r
+ printf("Segment Length: %d\n", sd->len);\r
+\r
+ outdata = (char*)malloc(sd->len);\r
+ outsize = sd->len;\r
+ break;\r
+ }\r
+ case 0x90: /* PUBDEF */\r
+ p = in+5;\r
+ if(in[5] == 0)\r
+ p += 2;\r
+ while(p < in+head.len+2)\r
+ {\r
+ memcpy(str, p+1, (unsigned char)*p);\r
+ str[(unsigned char)*p] = 0;\r
+ printf("Public Name: %s\n", str);\r
+\r
+ p += (unsigned char)*p+4;\r
+ }\r
+ break;\r
+ case 0xA0: /* LEDATA */\r
+ printf("Writing data at %d (%d)\n", *(unsigned short*)(in+4), head.len-4);\r
+ memcpy(outdata+*(unsigned short*)(in+4), in+6, head.len-4);\r
+ break;\r
+ case 0x8A: /* MODEND */\r
+ /* Ignore */\r
+ break;\r
+ default:\r
+ printf("Unknown header type %X @ %x ignored.\n", head.type, (unsigned int)(in - start));\r
+ break;\r
+ }\r
+\r
+ in += 3 + head.len;\r
+ }\r
+\r
+ WriteFile(outfn, outdata, outsize);\r
+\r
+ free((char*)start);\r
+ free(outdata);\r
+}\r
+\r
+void CheckSum(char *s, unsigned short len)\r
+{\r
+ int sum;\r
+\r
+ len += 3;\r
+\r
+ sum = 0;\r
+ while(len > 1)\r
+ {\r
+ sum += *(unsigned char*)s;\r
+ ++s;\r
+ --len;\r
+ }\r
+ *s = (unsigned char)(0x100-(sum&0xFF));\r
+}\r
+\r
+void MakeDataObj(const char* infn, const char* outfn, const char* segname, const char* symname, int altmode)\r
+{\r
+#define Flush() fwrite(d.buf, d.head.len+3, 1, f)\r
+ union\r
+ {\r
+ char buf[4096];\r
+ SegHeader head;\r
+ } d;\r
+ int i;\r
+ FILE *f;\r
+ int insize;\r
+ const char *in;\r
+ const char *infn_stripped = strrchr(infn, '/');\r
+ if(strrchr(infn, '\\') > infn_stripped)\r
+ infn_stripped = strrchr(infn, '\\');\r
+ if(infn_stripped == NULL)\r
+ infn_stripped = infn;\r
+ else\r
+ ++infn_stripped;\r
+\r
+ f = fopen(outfn, "wb");\r
+\r
+ in = ReadFile(infn, &insize);\r
+\r
+ d.head.type = 0x80;\r
+ d.head.len = 14;\r
+ d.buf[3] = 12;\r
+ if(d.buf[3] > 12)\r
+ d.buf[3] = 12;\r
+ sprintf(&d.buf[4], "%-12s", infn_stripped);\r
+ for(i = 0;i < strlen(infn_stripped) && i < 12;++i)\r
+ d.buf[4+i] = toupper(d.buf[4+i]);\r
+ /* CheckSum(d.buf, d.head.len); */\r
+ d.buf[17] = 0; /* For some reason this one isn't checksummed by MakeOBJ */\r
+ Flush();\r
+\r
+ d.head.type = 0x88;\r
+ d.head.len = 15;\r
+ d.buf[3] = 0;\r
+ d.buf[4] = 0;\r
+ /* We're not really MakeOBJ v1.1, but to allow us to verify with md5sums */\r
+ memcpy(&d.buf[5], "MakeOBJ v1.1", 12);\r
+ CheckSum(d.buf, d.head.len);\r
+ Flush();\r
+\r
+ d.head.type = 0x96;\r
+ d.head.len = strlen(infn_stripped)+40;\r
+ d.buf[3] = 6;\r
+ memcpy(&d.buf[4], "DGROUP", 6);\r
+ d.buf[10] = 5;\r
+ memcpy(&d.buf[11], "_DATA", 5);\r
+ d.buf[16] = 4;\r
+ memcpy(&d.buf[17], "DATA", 4);\r
+ d.buf[21] = 0;\r
+ d.buf[22] = 5;\r
+ memcpy(&d.buf[23], "_TEXT", 5);\r
+ d.buf[28] = 4;\r
+ memcpy(&d.buf[29], "CODE", 4);\r
+ d.buf[33] = 8;\r
+ memcpy(&d.buf[34], "FAR_DATA", 8);\r
+ if(!segname)\r
+ {\r
+ if(!altmode)\r
+ {\r
+ d.buf[42] = strlen(infn_stripped)-1;\r
+ for(i = 0;i < strlen(infn_stripped)-4;++i)\r
+ {\r
+ if(i == 0)\r
+ d.buf[43] = toupper(infn_stripped[0]);\r
+ else\r
+ d.buf[43+i] = tolower(infn_stripped[i]);\r
+ }\r
+ memcpy(&d.buf[43+i], "Seg", 3);\r
+ }\r
+ else\r
+ {\r
+ d.head.len = 40;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ d.head.len = strlen(segname)+41;\r
+ d.buf[42] = strlen(segname);\r
+ strcpy(&d.buf[43], segname);\r
+ }\r
+ CheckSum(d.buf, d.head.len);\r
+ Flush();\r
+\r
+ d.head.type = 0x98;\r
+ d.head.len = 7;\r
+ *(unsigned short*)(d.buf+4) = insize;\r
+ if(altmode == 0)\r
+ {\r
+ d.buf[3] = (char)((unsigned char)0x60);\r
+ d.buf[6] = 8;\r
+ d.buf[7] = 7;\r
+ d.buf[8] = 4;\r
+ }\r
+ else\r
+ {\r
+ d.buf[3] = (char)((unsigned char)0x48);\r
+ d.buf[6] = 2;\r
+ d.buf[7] = 3;\r
+ d.buf[8] = 4;\r
+ }\r
+ CheckSum(d.buf, d.head.len);\r
+ Flush();\r
+\r
+ if(altmode)\r
+ {\r
+ d.head.type = 0x9A;\r
+ d.head.len = 4;\r
+ d.buf[3] = 1;\r
+ d.buf[4] = (char)((unsigned char)0xFF);\r
+ d.buf[5] = 1;\r
+ CheckSum(d.buf, d.head.len);\r
+ Flush();\r
+ }\r
+\r
+ d.head.type = 0x90;\r
+ d.head.len = strlen(infn_stripped)+4;\r
+ d.buf[3] = 1;\r
+ d.buf[4] = 1;\r
+ if(!symname)\r
+ {\r
+ d.buf[5] = strlen(infn_stripped)-3;\r
+ d.buf[6] = '_';\r
+ for(i = 0;i < strlen(infn_stripped)-4;++i)\r
+ d.buf[7+i] = tolower(infn_stripped[i]);\r
+ }\r
+ else\r
+ {\r
+ d.head.len = strlen(symname)+7;\r
+ d.buf[5] = strlen(symname);\r
+ strcpy(&d.buf[6], symname);\r
+ i = strlen(symname)-1;\r
+ }\r
+ d.buf[7+i] = 0;\r
+ d.buf[8+i] = 0;\r
+ d.buf[9+i] = 0;\r
+ /* This checksum is calculated wrong in MakeOBJ, although I don't know in what way. */\r
+ CheckSum(d.buf, d.head.len);\r
+ Flush();\r
+\r
+#define LEDATA_LEN 1024\r
+ for(i = 0;i < insize;i += LEDATA_LEN)\r
+ {\r
+ d.head.type = 0xA0;\r
+ d.head.len = insize - i > LEDATA_LEN ? LEDATA_LEN+4 : insize - i + 4;\r
+ d.buf[3] = 1;\r
+ *(unsigned short*)(d.buf+4) = i;\r
+ memcpy(&d.buf[6], &in[i], d.head.len-4);\r
+ CheckSum(d.buf, d.head.len);\r
+ Flush();\r
+ }\r
+\r
+ d.head.type = 0x8A;\r
+ d.head.len = 2;\r
+ d.buf[3] = 0;\r
+ d.buf[4] = 0;\r
+ CheckSum(d.buf, d.head.len);\r
+ Flush();\r
+\r
+ fclose(f);\r
+ free((char*)in);\r
+}\r
+\r
+void DumpData(const char* infn, const char* outfn, int skip)\r
+{\r
+ FILE *f;\r
+ int i;\r
+ int insize;\r
+ char symname[9];\r
+ const char *in;\r
+ const char *infn_stripped = strrchr(infn, '/');\r
+ if(strrchr(infn, '\\') > infn_stripped)\r
+ infn_stripped = strrchr(infn, '\\');\r
+ if(infn_stripped == NULL)\r
+ infn_stripped = infn;\r
+ else\r
+ ++infn_stripped;\r
+\r
+ f = fopen(outfn, "wb");\r
+\r
+ memset(symname, 0, 9);\r
+ memcpy(symname, infn_stripped, strlen(infn_stripped)-4);\r
+ fprintf(f, "char far %s[] ={\r\n", symname);\r
+\r
+ in = ReadFile(infn, &insize);\r
+\r
+ for(i = skip;i < insize;++i)\r
+ {\r
+ fprintf(f, "%d", (unsigned char)in[i]);\r
+ if(i != insize-1)\r
+ fprintf(f, ",\r\n");\r
+ }\r
+ fprintf(f, " };\r\n");\r
+\r
+ fclose(f);\r
+ free((char*)in);\r
+}\r
+\r
+int main(int argc, char* argv[])\r
+{\r
+ if(argc < 3)\r
+ {\r
+ printf("Converts file to OMF.\nUseage:\n ./makeobj [fx] <input> ...\n");\r
+ return 0;\r
+ }\r
+\r
+ switch(argv[1][0])\r
+ {\r
+ case 'c':\r
+ if(argc < 4)\r
+ {\r
+ printf("Need an output location. (Extra parms: <output> [<symbol>])\n");\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ const char *symname = NULL;\r
+ if(argc >= 5)\r
+ symname = argv[4];\r
+ MakeDataObj(argv[2], argv[3], NULL, symname, 1);\r
+ }\r
+ break;\r
+ default:\r
+ case 'f':\r
+ if(argc < 4)\r
+ {\r
+ printf("Need an output location. (Extra parms: <output> [<segname> <symbol>])\n");\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ const char *segname = NULL, *symname = NULL;\r
+ if(argc >= 6)\r
+ {\r
+ segname = argv[4];\r
+ symname = argv[5];\r
+ }\r
+ MakeDataObj(argv[2], argv[3], segname, symname, 0);\r
+ }\r
+ break;\r
+ case 'x':\r
+ Extract(argv[2]);\r
+ break;\r
+ case 's':\r
+ if(argc < 4)\r
+ {\r
+ printf("Need an output location. (Extra parms: <output> [<skip>])\n");\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ int skip = 0;\r
+ if(argc >= 5)\r
+ {\r
+ skip = atoi(argv[4]);\r
+ }\r
+ DumpData(argv[2], argv[3], skip);\r
+ }\r
+ break;\r
+ break;\r
+ }\r
+ return 0;\r
+}\r