/********************************************\
 * this is FREE software                    *
 * covered by the GPL                       *
 * for the full terms and conditions, visit *
 * http://www.fsf.org/copyleft              *
 *                                          *
 * copyright 2001 Musicman                  *
 * contact: musicman@haveashittyday.com     *
\********************************************/

#include <stdio.h>
#include <stdarg.h>
#include <sys/stat.h>

/* basic IO */
void error(char *fmt, ...)
{	va_list ap;
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	exit(1);
}

FILE *swf = {0};

/* zlib interface */
#include <zlib.h>
z_stream z = {0};
unsigned char *zbuf = {0}, *zptr = {0};
int compressed = {0};
swgetc()
{	if(compressed)
		return((zptr < z.next_out) ? *zptr++ : 0);
	else
		return getc(swf);
}

swftell()
{	if(compressed)
		return(zptr - zbuf + 8);
	else
		return ftell(swf);
}

swfseek(offs)
{	if(compressed)
		zptr = zbuf + offs - 8;
	else
		fseek(swf, offs, 0);
}

swfread(to, sz, nelem)
char *to;
{	nelem *= sz;
	while(--nelem >= 0)
		*to++ = swgetc();
}

int bitoff = {0};
char lastch = {0};

#define alignbits() bitoff = 0;

getbits(int nbits)
{	int res = 0, nb, db;
	for(nb = 0 ; nb < nbits ; nb += db)
	{	if(bitoff == 0)
		{	lastch = swgetc();
			bitoff = 8;
		}
		db = nbits - nb;
		if(db > bitoff)
			db = bitoff;
		/* db bits von vorn wegnehmen */
		res <<= db;
		res |= (lastch >> (bitoff -= db)) & ((1 << db) - 1);
	}
	return res;
}
getsbits(nbits)
{	int res = getbits(nbits);
	if(res & (1 << (nbits-1)))
		res |= (-1) << nbits;
	return(res);
}

static version = {0};

/* print various types */
/* rectangle */
rect()
{	int nbits, xmin, xmax, ymin, ymax;
	nbits = getbits(5);
	xmin = getsbits(nbits);
	xmax = getsbits(nbits);
	ymin = getsbits(nbits);
	ymax = getsbits(nbits);
	printf("rect %.2f,%.2f %.2f,%.2f\n", xmin/20., ymin/20., xmax/20., ymax/20.);
}
/* matrix */
matrix()
{	int hasscale, nscalebits, scalex, scaley;
	int hasrotate, nrotatebits, rotateskew0, rotateskew1;
	int ntranslatebits, translatex, translatey;
	if(hasscale = getbits(1))
	{	nscalebits = getbits(5);
		scalex = getsbits(nscalebits);
		scaley = getsbits(nscalebits);
		printf("scale %d %d\n", scalex, scaley);
	}
	if(hasrotate = getbits(1))
	{	nrotatebits = getbits(5);
		rotateskew0 = getsbits(nrotatebits);
		rotateskew1 = getsbits(nrotatebits);
		printf("skew %d %d\n", rotateskew0, rotateskew1);
	}
	ntranslatebits = getbits(5);
	translatex = getsbits(ntranslatebits);
	translatey = getsbits(ntranslatebits);
	printf("translate %d %d\n", translatex, translatey);
}
/* rgb */
rgb()
{	int r, g, b;
	alignbits();
	r = swgetc(); g = swgetc(); b = swgetc();
	printf("rgb %x %x %x\n", r, g, b);
}
rgba()
{	int r, g, b, a;
	alignbits();
	r = swgetc(); g = swgetc(); b = swgetc();
	a = swgetc();
	printf("rgba %x %x %x %x\n", r, g, b, a);
}
readint2()
{	int res = swgetc();
	res |= swgetc() << 8;
	return res;
}
readint4()
{	int res = swgetc();
	res |= swgetc() << 8;
	res |= swgetc() << 16;
	res |= swgetc() << 24;
	return res;
}

struct fontdata
{	struct fontdata *next;
	unsigned short id;
	int nglyphs, wide;
	short *codes;
} *fontlist = {0};

struct fontdata *addfont(id, nglyph, wide)
{	struct fontdata *fp;
	
	for(fp = (struct fontdata *)&fontlist ; fp->next ; )
		fp = fp->next;
	fp = fp->next = (struct fontdata *)malloc(sizeof(struct fontdata));
	fp->next = 0;
	fp->id = id;
	fp->nglyphs = nglyph;
	fp->wide = wide;
	fp->codes = 0;
	return fp;
}

prchar(struct fontdata *fp, short code)
{	if(fp->codes[code] > ' ' && fp->codes[code] < 0177)
		printf("%c", fp->codes[code]);
	else if(fp->wide)
		printf("0x%x", fp->codes[code]);
	else
		printf("%03o", fp->codes[code]);
}

/* definefont */
definefont(realfont)
{	unsigned short fontid, firstoffs, *offsets, nglyphs;
	long startoffs;
	int n;

	fontid = readint2();
	if(!realfont)
	{	printf("font %d: browserfont\n", fontid);
		return;
	}
	startoffs = swftell();
	firstoffs = readint2();
	nglyphs = firstoffs / 2;
	printf("font %d: %d glyphs\n", fontid, nglyphs);
	addfont(fontid, nglyphs, 0);
	offsets = (unsigned short *)malloc(nglyphs * 2);
	*offsets = firstoffs;
	swfread(offsets+1, sizeof(short), nglyphs-1);
	for(n = 0 ; n < nglyphs ; n++)
	{	printf("%d, offs %d:\n", n, offsets[n]);
		swfseek(startoffs + offsets[n]);
		shape(0);
	}
}

