shithub: raven

ref: bc96874813d62c86c475df2c6b311848169a30e6
dir: /acs.c/

View raw version
#include <u.h>
#include <libc.h>

uvlong
unpack(uchar *from, int n)
{
	uvlong x;
	int i;

	for(i = x = 0; i < n; i++)
		x |= (from[i] << (i*8));
	return x;
}

struct {
	char *name;
	int argc;
} functab[] = {
	"NOP", 0,
	"Terminate", 0,
	"Suspend", 0,
	"PushNumber", 1,
	"LSpec1", 1,
	"LSpec2", 1,
	"LSpec3", 1,
	"LSpec4", 1,
	"LSpec5", 1,
	"LSpec1Direct", 2,
	"LSpec2Direct", 3,
	"LSpec3Direct", 4,
	"LSpec4Direct", 5,
	"LSpec5Direct", 6,
	"Add", 0,
	"Subtract", 0,
	"Multiply", 0,
	"Divide", 0,
	"Modulus", 0,
	"EQ", 0,
	"NE", 0,
	"LT", 0,
	"GT", 0,
	"LE", 0,
	"GE", 0,
	"AssignScriptVar", 1,
	"AssignMapVar", 1,
	"AssignWorldVar", 1,
	"PushScriptVar", 1,
	"PushMapVar", 1,
	"PushWorldVar", 1,
	"AddScriptVar", 1,
	"AddMapVar", 1,
	"AddWorldVar", 1,
	"SubScriptVar", 1,
	"SubMapVar", 1,
	"SubWorldVar", 1,
	"MulScriptVar", 1,
	"MulMapVar", 1,
	"MulWorldVar", 1,
	"DivScriptVar", 1,
	"DivMapVar", 1,
	"DivWorldVar", 1,
	"ModScriptVar", 1,
	"ModMapVar", 1,
	"ModWorldVar", 1,
	"IncScriptVar", 1,
	"IncMapVar", 1,
	"IncWorldVar", 1,
	"DecScriptVar", 1,
	"DecMapVar", 1,
	"DecWorldVar", 1,
	"Goto", 1,
	"IfGoto", 1,
	"Drop", 0,
	"Delay", 0,
	"DelayDirect", 1,
	"Random", 0,
	"RandomDirect", 2,
	"ThingCount", 0,
	"ThingCountDirect", 2,
	"TagWait", 0,
	"TagWaitDirect", 1,
	"PolyWait", 0,
	"PolyWaitDirect", 1,
	"ChangeFloor", 0,
	"ChangeFloorDirect", 1,
	"ChangeCeiling", 0,
	"ChangeCeilingDirect", 1,
	"Restart", 0,
	"AndLogical", 0,
	"OrLogical", 0,
	"AndBitwise", 0,
	"OrBitwise", 0,
	"EorBitwise", 0,
	"NegateLogical", 0,
	"LShift", 0,
	"RShift", 0,
	"UnaryMinus", 0,
	"IfNotGoto", 1,
	"LineSide", 0,
	"ScriptWait", 0,
	"ScriptWaitDirect", 1,
	"ClearLineSpecial", 0,
	"CaseGoto", 1,
	"BeginPrint", 0,
	"EndPrint", 0,
	"PrintString", 0,
	"PrintNumber", 0,
	"PrintCharacter", 0,
	"PlayerCount", 0,
	"GameType", 0,
	"GameSkill", 0,
	"Timer", 0,
	"SectorSound", 0,
	"AmbientSound", 0,
	"SoundSequence", 0,
	"SetLineTexture", 0,
	"SetLineBlocking", 0,
	"SetLineSpecial", 0,
	"ThingSound", 0,
	"EndPrintBold", 0,
};

typedef struct {
	int	index;
	uchar	*address;
	int	argc;
	int	state;
	int	wait;
} Script;

typedef struct {
	int marker;
	int off;
	int code;
	int count;
	int nstring;
	uchar *base;
	char **strings;
	Script scripts[];
} Lump;

Lump*
parsescript(uchar *b, int)
{
	uchar *base;
	Lump *s;
	Script *info;
	Lump s2;
	int i;

	s2.base = base = b;
	s2.marker = unpack(b, 4);
	s2.off = unpack(b + 4, 4);
	s2.code = unpack(b + 8, 4);

	b += s2.off;
	s2.count = (int)unpack(b, 4);
	b += 4;

	s = mallocz(sizeof(Lump) * sizeof(Script)*s2.count, 1);
	*s = s2;
	for(i = 0; i < s->count; i++){
		info = s->scripts + i;
		info->index = unpack(b, 4);
		info->address = base + unpack(b + 4, 4);
		info->argc = unpack(b + 8, 4);
		b += 12;
	}
	s->nstring = unpack(b, 4);
	b += 4;
	s->strings = mallocz(sizeof(char*) * s->nstring, 1);
	for(i = 0; i < s->nstring; i++, b += 4)
		s->strings[i] = (char*)base + unpack(b, 4);
	return s;
}

void
dump(Lump *s)
{
	int i, j, k;
	int *ip, *ap;
	int cmd;
	static uchar *labels[8192];
	int nlabel;
	int ctx;

	ctx = 0;
	for(i = 0; i < s->count; i++){
		ip = (int*)(s->scripts[i].address);
		print("script %d {\n", i);
		nlabel = 0;
		for(;;){
			cmd = *ip;
			if(cmd >= nelem(functab)){
				break;
			}
			print("%.2d\t\t%s(", nlabel, functab[cmd].name);
			labels[nlabel++] = (uchar*)ip;
			assert(nlabel != 1024);
			ap = ip + 1;
			for(j = 0; j < functab[cmd].argc; j++){
				ctx = *ap;
				if(j == functab[cmd].argc-1)
					print("%d", *ap);
				else
					print("%d, ", *ap);
				ap++;
				ip++;
			}
			ip++;
			
			if(cmd == 52){
				for(k = 0; k < nlabel; k++)
				if(labels[k] == s->base + ctx){
					print(") //%d\n", k);
					break;
				}
			}
			print(")\n");
			if(cmd == 1)
				break;
		}
		print("}\n");
	}
}

uchar file[1024*64];
int nfile;

void
usage(void)
{
	fprint(2, "usage: %s <script>\n", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	int fd;
	int w;
	Lump *s;

	ARGBEGIN{
	default:
		usage();
		return;
	}ARGEND
	if(argc)
		fd = open(argv[0], OREAD);
	else
		fd = 0;
	if(fd < 0)
		sysfatal("open: %r");

	for(nfile = 0; nfile < sizeof file;){
		w = read(fd, file + nfile, sizeof file - nfile);
		if(w <= 0)
			break;
		nfile += w;
	}
	if(nfile == 0)
		return;
	if(nfile == sizeof file)
		fprint(2, "file truncated\n");

	s = parsescript(file, nfile);
	dump(s);
}