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 program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22 #include "../config.h"
24 #ifdef HAVE_SYS_STAT_H
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
40 #include "../lib/rfxswf.h"
41 #include "../lib/args.h"
43 static char * filename = 0;
45 /* idtab stores the ids which are defined in the file. This allows us
46 to detect errors in the file. (i.e. ids which are defined more than
48 static char idtab[65536];
49 static char * indent = " ";
51 static int placements = 0;
52 static int action = 0;
55 static int showtext = 0;
56 static int showshapes = 0;
61 static struct options_t options[] = {
80 int args_callback_option(char*name,char*val)
82 if(!strcmp(name, "V")) {
83 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
86 else if(name[0]=='a') {
90 else if(name[0]=='p') {
94 else if(name[0]=='t') {
98 else if(name[0]=='s') {
102 else if(name[0]=='e') {
106 else if(name[0]=='X') {
110 else if(name[0]=='Y') {
114 else if(name[0]=='r') {
118 else if(name[0]=='f') {
122 else if(name[0]=='d') {
126 else if(name[0]=='u') {
130 else if(name[0]=='b') {
134 else if(name[0]=='D') {
135 action = placements = showtext = showshapes = 1;
139 printf("Unknown option: -%s\n", name);
145 int args_callback_longoption(char*name,char*val)
147 return args_long2shortoption(options, name, val);
149 void args_callback_usage(char *name)
152 printf("Usage: %s [-atpdu] file.swf\n", name);
154 printf("-h , --help Print short help message and exit\n");
155 printf("-D , --full Show everything. Same as -atp\n");
156 printf("-V , --version Print version info and exit\n");
157 printf("-e , --html Print out html code for embedding the file\n");
158 printf("-a , --action Disassemble action tags\n");
159 printf("-t , --text Show text fields (like swfstrings).\n");
160 printf("-s , --shapes Show shape coordinates/styles\n");
161 printf("-p , --placements Show placement information\n");
162 printf("-X , --width Prints out a string of the form \"-X width\".\n");
163 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
164 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
165 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
166 printf("-d , --hex Print hex output of tag data, too.\n");
167 printf("-u , --used Show referred IDs for each Tag.\n");
170 int args_callback_command(char*name,char*val)
173 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
181 char* testfunc(char*str)
183 printf("%s: %s\n", what, str);
187 void dumpButton2Actions(TAG*tag, char*prefix)
193 oldTagPos = swf_GetTagPos(tag);
195 // scan DefineButton2 Record
197 swf_GetU16(tag); // Character ID
198 swf_GetU8(tag); // Flags;
200 offsetpos = swf_GetTagPos(tag); // first offset
203 while (swf_GetU8(tag)) // state -> parse ButtonRecord
204 { swf_GetU16(tag); // id
205 swf_GetU16(tag); // layer
206 swf_GetMatrix(tag,NULL); // matrix
207 swf_GetCXForm(tag,NULL,1); // cxform
214 if(tag->pos >= tag->len)
217 offsetpos = swf_GetU16(tag);
218 condition = swf_GetU16(tag); // condition
220 actions = swf_ActionGet(tag);
221 printf("%s condition %04x\n", prefix, condition);
222 swf_DumpActions(actions, prefix);
225 swf_SetTagPos(tag,oldTagPos);
229 void dumpButtonActions(TAG*tag, char*prefix)
232 swf_GetU16(tag); // id
233 while (swf_GetU8(tag)) // state -> parse ButtonRecord
234 { swf_GetU16(tag); // id
235 swf_GetU16(tag); // layer
236 swf_GetMatrix(tag,NULL); // matrix
238 actions = swf_ActionGet(tag);
239 swf_DumpActions(actions, prefix);
246 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
249 printf(" <%2d glyphs in font %2d, color #%02x%02x%02x%02x> ",nr, fontid, color->r, color->g, color->b, color->a);
250 for(t=0;t<fontnum;t++)
252 if(fonts[t]->id == fontid) {
262 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
263 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
266 a = fonts[font]->glyph2ascii[glyphs[t]];
273 printf("\\x%x", (int)a);
278 void handleText(TAG*tag)
281 swf_ParseDefineText(tag,textcallback, 0);
284 void handleDefineSound(TAG*tag)
286 U16 id = swf_GetU16(tag);
287 U8 flags = swf_GetU8(tag);
288 int compression = (flags>>4)&3;
289 int rate = (flags>>2)&3;
290 int bits = flags&2?16:8;
291 int stereo = flags&1;
293 if(compression == 0) printf("Raw ");
294 else if(compression == 1) printf("ADPCM ");
295 else if(compression == 2) printf("MP3 ");
297 if(rate == 0) printf("5.5Khz ");
298 if(rate == 1) printf("11Khz ");
299 if(rate == 2) printf("22Khz ");
300 if(rate == 3) printf("44Khz ");
301 printf("%dBit ", bits);
302 if(stereo) printf("stereo");
307 void handleDefineBits(TAG*tag)
313 id = swf_GetU16(tag);
314 mode = swf_GetU8(tag);
315 width = swf_GetU16(tag);
316 height = swf_GetU16(tag);
317 printf(" image %dx%d",width,height);
318 if(mode == 3) printf(" (8 bpp)");
319 else if(mode == 4) printf(" (16 bpp)");
320 else if(mode == 5) printf(" (32 bpp)");
321 else printf(" (? bpp)");
324 void handleEditText(TAG*tag)
329 id = swf_GetU16(tag);
332 //swf_ResetReadBits(tag);
338 flags = swf_GetBits(tag,16);
339 if(flags & ET_HASFONT) {
340 swf_GetU16(tag); //font
341 swf_GetU16(tag); //fontheight
343 if(flags & ET_HASTEXTCOLOR) {
344 swf_GetU8(tag); //rgba
349 if(flags & ET_HASMAXLENGTH) {
350 swf_GetU16(tag); //maxlength
352 if(flags & ET_HASLAYOUT) {
353 swf_GetU8(tag); //align
354 swf_GetU16(tag); //left margin
355 swf_GetU16(tag); //right margin
356 swf_GetU16(tag); //indent
357 swf_GetU16(tag); //leading
359 printf(" variable \"%s\" ", &tag->data[tag->pos]);
360 if(flags & ET_HTML) printf("(html)");
361 if(flags & ET_NOSELECT) printf("(noselect)");
362 if(flags & ET_PASSWORD) printf("(password)");
363 if(flags & ET_READONLY) printf("(readonly)");
365 if(flags & (ET_X1 | ET_X3 ))
367 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
370 while(tag->data[tag->pos++]);
371 if(flags & ET_HASTEXT)
372 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
375 void printhandlerflags(U32 handlerflags)
377 if(handlerflags&1) printf("[on load]");
378 if(handlerflags&2) printf("[enter frame]");
379 if(handlerflags&4) printf("[unload]");
380 if(handlerflags&8) printf("[mouse move]");
381 if(handlerflags&16) printf("[mouse down]");
382 if(handlerflags&32) printf("[mouse up]");
383 if(handlerflags&64) printf("[key down]");
384 if(handlerflags&128) printf("[key up]");
386 if(handlerflags&256) printf("[data]");
387 if(handlerflags&512) printf("[initialize]");
388 if(handlerflags&1024) printf("[mouse press]");
389 if(handlerflags&2048) printf("[mouse release]");
390 if(handlerflags&4096) printf("[mouse release outside]");
391 if(handlerflags&8192) printf("[mouse rollover]");
392 if(handlerflags&16384) printf("[mouse rollout]");
393 if(handlerflags&32768) printf("[mouse drag over]");
395 if(handlerflags&0x10000) printf("[mouse drag out]");
396 if(handlerflags&0x20000) printf("[key press]");
397 if(handlerflags&0x40000) printf("[construct even]");
398 if(handlerflags&0xfff80000) printf("[???]");
400 void handleVideoStream(TAG*tag, char*prefix)
402 U16 id = swf_GetU16(tag);
403 U16 frames = swf_GetU16(tag);
404 U16 width = swf_GetU16(tag);
405 U16 height = swf_GetU16(tag);
406 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
407 U8 codec = swf_GetU8(tag);
408 printf(" (%d frames, %dx%d", frames, width, height);
412 printf(" sorenson h.263)");
414 printf(" codec 0x%02x)", codec);
416 void handleVideoFrame(TAG*tag, char*prefix)
418 U32 code, version, reference, sizeflags;
419 U32 width=0, height=0;
421 U16 id = swf_GetU16(tag);
422 U16 frame = swf_GetU16(tag);
423 U8 deblock,flags, tmp, bit;
425 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
426 printf(" (frame %d) ", frame);
428 /* video packet follows */
429 code = swf_GetBits(tag, 17);
430 version = swf_GetBits(tag, 5);
431 reference = swf_GetBits(tag, 8);
433 sizeflags = swf_GetBits(tag, 3);
436 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
437 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
438 case 2: width = 352; height = 288; break;
439 case 3: width = 176; height = 144; break;
440 case 4: width = 128; height = 96; break;
441 case 5: width = 320; height = 240; break;
442 case 6: width = 160; height = 120; break;
443 case 7: width = -1; height = -1;/*reserved*/ break;
445 printf("%dx%d ", width, height);
446 type = swf_GetBits(tag, 2);
447 printf("%s", types[type]);
449 deblock = swf_GetBits(tag, 1);
451 printf(" deblock ", deblock);
452 quantizer = swf_GetBits(tag, 5);
453 printf(" quant: %d ", quantizer);
456 void handlePlaceObject2(TAG*tag, char*prefix)
458 U8 flags = swf_GetU8(tag);
462 int ppos[3] = {0,0,0};
463 swf_GetU16(tag); //depth
466 if(flags&2) swf_GetU16(tag); //id
468 swf_GetMatrix(tag,&m);
470 ppos[0] += sprintf(pstr[0], "| Matrix ");
471 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
472 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
476 swf_GetCXForm(tag, &cx, 1);
478 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
479 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);
480 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
484 U16 ratio = swf_GetU16(tag); //ratio
486 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
487 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
488 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
492 U16 clip = swf_GetU16(tag); //clip
494 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
495 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", clip);
496 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
499 if(flags&32) { while(swf_GetU8(tag)); }
500 if(placements && ppos[0]) {
502 printf("%s %s\n", prefix, pstr[0]);
503 printf("%s %s\n", prefix, pstr[1]);
504 printf("%s %s", prefix, pstr[2]);
513 reserved = swf_GetU16(tag); // must be 0
514 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
516 printf("Unknown parameter field not zero: %04x\n", reserved);
519 printf("global flags: %04x\n", globalflags);
521 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
523 handlerflags = swf_GetU32(tag);
526 while(handlerflags) {
531 globalflags &= ~handlerflags;
532 printf("%s flags %08x ",prefix, handlerflags);
533 printhandlerflags(handlerflags);
534 length = swf_GetU32(tag);
535 printf(", %d bytes actioncode\n",length);
536 a = swf_ActionGet(tag);
537 swf_DumpActions(a,prefix);
540 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
542 if(globalflags) // should go to sterr.
543 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
545 printf(" has action code\n");
550 void handlePlaceObject(TAG*tag, char*prefix)
552 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
554 U16 id = swf_GetU16(tag);
555 U16 depth = swf_GetU16(tag);
558 swf_GetMatrix(tag, &matrix);
559 swf_GetCXForm(tag, &cxform, 0);
562 swf_SetU16(tag2, depth);
563 swf_SetMatrix(tag2, &matrix);
564 swf_SetCXForm(tag2, &cxform, 1);
566 handlePlaceObject2(tag2, prefix);
569 char* fillstyle2str(FILLSTYLE*style)
571 switch(style->type) {
573 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
575 case 0x10: case 0x12:
576 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
578 case 0x40: case 0x41:
579 /* TODO: display information about that bitmap */
580 sprintf(stylebuf, "BITMAP %d", style->id_bitmap);
583 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
587 char* linestyle2str(LINESTYLE*style)
589 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
593 void handleShape(TAG*tag, char*prefix)
601 swf_ParseDefineShape(tag, &shape);
603 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
605 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
610 else printf("%s | (Neither line nor fill styles)\n", prefix);
613 printf("%s", prefix);
614 if(t < shape.numfillstyles) {
615 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
619 if(t < shape.numlinestyles) {
620 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
625 printf("%s |\n", prefix);
629 printf("%s | fill: %02d/%02d line:%02d - ",
634 if(line->type == moveTo) {
635 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
636 } else if(line->type == lineTo) {
637 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
638 } else if(line->type == splineTo) {
639 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
640 line->sx/20.0, line->sy/20.0,
641 line->x/20.0, line->y/20.0
646 printf("%s |\n", prefix);
649 void fontcallback1(void*self, U16 id,U8 * name)
653 void fontcallback2(void*self, U16 id,U8 * name)
655 swf_FontExtract(&swf,id,&fonts[fontnum]);
659 static U8 printable(U8 a)
661 if(a<32 || a==127) return '.';
664 void hexdumpTag(TAG*tag, char* prefix)
668 printf(" %s-=> ",prefix);
669 for(t=0;t<tag->len;t++) {
670 printf("%02x ", tag->data[t]);
671 ascii[t&15] = printable(tag->data[t]);
672 if((t && ((t&15)==15)) || (t==tag->len-1))
676 for(s=p-1;s<16;s++) {
680 printf(" %s\n", ascii);
682 printf(" %s\n %s-=> ",ascii,prefix);
687 void handleExportAssets(TAG*tag, char* prefix)
693 num = swf_GetU16(tag);
696 id = swf_GetU16(tag);
697 name = swf_GetString(tag);
698 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
702 void dumperror(const char* format, ...)
707 va_start(arglist, format);
708 vsprintf(buf, format, arglist);
712 printf("==== Error: %s ====\n", buf);
715 static char strbuf[800];
718 char* timestring(double f)
720 int hours = (int)(f/3600);
721 int minutes = (int)((f-hours*3600)/60);
722 int seconds = (int)((f-hours*3600-minutes*60));
723 int useconds = (int)((f-(int)f)*1000+0.5);
726 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
727 return &strbuf[bufpos];
730 int main (int argc,char ** argv)
738 char issprite = 0; // are we inside a sprite definition?
741 char* spriteframelabel = 0;
742 char* framelabel = 0;
746 memset(idtab,0,65536);
748 processargs(argc, argv);
752 fprintf(stderr, "You must supply a filename.\n");
756 f = open(filename,O_RDONLY|O_BINARY);
761 sprintf(buffer, "Couldn't open %s", filename);
765 if FAILED(swf_ReadSWF(f,&swf))
767 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
774 if(statbuf.st_size != swf.fileSize && !swf.compressed)
775 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
776 statbuf.st_size, swf.fileSize);
777 filesize = statbuf.st_size;
782 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
783 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
787 printf("-X %d", xsize);
793 printf("-Y %d", ysize);
799 printf("-r %.2f", swf.frameRate/256.0);
805 printf("-f %d", swf.frameCount);
812 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
813 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
814 if(swf.fileVersion>9) {
815 fprintf(stderr, "Fileversion>9\n");
818 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
820 //" BGCOLOR=#ffffffff\n"?
822 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
823 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
824 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
825 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
826 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
827 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
828 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
829 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
830 " TYPE=\"application/x-shockwave-flash\"\n"
831 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
833 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
834 filename, filename, xsize, ysize);
837 printf("[HEADER] File version: %d\n", swf.fileVersion);
839 printf("[HEADER] File is zlib compressed.");
840 if(filesize && swf.fileSize)
841 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
845 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
846 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
847 printf("[HEADER] Frame count: %d\n",swf.frameCount);
848 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
849 if(swf.movieSize.xmin)
850 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
853 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
854 if(swf.movieSize.ymin)
855 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
863 swf_FontEnumerate(&swf,&fontcallback1, 0);
864 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
866 swf_FontEnumerate(&swf,&fontcallback2, 0);
870 char*name = swf_TagGetName(tag);
873 dumperror("Unknown tag:0x%03x", tag->id);
877 if(swf_TagGetName(tag)) {
878 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
880 printf("[%03x] %9ld %sUNKNOWN TAG %03x", tag->id, tag->len, prefix, tag->id);
883 if(tag->id == ST_FREECHARACTER) {
884 U16 id = swf_GetU16(tag);
888 if(swf_isDefiningTag(tag)) {
889 U16 id = swf_GetDefineID(tag);
890 printf(" defines id %04d", id);
892 dumperror("Id %04d is defined more than once.", id);
895 else if(swf_isPseudoDefiningTag(tag)) {
896 U16 id = swf_GetDefineID(tag);
897 printf(" adds information to id %04d", id);
899 dumperror("Id %04d is not yet defined.\n", id);
901 else if(tag->id == ST_PLACEOBJECT) {
902 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
904 printf(" name \"%s\"",swf_GetName(tag));
906 else if(tag->id == ST_PLACEOBJECT2) {
913 printf(" id %04d",swf_GetPlaceID(tag));
917 printf(" at depth %04d", swf_GetDepth(tag));
919 printf(" name \"%s\"",swf_GetName(tag));
921 else if(tag->id == ST_REMOVEOBJECT) {
922 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
924 else if(tag->id == ST_REMOVEOBJECT2) {
925 printf(" removes object from depth %04d", swf_GetDepth(tag));
927 else if(tag->id == ST_FREECHARACTER) {
928 printf(" frees object %04d", swf_GetPlaceID(tag));
930 else if(tag->id == ST_STARTSOUND) {
933 id = swf_GetU16(tag);
934 flags = swf_GetU8(tag);
936 printf(" stops sound with id %04d", id);
938 printf(" starts sound with id %04d", id);
940 printf(" (if not already playing)");
946 printf(" looping %d times", swf_GetU16(tag));
949 else if(tag->id == ST_FRAMELABEL) {
950 int l = strlen(tag->data);
951 printf(" \"%s\"", tag->data);
953 printf(" has %d extra bytes", tag->len-1-l);
954 if(tag ->len-1-l == 1 && tag->data[tag->len-1] == 1)
957 if((framelabel && !issprite) ||
958 (spriteframelabel && issprite)) {
959 dumperror("Frame %d has more than one label",
960 issprite?spriteframe:mainframe);
962 if(issprite) spriteframelabel = tag->data;
963 else framelabel = tag->data;
965 else if(tag->id == ST_SHOWFRAME) {
966 char*label = issprite?spriteframelabel:framelabel;
967 int frame = issprite?spriteframe:mainframe;
970 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
972 if(issprite) spriteframe++;
978 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
980 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
981 timestring(frame*(256.0/(swf.frameRate+0.1))),
982 timestring(nframe*(256.0/(swf.frameRate+0.1)))
985 printf(" (label \"%s\")", label);
986 if(issprite) {spriteframe++; spriteframelabel = 0;}
987 if(!issprite) {mainframe++; framelabel = 0;}
990 if(tag->id == ST_SETBACKGROUNDCOLOR) {
991 U8 r = swf_GetU8(tag);
992 U8 g = swf_GetU8(tag);
993 U8 b = swf_GetU8(tag);
994 printf(" (%02x/%02x/%02x)\n",r,g,b);
996 else if(tag->id == ST_PROTECT) {
998 printf(" %s\n", swf_GetString(tag));
1003 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1004 tag->id == ST_DEFINEBITSLOSSLESS2) {
1005 handleDefineBits(tag);
1008 else if(tag->id == ST_DEFINESOUND) {
1009 handleDefineSound(tag);
1012 else if(tag->id == ST_VIDEOFRAME) {
1013 handleVideoFrame(tag, myprefix);
1016 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1017 handleVideoStream(tag, myprefix);
1020 else if(tag->id == ST_DEFINEEDITTEXT) {
1021 handleEditText(tag);
1024 else if(tag->id == ST_DEFINEMOVIE) {
1025 U16 id = swf_GetU16(tag);
1026 char*s = swf_GetString(tag);
1027 printf(" URL: %s\n", s);
1029 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1035 else if(tag->id == ST_PLACEOBJECT2) {
1037 else if(tag->id == ST_NAMECHARACTER) {
1039 printf(" \"%s\"\n", swf_GetString(tag));
1045 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1046 SRECT r = swf_GetDefineBBox(tag);
1047 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1054 sprintf(myprefix, " %s", prefix);
1056 if(tag->id == ST_DEFINESPRITE) {
1057 sprintf(prefix, " ");
1059 dumperror("Sprite definition inside a sprite definition");
1063 spriteframelabel = 0;
1065 else if(tag->id == ST_END) {
1068 spriteframelabel = 0;
1070 dumperror("End Tag not empty");
1072 else if(tag->id == ST_EXPORTASSETS) {
1073 handleExportAssets(tag, myprefix);
1075 else if(tag->id == ST_DOACTION && action) {
1077 actions = swf_ActionGet(tag);
1078 swf_DumpActions(actions, myprefix);
1080 else if(tag->id == ST_DOINITACTION && action) {
1082 swf_GetU16(tag); // id
1083 actions = swf_ActionGet(tag);
1084 swf_DumpActions(actions, myprefix);
1086 else if(tag->id == ST_DEFINEBUTTON && action) {
1087 dumpButtonActions(tag, myprefix);
1089 else if(tag->id == ST_DEFINEBUTTON2 && action) {
1090 dumpButton2Actions(tag, myprefix);
1092 else if(tag->id == ST_PLACEOBJECT) {
1093 handlePlaceObject(tag, myprefix);
1095 else if(tag->id == ST_PLACEOBJECT2) {
1096 handlePlaceObject2(tag, myprefix);
1098 else if(tag->id == ST_DEFINESHAPE ||
1099 tag->id == ST_DEFINESHAPE2 ||
1100 tag->id == ST_DEFINESHAPE3) {
1102 handleShape(tag, myprefix);
1105 if(tag->len && used) {
1106 int num = swf_GetNumUsedIDs(tag);
1110 used = (int*)malloc(sizeof(int)*num);
1111 swf_GetUsedIDs(tag, used);
1112 printf("%s%suses IDs: ", indent, prefix);
1113 for(t=0;t<num;t++) {
1115 swf_SetTagPos(tag, used[t]);
1116 id = swf_GetU16(tag);
1117 printf("%d%s", id, t<num-1?", ":"");
1119 dumperror("Id %04d is not yet defined.\n", id);
1126 if(tag->len && hex) {
1127 hexdumpTag(tag, prefix);