definefont2()
{	unsigned short fontid, nglyph, tmps, nkern, *codes;
	int haslayout, shiftjis, unicode, ansi, wideoffs, widecodes, italic, bold;
	int namelen, n, *offsets, tmpl;
	long startoffs;
	char ch;
	struct fontdata *fp;
	
	fontid = readint2();
	haslayout = getbits(1);
	shiftjis = getbits(1);
	unicode = getbits(1);
	ansi = getbits(1);
	wideoffs = getbits(1);
	widecodes = getbits(1);
	italic = getbits(1);
	bold = getbits(1);
	getbits(8);
	namelen = swgetc();
	printf("font %d: ", fontid);
	for(n = 0 ; n < namelen ; n++)
		putchar(ch = swgetc());
	putchar(' ');
	if(unicode)
		printf("unicode ");
	if(shiftjis)
		printf("shiftJIS ");
	if(ansi)
		printf("ANSI ");
	if(italic)
		printf("italic ");
	if(bold)
		printf("bold ");
	if(widecodes)
		printf("16bit ");
	nglyph = readint2();
	printf("%d glyphs\n", nglyph);
	startoffs = swftell();
	offsets = (int *)malloc((nglyph+1) * 4);
	for(n = 0 ; n <= nglyph ; n++)
	{	if(wideoffs)
			offsets[n] = readint4();
		else
			offsets[n] = readint2();
	}
	for(n = 0 ; n < nglyph ; n++)
	{	printf("%d, offs %d:\n", n, offsets[n]);
		swfseek(startoffs + offsets[n]);
		shape(0);
	}
	/* more to come from offsets[nglyph] */
	swfseek(startoffs + offsets[nglyph]);
	fp = addfont(fontid, nglyph, widecodes);
	codes = fp->codes = (short *)malloc(nglyph * sizeof(short));
	printf("codes:\n");
	for(n = 0 ; n < nglyph ; n++)
	{	if(widecodes)
		{	codes[n] = tmps = readint2();
			printf("%d: 0x%x\n", n, tmps);
		}
		else
		{	tmps = swgetc();
			codes[n] = tmps;
			if(tmps > ' ' && tmps < 0177)
				printf("%d: %c\n", n, tmps);
			else
				printf("%d: %03o\n", n, tmps);
		}
	}
	if(haslayout)
	{	tmps = readint2();
		printf("ascent %d", tmps);
		tmps = readint2();
		printf(", descent %d", tmps);
		tmps = readint2();
		printf(", leading %d\n", tmps);
		printf("widths:\n");
		for(n = 0 ; n < nglyph ; n++)
		{	tmps = readint2();
			prchar(fp, n);
			printf(": %d\n", tmps);
		}
		printf("bbox:\n");
		for(n = 0 ; n < nglyph ; n++)
		{	prchar(fp, n); printf(": ");
			alignbits();
			rect();
		}
		nkern = readint2();
		if(nkern)
		{	printf("kerning\n");
			for(n = 0 ; n < nkern ; n++)
			{	if(widecodes)
				{	tmps = readint2();
					printf("0x%x", tmps);
					tmps = readint2();
					printf(" 0x%x:", tmps);
				}
				else
				{	tmps = swgetc();
					if(tmps > ' ' && tmps < 0177)
						printf("%c", tmps);
					else
						printf("%03o", tmps);
					tmps = swgetc();
					if(tmps > ' ' && tmps < 0177)
						printf(" %c:", tmps);
					else
						printf(" %03o:", tmps);
				}
				tmps = readint2();
				printf(" %d\n", tmps);
			}
		}
	}
}

/* definefontinfo */
definefontinfo()
{	unsigned short fontid;
	unsigned char ch, tmp;
	int n, wide;
	struct fontdata *fp;

	fontid = readint2();
	tmp = swgetc();
	printf("font %d: ", fontid);
	for(n = 0 ; n < tmp ; n++)
		putchar(swgetc());
	putchar(' ');
	getbits(2);		/* reserved */
	if(getbits(1))
		printf("unicode ");
	if(getbits(1))
		printf("shiftJIS ");
	if(getbits(1))
		printf("ANSI ");
	if(getbits(1))
		printf("italic ");
	if(getbits(1))
		printf("bold ");
	if(wide = getbits(1))
		printf("16bit");
	printf("\n");
	alignbits();
	for(fp = fontlist ; fp ; fp = fp->next)
		if(fp->id == fontid)
			break;
	fp->codes = (short *)malloc(fp->nglyphs * sizeof(short));
	fp->wide = wide;
	for(n = 0 ; n < fp->nglyphs ; n++)
	{	unsigned short tmps;
		if(wide)
		{	fp->codes[n] = tmps = readint2();
			printf("%d: 0x%x\n", n, tmps);
		}
		else
		{	tmps = swgetc();
			fp->codes[n] = tmps;
			if(tmps > ' ' && tmps < 0177)
				printf("%d: %c\n", n, tmps);
			else
				printf("%d: %03o\n", n, tmps);
		}
	}
}

newfontinfo()
{	short id, namlen;
	struct fontdata *fp;
	int n, lang, wide;

	id = readint2();
	namlen = swgetc();
	printf("font %d: ", id);
	while(--namlen >= 0)
		putchar(swgetc());
	putchar(' ');
	getbits(5);
	if(getbits(1))
		printf("italic ");
	if(getbits(1))
		printf("bold ");
	if(wide = getbits(1))
		printf("16bit");
	lang = swgetc();
	printf(" lang %d\n", lang);
	for(fp = fontlist ; fp ; fp = fp->next)
		if(fp->id == id)
			break;
	fp->codes = (short *)malloc(fp->nglyphs * sizeof(short));
	fp->wide = wide;
	for(n = 0 ; n < fp->nglyphs ; n++)
	{	unsigned short tmps;
		fp->codes[n] = tmps = readint2();
		if(tmps > ' ' && tmps < 0177)
			printf("%d: %c\n", n, tmps);
		else if(tmps < 255)
			printf("%d: %03o\n", n, tmps);
		else
			printf("%d: 0x%x\n", n, tmps);
	}
}

/* textfield */
definetextfield()
{	short textid, fontid, maxc, ht, lmarg, rmarg, indent, lspace, align;
	int haslength, noedit, password, multiline, wordwrap, drawbox, noselect, html, usefont;
	int hascolor, haslayout, hastext, hasfont;
	char ch;
	
	textid = readint2();
	printf("textfield %d\n", textid);
	rect();
	alignbits();
	hastext = getbits(1);
	wordwrap = getbits(1);
	multiline = getbits(1);
	password = getbits(1);
	noedit = getbits(1);
	hascolor = getbits(1);
	haslength = getbits(1);
	hasfont = getbits(1);
	getbits(2);
	haslayout = getbits(1);
	noselect = getbits(1);
	drawbox = getbits(1);
	getbits(1);
	html = getbits(1);
	usefont = getbits(1);
	fontid = readint2();
	ht = readint2();
	printf("font %d ht %d ", fontid, ht);
	if(noedit) printf("noedit ");
	if(password) printf("password ");
	if(multiline) printf("multiline ");
	if(wordwrap) printf("wordwrap ");
	if(drawbox) printf("drawbox ");
	if(noselect) printf("noselect ");
	if(html) printf("html ");
	if(usefont) printf("usefont ");
	if(hascolor) rgba();
	if(haslength)
	{	maxc = readint2();
		printf("max %d chars ", maxc);
	}
	if(haslayout)
	{	align = swgetc();
		lmarg = readint2();
		rmarg = readint2();
		indent = readint2();
		lspace = readint2();
		printf("align %d left %d right %d indent %d leading %d\n", align, lmarg, rmarg, indent, lspace);
	}
	if(ch = swgetc())
	{	printf("varname ");
		putchar(ch);
		while(ch = swgetc())
			putchar(ch);
		putchar('\n');
	}
	if(hastext && (ch = swgetc()))
	{	printf("initial ");
		putchar(ch);
		while(ch = swgetc())
			putchar(ch);
		putchar('\n');
	}
}

