From: DeaDDooMER Date: Wed, 13 Jul 2016 17:31:11 +0000 (+0300) Subject: first commit X-Git-Url: http://deadsoftware.ru/gitweb?p=awtools.git;a=commitdiff_plain;h=a5b49eb88ce739a4ef00b51c3a03b88a3749871f first commit --- a5b49eb88ce739a4ef00b51c3a03b88a3749871f diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2fa0e39 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +all: unpk dis + +unpk: + cc -o unpk unpk.c + +dis: + cc -o dis dis.c dis_aw.c dis_intel.c dis_att.c + +#view: +# cc -lSDL2 -o view view.c view_vid.c + +distclean: + rm -f unpk dis view + +workclean: + rm -f file*.snd file*.mus file*.bmp file*.pal file*.obj file*.spr file*.unk diff --git a/README b/README new file mode 100644 index 0000000..5e3ab35 --- /dev/null +++ b/README @@ -0,0 +1,19 @@ +Another World (Out of This World) tools: + unpk - Resource unpacker + dis - Script disassembler + +unpk + No options. Just pwd into directory with MEMLIST.BIN and BANKs and run + programm. + +dis [-a | -i | -u] [-p] OBJECT OUTFILE + OBJECT - Binary script(fileXX.obj) + OUTFILE - Out assembler listing + -a | -i | -u - Generate with AnotherWorld/Intel/AT&T syntax + -p - print opcode address + +Licence: GPLv3 + +Links: + https://www.anotherworld.fr/anotherworld_uk/another_world.htm + https://github.com/cyxx/rawgl \ No newline at end of file diff --git a/dis.c b/dis.c new file mode 100644 index 0000000..e259e8f --- /dev/null +++ b/dis.c @@ -0,0 +1,309 @@ +#include +#include +#include +#include +#include + +#include "dis.h" +#include "dis_syn.h" + +/* + * Another World script disassembler + * Only DOS version are supported + */ + +#define MSG_USAGE "usage: disasm [-a | -i | -u] [-p] OBJECT OUTFILE\n" +#define MSG_OPENERR "can't open file %s.\n" +#define MSG_WRITEERR "can't create file %s.\n" +#define MSG_INVALIDOP "invalid opcode 0x%X\n" +#define MSG_INVALIDJMP "invalid jump opcode %u\n" + +char *input, *output; + +FILE *fp; + +uint8_t *code; +uint16_t codesize; +uint16_t pc, adr; + +struct labelinfo label[MAX_LABEL]; +int labelnum; +bool printcode; +bool printadr; + +void (*printlabel)(int); +void (*printopcode)(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, int); + +static uint8_t ubyte() { + return code[pc++]; +} + +static uint16_t uword() { + return (ubyte() << 8) | ubyte(); +} + +static int addlabel(uint16_t adr, int type) { + for(int i = 0; i < labelnum; i++) { + if(label[i].adr == adr) + return i; + } + + label[labelnum].adr = adr; + label[labelnum].type = type; + ++labelnum; + return labelnum - 1; +} + +static void fndlabel() { + for(int i = 0; i < labelnum; i++) { + if(label[i].adr == pc) { + printlabel(i); + return; + } + } + + printlabel(-1); +} + +static void step() { + adr = pc; + + if(printcode) + fndlabel(); + + uint8_t op = ubyte(); + uint16_t x = -1, y = -1, z = -1, w = -1; + int label = -666; + + if(op & 0x80) { /* spr */ + w = (((op << 8) | ubyte()) << 1) & 0x7FFF; + x = ubyte(); + y = ubyte(); + } else if(op & 0x40) { /* spr */ + w = (uword() << 1) & 0x7FFF; + + x = ubyte(); + if((op & 48) == 0) + x = (x << 8) | ubyte(); + else if((op & 48) == 48) + x = x + 256; + + y = ubyte(); + if((op & 12) == 0) + y = (y << 8) | ubyte(); + + if((op & 3) == 1 || (op & 3) == 2) + z = ubyte(); + else + z = 64; + } else { + switch(op) { + case 0x0: /* seti */ + x = ubyte(); + y = uword(); + break; + case 0x1: /* set */ + x = ubyte(); + y = ubyte(); + break; + case 0x2: /* add */ + x = ubyte(); + y = ubyte(); + break; + case 0x3: /* addi */ + x = ubyte(); + y = uword(); + break; + case 0x4: /* jsr */ + x = uword(); + label = addlabel(x, LT_CALL); + break; + case 0x5: /* return */ + break; + case 0x6: /* break */ + break; + case 0x7: /* jmp */ + x = uword(); + label = addlabel(x, LT_JUMP); + break; + case 0x8: /* setvec */ + x = ubyte(); + y = uword(); + label = addlabel(y, LT_VEC); + break; + case 0x9: /* dbra */ + x = ubyte(); + y = uword(); + label = addlabel(y, LT_JUMP); + break; + case 0xA: /* si */ + w = ubyte(); + x = ubyte(); + + if(w & 0x80) + y = ubyte(); + else if(w & 0x40) + y = uword(); + else + y = ubyte(); + + if((w & 7) > 5) { + printf(MSG_INVALIDJMP, w & 0x7); + exit(1); + } + + z = uword(); + label = addlabel(z, LT_JUMP); + break; + case 0xB: /* fade */ + x = uword() >> 8; + break; + case 0xC: /* vec */ + x = ubyte(); + y = ubyte(); + z = ubyte(); + break; + case 0xD: /* setws */ + x = ubyte(); + break; + case 0xE: /* clr */ + x = ubyte(); + y = ubyte(); + break; + case 0xF: /* copy */ + x = ubyte(); + y = ubyte(); + break; + case 0x10: /* show */ + x = ubyte(); + break; + case 0x11: /* bigend */ + break; + case 0x12: /* text */ + z = uword(); + x = ubyte(); + y = ubyte(); + w = ubyte(); + break; + case 0x13: /* sub */ + x = ubyte(); + y = ubyte(); + break; + case 0x14: /* andi */ + x = ubyte(); + y = uword(); + break; + case 0x15: /* ori */ + x = ubyte(); + y = uword(); + break; + case 0x16: /* lsl */ + x = ubyte(); + y = uword(); + break; + case 0x17: /* lsr */ + x = ubyte(); + y = uword(); + break; + case 0x18: /* play */ + z = uword(); + x = ubyte(); + y = ubyte(); + w = ubyte(); + break; + case 0x19: /* load */ + x = uword(); + break; + case 0x1A: /* song */ + x = uword(); + y = uword(); + z = ubyte(); + break; + default: + printf(MSG_INVALIDOP, op); + exit(1); + } + } + + if(printcode) + printopcode(op, x, y, z, w, label); +} + +static void readarg(int argc, char **argv) { + if(argc < 3) + goto error; + + printadr = false; + printlabel = aw_printlabel; + printopcode = aw_printopcode; + + int i = 1; + while((i < argc) && (argv[i][0] == '-')) { + if(strcmp("-a", argv[i]) == 0) { + printlabel = aw_printlabel; + printopcode = aw_printopcode; + } else if(strcmp("-i", argv[i]) == 0) { + printlabel = intel_printlabel; + printopcode = intel_printopcode; + } else if(strcmp("-u", argv[i]) == 0) { + printlabel = att_printlabel; + printopcode = att_printopcode; + } else if(strcmp("-p", argv[i]) == 0) { + printadr = true; + } else { + goto error; + } + + ++i; + } + + if((argc - i) != 2) + goto error; + + input = argv[i]; + output = argv[i + 1]; + return; + +error: + printf(MSG_USAGE); + exit(1); +} + +int main(int argc, char **argv) { + readarg(argc, argv); + + if((fp = fopen(input, "r")) == NULL) { + printf(MSG_OPENERR, input); + exit(1); + } + + fseek(fp, 0, SEEK_END); + codesize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + code = malloc(codesize); + fread(code, codesize, 1, fp); + fclose(fp); + + if((fp = fopen(output, "w")) == NULL) { + printf(MSG_WRITEERR, output); + exit(1); + } + + labelnum = 0; + + pc = 0; + printcode = false; + while(pc < codesize) + step(); /* read labels */ + + pc = 0; + printcode = true; + while(pc < codesize) + step(); /* print code */ + + fclose(fp); + free(code); + + return 0; +} diff --git a/dis.h b/dis.h new file mode 100644 index 0000000..97a8a21 --- /dev/null +++ b/dis.h @@ -0,0 +1,19 @@ +#include +#include +#include + +#define MAX_LABEL 4096 + +#define LT_JUMP 0 +#define LT_CALL 1 +#define LT_VEC 2 + +struct labelinfo { + uint16_t adr; + int type; +}; + +extern FILE *fp; +extern uint16_t adr; +extern struct labelinfo label[MAX_LABEL]; +extern bool printadr; diff --git a/dis_att.c b/dis_att.c new file mode 100644 index 0000000..4e6c28c --- /dev/null +++ b/dis_att.c @@ -0,0 +1,227 @@ +#include +#include +#include "dis.h" + +/* + * AT&T style target + * + * This target uses another mnemonics: + * spr = spr1, spr2 + * mov = set, seti + * add = add, addi + * jsr = jsr + * ret = return + * wait = break + * jmp = jmp + * setv = setvec + * jnz = dbra + * je, jne, jg, jge, jl, jle = si (=, !=, >, >=, <, <=) + * pal = fade + * vec = vec + * page = setws + * clr = clr + * copy = copy + * show = show + * kill = bigend + * text = text + * sub = sub + * and = andi + * or = ori + * shl = lsl + * shr = lsr + * snd = play + * ld = load + * mus = song + */ + +void att_printlabel(int i) { + if(i != -1) { + if(label[i].type != LT_JUMP && adr != 0) + fputc('\n', fp); + + if(label[i].type == LT_CALL) + fprintf(fp, "# Procedure code\n"); + else if(label[i].type == LT_VEC) + fprintf(fp, "# Task code\n"); + + fprintf(fp, ".L%X:\n", i); + } + + if(printadr) + fprintf(fp, "/* %5u */", adr); + + fprintf(fp, "\t"); +} + +void att_printopcode(uint16_t op, uint16_t x, uint16_t y, uint16_t z, uint16_t w, int label) { + char *s; + char c1[16], c2[16], c3[16]; + + if(op & 0x80) { + fprintf(fp, "spr\t0x%x, $%u, $%u\n", w, x, y); + } else if(op & 0x40) { + char *seg = ""; + + switch(op & 48) { + case 0: + snprintf(c1, 16, "$%i", (int16_t)x); + break; + case 16: + snprintf(c1, 16, "%%v%u", x); + break; + case 32: + snprintf(c1, 16, "$%u", x); + break; + case 48: + snprintf(c1, 16, "%%%u", x+256); + break; + } + + switch(op & 12) { + case 0: + snprintf(c2, 16, "$%i", (int16_t)y); + break; + case 4: + snprintf(c2, 16, "%%v%u", y); + break; + case 8: + case 12: + snprintf(c2, 16, "$%u", y); + break; + } + + switch(op & 3) { + case 0: + snprintf(c3, 16, "$64"); + break; + case 1: + snprintf(c3, 16, "%%v%u", z); + break; + case 2: + snprintf(c3, 16, "$%u", z); + break; + case 3: + seg = "(%vid2)"; + snprintf(c3, 16, "$64"); + break; + } + + fprintf(fp, "spr\t0x%x%s, %s, %s, %s\n", w, seg, c1, c2, c3); + } else { + switch(op) { + case 0x0: + fprintf(fp, "mov\t$%i, %%v%u\n", (int16_t)y, x); + break; + case 0x1: + fprintf(fp, "mov\t%%v%u, %%v%u\n", y, x); + break; + case 0x2: + fprintf(fp, "add\t%%v%u, %%v%u\n", y, x); + break; + case 0x3: + fprintf(fp, "add\t$%u, %%v%u\n", y, x); + break; + case 0x4: + fprintf(fp, "jsr\t.L%X\n", label); + break; + case 0x5: + fprintf(fp, "ret\n"); + break; + case 0x6: + fprintf(fp, "wait\n"); + break; + case 0x7: + fprintf(fp, "jmp\t.L%X\n", label); + break; + case 0x8: + fprintf(fp, "setv\t$%u, .L%X\n", x, label); + break; + case 0x9: + fprintf(fp, "jnz\t%%v%u, .L%X\n", x, label); + break; + case 0xA: + if(w & 0x80) + snprintf(c1, 16, "%%v%u", y); + else if(w & 0x40) + snprintf(c1, 16, "$%i", (int16_t)y); + else + snprintf(c1, 16, "$%u", y); + + switch(w & 0x7) { + case 0: + s = "je"; + break; + case 1: + s = "jne"; + break; + case 2: + s = "jg"; + break; + case 3: + s = "jge"; + break; + case 4: + s = "jl"; + break; + case 5: + s = "jle"; + break; + default: + s = "unk_jmp"; + } + + fprintf(fp, "%s\t%%v%u, %s, .L%X\n", s, x, c1, label); + break; + case 0xB: + fprintf(fp, "pal\t$%u\n", x); + break; + case 0xC: + fprintf(fp, "vec\t$%u, $%u, $%u\n", x, y, z); + break; + case 0xD: + fprintf(fp, "page\t$%u\n", x); + break; + case 0xE: + fprintf(fp, "clr\t$%u, $%u\n", x, y); + break; + case 0xF: + fprintf(fp, "copy\t$%u, $%u\n", x, y); + break; + case 0x10: + fprintf(fp, "show\t$%u\n", x); + break; + case 0x11: + fprintf(fp, "kill\n"); + break; + case 0x12: + fprintf(fp, "text\t$%u, $%u, $%u, $%u\n", z, x, y, w); + break; + case 0x13: + fprintf(fp, "sub\t%%v%u, %%v%u\n", y, x); + break; + case 0x14: + fprintf(fp, "and\t$%u, %%v%u\n", y, x); + break; + case 0x15: + fprintf(fp, "or\t$%u, %%v%u\n", y, x); + break; + case 0x16: + fprintf(fp, "shl\t$%u, %%v%u\n", y, x); + break; + case 0x17: + fprintf(fp, "shr\t$%u, %%v%u\n", y, x); + break; + case 0x18: + fprintf(fp, "snd\t$%u, $%u, $%u, $%u\n", z, x, y, w); + break; + case 0x19: + fprintf(fp, "ld\t$%u\n", x); + break; + case 0x1A: + fprintf(fp, "mus\t$%u, $%u, $%u\n", x, y, z); + break; + default: + fprintf(fp, "unk_%x\n", op); + } + } +} diff --git a/dis_aw.c b/dis_aw.c new file mode 100644 index 0000000..66803ad --- /dev/null +++ b/dis_aw.c @@ -0,0 +1,192 @@ +#include +#include +#include "dis.h" + +/* + * Eric Chahi's style target + * i.e. native Another World script syntax + */ + +void aw_printlabel(int i) { + if(printadr) + fprintf(fp, "%u\t", adr); + + if(i == -1) + fprintf(fp, "\t"); + else + fprintf(fp, "L%i\t", i); +} + +void aw_printopcode(uint16_t op, uint16_t x, uint16_t y, uint16_t z, uint16_t w, int label) { + char *s; + char c1[16], c2[16], c3[16]; + + if(op & 0x80) { + fprintf(fp, "spr1\t%u\t%u\t%u\n", w, x, y); + } else if(op & 0x40) { + char seg = '1'; + + switch(op & 48) { + case 0: + snprintf(c1, 16, "%i", (int16_t)x); + break; + case 16: + snprintf(c1, 16, "v%u", x); + break; + case 32: + snprintf(c1, 16, "%u", x); + break; + case 48: + snprintf(c1, 16, "%u", x+256); + break; + } + + switch(op & 12) { + case 0: + snprintf(c2, 16, "%i", (int16_t)y); + break; + case 4: + snprintf(c2, 16, "v%u", y); + break; + case 8: + case 12: + snprintf(c2, 16, "%u", y); + break; + } + + switch(op & 3) { + case 0: + snprintf(c3, 16, "64"); + break; + case 1: + snprintf(c3, 16, "v%u", z); + break; + case 2: + snprintf(c3, 16, "%u", z); + break; + case 3: + seg = '2'; + snprintf(c3, 16, "64"); + break; + } + + /* Maybe graphics segmet is changed using file name */ + fprintf(fp, "spr%c\t%u\t%s\t%s\t%s\n", seg, w, c1, c2, c3); + } else { + switch(op) { + case 0x0: + fprintf(fp, "seti\tv%u\t%i\n", x, (int16_t)y); + break; + case 0x1: + fprintf(fp, "set\tv%u\tv%u\n", x, y); + break; + case 0x2: + fprintf(fp, "add\tv%u\tv%u\n", x, y); + break; + case 0x3: + fprintf(fp, "addi\tv%u\t%u\n", x, y); + break; + case 0x4: + fprintf(fp, "jsr\tL%u\n", label); + break; + case 0x5: + fprintf(fp, "return\n"); + break; + case 0x6: + fprintf(fp, "break\n"); + break; + case 0x7: + fprintf(fp, "jmp\tL%u\n", label); + break; + case 0x8: + fprintf(fp, "setvec\t%u\tL%u\n", x, label); + break; + case 0x9: + fprintf(fp, "dbra\tv%u\tL%u\n", x, label); + break; + case 0xA: + if(w & 0x80) + snprintf(c1, 16, "v%u", y); + else if(w & 0x40) + snprintf(c1, 16, "%i", (int16_t)y); + else + snprintf(c1, 16, "%u", y); + + switch(w & 0x7) { + case 0: + s = "="; + break; + case 1: + s = "<>"; + break; + case 2: + s = ">"; + break; + case 3: + s = ">="; + break; + case 4: + s = "<"; + break; + case 5: + s = "<="; + break; + default: + s = "unk"; + } + + fprintf(fp, "si\tv%u\t%s\t%s\tL%u\n", x, s, c1, label); + break; + case 0xB: + fprintf(fp, "fade\t%u\n", x); + break; + case 0xC: + fprintf(fp, "vec\t%u\t%u\t%u\n", x, y, z); + break; + case 0xD: + fprintf(fp, "setws\t%u\n", x); + break; + case 0xE: + fprintf(fp, "clr\t%u\t%u\n", x, y); + break; + case 0xF: + fprintf(fp, "copy\t%u\t%u\n", x, y); + break; + case 0x10: + fprintf(fp, "show\t%u\n", x); + break; + case 0x11: + fprintf(fp, "bigend\n"); + break; + case 0x12: + fprintf(fp, "text\t%u\t%u\t%u\t%u\n", z, x, y, w); + break; + case 0x13: + fprintf(fp, "sub\tv%u\tv%u\n", x, y); + break; + case 0x14: + fprintf(fp, "andi\tv%u\t%u\n", x, y); + break; + case 0x15: + fprintf(fp, "ori\tv%u\t%u\n", x, y); + break; + case 0x16: + fprintf(fp, "lsl\tv%u\t%u\n", x, y); + break; + case 0x17: + fprintf(fp, "lsr\tv%u\t%u\n", x, y); + break; + case 0x18: + fprintf(fp, "play\t%u\t%u\t%u\t%u\n", z, x, y, w); + break; + case 0x19: + fprintf(fp, "load\t%u\n", x); + break; + case 0x1A: + fprintf(fp, "song\t%u\t%u\t%u\n", x, y, z); + break; + default: + fprintf(fp, "unk_%x\n", op); + } + } +} diff --git a/dis_intel.c b/dis_intel.c new file mode 100644 index 0000000..adc28dc --- /dev/null +++ b/dis_intel.c @@ -0,0 +1,227 @@ +#include +#include +#include "dis.h" + +/* + * Intel style target + * + * This target uses another mnemonics: + * spr = spr1, spr2 + * mov = set, seti + * add = add, addi + * jsr = jsr + * ret = return + * wait = break + * jmp = jmp + * setv = setvec + * jnz = dbra + * je, jne, jg, jge, jl, jle = si (=, !=, >, >=, <, <=) + * pal = fade + * vec = vec + * page = setws + * clr = clr + * copy = copy + * show = show + * kill = bigend + * text = text + * sub = sub + * and = andi + * or = ori + * shl = lsl + * shr = lsr + * snd = play + * ld = load + * mus = song + */ + +void intel_printlabel(int i) { + if(i != -1) { + if(label[i].type != LT_JUMP && adr != 0) + fputc('\n', fp); + + if(label[i].type == LT_CALL) + fprintf(fp, "; Procedure code\n"); + else if(label[i].type == LT_VEC) + fprintf(fp, "; Task code\n"); + + fprintf(fp, "L%i:\n", i); + } + + if(printadr) + fprintf(fp, "/* %5u */", adr); + + fprintf(fp, "\t"); +} + +void intel_printopcode(uint16_t op, uint16_t x, uint16_t y, uint16_t z, uint16_t w, int label) { + char *s; + char c1[16], c2[16], c3[16]; + + if(op & 0x80) { + fprintf(fp, "spr\t[%xh], %u, %u\n", w, x, y); + } else if(op & 0x40) { + char *seg = ""; + + switch(op & 48) { + case 0: + snprintf(c1, 16, "%i", (int16_t)x); + break; + case 16: + snprintf(c1, 16, "v%u", x); + break; + case 32: + snprintf(c1, 16, "%u", x); + break; + case 48: + snprintf(c1, 16, "%u", x+256); + break; + } + + switch(op & 12) { + case 0: + snprintf(c2, 16, "%i", (int16_t)y); + break; + case 4: + snprintf(c2, 16, "v%u", y); + break; + case 8: + case 12: + snprintf(c2, 16, "%u", y); + break; + } + + switch(op & 3) { + case 0: + snprintf(c3, 16, "%u", z); + break; + case 1: + snprintf(c3, 16, "v%u", z); + break; + case 2: + snprintf(c3, 16, "%u", z); + break; + case 3: + seg = "2:"; + snprintf(c3, 16, "%u", z); + break; + } + + fprintf(fp, "spr\t[%s%xh], %s, %s, %s\n", seg, w, c1, c2, c3); + } else { + switch(op) { + case 0x0: + fprintf(fp, "mov\tv%u, %i\n", x, (int16_t)y); + break; + case 0x1: + fprintf(fp, "mov\tv%u, v%u\n", x, y); + break; + case 0x2: + fprintf(fp, "add\tv%u, v%u\n", x, y); + break; + case 0x3: + fprintf(fp, "add\tv%u, %u\n", x, y); + break; + case 0x4: + fprintf(fp, "jsr\tL%u\n", label); + break; + case 0x5: + fprintf(fp, "ret\n"); + break; + case 0x6: + fprintf(fp, "wait\n"); + break; + case 0x7: + fprintf(fp, "jmp\tL%u\n", label); + break; + case 0x8: + fprintf(fp, "setv\t%u, L%u\n", x, label); + break; + case 0x9: + fprintf(fp, "jnz\tv%u, L%u\n", x, label); + break; + case 0xA: + if(w & 0x80) + snprintf(c1, 16, "v%u", y); + else if(w & 0x40) + snprintf(c1, 16, "%i", (int16_t)y); + else + snprintf(c1, 16, "%u", y); + + switch(w & 0x7) { + case 0: + s = "je"; + break; + case 1: + s = "jne"; + break; + case 2: + s = "jg"; + break; + case 3: + s = "jge"; + break; + case 4: + s = "jl"; + break; + case 5: + s = "jle"; + break; + default: + s = "unk_jmp"; + } + + fprintf(fp, "%s\tv%u, %s, L%u\n", s, x, c1, label); + break; + case 0xB: + fprintf(fp, "pal\t%u\n", x); + break; + case 0xC: + fprintf(fp, "vec\t%u, %u, %u\n", x, y, z); + break; + case 0xD: + fprintf(fp, "page\t%u\n", x); + break; + case 0xE: + fprintf(fp, "clr\t%u, %u\n", x, y); + break; + case 0xF: + fprintf(fp, "copy\t%u, %u\n", x, y); + break; + case 0x10: + fprintf(fp, "show\t%u\n", x); + break; + case 0x11: + fprintf(fp, "kill\n"); + break; + case 0x12: + fprintf(fp, "text\t%u, %u, %u, %u\n", z, x, y, w); + break; + case 0x13: + fprintf(fp, "sub\tv%u, v%u\n", x, y); + break; + case 0x14: + fprintf(fp, "and\tv%u, %u\n", x, y); + break; + case 0x15: + fprintf(fp, "or\tv%u, %u\n", x, y); + break; + case 0x16: + fprintf(fp, "shl\tv%u, %u\n", x, y); + break; + case 0x17: + fprintf(fp, "shr\tv%u, %u\n", x, y); + break; + case 0x18: + fprintf(fp, "snd\t%u, %u, %u, %u\n", z, x, y, w); + break; + case 0x19: + fprintf(fp, "ld\t%u\n", x); + break; + case 0x1A: + fprintf(fp, "mus\t%u, %u, %u\n", x, y, z); + break; + default: + fprintf(fp, "unk_%x\n", op); + } + } +} diff --git a/dis_syn.h b/dis_syn.h new file mode 100644 index 0000000..e9a3108 --- /dev/null +++ b/dis_syn.h @@ -0,0 +1,6 @@ +void aw_printlabel(int); +void aw_printopcode(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, int); +void intel_printlabel(int); +void intel_printopcode(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, int); +void att_printlabel(int); +void att_printopcode(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, int); \ No newline at end of file diff --git a/unpk.c b/unpk.c new file mode 100644 index 0000000..ca77dea --- /dev/null +++ b/unpk.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include + +/* + * Another World game data unpacker + * Only DOS version are supported + */ + +#define MAX_MEMINFO 256 +#define MSG_OPENERR "can't open file %s.\n" +#define MSG_WRITEERR "can't create file %s.\n" +#define MSG_UNPKERR "error while unpack file %s.\n" + +struct __attribute__ ((__packed__)) memrec { + uint8_t state; + uint8_t type; + uint32_t unk0; + uint8_t unk1; + uint8_t bank; + uint32_t offset; + uint16_t unk2; + uint16_t pksize; + uint16_t unk3; + uint16_t size; +}; + +FILE *fp; +struct memrec meminfo[MAX_MEMINFO]; +int count; + +uint8_t *pk; +uint32_t size, datasize; +uint32_t start, idx, oidx; +uint32_t crc, chk; + +uint32_t pkint(int adr) { + return ((pk[adr]) << 24) | + ((pk[adr + 1]) << 16) | + ((pk[adr + 2]) << 8) | + (pk[adr + 3]); +} + +bool rcr(bool cf) { + bool rcf = chk & 1; + chk >>= 1; + if(cf) + chk |= 0x80000000; + return rcf; +} + +bool nextChunk() { + bool cf = rcr(false); + if(chk == 0) { + chk = pkint(idx); + idx -= 4; + crc ^= chk; + cf = rcr(true); + } + return cf; +} + +int getCode(int numChunks) { + int c = 0; + while(numChunks--) { + c <<= 1; + if(nextChunk()) + c |= 1; + } + return c; +} + +void decUnk1(int numChunks, int addCount) { + int count = getCode(numChunks) + addCount + 1; + datasize -= count; + while(count--) { + pk[oidx] = getCode(8); + --oidx; + } +} + +void decUnk2(int numChunks) { + int i = getCode(numChunks); + int count = size + 1; + datasize -= count; + while(count--) { + pk[oidx] = pk[oidx + i]; + --oidx; + } +} + +bool unpack() { + size = 0; + datasize = pkint(idx); + idx -= 4; + oidx = start + datasize - 1; + crc = pkint(idx); + idx -= 4; + chk = pkint(idx); + idx -= 4; + crc ^= chk; + + do { + if(!nextChunk()) { + size = 1; + if(!nextChunk()) + decUnk1(3, 0); + else + decUnk2(8); + } else { + int c = getCode(2); + if(c == 3) { + decUnk1(8, 8); + } else { + if(c < 2) { + size = c + 2; + decUnk2(c + 9); + } else { + size = getCode(8); + decUnk2(12); + } + } + } + } while(datasize > 0); + + return crc == 0; +} + +bool pkload(int i) { + struct memrec *r = &meminfo[i]; + + char name[64]; + char *nnum = (r->bank <= 0xF)?"0":""; + snprintf(name, 64, "BANK%s%X", nnum, r->bank); + + if((fp = fopen(name, "r")) == NULL) { + printf(MSG_OPENERR, name); + return 0; + } + + pk = malloc(r->size); + + fseek(fp, r->offset, SEEK_SET); + fread(pk, r->pksize, 1, fp); + fclose(fp); + + if(r->pksize == r->size) { + return true; + } else { + start = 0; + idx = start + r->pksize - 4; + return unpack(); + } +} + +void readmem() { + count = 0; + + printf("NUM STATE TYPE BANK OFFSET PKSIZE SIZE\n"); + + while(count < MAX_MEMINFO) { + struct memrec *r = &meminfo[count]; + fread(r, sizeof(struct memrec), 1, fp); + r->offset = ntohl(r->offset); + r->pksize = ntohs(r->pksize); + r->size = ntohs(r->size); + printf("%3i %5u %4u %4X %8X %6u %5u\n", count, r->state, r->type, + r->bank, r->offset, r->pksize, r->size); + + if(r->state == 0xFF) + break; + + ++count; + } +} + +int main(int argc, char **argv) { + if((fp = fopen("MEMLIST.BIN", "r")) == NULL) { + printf(MSG_OPENERR, "MEMLIST.BIN"); + exit(1); + } + + readmem(); + + fclose(fp); + + for(int i = 0; i < count - 1; i++) { + char name[64]; + char *ext; + + switch(meminfo[i].type) { + case 0: /* sound */ + ext = "snd"; + break; + case 1: /* music */ + ext = "mus"; + break; + case 2: /* bitmap */ + ext = "bmp"; + break; + case 3: /* palette */ + ext = "pal"; + break; + case 4: /* code */ + ext = "obj"; + break; + case 5: /* polygons */ + ext = "spr"; + break; + default: /* other */ + ext = "unk"; + break; + } + + snprintf(name, 64, "file%i.%s", i, ext); + + if(!pkload(i)) { + printf(MSG_UNPKERR, name); + goto error; + } + + if((fp = fopen(name, "w")) == NULL) { + printf(MSG_WRITEERR, name); + goto error; + } + + fwrite(pk, meminfo[i].size, 1, fp); + + fclose(fp); + error: + free(pk); + } + + return 0; +}