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