/* definetext */
definetext(lev)
{	unsigned short textid;
	int nglyphbits, nadvancebits;
	int n, nglyphs, chcode, dx;
	int hasfont, hascolor, hasyoffset, hasxoffset;
	unsigned short font, height;
	signed short xoffs, yoffs;
	struct fontdata *fp;
			
	textid = readint2();
	printf("text %d\n", textid);
	rect();
	alignbits();
	matrix();
	nglyphbits = swgetc();
	nadvancebits = swgetc();
	alignbits();
	while(1)
	{	if(!getbits(1))
		{	nglyphs = getbits(7);
			if(!nglyphs)
				break;
printf("%d chars:\n", nglyphs);
			for(n = 0 ; n < nglyphs ; n++)
			{	chcode = getbits(nglyphbits);
				dx = getsbits(nadvancebits);
				if(fp && fp->codes)
				{	printf("code ");
					prchar(fp, chcode);
					printf(" dx %d\n", dx);
				}
				else
					printf("code %d dx %d\n", chcode, dx);
			}
		}
		else
		{	getbits(3);
			hasfont = getbits(1);
			hascolor = getbits(1);
			hasyoffset = getbits(1);
			hasxoffset = getbits(1);
			if(hasfont)
			{	font = readint2();
				for(fp = fontlist ; fp ; fp = fp->next)
					if(fp->id == font)
						break;
			}
			if(hascolor)
				if(lev == 2) rgba(); else rgb();
			if(hasxoffset)
			{	xoffs = readint2();
				printf("dx %d\n", xoffs);
			}
			if(hasyoffset)
			{	yoffs = readint2();
				printf("dy %d\n", yoffs);
			}
			if(hasfont)
			{	height = readint2();
				printf("font %d size %d\n", font, height);
			}
		}
		alignbits();
	}
}
/* shape */
shaperecord(nfillbits, nlinebits, lev)
{	int type, statenewstyles, statelinestyle, statefillstyle1, statefillstyle0;
	int statemoveto, movebits, movex, movey, fill0style, fill1style, linestyle;
	int edgeflag, nbits, genlineflag, dx, dy, vertlineflag;
	int cdx, cdy, adx, ady;
	
	while(1)
	{	type = getbits(1);
		
		if(!type)
		{	statenewstyles = getbits(1);
			statelinestyle = getbits(1);
			statefillstyle1 = getbits(1);
			statefillstyle0 = getbits(1);
			if(statemoveto = getbits(1))
			{	movebits = getbits(5);
				movex = getsbits(movebits);
				movey = getsbits(movebits);
				printf("move %d %d\n", movex, movey);
			}
			if(statenewstyles == 0 && statelinestyle == 0 && statefillstyle1 == 0&& statefillstyle0 == 0 && statemoveto == 0)
				break;
			if(statefillstyle0)
			{	fill0style = getbits(nfillbits);
				printf("fillstyle0 %d\n", fill0style);
			}
			if(statefillstyle1)
			{	fill1style = getbits(nfillbits);
				printf("fillstyle1 %d\n", fill1style);
			}
			if(statelinestyle)
			{	linestyle = getbits(nlinebits);
				printf("linestyle %d\n", linestyle);
			}
/* contrary to document, but
 ... seems to work AND make sense
 */
			if(statefillstyle0 || statefillstyle1 || statelinestyle)
				;
			else
			if(statenewstyles)
				fillandlinestyles(lev);
		}
		else
		{	edgeflag = getbits(1);
			if(!edgeflag)	/* curve */
			{	nbits = getbits(4)+2;
				cdx = getsbits(nbits);
				cdy = getsbits(nbits);
				adx = getsbits(nbits);
				ady = getsbits(nbits);
				printf("curve %d,%d %d,%d\n", cdx, cdy, adx, ady);
			}
			else
			{	nbits = getbits(4)+2;
				if(genlineflag = getbits(1))
				{	dx = getsbits(nbits);
					dy = getsbits(nbits);
				}
				else if(vertlineflag = getbits(1))
				{	dx = 0;
					dy = getsbits(nbits);
				}
				else
				{	dx = getsbits(nbits);
					dy = 0;
				}
				printf("line %d,%d\n", dx, dy);
			}
		}
	}
}

gradient(alpha)
{	int n, ngrad, r1, r2;
	
	alignbits();
	ngrad = swgetc();
	for(n = 0 ; n < ngrad ; n++)
	{	r1 = swgetc();
		printf("ratio %d\n", r1);
		if(alpha) rgba(); else rgb();
	}
}

fillstyle(lev)
{	unsigned short id;
	char cod;

	alignbits();
	cod = swgetc();
	switch(cod)
	{	case 0:
			printf("solid fill:\n"); break;
		case 0x10:
			printf("linear gradient fill\n"); break;
		case 0x12:
			printf("radial gradient fill:\n"); break;
		case 0x40:
			printf("tiled bitmap fill:\n"); break;
		case 0x41:
			printf("clipped bitmap fill\n"); break;
	}
	if(cod == 0)
		if(lev == 3) rgba(); else rgb();
	else if(cod == 0x10 || cod == 0x12)
	{	matrix();
		gradient(lev == 3);
	}
	else if(cod == 0x40 || cod == 0x41)
	{	id = readint2();
		printf("fill with id %d\n", id);
		matrix();
	}
	else
		printf("UNEXPEDCED %x\n", cod);
}

morphgradient()
{	int n, ngrad, r1, r2;
	
	alignbits();
	ngrad = swgetc();
	for(n = 0 ; n < ngrad ; n++)
	{	r1 = swgetc();
		printf("ratio %d\n", r1);
		rgba();
		r2 = swgetc();
		printf("ratio %d\n", r2);
		rgba();
	}
}

morphfillstyle()
{	unsigned short id;
	char cod;

	alignbits();
	cod = swgetc();
	switch(cod)
	{	case 0:
			printf("solid fill:\n"); break;
		case 0x10:
			printf("linear gradient fill\n"); break;
		case 0x12:
			printf("radial gradient fill:\n"); break;
		case 0x40:
			printf("tiled bitmap fill:\n"); break;
		case 0x41:
			printf("clipped bitmap fill\n"); break;
	}
	if(cod == 0)
	{	rgba();
		rgba();
	}
	else if(cod == 0x10 || cod == 0x12)
	{	matrix();
		alignbits();
		matrix();
		morphgradient();
	}
	else if(cod == 0x40 || cod == 0x41)
	{	id = readint2();
		printf("fill with id %d\n", id);
		matrix();
		alignbits();
		matrix();
	}
	else
		printf("UNEXPEDCED %x\n", cod);
}

fillandlinestyles(lev)
{	int n, nfill, nline;
	unsigned short w1;
	alignbits();
	nfill = swgetc();
	if(nfill == 0xff)
		nfill = readint2();
	printf ("%d fill styles\n", nfill);
	for(n = 0 ; n < nfill ; n++)
		fillstyle(lev);
	alignbits();
	nline = swgetc();
	if(nline == 0xff)
		nline = readint2();
	printf ("%d line styles\n", nline);
	for(n = 0 ; n < nline ; n++)
		linestyle(lev);
}

linestyle(lev)
{	unsigned short w;
	w = readint2();
	printf ("w %d\n", w);
	if(lev == 3) rgba(); else rgb();
}

morphlinestyle()
{	unsigned short w1, w2;
	w1 = readint2();
	w2 = readint2();
	printf("w %d => %d\n", w1, w2);
	rgba(); rgba();
}

defineshape(lev)
{	int n, cod, nfill, nline;
	unsigned short id, w1, w2;
	id = readint2();
	printf("shape %d\n", id);
	rect();
	fillandlinestyles(lev);
	shape(lev);
}

