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("-b , --bbox Print tag's bounding boxes\n");
163 printf("-X , --width Prints out a string of the form \"-X width\".\n");
164 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
165 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
166 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
167 printf("-d , --hex Print hex output of tag data, too.\n");
168 printf("-u , --used Show referred IDs for each Tag.\n");
171 int args_callback_command(char*name,char*val)
174 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
182 char* testfunc(char*str)
184 printf("%s: %s\n", what, str);
188 void dumpButton2Actions(TAG*tag, char*prefix)
194 oldTagPos = swf_GetTagPos(tag);
196 // scan DefineButton2 Record
198 swf_GetU16(tag); // Character ID
199 swf_GetU8(tag); // Flags;
201 offsetpos = swf_GetTagPos(tag); // first offset
204 while (swf_GetU8(tag)) // state -> parse ButtonRecord
205 { swf_GetU16(tag); // id
206 swf_GetU16(tag); // layer
207 swf_GetMatrix(tag,NULL); // matrix
208 swf_GetCXForm(tag,NULL,1); // cxform
215 if(tag->pos >= tag->len)
218 offsetpos = swf_GetU16(tag);
219 condition = swf_GetU16(tag); // condition
221 actions = swf_ActionGet(tag);
222 printf("%s condition %04x\n", prefix, condition);
223 swf_DumpActions(actions, prefix);
226 swf_SetTagPos(tag,oldTagPos);
230 void dumpButtonActions(TAG*tag, char*prefix)
233 swf_GetU16(tag); // id
234 while (swf_GetU8(tag)) // state -> parse ButtonRecord
235 { swf_GetU16(tag); // id
236 swf_GetU16(tag); // layer
237 swf_GetMatrix(tag,NULL); // matrix
239 actions = swf_ActionGet(tag);
240 swf_DumpActions(actions, prefix);
247 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
250 printf(" <%2d glyphs in font %2d, color #%02x%02x%02x%02x> ",nr, fontid, color->r, color->g, color->b, color->a);
251 for(t=0;t<fontnum;t++)
253 if(fonts[t]->id == fontid) {
263 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
264 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
267 a = fonts[font]->glyph2ascii[glyphs[t]];
274 printf("\\x%x", (int)a);
279 void handleText(TAG*tag)
282 swf_ParseDefineText(tag,textcallback, 0);
285 void handleDefineSound(TAG*tag)
287 U16 id = swf_GetU16(tag);
288 U8 flags = swf_GetU8(tag);
289 int compression = (flags>>4)&3;
290 int rate = (flags>>2)&3;
291 int bits = flags&2?16:8;
292 int stereo = flags&1;
294 if(compression == 0) printf("Raw ");
295 else if(compression == 1) printf("ADPCM ");
296 else if(compression == 2) printf("MP3 ");
298 if(rate == 0) printf("5.5Khz ");
299 if(rate == 1) printf("11Khz ");
300 if(rate == 2) printf("22Khz ");
301 if(rate == 3) printf("44Khz ");
302 printf("%dBit ", bits);
303 if(stereo) printf("stereo");
308 void handleDefineBits(TAG*tag)
314 id = swf_GetU16(tag);
315 mode = swf_GetU8(tag);
316 width = swf_GetU16(tag);
317 height = swf_GetU16(tag);
318 printf(" image %dx%d",width,height);
319 if(mode == 3) printf(" (8 bpp)");
320 else if(mode == 4) printf(" (16 bpp)");
321 else if(mode == 5) printf(" (32 bpp)");
322 else printf(" (? bpp)");
325 void handleEditText(TAG*tag)
330 id = swf_GetU16(tag);
333 //swf_ResetReadBits(tag);
339 flags = swf_GetBits(tag,16);
340 if(flags & ET_HASFONT) {
341 swf_GetU16(tag); //font
342 swf_GetU16(tag); //fontheight
344 if(flags & ET_HASTEXTCOLOR) {
345 swf_GetU8(tag); //rgba
350 if(flags & ET_HASMAXLENGTH) {
351 swf_GetU16(tag); //maxlength
353 if(flags & ET_HASLAYOUT) {
354 swf_GetU8(tag); //align
355 swf_GetU16(tag); //left margin
356 swf_GetU16(tag); //right margin
357 swf_GetU16(tag); //indent
358 swf_GetU16(tag); //leading
360 printf(" variable \"%s\" ", &tag->data[tag->pos]);
361 if(flags & ET_HTML) printf("(html)");
362 if(flags & ET_NOSELECT) printf("(noselect)");
363 if(flags & ET_PASSWORD) printf("(password)");
364 if(flags & ET_READONLY) printf("(readonly)");
366 if(flags & (ET_X1 | ET_X3 ))
368 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
371 while(tag->data[tag->pos++]);
372 if(flags & ET_HASTEXT)
373 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
376 void printhandlerflags(U32 handlerflags)
378 if(handlerflags&1) printf("[on load]");
379 if(handlerflags&2) printf("[enter frame]");
380 if(handlerflags&4) printf("[unload]");
381 if(handlerflags&8) printf("[mouse move]");
382 if(handlerflags&16) printf("[mouse down]");
383 if(handlerflags&32) printf("[mouse up]");
384 if(handlerflags&64) printf("[key down]");
385 if(handlerflags&128) printf("[key up]");
387 if(handlerflags&256) printf("[data]");
388 if(handlerflags&512) printf("[initialize]");
389 if(handlerflags&1024) printf("[mouse press]");
390 if(handlerflags&2048) printf("[mouse release]");
391 if(handlerflags&4096) printf("[mouse release outside]");
392 if(handlerflags&8192) printf("[mouse rollover]");
393 if(handlerflags&16384) printf("[mouse rollout]");
394 if(handlerflags&32768) printf("[mouse drag over]");
396 if(handlerflags&0x10000) printf("[mouse drag out]");
397 if(handlerflags&0x20000) printf("[key press]");
398 if(handlerflags&0x40000) printf("[construct even]");
399 if(handlerflags&0xfff80000) printf("[???]");
401 void handleVideoStream(TAG*tag, char*prefix)
403 U16 id = swf_GetU16(tag);
404 U16 frames = swf_GetU16(tag);
405 U16 width = swf_GetU16(tag);
406 U16 height = swf_GetU16(tag);
407 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
408 U8 codec = swf_GetU8(tag);
409 printf(" (%d frames, %dx%d", frames, width, height);
413 printf(" sorenson h.263)");
415 printf(" codec 0x%02x)", codec);
417 void handleVideoFrame(TAG*tag, char*prefix)
419 U32 code, version, reference, sizeflags;
420 U32 width=0, height=0;
422 U16 id = swf_GetU16(tag);
423 U16 frame = swf_GetU16(tag);
424 U8 deblock,flags, tmp, bit;
426 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
427 printf(" (frame %d) ", frame);
429 /* video packet follows */
430 code = swf_GetBits(tag, 17);
431 version = swf_GetBits(tag, 5);
432 reference = swf_GetBits(tag, 8);
434 sizeflags = swf_GetBits(tag, 3);
437 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
438 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
439 case 2: width = 352; height = 288; break;
440 case 3: width = 176; height = 144; break;
441 case 4: width = 128; height = 96; break;
442 case 5: width = 320; height = 240; break;
443 case 6: width = 160; height = 120; break;
444 case 7: width = -1; height = -1;/*reserved*/ break;
446 printf("%dx%d ", width, height);
447 type = swf_GetBits(tag, 2);
448 printf("%s", types[type]);
450 deblock = swf_GetBits(tag, 1);
452 printf(" deblock ", deblock);
453 quantizer = swf_GetBits(tag, 5);
454 printf(" quant: %d ", quantizer);
457 void handlePlaceObject2(TAG*tag, char*prefix)
459 U8 flags = swf_GetU8(tag);
463 int ppos[3] = {0,0,0};
464 swf_GetU16(tag); //depth
467 if(flags&2) swf_GetU16(tag); //id
469 swf_GetMatrix(tag,&m);
471 ppos[0] += sprintf(pstr[0], "| Matrix ");
472 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
473 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
477 swf_GetCXForm(tag, &cx, 1);
479 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
480 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);
481 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
485 U16 ratio = swf_GetU16(tag); //ratio
487 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
488 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
489 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
493 U16 clip = swf_GetU16(tag); //clip
495 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
496 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", clip);
497 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
500 if(flags&32) { while(swf_GetU8(tag)); }
501 if(placements && ppos[0]) {
503 printf("%s %s\n", prefix, pstr[0]);
504 printf("%s %s\n", prefix, pstr[1]);
505 printf("%s %s", prefix, pstr[2]);
514 reserved = swf_GetU16(tag); // must be 0
515 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
517 printf("Unknown parameter field not zero: %04x\n", reserved);
520 printf("global flags: %04x\n", globalflags);
522 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
524 handlerflags = swf_GetU32(tag);
527 while(handlerflags) {
532 globalflags &= ~handlerflags;
533 printf("%s flags %08x ",prefix, handlerflags);
534 printhandlerflags(handlerflags);
535 length = swf_GetU32(tag);
536 printf(", %d bytes actioncode\n",length);
537 a = swf_ActionGet(tag);
538 swf_DumpActions(a,prefix);
541 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
543 if(globalflags) // should go to sterr.
544 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
546 printf(" has action code\n");
551 void handlePlaceObject(TAG*tag, char*prefix)
553 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
555 U16 id = swf_GetU16(tag);
556 U16 depth = swf_GetU16(tag);
559 swf_GetMatrix(tag, &matrix);
560 swf_GetCXForm(tag, &cxform, 0);
563 swf_SetU16(tag2, depth);
564 swf_SetMatrix(tag2, &matrix);
565 swf_SetCXForm(tag2, &cxform, 1);
567 handlePlaceObject2(tag2, prefix);
570 char* fillstyle2str(FILLSTYLE*style)
572 switch(style->type) {
574 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
576 case 0x10: case 0x12:
577 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
579 case 0x40: case 0x41:
580 /* TODO: display information about that bitmap */
581 sprintf(stylebuf, "BITMAP %d", style->id_bitmap);
584 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
588 char* linestyle2str(LINESTYLE*style)
590 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
594 void handleShape(TAG*tag, char*prefix)
602 swf_ParseDefineShape(tag, &shape);
604 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
606 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
611 else printf("%s | (Neither line nor fill styles)\n", prefix);
614 printf("%s", prefix);
615 if(t < shape.numfillstyles) {
616 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
620 if(t < shape.numlinestyles) {
621 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
626 printf("%s |\n", prefix);
630 printf("%s | fill: %02d/%02d line:%02d - ",
635 if(line->type == moveTo) {
636 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
637 } else if(line->type == lineTo) {
638 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
639 } else if(line->type == splineTo) {
640 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
641 line->sx/20.0, line->sy/20.0,
642 line->x/20.0, line->y/20.0
647 printf("%s |\n", prefix);
650 void fontcallback1(void*self, U16 id,U8 * name)
654 void fontcallback2(void*self, U16 id,U8 * name)
656 swf_FontExtract(&swf,id,&fonts[fontnum]);
660 static U8 printable(U8 a)
662 if(a<32 || a==127) return '.';
665 void hexdumpTag(TAG*tag, char* prefix)
669 printf(" %s-=> ",prefix);
670 for(t=0;t<tag->len;t++) {
671 printf("%02x ", tag->data[t]);
672 ascii[t&15] = printable(tag->data[t]);
673 if((t && ((t&15)==15)) || (t==tag->len-1))
677 for(s=p-1;s<16;s++) {
681 printf(" %s\n", ascii);
683 printf(" %s\n %s-=> ",ascii,prefix);
688 void handleExportAssets(TAG*tag, char* prefix)
694 num = swf_GetU16(tag);
697 id = swf_GetU16(tag);
698 name = swf_GetString(tag);
699 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
703 void dumperror(const char* format, ...)
708 va_start(arglist, format);
709 vsprintf(buf, format, arglist);
713 printf("==== Error: %s ====\n", buf);
716 static char strbuf[800];
719 char* timestring(double f)
721 int hours = (int)(f/3600);
722 int minutes = (int)((f-hours*3600)/60);
723 int seconds = (int)((f-hours*3600-minutes*60));
724 int useconds = (int)((f-(int)f)*1000+0.5);
727 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
728 return &strbuf[bufpos];
731 int main (int argc,char ** argv)
739 char issprite = 0; // are we inside a sprite definition?
742 char* spriteframelabel = 0;
743 char* framelabel = 0;
747 memset(idtab,0,65536);
749 processargs(argc, argv);
753 fprintf(stderr, "You must supply a filename.\n");
757 f = open(filename,O_RDONLY|O_BINARY);
762 sprintf(buffer, "Couldn't open %s", filename);
766 if FAILED(swf_ReadSWF(f,&swf))
768 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
775 if(statbuf.st_size != swf.fileSize && !swf.compressed)
776 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
777 statbuf.st_size, swf.fileSize);
778 filesize = statbuf.st_size;
783 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
784 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
788 printf("-X %d", xsize);
794 printf("-Y %d", ysize);
800 printf("-r %.2f", swf.frameRate/256.0);
806 printf("-f %d", swf.frameCount);
813 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
814 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
815 if(swf.fileVersion>9) {
816 fprintf(stderr, "Fileversion>9\n");
819 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
821 //" BGCOLOR=#ffffffff\n"?
823 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
824 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
825 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
826 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
827 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
828 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
829 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
830 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
831 " TYPE=\"application/x-shockwave-flash\"\n"
832 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
834 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
835 filename, filename, xsize, ysize);
838 printf("[HEADER] File version: %d\n", swf.fileVersion);
840 printf("[HEADER] File is zlib compressed.");
841 if(filesize && swf.fileSize)
842 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
846 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
847 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
848 printf("[HEADER] Frame count: %d\n",swf.frameCount);
849 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
850 if(swf.movieSize.xmin)
851 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
854 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
855 if(swf.movieSize.ymin)
856 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
864 swf_FontEnumerate(&swf,&fontcallback1, 0);
865 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
867 swf_FontEnumerate(&swf,&fontcallback2, 0);
871 char*name = swf_TagGetName(tag);
874 dumperror("Unknown tag:0x%03x", tag->id);
878 if(swf_TagGetName(tag)) {
879 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
881 printf("[%03x] %9ld %sUNKNOWN TAG %03x", tag->id, tag->len, prefix, tag->id);
884 if(tag->id == ST_FREECHARACTER) {
885 U16 id = swf_GetU16(tag);
889 if(swf_isDefiningTag(tag)) {
890 U16 id = swf_GetDefineID(tag);
891 printf(" defines id %04d", id);
893 dumperror("Id %04d is defined more than once.", id);
896 else if(swf_isPseudoDefiningTag(tag)) {
897 U16 id = swf_GetDefineID(tag);
898 printf(" adds information to id %04d", id);
900 dumperror("Id %04d is not yet defined.\n", id);
902 else if(tag->id == ST_PLACEOBJECT) {
903 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
905 printf(" name \"%s\"",swf_GetName(tag));
907 else if(tag->id == ST_PLACEOBJECT2) {
914 printf(" id %04d",swf_GetPlaceID(tag));
918 printf(" at depth %04d", swf_GetDepth(tag));
920 printf(" name \"%s\"",swf_GetName(tag));
922 else if(tag->id == ST_REMOVEOBJECT) {
923 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
925 else if(tag->id == ST_REMOVEOBJECT2) {
926 printf(" removes object from depth %04d", swf_GetDepth(tag));
928 else if(tag->id == ST_FREECHARACTER) {
929 printf(" frees object %04d", swf_GetPlaceID(tag));
931 else if(tag->id == ST_STARTSOUND) {
934 id = swf_GetU16(tag);
935 flags = swf_GetU8(tag);
937 printf(" stops sound with id %04d", id);
939 printf(" starts sound with id %04d", id);
941 printf(" (if not already playing)");
947 printf(" looping %d times", swf_GetU16(tag));
950 else if(tag->id == ST_FRAMELABEL) {
951 int l = strlen(tag->data);
952 printf(" \"%s\"", tag->data);
954 printf(" has %d extra bytes", tag->len-1-l);
955 if(tag ->len-1-l == 1 && tag->data[tag->len-1] == 1)
958 if((framelabel && !issprite) ||
959 (spriteframelabel && issprite)) {
960 dumperror("Frame %d has more than one label",
961 issprite?spriteframe:mainframe);
963 if(issprite) spriteframelabel = tag->data;
964 else framelabel = tag->data;
966 else if(tag->id == ST_SHOWFRAME) {
967 char*label = issprite?spriteframelabel:framelabel;
968 int frame = issprite?spriteframe:mainframe;
971 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
973 if(issprite) spriteframe++;
979 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
981 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
982 timestring(frame*(256.0/(swf.frameRate+0.1))),
983 timestring(nframe*(256.0/(swf.frameRate+0.1)))
986 printf(" (label \"%s\")", label);
987 if(issprite) {spriteframe++; spriteframelabel = 0;}
988 if(!issprite) {mainframe++; framelabel = 0;}
991 if(tag->id == ST_SETBACKGROUNDCOLOR) {
992 U8 r = swf_GetU8(tag);
993 U8 g = swf_GetU8(tag);
994 U8 b = swf_GetU8(tag);
995 printf(" (%02x/%02x/%02x)\n",r,g,b);
997 else if(tag->id == ST_PROTECT) {
999 printf(" %s\n", swf_GetString(tag));
1004 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1005 tag->id == ST_DEFINEBITSLOSSLESS2) {
1006 handleDefineBits(tag);
1009 else if(tag->id == ST_DEFINESOUND) {
1010 handleDefineSound(tag);
1013 else if(tag->id == ST_VIDEOFRAME) {
1014 handleVideoFrame(tag, myprefix);
1017 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1018 handleVideoStream(tag, myprefix);
1021 else if(tag->id == ST_DEFINEEDITTEXT) {
1022 handleEditText(tag);
1025 else if(tag->id == ST_DEFINEMOVIE) {
1026 U16 id = swf_GetU16(tag);
1027 char*s = swf_GetString(tag);
1028 printf(" URL: %s\n", s);
1030 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1036 else if(tag->id == ST_PLACEOBJECT2) {
1038 else if(tag->id == ST_NAMECHARACTER) {
1040 printf(" \"%s\"\n", swf_GetString(tag));
1046 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1047 SRECT r = swf_GetDefineBBox(tag);
1048 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1055 sprintf(myprefix, " %s", prefix);
1057 if(tag->id == ST_DEFINESPRITE) {
1058 sprintf(prefix, " ");
1060 dumperror("Sprite definition inside a sprite definition");
1064 spriteframelabel = 0;
1066 else if(tag->id == ST_END) {
1069 spriteframelabel = 0;
1071 dumperror("End Tag not empty");
1073 else if(tag->id == ST_EXPORTASSETS) {
1074 handleExportAssets(tag, myprefix);
1076 else if(tag->id == ST_DOACTION && action) {
1078 actions = swf_ActionGet(tag);
1079 swf_DumpActions(actions, myprefix);
1081 else if(tag->id == ST_DOINITACTION && action) {
1083 swf_GetU16(tag); // id
1084 actions = swf_ActionGet(tag);
1085 swf_DumpActions(actions, myprefix);
1087 else if(tag->id == ST_DEFINEBUTTON && action) {
1088 dumpButtonActions(tag, myprefix);
1090 else if(tag->id == ST_DEFINEBUTTON2 && action) {
1091 dumpButton2Actions(tag, myprefix);
1093 else if(tag->id == ST_PLACEOBJECT) {
1094 handlePlaceObject(tag, myprefix);
1096 else if(tag->id == ST_PLACEOBJECT2) {
1097 handlePlaceObject2(tag, myprefix);
1099 else if(tag->id == ST_DEFINESHAPE ||
1100 tag->id == ST_DEFINESHAPE2 ||
1101 tag->id == ST_DEFINESHAPE3) {
1103 handleShape(tag, myprefix);
1106 if(tag->len && used) {
1107 int num = swf_GetNumUsedIDs(tag);
1111 used = (int*)malloc(sizeof(int)*num);
1112 swf_GetUsedIDs(tag, used);
1113 printf("%s%suses IDs: ", indent, prefix);
1114 for(t=0;t<num;t++) {
1116 swf_SetTagPos(tag, used[t]);
1117 id = swf_GetU16(tag);
1118 printf("%d%s", id, t<num-1?", ":"");
1120 dumperror("Id %04d is not yet defined.\n", id);
1127 if(tag->len && hex) {
1128 hexdumpTag(tag, prefix);