471 lines
10 KiB
C
471 lines
10 KiB
C
/*
|
|
** 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 <stdio.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
|
|
#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] <input> ...\n");
|
|
return 0;
|
|
}
|
|
|
|
switch(argv[1][0])
|
|
{
|
|
case 'c':
|
|
if(argc < 4)
|
|
{
|
|
printf("Need an output location. (Extra parms: <output> [<symbol>])\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: <output> [<segname> <symbol>])\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: <output> [<skip>])\n");
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
int skip = 0;
|
|
if(argc >= 5)
|
|
{
|
|
skip = atoi(argv[4]);
|
|
}
|
|
DumpData(argv[2], argv[3], skip);
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|