shape(lev)
{	int nfillbits, nlinebits;
	alignbits();
	nfillbits = getbits(4);
	nlinebits = getbits(4);
	shaperecord(nfillbits, nlinebits,lev);
}

bits_req(n)
{	int j, k;
	for(j = 1, k = 0 ; j <= n ; k++)
		j <<= 1;
	return k;
}

morphshape()
{	unsigned short id, fcnt, lcnt;
	unsigned long loff;
	int n;

	id = readint2();
	printf("morph %d\n", id);
	rect();
	alignbits();
	rect();
	loff = readint4();
	loff += swftell();
	fcnt = swgetc();
	if(fcnt == 0xff)
		fcnt = readint2();
	printf ("%d fill styles\n", fcnt);
	for(n = 0 ; n < fcnt ; n++)
	{	alignbits();
		morphfillstyle();
	}
	lcnt = swgetc();
	if(lcnt == 0xff)
		lcnt = readint2();
	printf ("%d line styles\n", lcnt);
	for(n = 0 ; n < lcnt ; n++)
	{	alignbits();
		morphlinestyle();
	}
/*	for(n = 0 ; swftell() < loff ; n++)
	{	alignbits();
		shaperecord(bits_req(fcnt), bits_req(lcnt), 3);
	}
	for( ; n > 0 ; --n)
	{	alignbits();
		shaperecord(bits_req(fcnt), bits_req(lcnt), 3);
	}*/
	shape(3);
	shape(3);
}

/* check file header */
struct _hdr1
{	char sign[3], vers;
	long fsize;
};

struct _hdr2
{	unsigned short frate;
	unsigned short nframes;
};
int swfhdr()
{	struct _hdr1 hdr1;
	struct _hdr2 hdr2;
	fread(&hdr1, sizeof(hdr1), 1, swf);
	if((hdr1.sign[0] != 'F' && hdr1.sign[0] != 'C') || hdr1.sign[1] != 'W' || hdr1.sign[2] != 'S')
		error("not a swf file\n");
	printf("SWF version %d", hdr1.vers);
	version = hdr1.vers;
	if(compressed = (hdr1.sign[0] == 'C'))
		printf(" compressed");
	printf("\nfile size %d", hdr1.fsize);
	if(compressed)
	{	struct stat sbuf;
		fstat(fileno(swf), &sbuf);
		printf(", compressed %d", sbuf.st_size);
		z.next_in = (unsigned char *)malloc(z.avail_in = sbuf.st_size - 8);
		fread(z.next_in, z.avail_in, 1, swf);
		zbuf = zptr = z.next_out = (unsigned char *)malloc(z.avail_out = hdr1.fsize - 8);
		inflateInit(&z);
		inflate(&z, Z_FINISH);
		inflateEnd(&z);
	}
	printf("\n");
	rect();
	alignbits();
	hdr2.frate = readint2();
	hdr2.nframes = readint2();
	printf("frame rate %.2f\n", ((double)hdr2.frate) / 256);
	printf("%d frames\n", hdr2.nframes);
	return(hdr1.fsize);
}

/* get next tag from file */
int swftag(long *nbytes)
{	unsigned short xx;
	unsigned res;
	xx = readint2();
	res = xx >> 6;
	*nbytes = xx & 63;
	if(*nbytes == 63)
		*nbytes = readint4();
	alignbits();
	return(res);
}

placeobject()
{	short depth, charid;
	charid = readint2();
	depth = readint2();
	printf("char %d depth %d\n", charid, depth);
	matrix();
}

removeobject()
{	short depth, charid;
	charid = readint2();
	depth = readint2();
	printf("char %d depth %d\n", charid, depth);
}

placeob2flags(flags)
{	if(flags & 0x40000)
		printf(" construct");
	if(flags & 0x20000)
		printf(" keypress");
	if(flags & 0x10000)
		printf(" dragout6");
	if(flags & 0x8000)
		printf(" dragover6");
	if(flags & 0x4000)
		printf(" mouseout6");
	if(flags & 0x2000)
		printf(" mouseover6");
	if(flags & 0x1000)
		printf(" mouseupoutside6");
	if(flags & 0x800)
		printf(" mouseup6");
	if(flags & 0x400)
		printf(" mousedown6");
	if(flags & 0x200)
		printf(" init");
	if(flags & 0x100)
		printf(" data");
	if(flags & 0x80)
		printf(" keyup");
	if(flags & 0x40)
		printf(" keydown");
	if(flags & 0x20)
		printf(" mouseup");
	if(flags & 0x10)
		printf(" mousedown");
	if(flags & 0x8)
		printf(" mousemove");
	if(flags & 0x4)
		printf(" unload");
	if(flags & 0x2)
		printf(" enterframe");
	if(flags & 0x1)
		printf(" load");
}

placeobject2()
{	int hasname, hasratio, hascxform, hasmatrix, haschar, hasmove, hasactions, hasmask;
	short depth, charid, act;
	int base, len, flags;
	char ch;
	hasactions = getbits(1);
	hasmask = getbits(1);
	hasname = getbits(1);
	hasratio = getbits(1);
	hascxform = getbits(1);
	hasmatrix = getbits(1);
	haschar = getbits(1);
	hasmove = getbits(1);
	depth = readint2();
	if(haschar)
	{	charid = readint2();
		printf("char %d depth %d\n", charid, depth);
	}
	else
	{	printf("move depth %d\n", depth);
	}
	if(hasmatrix)
		matrix();
	if(hascxform)
	{	alignbits();
		cxform(1);	// ?????
	}
	if(hasratio)
	{	alignbits();
		depth = readint2();
		printf("ratio %d\n", depth);
	}
	if(hasname)
	{	printf("name ");
		while(ch = swgetc())
			putchar(ch);
		putchar('\n');
	}
	if(hasmask)
	{	flags = readint2();
		printf("MASK %d\n", flags);
	}
	if(hasactions)
	{	flags = readint2();	// reserved
		if(version >= 6)
			flags = readint4();
		else
			flags = readint2();
		printf("all action flags %x", flags);
		placeob2flags(flags);
		printf("\n");
		while(1)
		{	if(version >= 6)
				flags = readint4();
			else
				flags = readint2();
			if(!flags)
				break;
			len = readint4();
			printf("actionflags %x", flags);
			placeob2flags(flags);
			if(flags & 0x20000)
				printf(" keycode %d", swgetc());
			printf(" (%d bytes)\n", len);
			base = swftell();
			while(swftell() < base+len)
			{	act = swgetc();
				dooneaction(act, base);	
			}
		}
	}
}

removeobject2()
{	short depth;
	depth = readint2();
	printf("char at depth %d\n", depth);
}

cxform(alpha)
{	int hasadd, hasmult, nbits;
	int ra, ga, ba, aa, rm, gm, bm, am;
	hasadd = getbits(1);
	hasmult = getbits(1);
	nbits = getbits(4);
	printf("cxform ");
	if(hasmult)
	{	rm = getsbits(nbits);
		gm = getsbits(nbits);
		bm = getsbits(nbits);
		if(alpha) am  = getsbits(nbits);
		printf("mul %d %d %d ", rm, gm, bm);
		if(alpha) printf("%d ", am);
	}
	if(hasadd)
	{	ra = getsbits(nbits);
		ga = getsbits(nbits);
		ba = getsbits(nbits);
		if(alpha) aa = getsbits(nbits);
		printf("add %d %d %d", ra, ga, ba);
		if(alpha) printf(" %d", am);
	}
	printf("\n");
}

