2 Shows the structure of a swf file
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This file is distributed under the GPL, see file COPYING for details */
10 #include "../config.h"
12 #ifdef HAVE_SYS_STAT_H
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
28 #include "../lib/rfxswf.h"
29 #include "../lib/args.h"
31 static char * filename = 0;
33 /* idtab stores the ids which are defined in the file. This allows us
34 to detect errors in the file. (i.e. ids which are defined more than
36 static char idtab[65536];
37 static char * indent = " ";
39 static int placements = 0;
40 static int action = 0;
43 static int showtext = 0;
47 struct options_t options[] =
66 int args_callback_option(char*name,char*val)
68 if(!strcmp(name, "V")) {
69 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
72 else if(name[0]=='a') {
76 else if(name[0]=='p') {
80 else if(name[0]=='t') {
84 else if(name[0]=='e') {
88 else if(name[0]=='X') {
92 else if(name[0]=='Y') {
96 else if(name[0]=='r') {
100 else if(name[0]=='f') {
104 else if(name[0]=='d') {
108 else if(name[0]=='u') {
112 else if(name[0]=='D') {
113 action = placements = showtext = 1;
117 printf("Unknown option: -%s\n", name);
123 int args_callback_longoption(char*name,char*val)
125 return args_long2shortoption(options, name, val);
127 void args_callback_usage(char*name)
129 printf("Usage: %s [-at] file.swf\n", name);
130 printf("\t-h , --help\t\t Print help and exit\n");
131 printf("\t-D , --full\t\t Show everything. The same as -atp\n");
132 printf("\t-e , --html\t\t Create html output embedding the file (simple, but useful)\n");
133 printf("\t-X , --width\t\t Prints out a string of the form \"-X width\"\n");
134 printf("\t-Y , --height\t\t Prints out a string of the form \"-Y height\"\n");
135 printf("\t-r , --rate\t\t Prints out a string of the form \"-r rate\"\n");
136 printf("\t-f , --frames\t\t Prints out a string of the form \"-f framenum\"\n");
137 printf("\t-a , --action\t\t Disassemble action tags\n");
138 printf("\t-p , --placements\t\t Show extra placement information\n");
139 printf("\t-t , --text\t\t Show text data\n");
140 printf("\t-d , --hex\t\t Print hex output of tag data, too\n");
141 printf("\t-u , --used\t\t Show referred IDs for each Tag\n");
142 printf("\t-V , --version\t\t Print program version and exit\n");
144 int args_callback_command(char*name,char*val)
147 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
155 char* testfunc(char*str)
157 printf("%s: %s\n", what, str);
161 void dumpButton2Actions(TAG*tag, char*prefix)
167 oldTagPos = swf_GetTagPos(tag);
169 // scan DefineButton2 Record
171 swf_GetU16(tag); // Character ID
172 swf_GetU8(tag); // Flags;
174 offsetpos = swf_GetTagPos(tag); // first offset
177 while (swf_GetU8(tag)) // state -> parse ButtonRecord
178 { swf_GetU16(tag); // id
179 swf_GetU16(tag); // layer
180 swf_GetMatrix(tag,NULL); // matrix
181 swf_GetCXForm(tag,NULL,1); // cxform
188 if(tag->pos >= tag->len)
191 offsetpos = swf_GetU16(tag);
192 condition = swf_GetU16(tag); // condition
194 actions = swf_ActionGet(tag);
195 printf("%s condition %04x\n", prefix, condition);
196 swf_DumpActions(actions, prefix);
199 swf_SetTagPos(tag,oldTagPos);
203 void dumpButtonActions(TAG*tag, char*prefix)
206 swf_GetU16(tag); // id
207 while (swf_GetU8(tag)) // state -> parse ButtonRecord
208 { swf_GetU16(tag); // id
209 swf_GetU16(tag); // layer
210 swf_GetMatrix(tag,NULL); // matrix
212 actions = swf_ActionGet(tag);
213 swf_DumpActions(actions, prefix);
216 #define ET_HASTEXT 32768
217 #define ET_WORDWRAP 16384
218 #define ET_MULTILINE 8192
219 #define ET_PASSWORD 4096
220 #define ET_READONLY 2048
221 #define ET_HASTEXTCOLOR 1024
222 #define ET_HASMAXLENGTH 512
223 #define ET_HASFONT 256
226 #define ET_HASLAYOUT 32
227 #define ET_NOSELECT 16
231 #define ET_USEOUTLINES 1
237 void textcallback(int*glyphs, int nr, int fontid)
240 printf(" <%2d glyphs in font %2d> ",nr, fontid);
241 for(t=0;t<fontnum;t++)
243 if(fonts[t]->id == fontid) {
253 if(glyphs[t] >= fonts[font]->numchars)
255 a = fonts[font]->glyph2ascii[glyphs[t]];
262 printf("\\x%x", (int)a);
267 void handleText(TAG*tag)
270 swf_FontExtract_DefineTextCallback(-1,0,tag,4, textcallback);
273 void handleDefineSound(TAG*tag)
275 U16 id = swf_GetU16(tag);
276 U8 flags = swf_GetU8(tag);
277 int compression = (flags>>4)&3;
278 int rate = (flags>>2)&3;
279 int bits = flags&2?16:8;
280 int stereo = flags&1;
282 if(compression == 0) printf("Raw ");
283 else if(compression == 1) printf("ADPCM ");
284 else if(compression == 2) printf("MP3 ");
286 if(rate == 0) printf("5.5Khz ");
287 if(rate == 1) printf("11Khz ");
288 if(rate == 2) printf("22Khz ");
289 if(rate == 3) printf("44Khz ");
290 printf("%dBit ", bits);
291 if(stereo) printf("stereo");
296 void handleDefineBits(TAG*tag)
302 id = swf_GetU16(tag);
303 mode = swf_GetU8(tag);
304 width = swf_GetU16(tag);
305 height = swf_GetU16(tag);
306 printf(" image %dx%d",width,height);
307 if(mode == 3) printf(" (8 bpp)");
308 else if(mode == 4) printf(" (16 bpp)");
309 else if(mode == 5) printf(" (32 bpp)");
310 else printf(" (? bpp)");
313 void handleEditText(TAG*tag)
318 id = swf_GetU16(tag);
320 //swf_ResetReadBits(tag);
325 flags = swf_GetBits(tag,16);
326 if(flags & ET_HASFONT) {
327 swf_GetU16(tag); //font
328 swf_GetU16(tag); //fontheight
330 if(flags & ET_HASTEXTCOLOR) {
331 swf_GetU8(tag); //rgba
336 if(flags & ET_HASMAXLENGTH) {
337 swf_GetU16(tag); //maxlength
339 if(flags & ET_HASLAYOUT) {
340 swf_GetU8(tag); //align
341 swf_GetU16(tag); //left margin
342 swf_GetU16(tag); //right margin
343 swf_GetU16(tag); //indent
344 swf_GetU16(tag); //leading
346 printf(" variable \"%s\"", &tag->data[tag->pos]);
348 if(flags & (ET_X1 | ET_X2 | ET_X3 | ET_X0))
350 printf(" undefined flags: %d%d%d%d",
357 while(tag->data[tag->pos++]);
358 if(flags & ET_HASTEXT)
359 // printf(" text \"%s\"\n", &tag->data[tag->pos])
362 void printhandlerflags(U16 handlerflags)
364 if(handlerflags&1) printf("[on load]");
365 if(handlerflags&2) printf("[enter frame]");
366 if(handlerflags&4) printf("[unload]");
367 if(handlerflags&8) printf("[mouse move]");
368 if(handlerflags&16) printf("[mouse down]");
369 if(handlerflags&32) printf("[mouse up]");
370 if(handlerflags&64) printf("[key down]");
371 if(handlerflags&128) printf("[key up]");
372 if(handlerflags&256) printf("[data]");
373 if(handlerflags&0xfe00) printf("[???]");
375 void handlePlaceObject2(TAG*tag, char*prefix)
377 U8 flags = swf_GetU8(tag);
381 int ppos[3] = {0,0,0};
382 swf_GetU16(tag); //depth
384 if(flags&2) swf_GetU16(tag); //id
386 swf_GetMatrix(tag,&m);
388 ppos[0] += sprintf(pstr[0], "| Matrix ");
389 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
390 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
394 swf_GetCXForm(tag, &cx, 1);
396 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
397 ppos[1] += sprintf(pstr[1]+ppos[1], "| mul %4.1f %4.1f %4.1f %4.1f ", cx.r0/256.0, cx.g0/256.0, cx.b0/256.0, cx.a0/256.0);
398 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
402 U16 ratio = swf_GetU16(tag); //ratio
404 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
405 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
406 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
410 U16 clip = swf_GetU16(tag); //clip
412 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
413 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", clip);
414 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
417 if(flags&32) { while(swf_GetU8(tag)); }
418 if(placements && ppos[0]) {
420 printf("%s %s\n", prefix, pstr[0]);
421 printf("%s %s\n", prefix, pstr[1]);
422 printf("%s %s", prefix, pstr[2]);
431 unknown = swf_GetU16(tag);
432 globalflags = swf_GetU16(tag);
434 printf("Unknown parameter field not zero: %04x\n", unknown);
437 printf("global flags: %04x\n", globalflags);
438 handlerflags = swf_GetU16(tag);
440 handlerflags = swf_GetU32(tag);
443 while(handlerflags) {
448 globalflags &= ~handlerflags;
449 printf("%s flags %08x ",prefix, handlerflags);
450 printhandlerflags(handlerflags);
451 length = swf_GetU32(tag);
452 printf(", %d bytes actioncode\n",length);
453 a = swf_ActionGet(tag);
454 swf_DumpActions(a,prefix);
457 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag);
459 if(globalflags) // should go to sterr.
460 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
462 printf(" has action code\n");
467 void handlePlaceObject(TAG*tag, char*prefix)
472 void fontcallback1(U16 id,U8 * name)
476 void fontcallback2(U16 id,U8 * name)
478 swf_FontExtract(&swf,id,&fonts[fontnum]);
482 void hexdumpTag(TAG*tag, char* prefix)
485 printf(" %s-=> ",prefix);
486 for(t=0;t<tag->len;t++) {
487 printf("%02x ", tag->data[t]);
488 if((t && ((t&15)==15)) || (t==tag->len-1))
493 printf("\n %s-=> ",prefix);
498 void handleExportAssets(TAG*tag, char* prefix)
504 num = swf_GetU16(tag);
507 id = swf_GetU16(tag);
508 name = swf_GetString(tag);
509 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
513 void dumperror(const char* format, ...)
518 va_start(arglist, format);
519 vsprintf(buf, format, arglist);
523 printf("==== Error: %s ====\n", buf);
526 static char strbuf[800];
529 char* timestring(double f)
531 int hours = (int)(f/3600);
532 int minutes = (int)((f-hours*3600)/60);
533 int seconds = (int)((f-hours*3600-minutes*60));
534 int useconds = (int)((f-(int)f)*1000+0.5);
537 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
538 return &strbuf[bufpos];
541 int main (int argc,char ** argv)
549 char issprite = 0; // are we inside a sprite definition?
552 char* spriteframelabel = 0;
553 char* framelabel = 0;
557 memset(idtab,0,65536);
559 processargs(argc, argv);
563 fprintf(stderr, "You must supply a filename.\n");
567 f = open(filename,O_RDONLY);
571 perror("Couldn't open file: ");
574 if FAILED(swf_ReadSWF(f,&swf))
576 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
583 if(statbuf.st_size != swf.fileSize && !swf.compressed)
584 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
585 statbuf.st_size, swf.fileSize);
586 filesize = statbuf.st_size;
591 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
592 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
596 printf("-X %d", xsize);
602 printf("-Y %d", ysize);
608 printf("-r %d", swf.frameRate*100/256);
614 printf("-f %d", swf.frameCount);
621 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
622 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0"};
623 if(swf.fileVersion>8) {
624 fprintf(stderr, "Fileversion>8\n");
627 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
629 //" BGCOLOR=#ffffffff\n"?
631 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
632 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
633 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
634 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
635 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
636 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
637 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
638 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
639 " TYPE=\"application/x-shockwave-flash\"\n"
640 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
642 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
643 filename, filename, xsize, ysize);
646 printf("[HEADER] File version: %d\n", swf.fileVersion);
648 printf("[HEADER] File is zlib compressed.");
649 if(filesize && swf.fileSize)
650 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
654 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
655 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
656 printf("[HEADER] Frame count: %d\n",swf.frameCount);
657 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
658 if(swf.movieSize.xmin)
659 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
662 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
663 if(swf.movieSize.ymin)
664 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
672 swf_FontEnumerate(&swf,&fontcallback1);
673 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
675 swf_FontEnumerate(&swf,&fontcallback2);
679 char*name = swf_TagGetName(tag);
682 dumperror("Unknown tag:0x%03x", tag->id);
686 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
688 if(tag->id == ST_FREECHARACTER) {
689 U16 id = swf_GetU16(tag);
693 if(swf_isDefiningTag(tag)) {
694 U16 id = swf_GetDefineID(tag);
695 printf(" defines id %04d", id);
697 dumperror("Id %04d is defined more than once.", id);
700 else if(swf_isPseudoDefiningTag(tag)) {
701 U16 id = swf_GetDefineID(tag);
702 printf(" adds information to id %04d", id);
704 dumperror("Id %04d is not yet defined.\n", id);
706 else if(tag->id == ST_PLACEOBJECT) {
707 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
709 printf(" name \"%s\"",swf_GetName(tag));
710 handlePlaceObject(tag, myprefix);
712 else if(tag->id == ST_PLACEOBJECT2) {
719 printf(" id %04d",swf_GetPlaceID(tag));
723 printf(" at depth %04d", swf_GetDepth(tag));
725 printf(" name \"%s\"",swf_GetName(tag));
727 else if(tag->id == ST_REMOVEOBJECT) {
728 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
730 else if(tag->id == ST_REMOVEOBJECT2) {
731 printf(" removes object from depth %04d", swf_GetDepth(tag));
733 else if(tag->id == ST_FREECHARACTER) {
734 printf(" frees object %04d", swf_GetPlaceID(tag));
736 else if(tag->id == ST_STARTSOUND) {
739 id = swf_GetU16(tag);
740 flags = swf_GetU8(tag);
742 printf(" stops sound with id %04d", id);
744 printf(" starts sound with id %04d", id);
746 printf(" (if not already playing)");
752 printf(" looping %d times", swf_GetU16(tag));
755 else if(tag->id == ST_FRAMELABEL) {
756 int l = strlen(tag->data);
757 printf(" \"%s\"", tag->data);
759 printf(" has %d extra bytes", tag->len-1-l);
760 if(tag ->len-1-l == 1 && tag->data[tag->len-1] == 1)
763 if((framelabel && !issprite) ||
764 (spriteframelabel && issprite)) {
765 dumperror("Frame %d has more than one label",
766 issprite?spriteframe:mainframe);
768 if(issprite) spriteframelabel = tag->data;
769 else framelabel = tag->data;
771 else if(tag->id == ST_SHOWFRAME) {
772 char*label = issprite?spriteframelabel:framelabel;
773 int frame = issprite?spriteframe:mainframe;
776 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
778 if(issprite) spriteframe++;
784 printf(" %d (%s)", frame, timestring(frame*(256.0/(swf.frameRate+0.1))));
786 printf(" %d-%d (%s-%s)", frame, nframe,
787 timestring(frame*(256.0/(swf.frameRate+0.1))),
788 timestring(nframe*(256.0/(swf.frameRate+0.1)))
791 printf(" (label \"%s\")", label);
792 if(issprite) {spriteframe++; spriteframelabel = 0;}
793 if(!issprite) {mainframe++; framelabel = 0;}
796 if(tag->id == ST_SETBACKGROUNDCOLOR) {
797 U8 r = swf_GetU8(tag);
798 U8 g = swf_GetU8(tag);
799 U8 b = swf_GetU8(tag);
800 printf(" (%02x/%02x/%02x)\n",r,g,b);
802 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
803 tag->id == ST_DEFINEBITSLOSSLESS2) {
804 handleDefineBits(tag);
807 else if(tag->id == ST_DEFINESOUND) {
808 handleDefineSound(tag);
811 else if(tag->id == ST_DEFINEEDITTEXT) {
815 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
821 else if(tag->id == ST_PLACEOBJECT2) {
823 else if(tag->id == ST_NAMECHARACTER) {
825 printf(" \"%s\"\n", swf_GetString(tag));
831 sprintf(myprefix, " %s", prefix);
833 if(tag->id == ST_DEFINESPRITE) {
834 sprintf(prefix, " ");
836 dumperror("Sprite definition inside a sprite definition");
840 spriteframelabel = 0;
842 else if(tag->id == ST_END) {
845 spriteframelabel = 0;
847 dumperror("End Tag not empty");
849 else if(tag->id == ST_EXPORTASSETS) {
850 handleExportAssets(tag, myprefix);
852 else if(tag->id == ST_DOACTION && action) {
854 actions = swf_ActionGet(tag);
855 swf_DumpActions(actions, myprefix);
857 else if(tag->id == ST_DEFINEBUTTON && action) {
858 dumpButtonActions(tag, myprefix);
860 else if(tag->id == ST_DEFINEBUTTON2 && action) {
861 dumpButton2Actions(tag, myprefix);
863 else if(tag->id == ST_PLACEOBJECT2) {
864 handlePlaceObject2(tag, myprefix);
867 if(tag->len && used) {
868 int num = swf_GetNumUsedIDs(tag);
872 used = (int*)malloc(sizeof(int)*num);
873 swf_GetUsedIDs(tag, used);
874 printf("%s%suses IDs: ", indent, prefix);
876 swf_SetTagPos(tag, used[t]);
877 printf("%d%s", swf_GetU16(tag), t<num-1?", ":"");
883 if(tag->len && hex) {
884 hexdumpTag(tag, prefix);