1 /*
2 flasm, command line assembler & disassembler of flash actionscript bytecode
3 Copyright (c) 2001 Opaque Industries, (c) 2002-2007 Igor Kogan, (c) 2005 Wang Zhen
4 All rights reserved. See LICENSE.TXT for terms of use.
5 */
6 
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <math.h>
13 #include <time.h>
14 
15 #ifdef MEMWATCH
16 #include "memwatch.h"
17 #endif
18 
19 #include "util.h"
20 #include "action.h"
21 
22 void disassembleSWF(FILE *f, char *fname);
23 void skipProtected(FILE *f, unsigned long int length);
24 
25 extern void tellUser(int isError, char *s, ...);
26 
27 static int indent = 1;
28 static int targetIndent = 0;
29 static long int swfabspos = -1;
30 static long int swfrelpos = -1;
31 
32 extern int swfVersion;
33 
34 static int showLiterals;
35 static int nDict = 0;
36 struct _dict {
37 	char *value;
38 	int count;
39 };
40 static struct _dict dictionary[MAX_CONSTANTS];
41 static char *flasmDict = NULL;
42 
43 static long int numLabels = 0;
44 static long int curLabel = 0;
45 static unsigned long int *labels = NULL;
46 
47 static unsigned long int conststart = 0, constend = 0;
48 
49 /* from flasm.c */
50 extern int mode;
51 extern char wasCompressed;
52 
53 /* from flasm.c <- flasm.ini */
54 extern int showoffset, hexoffset, literalregisters, literalconstants;
55 
56 enum {
57 	eventLoad			= 0x01,
58 	eventEnterFrame		= 0x02,
59 	eventUnload			= 0x04,
60 	eventMouseMove		= 0x08,
61 	eventMouseDown		= 0x10,
62 	eventMouseUp		= 0x20,
63 	eventKeyDown		= 0x40,
64 	eventKeyUp			= 0x80,
65 	eventData			= 0x100,
66 	eventInitialize		= 0x200, /* flash 6/7 only; flash 5 stores smartClip parameters in eventLoad */
67 	eventPress			= 0x400,
68 	eventRelease		= 0x800,
69 	eventReleaseOutside	= 0x1000,
70 	eventRollOver		= 0x2000,
71 	eventRollOut		= 0x4000,
72 	eventDragOver		= 0x8000,
73 	eventDragOut		= 0x10000,
74 	eventKeyPress		= 0x20000,
75 	eventConstruct		= 0x40000 /* flash 7 only */
76 };
77 
78 enum {
79 	IdleToOverUp		= 0x01,
80 	OverUpToIdle		= 0x02,
81 	OverUpToOverDown	= 0x04,
82 	OverDownToOverUp	= 0x08,
83 	OverDownToOutDown	= 0x10,
84 	OutDownToOverDown	= 0x20,
85 	OutDownToIdle		= 0x40,
86 	IdleToOverDown		= 0x80,
87 	OverDownToIdle		= 0x100
88 };
89 
90 enum {
91 	keyLeft				= 1,
92 	keyRight			= 2,
93 	keyHome				= 3,
94 	keyEnd				= 4,
95 	keyInsert			= 5,
96 	keyDelete			= 6,
97 	keyBackspace		= 8,
98 	keyEnter			= 13,
99 	keyUp				= 14,
100 	keyDown				= 15,
101 	keyPageUp			= 16,
102 	keyPageDown			= 17,
103 	keyTab				= 18,
104 	keyEscape			= 19,
105 	keySpace			= 32
106 };
107 
108 /* names of automatic values for function2 */
109 char *arNames[] = {"this", "arguments", "super", "_root", "_parent", "_global"};
110 /* preload flags set for particular automatic value */
111 unsigned int arPreFlags[] = {0x0001, 0x0004, 0x0010, 0x0040, 0x0080, 0x0100};
112 /* suppress flags set for particular automatic value */
113 unsigned int arSupFlags[] = {0x0002, 0x0008, 0x0020, 0x0000, 0x0000, 0x0000};
114 
115 
skipProtected(FILE * f,unsigned long int length)116 void skipProtected(FILE *f, unsigned long int length)
117 {
118 	if (fseek(f, length, SEEK_CUR) != 0)
119 		tellUser(1, "Unexpected end of file");
120 }
121 
printIndent(int i)122 static void printIndent(int i)
123 {
124 	size_t buflen = INDENT_LEVEL*i;
125 	static long int lastpos = 0;
126 	long int swfpos;
127 
128 	if (showoffset > 0) {
129 		if (showoffset == 1)
130 			swfpos = swfrelpos;
131 		else
132 			swfpos = swfabspos+swfrelpos;
133 
134 		/* don't print adress if unchanged */
135 		if (swfpos >= 0 && (swfpos > lastpos || swfpos == 0)) {
136 			lastpos = swfpos;
137 			if (hexoffset == 1)
138 				/* big endian issues? */
139 				printf("%04X%04X", (unsigned int) (0xFFFF & (swfpos>>16)), (unsigned int) (0xFFFF & swfpos));
140 			else
141 				printf("%08li", swfpos);
142 		}
143 		else
144 			buflen += 8;
145 	}
146 
147 	if (i>0) {
148 		char buf[buflen];
149 		memset(buf, ' ', buflen);
150 		fwrite(buf, sizeof(char), buflen, stdout);
151 	}
152 }
153 
print(char * s,...)154 static void print(char *s, ...)
155 {
156 	va_list ap;
157 
158 	printIndent(indent);
159 
160 	va_start(ap, s);
161 	vprintf(s, ap);
162 	va_end(ap);
163 }
164 
printstr(char * str)165 static void printstr(char *str)
166 {
167 	char buf[strlen(str)*2+3];
168 	char *bufp = buf, *bufstr = str;
169 
170 	*bufp++ = '\'';
171 	while (*bufstr++ != '\0') {
172 		switch (*(bufstr-1)) {
173 			case '\b':
174 				*bufp++ = '\\';	*bufp++ = 'b';
175 				break;
176 			case '\t':
177 				*bufp++ = '\\';	*bufp++ = 't';
178 				break;
179 			case '\n':
180 				*bufp++ = '\\';	*bufp++ = 'n';
181 				break;
182 			case '\f':
183 				*bufp++ = '\\';	*bufp++ = 'f';
184 				break;
185 			case '\r':
186 				*bufp++ = '\\';	*bufp++ = 'r';
187 				break;
188 			case '\'':
189 				*bufp++ = '\\';	*bufp++ = '\'';
190 				break;
191 			case  '\\':
192 				*bufp++ = '\\';
193 				*bufp++ = '\\';
194 				break;
195 			default:
196 				*bufp++ = *(bufstr-1);
197 		}
198 	}
199 	*bufp++ = '\'';
200     fwrite(buf, sizeof(char), bufp-buf, stdout);
201 }
202 
printFloat(float f,int intCast)203 static void printFloat(float f, int intCast)
204 {
205 	char s[60];
206 	char *sp, *xpn;
207 
208 	if (f != f)
209 		printf("_NANF");
210 	else if (f == (1.0f / 0.0f))
211 		printf("POSITIVE_INFINITYF");
212 	else if (f == (-1.0f / 0.0f))
213 		printf("NEGATIVE_INFINITYF");
214 	else {
215 		sprintf(s, "%#g", (double) f);
216 
217 		if ((xpn = strchr(s, 'e')) == NULL)
218 			sp = s + strlen(s) - 1;
219 		else
220 			sp = xpn - 2;
221 
222 		while (*sp == '0')
223 			--sp;
224 
225 		if (intCast == 1) {
226 			if (*sp == '.')
227 				--sp;
228 			*(sp + 1) = '\0';
229 			printf("%s", s);
230 		}
231 		else {
232 			if (*sp == '.')
233 				*++sp = '0';
234 			*++sp = '\0';
235 			printf("%s", s);
236 			if (xpn != NULL)
237 				printf("%s", xpn);
238 			putchar('f');
239 		}
240 	}
241 }
242 
243 static unsigned int bitPos;
244 static unsigned int bitBuf;
245 
InitBits(FILE * f)246 static void InitBits(FILE *f)
247 {
248 	bitPos = 8;
249 	bitBuf = ((unsigned int) fgetc(f)) & 0xff;
250 }
251 
getBits(FILE * f,unsigned int n)252 static unsigned int getBits(FILE *f, unsigned int n)
253 {
254 	unsigned long int v = 0;
255 
256 	while (n > bitPos) {
257 		n -= bitPos;
258 		v |= bitBuf << n;
259 		bitBuf = ((unsigned int) fgetc(f)) & 0xff;
260 		bitPos = 8;
261 	}
262 
263 	bitPos -= n;
264 	v |= bitBuf >> bitPos;
265 	bitBuf &= 0xff >> (8 - bitPos);
266 	/* never need more than 16 bits */
267 	return (unsigned int) v & 0xffff;
268 }
269 
printFrameNum(unsigned int frameNum)270 static void printFrameNum(unsigned int frameNum)
271 {
272 	printf("\n");
273 	printIndent(indent);
274 	printf("frame %u\n", frameNum);
275 }
276 
addLabel(unsigned long int offset)277 static void addLabel(unsigned long int offset)
278 {
279 	long int i;
280 
281 	for (i = 0; i < numLabels; ++i) {
282 		if (labels[i] == offset)
283 			return;
284 	}
285 
286 	SUREALLOC(numLabels, labels, sizeof (unsigned long int));
287 
288 	if (labels == NULL)
289 		tellUser(1, "Not enough memory to store all labels");
290 
291 	labels[numLabels++] = offset;
292 }
293 
294 static void processASMLine(char *line);
295 
includeFile(const char * ifilename)296 static void includeFile(const char *ifilename)
297 {
298 	FILE *ifile;
299 	char buf[256];
300 
301 	while (*ifilename == ' ' || *ifilename == '\t')
302 		ifilename++;
303 
304 	if ((ifile = fopen(ifilename, "rt")) == NULL)
305 		tellUser(1, "Couldn't include file: %s", ifilename);
306 
307 	printf("\n// start of %s\n", ifilename);
308 
309 	while (fgets(buf, 256, ifile))
310 		processASMLine(buf);
311 
312 	printf("\n// end of %s\n", ifilename);
313 
314 	fclose(ifile);
315 }
316 
processASMLine(char * line)317 static void processASMLine(char *line)
318 {
319 	char *ci = strIstr(line, "constants ");
320 	char *fi = strIstr(line, "#include ");
321 
322 	if ((ci == NULL) || (constend == 0) || !showLiterals) {
323 		/* line contains no 'constants' or prev constant declaration absent */
324 		/* or multiple/broken constant pools found in action block */
325 		if (fi != NULL)
326 			includeFile(fi + 9);
327 		else
328 			printf("%s", line);
329 	}
330 	else if (flasmDict == NULL) {
331 		/* start dict */
332 		flasmDict = strdup(ci + 10);
333 	}
334 	else {
335 		/* add user constants */
336 		flasmDict = realloc(flasmDict, strlen(flasmDict) + strlen(ci + 10) + 3);
337 		strcat(flasmDict, ", ");
338 		strcat(flasmDict, ci + 10);
339 	}
340 }
341 
checkLabel(unsigned long int addr)342 static void checkLabel(unsigned long int addr)
343 {
344 	if (curLabel < numLabels) {
345 		while (addr > labels[curLabel]) {
346 			printIndent(indent-1);
347 			printf(" %s%li: // Wild label in the middle of an action, now placed before next action\n", mode < MODE_UPDATE ? "label" : "lbl", ++curLabel);
348 			tellUser(0, "Branch into the middle of an action, %s%li (off by %i bytes) is placed before next action", mode < MODE_UPDATE ? "label" : "lbl", curLabel, (int)(addr - labels[curLabel-1]));
349 		}
350 		if (addr == labels[curLabel]) {
351 			printIndent(indent-1);
352 			/* make sure generated labels don't match user labels */
353 			printf(" %s%li:\n", mode < MODE_UPDATE ? "label" : "lbl", ++curLabel);
354 		}
355 	}
356 }
357 
358 static byte *buffer;
359 
360 static void printActionRecord(byte *p, Action type, unsigned int *lenptr, char **regtable);
361 
printActions(byte * p,unsigned long int length,unsigned long int maxActions,char ** regtable)362 static unsigned long int printActions(byte *p, unsigned long int length, unsigned long int maxActions, char **regtable)
363 {
364 	/*
365 	   processes also nested blocks like 'function', 'with', and 'ifFrameLoaded'
366 	   stops at given length (in bytes) or after given numActions
367 	   give ANY_VALUE as parameter, if one of them is unused
368 	 */
369 	unsigned long int i = 0;
370 	unsigned long int curAction = 0;
371 	unsigned int blocklen;
372 
373 	while ((i < length) && (curAction < maxActions)) {
374 		Action type = (Action) p[i];
375 
376 		checkLabel(p + i - buffer);
377 		swfrelpos = p + i - buffer;
378 
379 		++i;
380 
381 		if ((type & 0x80) != 0) {
382 			blocklen = S16(p + i);
383 			i += 2;
384 		}
385 		else
386 			blocklen = 0;
387 
388 		if (i+blocklen <= length)
389 			printActionRecord(p + i, type, &blocklen, regtable);
390 		else {
391 			tellUser(0, "Disassembly may be incomplete: wrong action length encountered");
392 			return length;
393 		}
394 
395 		i += blocklen;
396 		curAction++;
397 	}
398 
399 	checkLabel(p + i - buffer);
400 
401 	return i;
402 }
403 
printActionRecord(byte * p,Action type,unsigned int * lenptr,char ** regtable)404 static void printActionRecord(byte *p, Action type, unsigned int *lenptr, char **regtable)
405 {
406 	unsigned int len = *lenptr;
407 
408 	switch (type) {
409 		case SWFACTION_ADD:
410 			print("oldAdd\n");
411 			break;
412 		case SWFACTION_SUBTRACT:
413 			print("subtract\n");
414 			break;
415 		case SWFACTION_MULTIPLY:
416 			print("multiply\n");
417 			break;
418 		case SWFACTION_DIVIDE:
419 			print("divide\n");
420 			break;
421 		case SWFACTION_EQUALS:
422 			print("oldEquals\n");
423 			break;
424 		case SWFACTION_LESSTHAN:
425 			print("oldLessThan\n");
426 			break;
427 		case SWFACTION_LOGICALAND:
428 			print("and\n");
429 			break;
430 		case SWFACTION_LOGICALOR:
431 			print("or\n");
432 			break;
433 		case SWFACTION_LOGICALNOT:
434 			print("not\n");
435 			break;
436 		case SWFACTION_STRINGEQ:
437 			print("stringEq\n");
438 			break;
439 		case SWFACTION_STRINGLENGTH:
440 			print("stringLength\n");
441 			break;
442 		case SWFACTION_SUBSTRING:
443 			print("substring\n");
444 			break;
445 		case SWFACTION_INT:
446 			print("int\n");
447 			break;
448 		case SWFACTION_POP:
449 			print("pop\n");
450 			break;
451 		case SWFACTION_SWAP:
452 			print("swap\n");
453 			break;
454 		case SWFACTION_INITOBJECT:
455 			print("initObject\n");
456 			break;
457 		case SWFACTION_INITARRAY:
458 			print("initArray\n");
459 			break;
460 		case SWFACTION_GETVARIABLE:
461 			print("getVariable\n");
462 			break;
463 		case SWFACTION_SETVARIABLE:
464 			print("setVariable\n");
465 			break;
466 		case SWFACTION_STRINGCONCAT:
467 			print("concat\n");
468 			break;
469 		case SWFACTION_GETPROPERTY:
470 			print("getProperty\n");
471 			break;
472 		case SWFACTION_SETPROPERTY:
473 			print("setProperty\n");
474 			break;
475 		case SWFACTION_DUPLICATECLIP:
476 			print("duplicateClip\n");
477 			break;
478 		case SWFACTION_REMOVECLIP:
479 			print("removeClip\n");
480 			break;
481 		case SWFACTION_TRACE:
482 			print("trace\n");
483 			break;
484 		case SWFACTION_STARTDRAGMOVIE:
485 			print("startDrag\n");
486 			break;
487 		case SWFACTION_STOPDRAGMOVIE:
488 			print("stopDrag\n");
489 			break;
490 		case SWFACTION_STRINGLESSTHAN:
491 			print("stringLessThan\n");
492 			break;
493 		case SWFACTION_STRINGGREATERTHAN:
494 			print("stringGreaterThan\n");
495 			break;
496 		case SWFACTION_RANDOM:
497 			print("random\n");
498 			break;
499 		case SWFACTION_MBLENGTH:
500 			print("mbLength\n");
501 			break;
502 		case SWFACTION_ORD:
503 			print("ord\n");
504 			break;
505 		case SWFACTION_CHR:
506 			print("chr\n");
507 			break;
508 		case SWFACTION_GETTIMER:
509 			print("getTimer\n");
510 			break;
511 		case SWFACTION_MBSUBSTRING:
512 			print("mbSubstring\n");
513 			break;
514 		case SWFACTION_MBORD:
515 			print("mbOrd\n");
516 			break;
517 		case SWFACTION_MBCHR:
518 			print("mbChr\n");
519 			break;
520 		case SWFACTION_NEXTFRAME:
521 			print("nextFrame\n");
522 			break;
523 		case SWFACTION_PREVFRAME:
524 			print("prevFrame\n");
525 			break;
526 		case SWFACTION_PLAY:
527 			print("play\n");
528 			break;
529 		case SWFACTION_STOP:
530 			print("stop\n");
531 			break;
532 		case SWFACTION_TOGGLEQUALITY:
533 			print("toggleQuality\n");
534 			break;
535 		case SWFACTION_STOPSOUNDS:
536 			print("stopSounds\n");
537 			break;
538 
539 			/* ops with args */
540 		case SWFACTION_PUSHDATA:
541 			{
542 				byte pushtype;
543 				byte *start = p;
544 				long int pushstart;
545 				int n = 0;
546 
547 				/* may need to go back and erase push while processing flasm macros */
548 				pushstart = ftell(stdout);
549 
550 				print("push ");
551 
552 				while (p < start + len) {
553 					switch (pushtype = *p++) {
554 						case 0:														 /* string */
555 							{
556 								char *d = (char *) p;
557 
558 								if (mode >= MODE_UPDATE && (Action) start[len] == SWFACTION_POP) {
559 									fseek(stdout, pushstart, SEEK_SET);				 /* go back to overwrite 'push'            */
560 									processASMLine(d);
561 									p = start + len;								 /* skip to the end of push statement      */
562 									*lenptr += 1;
563 								}
564 								else {
565 									printf("%s", n++ > 0 ? ", " : "");
566 									printstr(d);
567 									p += strlen(d) + 1;
568 								}
569 								break;
570 							}
571 
572 						case 1:														 /* float, used by flash for properties only */
573 							{
574 								float f;
575 								double prop;
576 
577 								if (byteorder == FLASM_BIG_ENDIAN) {
578 									byte *fp = (byte *) (&f);
579 
580 									fp[0] = p[3];
581 									fp[1] = p[2];
582 									fp[2] = p[1];
583 									fp[3] = p[0];
584 								}
585 								else
586 									f = *(float *) p;
587 
588 								printf("%s", (n++ > 0) ? ", " : "");
589 
590 								if (modf((double) f, &prop) == 0) {						 /* integer, most likely property */
591 									switch ((int) prop) {
592 										case 0:
593 											printf("X_PROPERTY");
594 											break;
595 										case 1:
596 											printf("Y_PROPERTY");
597 											break;
598 										case 2:
599 											printf("XSCALE_PROPERTY");
600 											break;
601 										case 3:
602 											printf("YSCALE_PROPERTY");
603 											break;
604 										case 4:
605 											printf("CURRENTFRAME_PROPERTY");
606 											break;
607 										case 5:
608 											printf("TOTALFRAMES_PROPERTY");
609 											break;
610 										case 6:
611 											printf("ALPHA_PROPERTY");
612 											break;
613 										case 7:
614 											printf("VISIBLE_PROPERTY");
615 											break;
616 										case 8:
617 											printf("WIDTH_PROPERTY");
618 											break;
619 										case 9:
620 											printf("HEIGHT_PROPERTY");
621 											break;
622 										case 10:
623 											printf("ROTATION_PROPERTY");
624 											break;
625 										case 11:
626 											printf("TARGET_PROPERTY");
627 											break;
628 										case 12:
629 											printf("FRAMESLOADED_PROPERTY");
630 											break;
631 										case 13:
632 											printf("NAME_PROPERTY");
633 											break;
634 										case 14:
635 											printf("DROPTARGET_PROPERTY");
636 											break;
637 										case 15:
638 											printf("URL_PROPERTY");
639 											break;
640 										case 16:
641 											printf("HIGHQUALITY_PROPERTY");
642 											break;
643 										case 17:
644 											printf("FOCUSRECT_PROPERTY");
645 											break;
646 										case 18:
647 											printf("SOUNDBUFTIME_PROPERTY");
648 											break;
649 										case 19:
650 											printf("QUALITY_PROPERTY");
651 											break;
652 										case 20:
653 											printf("XMOUSE_PROPERTY");
654 											break;
655 										case 21:
656 											printf("YMOUSE_PROPERTY");
657 											break;
658 										default:
659 											printFloat(f, 0);
660 									}
661 								}
662 								else
663 									printFloat(f, 0);
664 
665 								p += 4;
666 								break;
667 							}
668 
669 						case 2:
670 							/* null */
671 							printf("%sNULL", (n++ > 0) ? ", " : "");
672 							break;
673 
674 						case 3:
675 							/* undefined */
676 							printf("%sUNDEF", (n++ > 0) ? ", " : "");
677 							break;
678 
679 						case 4:
680 							/* register */
681 							if (n++ > 0)
682 								printf(", ");
683 							if (literalregisters && regtable != NULL && regtable[*p] != NULL && *regtable[*p] != '\0') {
684 								if (goodID(regtable[*p]))
685 									printf("r:%s", regtable[*p]);
686 								else
687 									printf("r:'%s'", regtable[*p]);
688 							}
689 							else {
690 								printf("r:%i", *p);
691 							}
692 							p++;
693 							break;
694 
695 						case 5:
696 							/* boolean */
697 							if (*p++)
698 								printf("%sTRUE", (n++ > 0) ? ", " : "");
699 							else
700 								printf("%sFALSE", (n++ > 0) ? ", " : "");
701 							break;
702 
703 						case 6:
704 							/* double */
705 							{
706 								double d;
707 								byte *dp = (byte *) (&d);
708 								char s[100];
709 								char *sp, *xpn;
710 
711 								if (byteorder == FLASM_BIG_ENDIAN) {
712 									dp[0] = p[3];
713 									dp[1] = p[2];
714 									dp[2] = p[1];
715 									dp[3] = p[0];
716 									dp[4] = p[7];
717 									dp[5] = p[6];
718 									dp[6] = p[5];
719 									dp[7] = p[4];
720 								}
721 								else {
722 									dp[0] = p[4];
723 									dp[1] = p[5];
724 									dp[2] = p[6];
725 									dp[3] = p[7];
726 									dp[4] = p[0];
727 									dp[5] = p[1];
728 									dp[6] = p[2];
729 									dp[7] = p[3];
730 								}
731 
732 								/* the old way without '1.5e-24'-like notation
733 								   fprec = 15-floor(log10(fabs(d)));
734 								   sprintf(s,"%.*f",fprec,d); */
735 
736 								printf("%s", (n++ > 0) ? ", " : "");
737 
738 								if (d == 0) {
739 									if (mode < MODE_UPDATE)
740 										printf("0.0");
741 									else
742 										printf("0");									 /* save some bytes in update mode - integer instead of double */
743 								}
744 								else if (d != d)
745 									printf("_NAN");
746 								else if (d == (1.0 / 0.0))
747 									printf("POSITIVE_INFINITY");
748 								else if (d == (-1.0 / 0.0))
749 									printf("NEGATIVE_INFINITY");
750 								else {
751 									sprintf(s, "%#.*g", 16, d);
752 
753 									if ((xpn = strchr(s, 'e')) == NULL)
754 										sp = s + strlen(s) - 1;
755 									else
756 										sp = xpn - 2;									 /* one digit less precision for exp form values
757 																						    preventing MAX_NUMBER rounding to INFINITY */
758 
759 									while (*sp == '0')									 /* delete 0's at the end of the number or mantissa */
760 										--sp;
761 
762 									if (*sp == '.')										 /* expand values like "1." to "1.0" */
763 										*++sp = '0';
764 
765 									*++sp = '\0';										 /* terminate buffer (exponent is cutted off) */
766 
767 									printf("%s", s);
768 
769 									if (xpn != NULL)									 /* if exponent here, print it */
770 										printf("%s", xpn);
771 								}
772 
773 								p += 8;
774 								break;
775 							}
776 
777 						case 7:
778 							/* integer */
779 							{
780 								int i;
781 
782 								if (byteorder == FLASM_BIG_ENDIAN) {
783 									byte *ip = (byte *) (&i);
784 
785 									ip[0] = p[3];
786 									ip[1] = p[2];
787 									ip[2] = p[1];
788 									ip[3] = p[0];
789 								}
790 								else
791 									i = *(int *) p;
792 
793 								printf("%s%i", (n++ > 0) ? ", " : "", i);
794 								p += 4;
795 								break;
796 							}
797 
798 						case 8:
799 							/* dictionary, 1-byte reference */
800 							{
801 								char *d;
802 								if (showLiterals && (*p < nDict)) {
803 									d = dictionary[*p].value;
804 									if (mode >= MODE_UPDATE && (Action) start[len] == SWFACTION_POP) {
805 										fseek(stdout, pushstart, SEEK_SET);			 /* go back to overwrite 'push'            */
806 										processASMLine(d);
807 										p = start + len;							 /* skip to the end of push statement      */
808 										*lenptr += 1;
809 									}
810 									else {
811 										printf("%s", n++ > 0 ? ", " : "");
812 										printstr(d);
813 										dictionary[*p].count++;						  /* constant used one more time */
814 										p++;
815 									}
816 								}
817 								else {
818 									printf("%sc:%u", n++ > 0 ? ", " : "", *p);
819 									p++;
820 								}
821 								break;
822 							}
823 
824 						case 9:
825 							/* dictionary, 2-byte reference */
826 							{
827 								char *d;
828 								if (showLiterals && (S16(p) < nDict)) {
829 									d = dictionary[S16(p)].value;
830 									if (mode >= MODE_UPDATE && (Action) start[len] == SWFACTION_POP) {
831 										fseek(stdout, pushstart, SEEK_SET);			 /* go back to overwrite 'push'            */
832 										processASMLine(d);
833 										p = start + len;							 /* skip to the end of push statement      */
834 										*lenptr += 1;
835 									}
836 									else {
837 										printf("%s", n++ > 0 ? ", " : "");
838 										printstr(d);
839 										dictionary[S16(p)].count++;					  /* constant used one more time */
840 										p += 2;
841 									}
842 								}
843 								else {
844 									printf("%sc:%u", n++ > 0 ? ", " : "", S16(p));
845 									p += 2;
846 								}
847 								break;
848 							}
849 
850 						default:
851 							printf("%s%s // unknown push type %i: rest of push skipped", (n++ > 0) ? ", " : "", "???", pushtype);
852 							tellUser(0, "Unknown push type %i: rest of push skipped", pushtype);
853 							p = start + len;
854 					}
855 				}
856 
857 				putchar('\n');
858 
859 				break;
860 			}
861 
862 		case SWFACTION_GOTOFRAME:
863 			print("gotoFrame %u\n", S16(p));
864 			p += 2;
865 			break;
866 
867 		case SWFACTION_GETURL:
868 		{
869 			char *url = (char *) p;
870 			p += strlen(url) + 1;
871 			print("getURL ");
872 			printstr(url);
873 			putchar(' ');
874 			printstr((char *) p);
875 			putchar('\n');
876 			break;
877 		}
878 
879 		case SWFACTION_BRANCHALWAYS:
880 		{
881 			long int l = longintBinaryFind((unsigned long int)(p + 2 + S16signed(p) - buffer), labels, numLabels);
882 			if (l >= 0) {
883 				print("branch %s%i", mode < MODE_UPDATE ? "label" : "lbl", l + 1, labels);
884 				if (showoffset == 0)
885 					putchar('\n');
886 				else
887 					printf(" // offset %i\n", S16signed(p));
888 			}
889 			else {
890 				print("branch %i // branch target not found\n", S16signed(p));
891 				tellUser(0, "branch target not found: %li", S16signed(p));
892 			}
893 			break;
894 		}
895 
896 		case SWFACTION_BRANCHIFTRUE:
897 		{
898 			long int l = longintBinaryFind((unsigned long int)(p + 2 + S16signed(p) - buffer), labels, numLabels);
899 			if (l >= 0) {
900 				print("branchIfTrue %s%i", mode < MODE_UPDATE ? "label" : "lbl", l + 1, labels);
901 				if (showoffset == 0)
902 					putchar('\n');
903 				else
904 					printf(" // offset %i\n", S16signed(p));
905 			}
906 			else {
907 				print("branchIfTrue %i // branch target not found\n", S16signed(p));
908 				tellUser(0, "branchIfTrue target not found: %li", S16signed(p));
909 			}
910 			break;
911 		}
912 
913 		case SWFACTION_GETURL2:
914 			{
915 				byte flags = *p;
916 				switch (flags) {
917 					case 0:
918 						print("getURL2\n");
919 						break;
920 					case 1:
921 						print("getURL2 GET\n");
922 						break;
923 					case 2:
924 						print("getURL2 POST\n");
925 						break;
926 					case 0x40:
927 						print("loadMovie\n");
928 						break;
929 					case 0x41:
930 						print("loadMovie GET\n");
931 						break;
932 					case 0x42:
933 						print("loadMovie POST\n");
934 						break;
935 					case 0x80:
936 						print("loadVariablesNum\n");
937 						break;
938 					case 0x81:
939 						print("loadVariablesNum GET\n");
940 						break;
941 					case 0x82:
942 						print("loadVariablesNum POST\n");
943 						break;
944 					case 0xC0:
945 						print("loadVariables\n");
946 						break;
947 					case 0xC1:
948 						print("loadVariables GET\n");
949 						break;
950 					case 0xC2:
951 						print("loadVariables POST\n");
952 						break;
953 					default:
954 						print("getURL2 0x%x // unknown flag\n", flags);
955 						tellUser(0, "Unknown getURL2 flag: 0x%x");
956 				}
957 
958 				break;
959 			}
960 
961 		case SWFACTION_CALLFRAME:
962 			print("callFrame\n");
963 			break;
964 
965 		case SWFACTION_GOTOEXPRESSION:
966 			print("goto");
967 			if (*p == 0)
968 				puts("AndStop");
969 			else if (*p == 1)
970 				puts("AndPlay");
971 			else if ((*p == 2) && (len == 3)) {
972 				/* undocumented additional argument - the number of frames in all previous scenes */
973 				p++;
974 				printf("AndStop skip %u\n", S16(p));
975 			}
976 			else if ((*p == 3) && (len == 3)) {
977 				/* undocumented additional argument - the number of frames in all previous scenes */
978 				p++;
979 				printf("AndPlay skip %u\n", S16(p));
980 			}
981 			else {
982 				/* what the hell is it? assume andPlay, since flag>1 */
983 				printf("AndPlay // unknown goto flag %i\n", *p);
984 				tellUser(0, "Unknown goto flag %i", *p);
985 			}
986 			break;
987 
988 		case SWFACTION_IFFRAMELOADED:
989 			{
990 				unsigned int frame = S16(p);
991 				byte frameLoadedActions;
992 				p += 2;
993 				print("ifFrameLoaded %u\n", frame);
994 				++indent;
995 				frameLoadedActions = *p++;
996 				*lenptr += printActions(p, ANY_VALUE, (unsigned long int) frameLoadedActions, regtable);
997 				--indent;
998 				print("end // of ifFrameLoaded %u\n\n", frame);
999 				break;
1000 			}
1001 
1002 		case SWFACTION_IFFRAMELOADEDEXPRESSION:
1003 			{
1004 				byte frameLoadedActions;
1005 				print("ifFrameLoadedExpr\n");
1006 				++indent;
1007 				frameLoadedActions = *p++;
1008 				*lenptr += printActions(p, ANY_VALUE, (unsigned long int) frameLoadedActions, regtable);
1009 				--indent;
1010 				print("end // of ifFrameLoadedExpr\n\n");
1011 				break;
1012 			}
1013 
1014 		case SWFACTION_SETTARGET:
1015 			print("setTarget '%s'\n", p);
1016 			break;
1017 
1018 		case SWFACTION_SETTARGETEXPRESSION:
1019 			print("setTargetExpr\n");
1020 			break;
1021 
1022 		case SWFACTION_GOTOLABEL:
1023 			print("gotoLabel '%s'\n", p);
1024 			break;
1025 
1026 		case SWFACTION_END:
1027 			break;
1028 
1029 			/* f5 ops */
1030 		case SWFACTION_DELETE:
1031 			print("delete\n");
1032 			break;
1033 		case SWFACTION_DELETE2:
1034 			print("delete2\n");
1035 			break;
1036 		case SWFACTION_VAR:
1037 			print("var\n");
1038 			break;
1039 		case SWFACTION_VAREQUALS:
1040 			print("varEquals\n");
1041 			break;
1042 		case SWFACTION_CALLFUNCTION:
1043 			print("callFunction\n");
1044 			break;
1045 		case SWFACTION_RETURN:
1046 			print("return\n");
1047 			break;
1048 		case SWFACTION_MODULO:
1049 			print("modulo\n");
1050 			break;
1051 		case SWFACTION_NEW:
1052 			print("new\n");
1053 			break;
1054 		case SWFACTION_TYPEOF:
1055 			print("typeof\n");
1056 			break;
1057 		case SWFACTION_TARGETPATH:
1058 			print("targetPath\n");
1059 			break;
1060 		case SWFACTION_NEWADD:
1061 			print("add\n");
1062 			break;
1063 		case SWFACTION_NEWLESSTHAN:
1064 			print("lessThan\n");
1065 			break;
1066 		case SWFACTION_NEWEQUALS:
1067 			print("equals\n");
1068 			break;
1069 		case SWFACTION_TONUMBER:
1070 			print("toNumber\n");
1071 			break;
1072 		case SWFACTION_TOSTRING:
1073 			print("toString\n");
1074 			break;
1075 		case SWFACTION_DUP:
1076 			print("dup\n");
1077 			break;
1078 		case SWFACTION_GETMEMBER:
1079 			print("getMember\n");
1080 			break;
1081 		case SWFACTION_SETMEMBER:
1082 			print("setMember\n");
1083 			break;
1084 		case SWFACTION_INCREMENT:
1085 			print("increment\n");
1086 			break;
1087 		case SWFACTION_DECREMENT:
1088 			print("decrement\n");
1089 			break;
1090 		case SWFACTION_NEWMETHOD:
1091 			print("newMethod\n");
1092 			break;
1093 		case SWFACTION_CALLMETHOD:
1094 			print("callMethod\n");
1095 			break;
1096 		case SWFACTION_BITWISEAND:
1097 			print("bitwiseAnd\n");
1098 			break;
1099 		case SWFACTION_BITWISEOR:
1100 			print("bitwiseOr\n");
1101 			break;
1102 		case SWFACTION_BITWISEXOR:
1103 			print("bitwiseXor\n");
1104 			break;
1105 		case SWFACTION_SHIFTLEFT:
1106 			print("shiftLeft\n");
1107 			break;
1108 		case SWFACTION_SHIFTRIGHT:
1109 			print("shiftRight\n");
1110 			break;
1111 		case SWFACTION_SHIFTRIGHT2:
1112 			print("shiftRight2\n");
1113 			break;
1114 
1115 		case SWFACTION_CONSTANTPOOL:
1116 			{
1117 				unsigned int i, n = S16(p);
1118 				int willInclude = 0;
1119 				unsigned int constlen = 2;
1120 
1121 				if (n > MAX_CONSTANTS)
1122 					tellUser(0, "Too many constants");
1123 
1124 				p += 2;
1125 				conststart = ftell(stdout);
1126 				print("constants ");
1127 
1128 				nDict = 0;
1129 
1130 				for (i = 0; i < n; ++i) {
1131 					if (strnIcmp((char *) p, "#include", 8) == 0)
1132 						willInclude = 1;
1133 
1134 					dictionary[i].value = (char *) p;
1135 					dictionary[i].count = 0;
1136 					nDict++;
1137 
1138 					printstr((char *) p);
1139 					if (i < n - 1)
1140 						printf("%s", ", ");
1141 					else
1142 						printf("%s", "  ");
1143 
1144 					constlen += strlen((char *) p) + 1;
1145 					p += strlen((char *) p) + 1;
1146 				}
1147 
1148 				if (constlen != len) {
1149 					tellUser(0, "Declared constant pool length %u differs from calculated length %u", len, constlen);
1150 					/* try to restore the real constant pool length */
1151 					*lenptr = 0xff & constlen;
1152 					*(lenptr+1) = 0xff & (constlen >> 8);
1153 				}
1154 
1155 				printf("%s", "\n");
1156 
1157 				/* put some free space after constant pool to add user constants from included file later */
1158 				if (mode >= MODE_UPDATE && willInclude == 1)
1159 					for (i = 0; i < MAX_INCLUDE_POOL; ++i)
1160 						putchar(' ');
1161 
1162 				constend = ftell(stdout);
1163 
1164 				break;
1165 			}
1166 
1167 		case SWFACTION_WITH:
1168 			{
1169 				unsigned int withlen = S16(p);
1170 
1171 				print("with\n");
1172 
1173 				++indent;
1174 				printActions(p + 2, (unsigned long int) withlen, ANY_VALUE, regtable);
1175 				--indent;
1176 
1177 				*lenptr += withlen;
1178 
1179 				print("end\n");
1180 
1181 				break;
1182 			}
1183 
1184 		case SWFACTION_DEFINEFUNCTION:
1185 			{
1186 				int nargs;
1187 				unsigned int funclen;
1188 				char *name = (char *) p;
1189 				char *argname;
1190 
1191 				p += strlen(name) + 1;
1192 				nargs = S16(p);
1193 				p += 2;
1194 
1195 				if (*name != '\0') {
1196 					if (mode < MODE_UPDATE && goodID(name))
1197 						print("function %s (", name);
1198 					else
1199 						print("function '%s' (", name);
1200 				}
1201 				else
1202 					print("function (");
1203 
1204 				if (nargs > 0) {
1205 					argname = (char *) p;
1206 					printf("'%s'", argname);
1207 					p += strlen(argname) + 1;
1208 					--nargs;
1209 				}
1210 
1211 				for (; nargs > 0; --nargs) {
1212 					argname = (char *) p;
1213 					printf(", '%s'", argname);
1214 					p += strlen(argname) + 1;
1215 				}
1216 
1217 				putchar(')');
1218 				putchar('\n');
1219 
1220 				funclen = S16(p);
1221 				p += 2;
1222 
1223 				++indent;
1224 				printActions(p, (unsigned long int) funclen, ANY_VALUE, NULL);
1225 				--indent;
1226 
1227 				print("end // of function %s\n\n", name);
1228 
1229 				*lenptr += funclen;
1230 
1231 				break;
1232 			}
1233 
1234 		case SWFACTION_ENUMERATE:
1235 			print("enumerate\n");
1236 			break;
1237 
1238 		case SWFACTION_SETREGISTER:
1239 			if (literalregisters && regtable != NULL && regtable[*p] != NULL && *regtable[*p] != '\0') {
1240 				if (goodID(regtable[*p]))
1241 					print("setRegister r:%s\n", regtable[*p]);
1242 				else
1243 					print("setRegister r:'%s'\n", regtable[*p]);
1244 			}
1245 			else
1246 				print("setRegister r:%i\n", *p);
1247 			break;
1248 
1249 		case SWFACTION_STRICTEQUALS:
1250 			print("strictEquals\n");
1251 			break;
1252 
1253 		case SWFACTION_GREATERTHAN:
1254 			print("greaterThan\n");
1255 			break;
1256 
1257 		case SWFACTION_ENUMERATEVALUE:
1258 			print("enumerateValue\n");
1259 			break;
1260 
1261 		case SWFACTION_INSTANCEOF:
1262 			print("instanceOf\n");
1263 			break;
1264 
1265 		case SWFACTION_STRICTMODE:
1266 			print("strictMode");
1267 			if (*p > 0)
1268 				puts(" ON");
1269 			else
1270 				puts(" OFF");
1271 			break;
1272 
1273 		case SWFACTION_DEFINEFUNCTION2:
1274 			{
1275 				unsigned int i, funclen, nargs, autoregFlags;
1276 				int firstprint = 1;
1277 				byte nregisters, curautoreg;
1278 				char *argnames[MAX_REGISTERS];
1279 				char *name = (char *) p;
1280 				memset(argnames, 0, MAX_REGISTERS * sizeof (char *));
1281 
1282 				p += strlen(name) + 1;
1283 				nargs = S16(p);
1284 				p += 2;
1285 				nregisters = *p++;
1286 				autoregFlags = S16(p);
1287 				p += 2;
1288 
1289 				if (*name != '\0') {
1290 					if (mode < MODE_UPDATE && goodID(name))
1291 						print("function2 %s (", name);
1292 					else
1293 						print("function2 '%s' (", name);
1294 				}
1295 				else
1296 					print("function2 (");
1297 
1298 				/* print function arguments, store links to their names in register allocation table */
1299 				for (; nargs > 0; nargs--) {
1300 					byte reg = *p;
1301 					char *arg = (char *)(p+1);
1302 
1303 					if (reg != 0) {
1304 						if (argnames[reg] != NULL) {
1305 							tellUser (0, "Duplicate register allocation in function2 %s: %s and %s both go to r:%u", name, argnames[reg], arg, reg);
1306 						}
1307 						argnames[reg] = arg;
1308 						printf("r:%u='%s'%s", reg, arg, nargs == 1 ? "" : ", ");
1309 					}
1310 					else
1311 						printf("'%s'%s", arg, nargs == 1 ? "" : ", ");
1312 
1313 					p += strlen(arg) + 2;
1314 				}
1315 
1316 				printf("%s", ") (");
1317 
1318 				/* allocate registers for "automatic" names based on flags, skip suppressed parameters */
1319 				curautoreg = 1;
1320 
1321 				for (i = 0; i < MAX_AUTO_REGS; i++) {
1322 					if ((autoregFlags & arPreFlags[i]) == arPreFlags[i]) {
1323 						/* preload flag */
1324 
1325 						if (argnames[curautoreg] != NULL && strcmp(argnames[curautoreg], arNames[i]))
1326 							tellUser (0, "Duplicate register allocation in function2 %s: %s and %s both go to r:%u", name, argnames[curautoreg], arNames[i], curautoreg);
1327 						if (autoregFlags & arSupFlags[i])
1328 							tellUser (0, "Preload and suppress flags are both set for %s parameter of function2 %s", arNames[i], name);
1329 
1330 						argnames[curautoreg] = arNames[i];
1331 						autoregFlags -= arPreFlags[i];
1332 						printf("%sr:%u='%s'", firstprint == 0 ? ", " : "", curautoreg, arNames[i]);
1333 						firstprint = 0;
1334 						curautoreg++;
1335 					}
1336 					else if ((autoregFlags & arSupFlags[i]) == arSupFlags[i]) {
1337 						/* suppress flag */
1338 						autoregFlags -= arSupFlags[i];
1339 					}
1340 					else {
1341 						/* the parameter is neither preloaded nor suppressed */
1342 						printf("%s'%s'", firstprint == 0 ? ", " : "", arNames[i]);
1343 						firstprint = 0;
1344 					}
1345 				}
1346 
1347 				printf("%s", ")\n");
1348 
1349 				if (autoregFlags != 0)
1350 					tellUser(0,"Unknown register flag for function2 %s: %u", name, autoregFlags);
1351 
1352 				funclen = S16(p);
1353 				p += 2;
1354 
1355 				++indent;
1356 				printActions(p, (unsigned long int) funclen, ANY_VALUE, argnames);
1357 				--indent;
1358 
1359 				print("end // of function %s\n\n", name);
1360 
1361 				*lenptr += funclen;
1362 
1363 				break;
1364 			}
1365 
1366 		case SWFACTION_THROW:
1367 			print("throw\n");
1368 			break;
1369 
1370 		case SWFACTION_EXTENDS:
1371 			print("extends\n");
1372 			break;
1373 
1374 		case SWFACTION_IMPLEMENTS:
1375 			print("implements\n");
1376 			break;
1377 
1378 		case SWFACTION_CAST:
1379 			print("cast\n");
1380 			break;
1381 
1382 		case SWFACTION_FSCOMMAND2:
1383 			print("FSCommand2\n");
1384 			break;
1385 
1386 		case SWFACTION_TRY:
1387 			{
1388 				unsigned int trylen, catchlen, finallylen;
1389 				/* try type */
1390 				byte catchtype = *p++;
1391 				trylen = S16(p);
1392 				p += 2;
1393 				catchlen = S16(p);
1394 				p += 2;
1395 				finallylen = S16(p);
1396 				p += 2;
1397 
1398 				if (catchtype & 4) {
1399 					/* error in register */
1400 					if (literalregisters && regtable != NULL && regtable[*p] != NULL && *regtable[*p] != '\0')
1401 						print("try r:%s\n", regtable[*p++]);
1402 					else
1403 						print("try r:%u\n", *p++);
1404 				}
1405 				else {
1406 					/* error in variable */
1407 					print("try");
1408 					if (*p != '\0')
1409 						printf(" '%s'", (char *) p);
1410 					putchar('\n');
1411 					p += len-7;
1412 				}
1413 
1414 				++indent;
1415 				printActions(p, (unsigned long int) trylen, ANY_VALUE, regtable);
1416 				--indent;
1417 
1418 				if (catchlen > 0) {
1419 					print("catch\n");
1420 					++indent;
1421 					printActions(p+trylen, (unsigned long int) catchlen, ANY_VALUE, regtable);
1422 					--indent;
1423 				}
1424 				if (finallylen > 0) {
1425 					print("finally\n");
1426 					++indent;
1427 					printActions(p+trylen+catchlen, (unsigned long int) finallylen, ANY_VALUE, regtable);
1428 					--indent;
1429 				}
1430 
1431 				*lenptr += trylen+catchlen+finallylen;
1432 				print("end // of try\n");
1433 				break;
1434 			}
1435 
1436 		default:
1437 			print("swfAction 0x%02x", type);
1438 			if (len > 0) {
1439 				unsigned int i;
1440 				printf("%s", " hexdata ");
1441 				for (i = 0; i < len; ++i) {
1442 					printf("0x%02X", *p);
1443 					if (i < len - 1)
1444 						printf("%s", ",");
1445 					p++;
1446 				}
1447 			}
1448 			printf("%s", " // unknown action\n");
1449 			tellUser(0, "Unknown action 0x%02x", type);
1450 	}
1451 	return;
1452 }
1453 
rebuildConstantPool(void)1454 static void rebuildConstantPool(void)
1455 {
1456 	long int curpos = ftell(stdout);
1457 	unsigned long int k;
1458 	int i;
1459 	int constOK = 0;
1460 
1461 	fseek(stdout, conststart, SEEK_SET);												 /* go back to the last constants declaration */
1462 
1463 	for (i = 0; i < nDict; ++i) {
1464 		/* remove constants used less than 2 times, and empty strings */
1465 		if ((dictionary[i].count > 1) && (strlen(dictionary[i].value) > 0)) {
1466 			if (constOK == 0) {
1467 				print("constants ");
1468 				constOK = 1;
1469 			}
1470 
1471 			printstr(dictionary[i].value);
1472 			printf("%s", ", ");
1473 		}
1474 	}
1475 
1476 	if (flasmDict != NULL) {
1477 		if (constOK == 0) {
1478 			print("constants ");
1479 			constOK = 1;
1480 		}
1481 		if (ftell(stdout) + strlen(flasmDict) >= constend)
1482 			tellUser(0, "Too many user constants: %s", flasmDict);
1483 		else
1484 			printf("%s", flasmDict);													 /* add user constants */
1485 	}
1486 	else if (constOK == 1)
1487 		fseek(stdout, -2, SEEK_CUR);													 /* remove last ", " */
1488 
1489 	putchar('\n');
1490 
1491 	for (k = ftell(stdout); k < constend - 1; ++k)										 /* fill the rest of former constants with spaces */
1492 		putchar(' ');
1493 
1494 	putchar('\n');
1495 
1496 	if (flasmDict != NULL) {
1497 		free(flasmDict);
1498 		flasmDict = NULL;
1499 	}
1500 	fseek(stdout, curpos, SEEK_SET);
1501 }
1502 
readActionBuffer(FILE * f,unsigned long int length)1503 static void readActionBuffer(FILE *f, unsigned long int length)
1504 {
1505 	if (length == 0)
1506 		return;
1507 
1508 	buffer = malloc(length);
1509 	if (buffer == NULL)
1510 		tellUser(1, "Not enough memory to process action block");
1511 
1512 	if (fread(buffer, 1, length, f) != length)
1513 		tellUser(1, "Attempt to read beyond EOF");
1514 }
1515 
createLabels(unsigned long int length)1516 static void createLabels(unsigned long int length)
1517 {
1518 	unsigned long int i;
1519 	unsigned int blocklen;
1520 	unsigned int numpools = 0;
1521 
1522 	numLabels = 0;
1523 	curLabel = 0;
1524 	for (i = 0; i < length; ++i) {
1525 		if (buffer[i] & 0x80) {
1526 			blocklen = S16(buffer + i + 1);
1527 
1528 			if ((Action) buffer[i] == SWFACTION_BRANCHALWAYS || (Action) buffer[i] == SWFACTION_BRANCHIFTRUE) {
1529 				if ((signed long int) (i + 3 + blocklen + S16signed(buffer + i + 3)) >= 0) {
1530 					addLabel(i + 3 + blocklen + S16signed(buffer + i + 3));
1531 				}
1532 			}
1533 			else if ((Action) buffer[i] == SWFACTION_CONSTANTPOOL) {
1534 				byte *p = buffer + i + 3;
1535 				unsigned int n, nStrings = S16(p);
1536 				numpools++;
1537 				p += 2;
1538 				for (n = 0; n < nStrings; ++n)
1539 					p += strlen((char *) p) + 1;
1540 
1541 				if (blocklen != p - buffer - i - 3) {
1542 					/* fix broken length */
1543 					blocklen = p - buffer - i - 3;
1544 				}
1545 			}
1546 
1547 			i += blocklen + 2;
1548 		}
1549 	}
1550 	if ((numpools > 1) && (literalconstants < 2))
1551 		showLiterals = 0;
1552 }
1553 
printActionBlock(FILE * f,unsigned long int length,abtype abtype,unsigned int flags,byte key)1554 static void printActionBlock(FILE *f, unsigned long int length, abtype abtype, unsigned int flags, byte key)
1555 {
1556 	swfabspos = ftell(f);
1557 	swfrelpos = 0;
1558 	conststart = constend = 0;
1559 
1560 	nDict = 0;
1561 	showLiterals = literalconstants;
1562 
1563 	++indent;
1564 
1565 	readActionBuffer(f, length);
1566 
1567 	createLabels(length);
1568 
1569 	qsort(labels, (size_t) numLabels, sizeof (unsigned long int), longintCompare);
1570 
1571 	printActions(buffer, length, ANY_VALUE, NULL);
1572 
1573 	if ((mode >= MODE_UPDATE) && (constend > 0) && showLiterals)
1574 		rebuildConstantPool();
1575 
1576 	if (targetIndent == 1) {
1577 		--indent;
1578 		print("end\n");
1579 		targetIndent = 0;
1580 	}
1581 
1582 	--indent;
1583 
1584 	if (buffer != NULL) {
1585 		free(buffer);
1586 		buffer = NULL;
1587 	}
1588 
1589 	if (labels != NULL) {
1590 		free(labels);
1591 		labels = NULL;
1592 	}
1593 
1594 	swfabspos = -1;
1595 	swfrelpos = -1;
1596 }
1597 
skipMatrix(FILE * f)1598 static void skipMatrix(FILE *f)
1599 {
1600 	InitBits(f);
1601 	if (getBits(f, 1))
1602 		getBits(f, getBits(f, 5) * 2);
1603 	if (getBits(f, 1))
1604 		getBits(f, getBits(f, 5) * 2);
1605 	getBits(f, getBits(f, 5) * 2);
1606 }
1607 
skipColorTransform(FILE * f)1608 static void skipColorTransform(FILE *f)
1609 {
1610 	unsigned int needAdd, needMul, nBits;
1611 	InitBits(f);
1612 	needAdd = getBits(f, 1);
1613 	needMul = getBits(f, 1);
1614 	nBits = getBits(f, 4);
1615 	if (needMul)
1616 		getBits(f, nBits * 4);
1617 	if (needAdd)
1618 		getBits(f, nBits * 4);
1619 }
1620 
skipFilters(FILE * f,byte numfilters)1621 static void skipFilters(FILE *f, byte numfilters)
1622 {
1623 	while(numfilters--) {
1624 		int filter = fgetc(f);
1625 		switch(filter){
1626 			case FILTER_DROPSHADOW:
1627 				skipProtected(f, 23);
1628 				break;
1629 			case FILTER_BLUR:
1630 				skipProtected(f, 9);
1631 				break;
1632 			case FILTER_GLOW:
1633 				skipProtected(f, 15);
1634 				break;
1635 			case FILTER_BEVEL:
1636 				skipProtected(f, 27);
1637 				break;
1638 			case FILTER_GRADIENTGLOW:
1639 				skipProtected(f, fgetc(f)*5 + 19);
1640 				break;
1641 			case FILTER_ADJUSTCOLOR:
1642 				skipProtected(f, 80);
1643 				break;
1644 			case FILTER_GRADIENTBEVEL:
1645 				skipProtected(f, fgetc(f)*5 + 19);
1646 				break;
1647 			default:
1648 				tellUser(1, "Unknown filter %i", filter);
1649 		}
1650 	}
1651 }
1652 
parseKeyPressEvent(byte onKey)1653 static void parseKeyPressEvent(byte onKey)
1654 {
1655 	printf("keyPress ");
1656 
1657 	if (onKey == keySpace)
1658 		printf("_SPACE");
1659 	else if (onKey == '\'')
1660 		printf("'%s'", "\\'");
1661 	else if (onKey == '\\')
1662 		printf("'%s'", "\\\\");
1663 	else if (onKey > 32)
1664 		printf("'%c'", onKey);
1665 	else
1666 		switch (onKey) {
1667 			case keyLeft:
1668 				printf("_LEFT");
1669 				break;
1670 			case keyRight:
1671 				printf("_RIGHT");
1672 				break;
1673 			case keyHome:
1674 				printf("_HOME");
1675 				break;
1676 			case keyEnd:
1677 				printf("_END");
1678 				break;
1679 			case keyInsert:
1680 				printf("_INSERT");
1681 				break;
1682 			case keyDelete:
1683 				printf("_DELETE");
1684 				break;
1685 			case keyBackspace:
1686 				printf("_BACKSPACE");
1687 				break;
1688 			case keyEnter:
1689 				printf("_ENTER");
1690 				break;
1691 			case keyUp:
1692 				printf("_UP");
1693 				break;
1694 			case keyDown:
1695 				printf("_DOWN");
1696 				break;
1697 			case keyPageUp:
1698 				printf("_PAGEUP");
1699 				break;
1700 			case keyPageDown:
1701 				printf("_PAGEDOWN");
1702 				break;
1703 			case keyTab:
1704 				printf("_TAB");
1705 				break;
1706 			case keyEscape:
1707 				printf("_ESCAPE");
1708 				break;
1709 			default:
1710 				printf("0x%02x // unknown key", onKey);
1711 				tellUser(0, "Unknown key 0x%02x in keyPress event", onKey);
1712 		}
1713 }
1714 
parseButtonEvent(FILE * f,unsigned int event,unsigned long int length)1715 static void parseButtonEvent(FILE *f, unsigned int event, unsigned long int length)
1716 {
1717 	char delim = ' ';
1718 	byte key = 0;
1719 
1720 	putchar('\n');
1721 	++indent;
1722 	print("on");
1723 
1724 	if (event & IdleToOverUp) {
1725 		putchar(delim);
1726 		printf("idleToOverUp");
1727 		delim = ',';
1728 	}
1729 
1730 	if (event & OverUpToIdle) {
1731 		putchar(delim);
1732 		printf("overUpToIdle");
1733 		delim = ',';
1734 	}
1735 
1736 	if (event & OverUpToOverDown) {
1737 		putchar(delim);
1738 		printf("overUpToOverDown");
1739 		delim = ',';
1740 	}
1741 
1742 	if (event & OverDownToOverUp) {
1743 		putchar(delim);
1744 		printf("overDownToOverUp");
1745 		delim = ',';
1746 	}
1747 
1748 	if (event & OverDownToOutDown) {
1749 		putchar(delim);
1750 		printf("overDownToOutDown");
1751 		delim = ',';
1752 	}
1753 
1754 	if (event & OutDownToOverDown) {
1755 		putchar(delim);
1756 		printf("outDownToOverDown");
1757 		delim = ',';
1758 	}
1759 
1760 	if (event & OutDownToIdle) {
1761 		putchar(delim);
1762 		printf("outDownToIdle");
1763 		delim = ',';
1764 	}
1765 
1766 	if (event & IdleToOverDown) {
1767 		putchar(delim);
1768 		printf("idleToOverDown");
1769 		delim = ',';
1770 	}
1771 
1772 	if (event & OverDownToIdle) {
1773 		putchar(delim);
1774 		printf("overDownToIdle");
1775 		delim = ',';
1776 	}
1777 
1778 	/* keyPress */
1779 	if (event > 0x1FF) {
1780 		key = (byte) (event >> 9);
1781 		putchar(delim);
1782 		parseKeyPressEvent(key);
1783 	}
1784 
1785 	printf("\n");
1786 	printActionBlock(f, length, AB_BUTTONEVENT, event, key);
1787 	print("end\n");
1788 	--indent;
1789 }
1790 
parseButton2(FILE * f,unsigned long int length)1791 static void parseButton2(FILE *f, unsigned long int length)
1792 {
1793 	unsigned int condition, buttonID, actionOffset;
1794 	unsigned long int lastABLength;
1795 
1796 	buttonID = getWord(f);
1797 	/* trackAsMenu */
1798 	fgetc(f);
1799 
1800 	actionOffset = getWord(f);
1801 	lastABLength = length - 8 - actionOffset;
1802 
1803 	if (actionOffset > 0) {
1804 		printf("\n");
1805 		print("defineButton %u\n", buttonID);
1806 
1807 		/* skip button data */
1808 		while (actionOffset > 2) {
1809 			fgetc(f);
1810 			--actionOffset;
1811 		}
1812 
1813 		while ((actionOffset = getWord(f)) > 0) {
1814 			lastABLength -= actionOffset;
1815 			condition = getWord(f);
1816 			parseButtonEvent(f, condition, actionOffset - 4);
1817 		}
1818 
1819 		/* last event */
1820 		condition = getWord(f);
1821 		parseButtonEvent(f, condition, lastABLength);
1822 
1823 		print("end // of defineButton %u\n", buttonID);
1824 	}
1825 	else {
1826 		/* no button events */
1827 		while (lastABLength + 2 > 0) {
1828 			fgetc(f);
1829 			--lastABLength;
1830 		}
1831 	}
1832 
1833 	/* button end */
1834 	fgetc(f);
1835 }
1836 
printBitMasked(unsigned long int * eventptr,unsigned long int e,char * delimptr,char * str)1837 static int printBitMasked(unsigned long int *eventptr, unsigned long int e, char *delimptr, char *str)
1838 {
1839 	if (*eventptr & e) {
1840 		*eventptr -= e;
1841 		printf("%c%s", *delimptr, str);
1842 		*delimptr = ',';
1843 		return 1;
1844 	}
1845 	else
1846 		return 0;
1847 }
1848 
parseEvent(FILE * f,unsigned long int event,unsigned long int length)1849 static void parseEvent(FILE *f, unsigned long int event, unsigned long int length)
1850 {
1851 	byte key = 0;
1852 	char delim = ' ';
1853 	unsigned long int event2 = event;
1854 
1855 	putchar('\n');
1856 	++indent;
1857 	print("onClipEvent");
1858 
1859 	printBitMasked(&event2, eventLoad,				&delim, "load");
1860 	printBitMasked(&event2, eventEnterFrame,		&delim, "enterFrame");
1861 	printBitMasked(&event2, eventUnload,			&delim, "unload");
1862 	printBitMasked(&event2, eventMouseMove,			&delim, "mouseMove");
1863 	printBitMasked(&event2, eventMouseDown,			&delim, "mouseDown");
1864 	printBitMasked(&event2, eventMouseUp,			&delim, "mouseUp");
1865 	printBitMasked(&event2, eventKeyDown,			&delim, "keyDown");
1866 	printBitMasked(&event2, eventKeyUp,				&delim, "keyUp");
1867 	printBitMasked(&event2, eventData,				&delim, "data");
1868 	printBitMasked(&event2, eventInitialize,		&delim, "initialize");
1869 	printBitMasked(&event2, eventConstruct,			&delim, "construct");
1870 	printBitMasked(&event2, eventPress,				&delim, "press");
1871 	printBitMasked(&event2, eventRelease,			&delim, "release");
1872 	printBitMasked(&event2, eventReleaseOutside,	&delim, "releaseOutside");
1873 	printBitMasked(&event2, eventRollOver,			&delim, "rollOver");
1874 	printBitMasked(&event2, eventRollOut,			&delim, "rollOut");
1875 	printBitMasked(&event2, eventDragOver,			&delim, "dragOver");
1876 	printBitMasked(&event2, eventDragOut,			&delim, "dragOut");
1877 
1878 	if (printBitMasked(&event2, eventKeyPress, &delim, "")) {
1879 		key = (byte) fgetc(f);
1880 		parseKeyPressEvent(key);
1881 		length--;
1882 		delim = ',';
1883 	}
1884 
1885 	if (event2 != 0) {
1886 		printf("%c%lu // unknown event", delim, event2);
1887 		tellUser(0, "Unknown event: %lu", event2);
1888 	}
1889 	printf("\n");
1890 	printActionBlock(f, length, AB_MCEVENT, event, key);
1891 	print("end\n");
1892 	--indent;
1893 }
1894 
parsePlaceObject(FILE * f,unsigned long int length,unsigned int type)1895 static void parsePlaceObject(FILE *f, unsigned long int length, unsigned int type)
1896 {
1897 	int i;
1898 	unsigned int flags;
1899 	unsigned int clipID = 0;
1900 	unsigned int depth;
1901 	unsigned long int curEvent;
1902 
1903 	if (type == TAG_PLACEOBJECT2)
1904 		flags = fgetc(f);
1905 	else
1906 		flags = getWord(f);
1907 
1908 	if (flags & PF_ONCLIPEVENTS) {
1909 		printf("\n");
1910 
1911 		/* character depth */
1912 		depth = getWord(f);
1913 
1914 		/* clipID should always be present */
1915 		if (flags & PF_CHARACTER) {
1916 			print("placeMovieClip %u ", clipID = getWord(f));
1917 		}
1918 		else {
1919 			print("placeMovieClip ??? ");
1920 			tellUser(0, "placeMovieClip: clip ID not found");
1921 		}
1922 
1923 		if (flags & PF_MATRIX)
1924 			skipMatrix(f);
1925 		if (flags & PF_COLORTRANSFORM)
1926 			skipColorTransform(f);
1927 		if (flags & PF_RATIO)
1928 			getWord(f);
1929 
1930 		if (flags & PF_NAME) {
1931 			printf("as ");
1932 			putchar('\'');
1933 			while ((i = fgetc(f)) != 0)
1934 				putchar((char) i);
1935 			putchar('\'');
1936 		}
1937 
1938 		if (flags & PF_DEFINECLIP)
1939 			getWord(f);
1940 
1941 		if (type == TAG_PLACEOBJECT3) {
1942 			if (flags & PF_FILTERS)
1943 				skipFilters(f, (byte) fgetc(f));
1944 			if (flags & PF_BLENDMODE)
1945 				fgetc(f);
1946 			if (flags & PF_BITMAPCACHING)
1947 				fgetc(f);
1948 		}
1949 
1950 		printf("\n");
1951 
1952 
1953 		/* reserved: always 0 */
1954 		getWord(f);
1955 
1956 		if (swfVersion >= 6 || type == TAG_PLACEOBJECT3) {
1957 			/* flash 6 supports button events for mcs, therefore going long here */
1958 			getDoubleWord(f);
1959 
1960 			while ((curEvent = getDoubleWord(f)) != 0)
1961 				parseEvent(f, curEvent, getDoubleWord(f));
1962 		}
1963 		else {
1964 			/* all events */
1965 			getWord(f);
1966 			while ((curEvent = (unsigned long int) getWord(f)) != 0)
1967 				parseEvent(f, curEvent, getDoubleWord(f));
1968 		}
1969 
1970 		if (flags & PF_CHARACTER)
1971 			print("end // of placeMovieClip %u\n", clipID);
1972 		else
1973 			print("end // of placeMovieClip ???\n");
1974 
1975 	}
1976 	else {
1977 		/* no events found, skip the rest of placeObject2/3 */
1978 		if (type == TAG_PLACEOBJECT3)
1979 			skipProtected(f, length - 2);
1980 		else
1981 			skipProtected(f, length - 1);
1982 	}
1983 }
1984 
parseMovieClip(FILE * f)1985 static void parseMovieClip(FILE *f)
1986 {
1987 	unsigned int clipID, frameNum = 0, framesTotal = 0;
1988 
1989 	clipID = getWord(f);
1990 	framesTotal = getWord(f);
1991 
1992 	printf("\n");
1993 	print("defineMovieClip %u // total frames: %u\n", clipID, framesTotal);
1994 	indent++;
1995 
1996 	while (!feof(f)) {
1997 		unsigned int type;
1998 		unsigned long int length;
1999 
2000 		parseTagHeader(f, &type, &length);
2001 
2002 		if (type == 0)
2003 			break;
2004 
2005 		switch (type) {
2006 			case TAG_DOACTION:
2007 				printFrameNum(frameNum);
2008 				printActionBlock(f, length, AB_FRAME, frameNum, 0);
2009 				print("end // of frame %u\n", frameNum);
2010 				break;
2011 
2012 			case TAG_PLACEOBJECT2:
2013 				/* possibly onClipEvents inside */
2014 				parsePlaceObject(f, length, TAG_PLACEOBJECT2);
2015 				break;
2016 
2017 			case TAG_PLACEOBJECT3:
2018 				/* possibly onClipEvents inside */
2019 				parsePlaceObject(f, length, TAG_PLACEOBJECT3);
2020 				break;
2021 
2022 			case TAG_SHOWFRAME:
2023 				++frameNum;
2024 				break;
2025 
2026 			default:
2027 				if (getTagString(type) == NULL) {
2028 					print("\n");
2029 					print("// unknown tag %lu length %li\n\n", type, length);
2030 				}
2031 				skipProtected(f, length);
2032 		}
2033 	}
2034 
2035 	--indent;
2036 	print("end // of defineMovieClip %u\n", clipID);
2037 }
2038 
disassembleSWF(FILE * f,char * fname)2039 void disassembleSWF(FILE *f, char *fname)
2040 {
2041 	unsigned int componentID, frameNum = 0, framesTotal = 0, bits;
2042 	unsigned long int i, size;
2043 	float frameRate, movieWidth, movieHeight;
2044 
2045 	swfVersion = fgetc(f);
2046 	size = getDoubleWord(f);
2047 
2048 	/* movie bounds */
2049 	InitBits(f);
2050 	bits = getBits(f, 5);
2051 	/* xMin - always 0 */
2052 	getBits(f, bits);
2053 	/* xMax */
2054 	movieWidth = ((float) getBits(f, bits)) / 20;
2055 	/* yMin - always 0 */
2056 	getBits(f, bits);
2057 	/* yMax */
2058 	movieHeight = ((float) getBits(f, bits)) / 20;
2059 
2060 	frameRate = ((float) fgetc(f)) / 256;
2061 	frameRate += (float) fgetc(f);
2062 
2063 	framesTotal = getWord(f);
2064 
2065 	printf("movie '%s'", fname);
2066 
2067 	if (wasCompressed)
2068 		printf(" compressed");
2069 	printf(" // flash %i, total frames: %u, frame rate: ", swfVersion, framesTotal);
2070 	printFloat(frameRate, 1);
2071 	printf(" fps, ");
2072 	printFloat(movieWidth, 1);
2073 	putchar('x');
2074 	printFloat(movieHeight, 1);
2075 	printf(" px\n");
2076 
2077 	while (!feof(f)) {
2078 		unsigned int type;
2079 		unsigned long int length;
2080 
2081 		parseTagHeader(f, &type, &length);
2082 
2083 		if (type == 0)
2084 			break;
2085 
2086 		switch (type) {
2087 			case TAG_DOACTION:
2088 				printFrameNum(frameNum);
2089 				printActionBlock(f, length, AB_FRAME, frameNum, 0);
2090 				print("end // of frame %u\n", frameNum);
2091 				break;
2092 
2093 			case TAG_INITMOVIECLIP:
2094 				print("\n");
2095 				componentID = getWord(f);
2096 				print("initMovieClip %i\n", componentID);
2097 				printActionBlock(f, length - 2, AB_INITMC, componentID, 0);
2098 				print("end // of initMovieClip %i\n", componentID);
2099 				break;
2100 
2101 			case TAG_PLACEOBJECT2:
2102 				/* possibly onClipEvents inside */
2103 				parsePlaceObject(f, length, TAG_PLACEOBJECT2);
2104 				break;
2105 
2106 			case TAG_PLACEOBJECT3:
2107 				/* possibly onClipEvents inside */
2108 				parsePlaceObject(f, length, TAG_PLACEOBJECT3);
2109 				break;
2110 
2111 			case TAG_DEFINEBUTTON2:
2112 				/* possibly button events inside */
2113 				parseButton2(f, length);
2114 				break;
2115 
2116 			case TAG_SHOWFRAME:
2117 				++frameNum;
2118 				break;
2119 
2120 			case TAG_SCRIPTLIMITS: {
2121 				unsigned int recursion = getWord(f);
2122 				unsigned int timeout = getWord(f);
2123 				print("\n");
2124 				print("scriptLimits recursion %u timeout %u\n", recursion, timeout);
2125 				break;
2126 			}
2127 
2128 			case TAG_PROTECT:
2129 				print("\n");
2130 				print("protect");
2131 				if (length > 0) {
2132 					/* password found */
2133 					printf(" '");
2134 					/* always 0 */
2135 					getWord(f);
2136 					for (i = 2; i < length - 1; ++i) {
2137 						putchar((char) fgetc(f));
2138 					}
2139 					/* always 0 - string end */
2140 					fgetc(f);
2141 					putchar('\'');
2142 				}
2143 				putchar('\n');
2144 				break;
2145 
2146 			case TAG_ENABLEDEBUGGER:
2147 				print("\n");
2148 				print("enableDebugger");
2149 				if (length > 0) {
2150 					/* password found */
2151 					/* debugger always uses password, even for empty one */
2152 					printf(" '");
2153 					/* always 0 */
2154 					getWord(f);
2155 					for (i = 2; i < length - 1; ++i) {
2156 						putchar((char) fgetc(f));
2157 					}
2158 					/* always 0 - string end */
2159 					fgetc(f);
2160 					putchar('\'');
2161 				}
2162 				putchar('\n');
2163 				break;
2164 
2165 			case TAG_ENABLEDEBUGGER2:
2166 				/* flash MX debugger */
2167 				print("\n");
2168 				print("enableDebugger2");
2169 				if (length > 0) {
2170 					/* password found */
2171 					/* debugger always uses password, even for empty one */
2172 					printf(" '");
2173 					/* reserved, always 0 */
2174 					getWord(f);
2175 					for (i = 2; i < length - 1; ++i) {
2176 						putchar((char) fgetc(f));
2177 					}
2178 					/* always 0 - string end */
2179 					fgetc(f);
2180 					putchar('\'');
2181 				}
2182 				putchar('\n');
2183 				break;
2184 
2185 			case TAG_DEFINEMOVIECLIP:
2186 				parseMovieClip(f);
2187 				break;
2188 
2189 			case TAG_EXPORTASSETS: {
2190 				unsigned int assetID, numAssets = getWord(f);
2191 				int n;
2192 				print("\n");
2193 				print("exportAssets\n");
2194 				++indent;
2195 				while (numAssets--) {
2196 					print("%u as '", assetID = getWord(f));
2197 					while ((n = fgetc(f)) != 0) {
2198 						putchar((char) n);
2199 					}
2200 					printf("'\n");
2201 				}
2202 				--indent;
2203 				print("end // of exportAssets\n");
2204 				break;
2205 			}
2206 
2207 			case TAG_IMPORTASSETS:
2208 			case TAG_IMPORTASSETS2: {
2209 				unsigned int assetID, numAssets, attr;
2210 				int n;
2211 				print("\n");
2212 				print("importAssets from '");
2213 				while ((n = fgetc(f)) != 0) {
2214 					putchar((char) n);
2215 				}
2216 				printf("'\n");
2217 				if (type == TAG_IMPORTASSETS2) {
2218 					/* Reserved: always 1 */
2219 					attr = getWord(f);
2220 					if (attr != 1)
2221 					   tellUser(0, "Unknown importAssets2 attribute: %u (should be 1)", attr);
2222 				}
2223 				numAssets = getWord(f);
2224 				++indent;
2225 				while (numAssets--) {
2226 					assetID = getWord(f);
2227 					print("'");
2228 					while ((n = fgetc(f)) != 0) {
2229 						putchar((char) n);
2230 					}
2231 					printf("' as %u\n", assetID);
2232 				}
2233 				--indent;
2234 				print("end // of importAssets\n");
2235 				break;
2236 			}
2237 
2238 			case TAG_METADATA: {
2239 				static char buf[MAX_BUFFER];
2240 				print("\n");
2241 				print("metadata ");
2242 				fread(buf, 1, length, f);
2243 				printstr(buf);
2244 				putchar('\n');
2245 				break;
2246 			}
2247 
2248 			case TAG_FILEATTRIBUTES: {
2249 				char delim = ' ';
2250 				unsigned long int attrs = getDoubleWord(f);
2251 				if (attrs) {
2252 					print("\n");
2253 					print("fileAttributes");
2254 				}
2255 				printBitMasked(&attrs, ATTR_USENETWORK,					&delim, "attrUseNetwork");
2256 				printBitMasked(&attrs, ATTR_RELATIVEURLS,				&delim, "attrRelativeURLs");
2257 				printBitMasked(&attrs, ATTR_SUPPRESSCROSSDOMAINCACHE,	&delim, "attrSuppressCrossDomainCache");
2258 				printBitMasked(&attrs, ATTR_ACTIONSCRIPT3,				&delim, "attrActionScript3");
2259 				printBitMasked(&attrs, ATTR_HASMETADATA,				&delim, "attrHasMetadata");
2260 				if (attrs != 0) {
2261 					printf("%c%lu // unknown attribute", delim, attrs);
2262 					tellUser(0, "Unknown file attribute: %lu", attrs);
2263 				}
2264 				printf("\n");
2265 				break;
2266 			}
2267 
2268 			default:
2269 				if (getTagString(type) == NULL) {
2270 					print("\n");
2271 					print("// unknown tag %lu length %li\n", type, length);
2272 				}
2273 				skipProtected(f, length);
2274 		}
2275 	}
2276 
2277 	fclose(f);
2278 	printf("end\n");
2279 }
2280