definebutton()
{	short butid, charid, layer;
	unsigned char bstate, act;
	long base;
	butid = readint2();
	printf("char %d:\n", butid);
	while(bstate = swgetc())
	{	if(bstate & 8)
			printf("hit test ");
		if(bstate & 4)
			printf("down ");
		if(bstate & 2)
			printf("over ");
		if(bstate & 1)
			printf("up");
		printf("\n");
		charid = readint2();
		layer = readint2();
		printf("char %d layer %d\n", charid, layer);
		alignbits();
		matrix();
	}
	base = swftell();
	while(act = swgetc())
		dooneaction(act, base);
}

char *btncond[] = {"OverDown2Idle","Idle2OverDown","OutDown2Idle","OutDown2OverDown","OverDown2OutDown","OverDown2OverUp","OverUp2OverDown","OverUp2Idle","Idle2OverUp"};
definebutton2()
{	short id, charid, offs, layer;
	unsigned char ch, bstate;
	long base;
	id = readint2();
	ch = swgetc();
	offs = readint2();
	printf("id %d %s action offset %d\n", id, ch ? "menu" : "button", offs);
	while(bstate = swgetc())
	{	if(bstate & 8)
			printf("hit test ");
		if(bstate & 4)
			printf("down ");
		if(bstate & 2)
			printf("over ");
		if(bstate & 1)
			printf("up");
		printf("\n");
		charid = readint2();
		layer = readint2();
		printf("char %d layer %d\n", charid, layer);
		alignbits();
		matrix();
		alignbits();
		cxform(1);
	}
	while(offs)
	{	offs = readint2();
		printf("next offset %d\n", offs);
		alignbits();
		printf("cond");
		for(ch = 0 ; ch < 9 ; ch++)
			if(getbits(1))
				printf(" %s", btncond[ch]);
		ch = getbits(7);
		if(ch)
			printf("keycode %d ", ch);
		printf("\n");
		base = swftell();
		while(ch = swgetc())
			dooneaction(ch, base);
	}
}

char **act_constants = {0}, *const_strings = {0};
int nconstants = {0};

dooneaction(op, base)
{	short len, num;
	int tmp;
	long _start, _end;
	unsigned char ch;
	static _endfunc;
	
	if(swftell()-1 == _endfunc)
	{	printf("%d: --- end subr ---\n", swftell()-1-base);
		_endfunc = 0;
	}
	printf("%d: ", swftell()-1-base);
	if(op & 0x80)
	{	_start = swftell();
		len = readint2();
		_end = _start + 2 + len;
	}
	switch(op & 0xff)
	{	case 0x4:
			printf("next frame\n");
			break;
		case 0x5:
			printf("prev frame\n");
			break;
		case 0x6:
			printf("play\n");
			break;
		case 0x7:
			printf("stop\n");
			break;
		case 0x8:
			printf("toggle quality\n");
			break;
		case 0x9:
			printf("stop all sounds\n");
			break;
		case 0xa:
			printf("add\n");
			break;
		case 0xb:
			printf("sub\n");
			break;
		case 0xc:
			printf("mul\n");
			break;
		case 0xd:
			printf("div\n");
			break;
		case 0xe:
			printf("eq\n");
			break;
		case 0xf:
			printf("lt\n");
			break;
		case 0x10:
			printf("and\n");
			break;
		case 0x11:
			printf("or\n");
			break;
		case 0x12:
			printf("not\n");
			break;
		case 0x13:
			printf("string eq\n");
			break;
		case 0x14:
			printf("string length\n");
			break;
		case 0x15:
			printf("substring\n");
			break;
		case 0x17:
			printf("pop\n");
			break;
		case 0x18:
			printf("int\n");
			break;
		case 0x1c:
			printf("eval\n");
			break;
		case 0x1d:
			printf("set\n");
			break;
		case 0x20:
			printf("settarget\n");
			break;
		case 0x21:
			printf("strcat\n");
			break;
		case 0x22:
			printf("getproperty\n");
			break;
		case 0x23:
			printf("setproperty\n");
			break;
		case 0x24:
			printf("duplicate clip\n");
			break;
		case 0x25:
			printf("remove clip\n");
			break;
		case  0x26:
			printf("trace\n");
			break;
		case 0x27:
			printf("start drag\n");
			break;
		case 0x28:
			printf("stop drag\n");
			break;
		case 0x29:
			printf("string lt\n");
			break;
		case 0x2a:
			printf("throw\n");
			break;
		case 0x2b:
			printf("cast\n");
			break;
		case 0x2c:
			printf("implements\n");
			break;
		case 0x30:
			printf("random\n");
			break;
		case 0x31:
			printf("MB string length\n");
			break;
		case 0x32:
			printf("chr\n");
			break;
		case 0x33:
			printf("ord\n");
			break;
		case 0x34:
			printf("gettimer\n");
			break;
		case 0x35:
			printf("MB substring\n");
			break;
		case 0x3a:
			printf("deletevar\n");
			break;
		case 0x3b:
			printf("deletevars\n");
			break;
		case 0x3c:
			printf("define_set_local\n");
			break;
		case 0x3d:
			printf("callfunc\n");
			break;
		case 0x3e:
			printf("return\n");
			break;
		case 0x3f:
			printf("mod\n");
			break;
		case 0x40:
			printf("newobj\n");
			break;
		case 0x41:
			printf("definelocal\n");
			break;
		case 0x42:
			printf("initarray\n");
			break;
		case 0x43:
			printf("initobject\n");
			break;
		case 0x44:
			printf("typeof\n");
			break;
		case 0x45:
			printf("targetpath\n");
			break;
		case 0x46:
			printf("enum\n");
			break;
		case 0x47:
			printf("add_type\n");
			break;
		case 0x48:
			printf("lt_type\n");
			break;
		case 0x49:
			printf("eq_type\n");
			break;
		case 0x4a:
			printf("to_number\n");
			break;
		case 0x4b:
			printf("to_string\n");
			break;
		case 0x4c:
			printf("dup\n");
			break;
		case 0x4d:
			printf("swap\n");
			break;
		case 0x4e:
			printf("getmember\n");
			break;
		case 0x4f:
			printf("setmember\n");
			break;
		case 0x50:
			printf("incr\n");
			break;
		case 0x51:
			printf("decr\n");
			break;
		case 0x52:
			printf("callmethod\n");
			break;
		case 0x53:
			printf("newmethod\n");
			break;
		case 0x54:
			printf("instanceof\n");
			break;
		case 0x55:
			printf("enum2\n");
			break;
		case 0x60:
			printf("bitand\n");
			break;
		case 0x61:
			printf("bitor\n");
			break;
		case 0x62:
			printf("bitxor\n");
			break;
		case 0x63:
			printf("shiftleft\n");
			break;
		case 0x64:
			printf("shiftright\n");
			break;
		case 0x65:
			printf("shiftrightU\n");
			break;
		case 0x66:
			printf("strictequals\n");
			break;
		case 0x67:
			printf("gt_type\n");
			break;
		case 0x68:
			printf("string gt\n");
			break;
		case 0x69:
			printf("extends\n");
			break;
		case 0x81:
			num = readint2();
			printf("goto %d\n", num);
			break;
		case 0x83:
			printf("get url ");
			while(ch = swgetc())
				putchar(ch);
			putchar(' ');
			while(ch = swgetc())
				putchar(ch);
			putchar('\n');
			break;
		case 0x87:
			ch = swgetc();
			printf("store %d\n", ch);
			break;
		case 0x88:
			printf("constants:");
			{	int nch = swgetc() & 0xff;
				int nv = 1;
				char *cp;
				free(act_constants);
				free(const_strings);
				nconstants = nch;
				cp = const_strings = (char *)malloc(len-1);
				ch = swgetc(); nch += ((ch&0xff) << 8);
				act_constants = (char **)malloc(nch * sizeof(char *));
				printf(" %d\n 0: ", nch);
				act_constants[0] = cp;
				for(num = 2 ; num < len ; num++)
				{	ch = swgetc(); *cp++ = ch;
					if(ch == 0)
					{	printf("\n");
						if(nv < nch)
						{	act_constants[nv] = cp;
							printf(" %d: ", nv++);
						}
					}
					else if(ch >= ' ' && ch < 0177)
						putchar(ch);
					else
						printf("\\%03o", ch);
				}
			}
			break;
		case 0x8a:
			num = readint2();
			ch = swgetc();
			printf("wait for frame %d, skip %d\n", num, ch);
			break;
		case 0x8b:
			printf("tell target ");
			while(ch = swgetc())
				putchar(ch);
			putchar('\n');
			break;
		case 0x8c:
			printf("goto ");
			while(ch = swgetc())
				putchar(ch);
			putchar('\n');
			break;
		case 0x8d:
			ch = swgetc();
			printf("waitfor frame (%d instr)\n");
			break;
		case 0x8e:
		{	int tmpr = 1;
			printf("definefunc2 ");
			while(ch= swgetc())
				putchar(ch);
			num = readint2();
			ch = swgetc();
			printf(" [%d regs] ", ch);
			ch = swgetc();
			if(ch & 0x2)
				printf(" !this");
			else if(ch & 0x1)
				printf(" this(r%d)", tmpr++);
			if(ch & 0x8)
				printf(" !arguments");
			else if(ch & 0x4)
				printf(" arguments(r%d)", tmpr++);
			if(ch & 0x20)
				printf(" !super");
			else if(ch & 0x10)
				printf(" super(r%d)", tmpr++);
			if(ch & 0x40)
				printf(" _root(r%d)", tmpr++);
			if(ch = 0x80)
				printf(" _parent(r%d)", tmpr++);
			ch = swgetc();
			if(ch & 0x1)
				printf(" _global(r%d)", tmpr++);
			printf(" (");
			{	int n, reg;
				for(n = 0 ; n < num ; n++)
				{	reg = swgetc();
					if(n)
						putchar(',');
					while(ch = swgetc())
						putchar(ch);
					if(reg)
						printf("(r%d)", reg);
				}
			}
			num = readint2();
			_endfunc = swftell() + num;
			printf(")  %d bytes\n", num);
		}
			break;
		case 0x8f:
		{	char flags;
			int trysize, catchsize, finallysize;
			long xbase, xend;
			flags = swgetc();
			printf("try ");
			if(flags & 4)
				printf("in_register ");
			if(flags & 2)
				printf("finally ");
			if(flags & 1)
				printf("catch ");
			trysize = readint2();
			printf("%d bytes(try), ", trysize);
			catchsize = readint2();
			printf("%d bytes(catch), ", catchsize);
			finallysize = readint2();
			printf("%d bytes(finally)", finallysize );
			if(flags & 4)
			{	ch = swgetc();
				printf("reg%d", ch);
			}
			else
			{	while(ch = swgetc())
					putchar(ch);
			}
			xbase = swftell();
			xend = xbase + trysize;
			printf("try:\n");
			while(swftell() < xend)
			{	ch = swgetc();
				dooneaction(ch, base);
			}
			xbase = xend;
			if(catchsize)
				printf("catch:\n");
			xend = xbase + catchsize;
			while(swftell() < xend)
			{	ch = swgetc();
				dooneaction(ch, base);
			}
			xbase = xend;
			if(finallysize)
				printf("finally:\n");
			xend = xbase + finallysize;
			while(swftell() < xend)
			{	ch = swgetc();
				dooneaction(ch, base);
			}
			printf("----------\n");
		}
			break;
		case 0x94:
			num = readint2();
			printf("with (%d bytes)\n", num);
			break;
		case 0x96:
			printf("push ");
			for(num = 0 ; num < len ; )			
			{	ch = swgetc(); num++;
				if(!ch)
				{	for( ; num < len ; )
					{	ch = swgetc(); num++;
						if(ch)
							putchar(ch);
						else
							break;
					}
				}
				else if(ch == 8)
				{	ch = swgetc();
					++num;
					printf("08 %02x (%s) ", ch & 0xff, act_constants[ch & 0xff]);
				}
				else if(ch == 9)
				{	ch = swgetc();
					ch |= swgetc() << 8;
					num += 2;
					printf("09 %04x (%s) ", ch, act_constants[ch]);
				}
				else if(ch == 2)
				{	printf("02 (NULL) ");
				}
				else if(ch == 4)
				{	ch = swgetc();
					num++;
					printf("r%d", ch & 0xff);
				}
				else
				{	int n;
					printf("%02x ", ch & 0xff);
					if(ch == 5)
						n = 1;
					else if(ch == 7)
						n = 4;
					else if(ch == 6)
						n = 8;
					else n = 0;
					while(--n >= 0 && num < len)
					{	ch = swgetc();
						printf("%02x ", ch & 0xff);
						++num;
					}
				}
				putchar(' ');
			}
			printf("\n");
			break;
#if 0
case 1 - flash 4 properties ...
0	_x
1	_y
2	_xscale
3	_yscale
4	_currentframe
5	_totalframes
6	_alpha
7	_visible
8	_width
9	_height
10	_rotation
11	_target
12	_framesloaded
13	_name
14	_droptarget
15	_url
16	_highquality
17	_focusrect
18	_soundbuftime
19	_quality
20	_xmouse
21	_ymouse
				num = readint2();
				switch(num)
				{	case 0:
						printf("_x\n"); break;
					case 0x3f80:
						printf("_y\n"); break;
					case 0x4000:
						printf("_xscale\n"); break;
					case 0x4040:
						printf("_scale\n"); break;
					case 0x40c0:
						printf("_alpha\n"); break;
					case 0x40e0:
						printf("_visible\n"); break;
					case 0x4120:
						printf("_rotation\n"); break;
					case 0x4140:
						printf("_name\n"); break;
					case 0x4180:
						printf("_highquality\n"); break;
					case 0x4188:
						printf("_showfocusrect\n"); break;
					case 0x4190:
						printf("_soundbuftime\n"); break;
					case 0x4680:
						printf("WTHIT\n"); break;
				}
			}
#endif
		case 0x99:
			num = readint2();
			tmp = swftell() + num - base;
			printf("branch always offset %d (%d)\n", num, tmp);
			break;
		case 0x9a:
			ch = swgetc();
			if(ch & 0x80)
				printf((ch & 0x40) ? "loadvariables " : "loadvariablesnum ");
			else
				printf((ch & 0x40) ? "loadmovie " : "loadmovienum ");
			if((ch &= 0x3f) == 0) printf("dont send\n");
			else if(ch == 1) printf("GET\n");
			else printf("POST\n");
			break;
		case 0x9b:
			printf("definefunc ");
			while(ch= swgetc())
				putchar(ch);
			num = readint2();
			printf("(");
			{	int n;
				for(n = 0 ; n < num ; n++)
				{	if(n)
						putchar(',');
					while(ch = swgetc())
						putchar(ch);
				}
			}
			num = readint2();
			_endfunc = swftell() + num;
			printf(")  %d bytes\n", num);
			break;
		case 0x9d:
			num = readint2();
			tmp = swftell() + num - base;
			printf("branch true offset %d (%d)\n", num, tmp);
			break;
		case 0x9e:
			printf("call frame\n");
			break;
		case 0x9f:
			ch = swgetc();
			printf("goto and %s\n", ch ? "play" : "stop");
			break;
		default:
			printf("action %x\n", op);
			//if(op & 0x80)
			//	fseek(swf, len, 1);
			break;
	}
	if(op & 0x80)
		swfseek(_end);
}

doaction()
{	unsigned char op;
	long base = swftell();

	while(op = swgetc())
		dooneaction(op, base);
}

clipinit()
{	unsigned char op;
	long base;
	int id;
	id = readint2();
	printf("init char %d\n", id);
	base = swftell();

	while(op = swgetc())
		dooneaction(op, base);
}

framelabel(int len)
{	char ch;
	while((--len >= 0) && (ch = swgetc()))
		putchar(ch);
	if(len > 0)
	{	ch = swgetc();
		if(ch == 1) printf(" (named anchor)");
		else printf(" (%d)", ch);
	} 
	putchar('\n');
}

startsound()
{	unsigned short id;
	id = readint2();
	printf("id %d\n", id);
	soundinfo(1);
}

definebuttonsound()
{	unsigned short id;
	int n;
	static char *inf[] = {"rollout", "rollover", "press", "release"};
	id = readint2();
	printf("button id %d\n", id);
	for(n = 0 ; n < 4 ; n++)
	{	id = readint2();
		if(id)
		{	printf("%s %d\n", inf[n], id);
			soundinfo(0);
		}
	}
}

soundinfo(show)
{	char flags, hasenvelope, hasloops, hasoutpoint, hasinpoint, npoints;
	signed short loops, lev0, lev1;
	int soundpoint, n;
	flags = getbits(4);
	hasenvelope = getbits(1);
	hasloops = getbits(1);
	hasoutpoint = getbits(1);
	hasinpoint = getbits(1);
	if(flags & 1)
		printf("no multiple ");
	if(flags & 2)
		printf("stop");
	if(show && !(flags & 3))
		printf("start");
	if(show || (flags & 3))
		putchar('\n');
	if(hasinpoint)
	{	soundpoint = readint4();
		printf("inpoint %d\n", soundpoint);
	}
	if(hasoutpoint)
	{	soundpoint = readint4();
		printf("outpoint %d\n", soundpoint);
	}
	if(hasloops)
	{	loops = readint2();
		printf("%d loops\n", loops);
	}
	if(hasenvelope)
	{	npoints = swgetc();
		for(n = 0 ; n < npoints ; n++)
		{	soundpoint = readint4();
			lev0 = readint2();
			lev1 = readint2();
			printf("%d: %d %d\n", soundpoint, lev0, lev1);
		}
	}
}

definebitslossless()
{	unsigned short id, wd, ht;
	char fmt, colors;	
	id = readint2();
	fmt = swgetc();
	wd = readint2();
	ht = readint2();
	printf("id %d ", id);
	switch(fmt)
	{	case 3: printf("8bit palette"); break;
		case 4: printf("15bit rgb"); break;
		case 5: printf("24bit rgb"); break;
	}
	printf(" w %d h %d", wd, ht);
	if(fmt == 3)
	{	colors = swgetc();
		printf(" %d colors", colors);
	}
	printf("\n");
}

definebitsjpeg()
{	unsigned short id;
	id = readint2();
	printf("id %d", id);
	printf("\n");
}

definesound()
{	unsigned short id;
	char format, rate, twobyte, stereo;
	int nsamp;
	static char *rates[] = {"5.5k", "11k", "22k", "44k"};
	static char *formats[] = {"raw", "adpcm", "mp3", "raw LE", "", "", "nellymoser", ""};
	id = readint2();
	format = getbits(4);
	rate = getbits(2);
	twobyte = getbits(1);
	stereo = getbits(1);
	nsamp = readint4();
	printf("id %d ", id);
	printf("%s ", formats[format]);
	printf("%s ", rates[rate]);
	if(twobyte) printf("16bit ");
	if(stereo) printf("stereo");
	printf("\n%d samples\n", nsamp);
}

soundstreamhead2()
{	int dummy, pbrate, pbtwobyte, pbstereo, format, rate, twobyte, stereo;
	int samples, latency;
	static char *rates[] = {"5.5k", "11k", "22k", "44k"};
	static char *formats[] = {"raw", "adpcm", "mp3", "raw LE", "", "", "nellymoser", ""};
	dummy = getbits(4);
	pbrate = getbits(2);
	pbtwobyte = getbits(1);
	pbstereo = getbits(1);
	format = getbits(4);
	rate = getbits(2);
	twobyte = getbits(1);
	stereo = getbits(1);
	samples = readint2();
	printf("%s play ", formats[format]);
	printf("%s ", rates[pbrate]);
	if(pbtwobyte) printf("16bit ");
	if(pbstereo) printf("stereo ");
	printf("stream ");
	printf("%s ", rates[rate]);
	if(twobyte) printf("16bit ");
	if(stereo) printf("stereo ");
	printf("%d samples", samples);
	if(format == 2)
		latency = readint2();
	printf("\n");
}

soundstreamblock()
{
}

definesprite(int len)
{	unsigned short id, nframes;
	long fpos;
	id = readint2();
	nframes = readint2();
	printf("id %d: %d frames\n", id, nframes);
	fpos = swftell();
	listfile(fpos, fpos+len-4);
	printf("*** end sprite\n");
	/* data until END marker should be indented... */
}

exportassets()
{	short n, nobj, id;
	char ch;
	nobj = readint2();
	for(n = 0 ; n < nobj ; n++)
	{	id = readint2();
		printf("%d ", id);
		while(ch = swgetc())
			putchar(ch);
		if(n < nobj-1) putchar(' '); else putchar('\n');
	}
}

importassets()
{	short n, nobj, id;
	char ch;
	
	printf("import from ");
	while(ch = swgetc())
		putchar(ch);
	putchar('\n');
	nobj = readint2();
	for(n = 0 ; n < nobj ; n++)
	{	id = readint2();
		printf("%d ", id);
		while(ch = swgetc())
			putchar(ch);
		if(n < nobj-1) putchar(' '); else putchar('\n');
	}
}

definevideostream()
{	short id, nframes;
	
	id = readint2();
	nframes = readint2();
	printf("id %d: %d frames\n", id, nframes);
}

videoframe()
{	short id;
	
	id = readint2();
	printf("stream id %d:\n", id);
}

#include "swf.h"

main(int ac, char **av)
{	long fpos, fend;

	--ac; ++av;
	if(ac == 0)
		swf = stdin;
	else if(!(swf = fopen(*av, "r")))
		error("could not open %s\n", *av);
	fend = swfhdr();
	listfile(swftell(), fend);
	exit(0);
}

listfile(long fpos, long fend)
{	int stag; long ltag;
	char *tagnam;

	for( ; fpos < fend ; )
	{	stag = swftag(&ltag);
		switch(stag)
		{
			case stagEnd:
				tagnam = "stagEnd"; break;
			case stagShowFrame:
				tagnam = "stagShowFrame"; break;
			case stagDefineShape:
				tagnam = "stagDefineShape"; break;
			case stagFreeCharacter:
				tagnam = "stagFreeCharacter"; break;
			case stagPlaceObject:
				tagnam = "stagPlaceObject"; break;
			case stagRemoveObject:
				tagnam = "stagRemoveObject"; break;
			case stagDefineBits:
				tagnam = "stagDefineBits"; break;
			case stagDefineButton:
				tagnam = "stagDefineButton"; break;
			case stagJPEGTables:
				tagnam = "stagJPEGTables"; break;
			case stagSetBackgroundColor:
				tagnam = "stagSetBackgroundColor"; break;
			case stagDefineFont:
				tagnam = "stagDefineFont"; break;
			case stagDefineText:
				tagnam = "stagDefineText"; break;
			case stagDoAction:
				tagnam = "stagDoAction"; break;
			case stagDefineFontInfo:
				tagnam = "stagDefineFontInfo"; break;
			case stagDefineSound:
				tagnam = "stagDefineSound"; break;
			case stagStartSound:
				tagnam = "stagStartSound"; break;
			case stagDefineButtonSound:
				tagnam = "stagDefineButtonSound"; break;
			case stagSoundStreamHead:
				tagnam = "stagSoundStreamHead"; break;
			case stagSoundStreamBlock:
				tagnam = "stagSoundStreamBlock"; break;
			case stagDefineBitsLossless:
				tagnam = "stagDefineBitsLossless"; break;
			case stagDefineBitsJPEG2:
				tagnam = "stagDefineBitsJPEG2"; break;
			case stagDefineShape2:
				tagnam = "stagDefineShape2"; break;
			case stagDefineButtonCxform:
				tagnam = "stagDefineButtonCxform"; break;
			case stagProtect:
				tagnam = "stagProtect"; break;
			case stagPlaceObject2:
				tagnam = "stagPlaceObject2"; break;
			case stagRemoveObject2:
				tagnam = "stagRemoveObject2"; break;
			case stagDefineShape3:
				tagnam = "stagDefineShape3"; break;
			case stagDefineText2:
				tagnam = "stagDefineText2"; break;
			case stagDefineButton2:
				tagnam = "stagDefineButton2"; break;
			case stagDefineBitsJPEG3:
				tagnam = "stagDefineBitsJPEG3"; break;
			case stagDefineBitsLossless2:
				tagnam = "stagDefineBitsLossless2"; break;
			case stagDefineTextField:
				tagnam = "stagDefineTextField"; break;
			case stagDefineSprite:
				tagnam = "stagDefineSprite"; break;
			case stagNameCharacter:
				tagnam = "stagNameCharacter"; break;
			case stagFrameLabel:
				tagnam = "stagFrameLabel"; break;
			case stagSoundStreamHead2:
				tagnam = "stagSoundStreamHead2"; break;
			case stagDefineMorphShape:
				tagnam = "stagDefineMorphShape"; break;
			case stagDefineFont2:
				tagnam = "stagDefineFont2"; break;
			case stagExportAssets:
				tagnam = "stagExportAssets"; break;
			case stagImportAssets:
				tagnam = "stagImportAssets"; break;
			case stagClipInit:
				tagnam = "stagClipInit"; break;
			case stagNewFontInfo:
				tagnam = "stagNewFontInfo"; break;
			case stagDefineVideoStream:
				tagnam = "stagDefineVideoStream"; break;
			case stagVideoFrame:
				tagnam = "stagVideoFrame"; break;
			default:
				tagnam = "unknown";
		}
		printf("tag %d %s at file offset %d\n", stag, tagnam, fpos);
		fpos = swftell();
		switch(stag)
		{
			case stagEnd:
				break;
			case stagShowFrame:
				break;
			case stagDefineShape:
				defineshape(1); break;
			case stagFreeCharacter:
				break;
			case stagPlaceObject:
				placeobject(); break;
			case stagRemoveObject:
				removeobject(); break;
			case stagDefineBits:
				break;
			case stagDefineButton:
				definebutton(); break;
			case stagJPEGTables:
				break;
			case stagSetBackgroundColor:
				rgb(); break;
			case stagDefineFont:
				definefont(ltag > 2); break;
			case stagDefineText:
				definetext(1); break;
			case stagDoAction:
			case 253:
				doaction(); break;
			case stagDefineFontInfo:
				definefontinfo(); break;
			case stagDefineSound:
				definesound(); break;
			case stagStartSound:
				startsound(); break;
			case stagDefineButtonSound:
				definebuttonsound(); break;
			case stagSoundStreamBlock:
				soundstreamblock(); break;
			case stagSoundStreamHead:
				break;
			case stagDefineBitsJPEG3:
			case stagDefineBitsJPEG2:
				definebitsjpeg();
				break;
			case stagDefineBitsLossless:
				definebitslossless(); break;
			case stagDefineShape2:
				defineshape(2); break;
			case stagDefineButtonCxform:
			case stagProtect:
				break;
			case stagPlaceObject2:
				placeobject2(); break;
			case stagRemoveObject2:
				removeobject2(); break;
			case stagDefineShape3:
				defineshape(3); break;
			case stagDefineText2:
				definetext(2); break;
			case stagDefineButton2:
				definebutton2(); break;
			case stagDefineBitsLossless2:
				definebitslossless(); break;
			case stagDefineTextField:
				definetextfield(); break;
			case stagDefineSprite:
				definesprite(ltag); break;
			case stagNameCharacter:
				break;
			case stagFrameLabel:
				framelabel(ltag); break;
			case stagSoundStreamHead2:
				soundstreamhead2(); break;
			case stagDefineMorphShape:
				morphshape(); break;
			case stagDefineFont2:
				definefont2(); break;
			case stagExportAssets:
				exportassets(); break;
			case stagImportAssets:
				importassets(); break;
			case stagClipInit:
				clipinit(); break;
			case stagNewFontInfo:
				newfontinfo(); break;
			case stagDefineVideoStream:
				definevideostream(); break;
			case stagVideoFrame:
				videoframe(); break;
		}
		swfseek(fpos += ltag);
		alignbits();
	}
}

