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;
56 static int showtext = 0;
57 static int showshapes = 0;
61 static int cumulative = 0;
63 static struct options_t options[] = {
83 int args_callback_option(char*name,char*val)
85 if(!strcmp(name, "V")) {
86 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
89 else if(name[0]=='a') {
93 else if(name[0]=='p') {
97 else if(name[0]=='t') {
101 else if(name[0]=='s') {
105 else if(name[0]=='e') {
109 else if(name[0]=='c') {
113 else if(name[0]=='E') {
118 else if(name[0]=='X') {
122 else if(name[0]=='Y') {
126 else if(name[0]=='r') {
130 else if(name[0]=='f') {
134 else if(name[0]=='d') {
138 else if(name[0]=='u') {
142 else if(name[0]=='b') {
146 else if(name[0]=='D') {
147 action = placements = showtext = showshapes = 1;
151 printf("Unknown option: -%s\n", name);
157 int args_callback_longoption(char*name,char*val)
159 return args_long2shortoption(options, name, val);
161 void args_callback_usage(char *name)
164 printf("Usage: %s [-atpdu] file.swf\n", name);
166 printf("-h , --help Print short help message and exit\n");
167 printf("-D , --full Show everything. Same as -atp\n");
168 printf("-V , --version Print version info and exit\n");
169 printf("-e , --html Print out html code for embedding the file\n");
170 printf("-E , --xhtml Print out xhtml code for embedding the file\n");
171 printf("-a , --action Disassemble action tags\n");
172 printf("-t , --text Show text fields (like swfstrings).\n");
173 printf("-s , --shapes Show shape coordinates/styles\n");
174 printf("-p , --placements Show placement information\n");
175 printf("-b , --bbox Print tag's bounding boxes\n");
176 printf("-X , --width Prints out a string of the form \"-X width\".\n");
177 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
178 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
179 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
180 printf("-d , --hex Print hex output of tag data, too.\n");
181 printf("-u , --used Show referred IDs for each Tag.\n");
184 int args_callback_command(char*name,char*val)
187 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
195 char* testfunc(char*str)
197 printf("%s: %s\n", what, str);
201 void dumpButton2Actions(TAG*tag, char*prefix)
207 oldTagPos = swf_GetTagPos(tag);
209 // scan DefineButton2 Record
211 swf_GetU16(tag); // Character ID
212 swf_GetU8(tag); // Flags;
214 offsetpos = swf_GetTagPos(tag); // first offset
217 while (swf_GetU8(tag)) // state -> parse ButtonRecord
218 { swf_GetU16(tag); // id
219 swf_GetU16(tag); // layer
220 swf_GetMatrix(tag,NULL); // matrix
221 swf_GetCXForm(tag,NULL,1); // cxform
228 if(tag->pos >= tag->len)
231 offsetpos = swf_GetU16(tag);
232 condition = swf_GetU16(tag); // condition
234 actions = swf_ActionGet(tag);
235 printf("%s condition %04x\n", prefix, condition);
236 swf_DumpActions(actions, prefix);
239 swf_SetTagPos(tag,oldTagPos);
243 void dumpButtonActions(TAG*tag, char*prefix)
246 swf_GetU16(tag); // id
247 while (swf_GetU8(tag)) // state -> parse ButtonRecord
248 { swf_GetU16(tag); // id
249 swf_GetU16(tag); // layer
250 swf_GetMatrix(tag,NULL); // matrix
252 actions = swf_ActionGet(tag);
253 swf_DumpActions(actions, prefix);
260 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
263 printf(" <%2d glyphs in font %2d, color #%02x%02x%02x%02x> ",nr, fontid, color->r, color->g, color->b, color->a);
264 for(t=0;t<fontnum;t++)
266 if(fonts[t]->id == fontid) {
276 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
277 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
280 if(fonts[font]->glyph2ascii[glyphs[t]])
281 a = fonts[font]->glyph2ascii[glyphs[t]];
291 printf("\\x%x", (int)a);
296 void handleText(TAG*tag)
299 swf_ParseDefineText(tag,textcallback, 0);
302 void handleDefineSound(TAG*tag)
304 U16 id = swf_GetU16(tag);
305 U8 flags = swf_GetU8(tag);
306 int compression = (flags>>4)&3;
307 int rate = (flags>>2)&3;
308 int bits = flags&2?16:8;
309 int stereo = flags&1;
311 if(compression == 0) printf("Raw ");
312 else if(compression == 1) printf("ADPCM ");
313 else if(compression == 2) printf("MP3 ");
315 if(rate == 0) printf("5.5Khz ");
316 if(rate == 1) printf("11Khz ");
317 if(rate == 2) printf("22Khz ");
318 if(rate == 3) printf("44Khz ");
319 printf("%dBit ", bits);
320 if(stereo) printf("stereo");
325 void handleDefineBits(TAG*tag)
331 id = swf_GetU16(tag);
332 mode = swf_GetU8(tag);
333 width = swf_GetU16(tag);
334 height = swf_GetU16(tag);
335 printf(" image %dx%d",width,height);
336 if(mode == 3) printf(" (8 bpp)");
337 else if(mode == 4) printf(" (16 bpp)");
338 else if(mode == 5) printf(" (32 bpp)");
339 else printf(" (? bpp)");
342 void handleEditText(TAG*tag)
347 id = swf_GetU16(tag);
350 //swf_ResetReadBits(tag);
356 flags = swf_GetBits(tag,16);
357 if(flags & ET_HASFONT) {
358 swf_GetU16(tag); //font
359 swf_GetU16(tag); //fontheight
361 if(flags & ET_HASTEXTCOLOR) {
362 swf_GetU8(tag); //rgba
367 if(flags & ET_HASMAXLENGTH) {
368 swf_GetU16(tag); //maxlength
370 if(flags & ET_HASLAYOUT) {
371 swf_GetU8(tag); //align
372 swf_GetU16(tag); //left margin
373 swf_GetU16(tag); //right margin
374 swf_GetU16(tag); //indent
375 swf_GetU16(tag); //leading
377 printf(" variable \"%s\" ", &tag->data[tag->pos]);
378 if(flags & ET_HTML) printf("(html)");
379 if(flags & ET_NOSELECT) printf("(noselect)");
380 if(flags & ET_PASSWORD) printf("(password)");
381 if(flags & ET_READONLY) printf("(readonly)");
383 if(flags & (ET_X1 | ET_X3 ))
385 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
388 while(tag->data[tag->pos++]);
389 if(flags & ET_HASTEXT)
390 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
393 void printhandlerflags(U32 handlerflags)
395 if(handlerflags&1) printf("[on load]");
396 if(handlerflags&2) printf("[enter frame]");
397 if(handlerflags&4) printf("[unload]");
398 if(handlerflags&8) printf("[mouse move]");
399 if(handlerflags&16) printf("[mouse down]");
400 if(handlerflags&32) printf("[mouse up]");
401 if(handlerflags&64) printf("[key down]");
402 if(handlerflags&128) printf("[key up]");
404 if(handlerflags&256) printf("[data]");
405 if(handlerflags&512) printf("[initialize]");
406 if(handlerflags&1024) printf("[mouse press]");
407 if(handlerflags&2048) printf("[mouse release]");
408 if(handlerflags&4096) printf("[mouse release outside]");
409 if(handlerflags&8192) printf("[mouse rollover]");
410 if(handlerflags&16384) printf("[mouse rollout]");
411 if(handlerflags&32768) printf("[mouse drag over]");
413 if(handlerflags&0x10000) printf("[mouse drag out]");
414 if(handlerflags&0x20000) printf("[key press]");
415 if(handlerflags&0x40000) printf("[construct even]");
416 if(handlerflags&0xfff80000) printf("[???]");
418 void handleVideoStream(TAG*tag, char*prefix)
420 U16 id = swf_GetU16(tag);
421 U16 frames = swf_GetU16(tag);
422 U16 width = swf_GetU16(tag);
423 U16 height = swf_GetU16(tag);
424 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
425 U8 codec = swf_GetU8(tag);
426 printf(" (%d frames, %dx%d", frames, width, height);
430 printf(" sorenson h.263)");
432 printf(" codec 0x%02x)", codec);
434 void handleVideoFrame(TAG*tag, char*prefix)
436 U32 code, version, reference, sizeflags;
437 U32 width=0, height=0;
439 U16 id = swf_GetU16(tag);
440 U16 frame = swf_GetU16(tag);
441 U8 deblock,flags, tmp, bit;
443 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
444 printf(" (frame %d) ", frame);
446 /* video packet follows */
447 code = swf_GetBits(tag, 17);
448 version = swf_GetBits(tag, 5);
449 reference = swf_GetBits(tag, 8);
451 sizeflags = swf_GetBits(tag, 3);
454 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
455 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
456 case 2: width = 352; height = 288; break;
457 case 3: width = 176; height = 144; break;
458 case 4: width = 128; height = 96; break;
459 case 5: width = 320; height = 240; break;
460 case 6: width = 160; height = 120; break;
461 case 7: width = -1; height = -1;/*reserved*/ break;
463 printf("%dx%d ", width, height);
464 type = swf_GetBits(tag, 2);
465 printf("%s", types[type]);
467 deblock = swf_GetBits(tag, 1);
469 printf(" deblock ", deblock);
470 quantizer = swf_GetBits(tag, 5);
471 printf(" quant: %d ", quantizer);
474 void handlePlaceObject2(TAG*tag, char*prefix)
480 int ppos[3] = {0,0,0};
481 swf_SetTagPos(tag, 0);
482 flags = swf_GetU8(tag);
483 swf_GetU16(tag); //depth
486 if(flags&2) swf_GetU16(tag); //id
488 swf_GetMatrix(tag,&m);
490 ppos[0] += sprintf(pstr[0], "| Matrix ");
491 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
492 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
496 swf_GetCXForm(tag, &cx, 1);
498 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
499 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);
500 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
504 U16 ratio = swf_GetU16(tag); //ratio
506 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
507 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
508 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
512 U16 clip = swf_GetU16(tag); //clip
514 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
515 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", clip);
516 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
519 if(flags&32) { while(swf_GetU8(tag)); }
520 if(placements && ppos[0]) {
522 printf("%s %s\n", prefix, pstr[0]);
523 printf("%s %s\n", prefix, pstr[1]);
524 printf("%s %s", prefix, pstr[2]);
533 reserved = swf_GetU16(tag); // must be 0
534 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
536 printf("Unknown parameter field not zero: %04x\n", reserved);
539 printf("global flags: %04x\n", globalflags);
541 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
543 handlerflags = swf_GetU32(tag);
546 while(handlerflags) {
551 globalflags &= ~handlerflags;
552 printf("%s flags %08x ",prefix, handlerflags);
553 printhandlerflags(handlerflags);
554 length = swf_GetU32(tag);
555 printf(", %d bytes actioncode\n",length);
556 a = swf_ActionGet(tag);
557 swf_DumpActions(a,prefix);
560 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
562 if(globalflags) // should go to sterr.
563 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
565 printf(" has action code\n");
570 void handlePlaceObject(TAG*tag, char*prefix)
572 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
577 swf_SetTagPos(tag, 0);
578 id = swf_GetU16(tag);
579 depth = swf_GetU16(tag);
580 swf_GetMatrix(tag, &matrix);
581 swf_GetCXForm(tag, &cxform, 0);
583 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
584 swf_SetU16(tag2, depth);
585 swf_SetU16(tag2, id);
586 swf_SetMatrix(tag2, &matrix);
587 swf_SetCXForm(tag2, &cxform, 1);
589 handlePlaceObject2(tag2, prefix);
592 char* fillstyle2str(FILLSTYLE*style)
594 switch(style->type) {
596 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
598 case 0x10: case 0x12:
599 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
602 /* TODO: display information about that bitmap */
603 sprintf(stylebuf, "BITMAPt %d", style->id_bitmap);
604 /* TODO: show matrix */
607 /* TODO: display information about that bitmap */
608 sprintf(stylebuf, "BITMAPc %d", style->id_bitmap);
609 /* TODO: show matrix */
612 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
616 char* linestyle2str(LINESTYLE*style)
618 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
622 void handleShape(TAG*tag, char*prefix)
630 swf_ParseDefineShape(tag, &shape);
632 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
634 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
639 else printf("%s | (Neither line nor fill styles)\n", prefix);
642 printf("%s", prefix);
643 if(t < shape.numfillstyles) {
644 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
648 if(t < shape.numlinestyles) {
649 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
654 printf("%s |\n", prefix);
658 printf("%s | fill: %02d/%02d line:%02d - ",
663 if(line->type == moveTo) {
664 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
665 } else if(line->type == lineTo) {
666 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
667 } else if(line->type == splineTo) {
668 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
669 line->sx/20.0, line->sy/20.0,
670 line->x/20.0, line->y/20.0
675 printf("%s |\n", prefix);
678 void fontcallback1(void*self, U16 id,U8 * name)
682 void fontcallback2(void*self, U16 id,U8 * name)
684 swf_FontExtract(&swf,id,&fonts[fontnum]);
688 static U8 printable(U8 a)
690 if(a<32 || a==127) return '.';
693 void hexdumpTag(TAG*tag, char* prefix)
697 printf(" %s-=> ",prefix);
698 for(t=0;t<tag->len;t++) {
699 printf("%02x ", tag->data[t]);
700 ascii[t&15] = printable(tag->data[t]);
701 if((t && ((t&15)==15)) || (t==tag->len-1))
705 for(s=p-1;s<16;s++) {
709 printf(" %s\n", ascii);
711 printf(" %s\n %s-=> ",ascii,prefix);
716 void handleExportAssets(TAG*tag, char* prefix)
722 num = swf_GetU16(tag);
725 id = swf_GetU16(tag);
726 name = swf_GetString(tag);
727 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
731 void dumperror(const char* format, ...)
736 va_start(arglist, format);
737 vsprintf(buf, format, arglist);
741 printf("==== Error: %s ====\n", buf);
744 static char strbuf[800];
747 char* timestring(double f)
749 int hours = (int)(f/3600);
750 int minutes = (int)((f-hours*3600)/60);
751 int seconds = (int)((f-hours*3600-minutes*60));
752 int useconds = (int)((f-(int)f)*1000+0.5);
755 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
756 return &strbuf[bufpos];
759 int main (int argc,char ** argv)
767 char issprite = 0; // are we inside a sprite definition?
770 char* spriteframelabel = 0;
771 char* framelabel = 0;
776 memset(idtab,0,65536);
778 processargs(argc, argv);
782 fprintf(stderr, "You must supply a filename.\n");
786 f = open(filename,O_RDONLY|O_BINARY);
791 sprintf(buffer, "Couldn't open %s", filename);
795 if FAILED(swf_ReadSWF(f,&swf))
797 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
804 if(statbuf.st_size != swf.fileSize && !swf.compressed)
805 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
806 statbuf.st_size, swf.fileSize);
807 filesize = statbuf.st_size;
812 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
813 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
817 printf("-X %d", xsize);
823 printf("-Y %d", ysize);
829 printf("-r %.2f", swf.frameRate/256.0);
835 printf("-f %d", swf.frameCount);
842 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
843 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
844 if(swf.fileVersion>9) {
845 fprintf(stderr, "Fileversion>9\n");
850 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
851 "<param name=\"movie\" value=\"%s\"/>\n"
852 "<param name=\"play\" value=\"true\"/>\n"
853 "<param name=\"loop\" value=\"false\"/>\n"
854 "<param name=\"quality\" value=\"high\"/>\n"
855 "<param name=\"loop\" value=\"false\"/>\n"
856 "</object>\n\n", filename, xsize, ysize, filename);
858 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
860 //" BGCOLOR=#ffffffff\n"?
862 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
863 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
864 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
865 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
866 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
867 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
868 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
869 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
870 " TYPE=\"application/x-shockwave-flash\"\n"
871 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
873 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
874 filename, filename, xsize, ysize);
878 printf("[HEADER] File version: %d\n", swf.fileVersion);
880 printf("[HEADER] File is zlib compressed.");
881 if(filesize && swf.fileSize)
882 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
886 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
887 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
888 printf("[HEADER] Frame count: %d\n",swf.frameCount);
889 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
890 if(swf.movieSize.xmin)
891 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
894 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
895 if(swf.movieSize.ymin)
896 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
904 swf_FontEnumerate(&swf,&fontcallback1, 0);
905 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
907 swf_FontEnumerate(&swf,&fontcallback2, 0);
911 char*name = swf_TagGetName(tag);
914 dumperror("Unknown tag:0x%03x", tag->id);
919 name = "UNKNOWN TAG";
923 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
925 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
928 if(swf_isDefiningTag(tag)) {
929 U16 id = swf_GetDefineID(tag);
930 printf(" defines id %04d", id);
932 dumperror("Id %04d is defined more than once.", id);
935 else if(swf_isPseudoDefiningTag(tag)) {
936 U16 id = swf_GetDefineID(tag);
937 printf(" adds information to id %04d", id);
939 dumperror("Id %04d is not yet defined.\n", id);
941 else if(tag->id == ST_PLACEOBJECT) {
942 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
944 printf(" name \"%s\"",swf_GetName(tag));
946 else if(tag->id == ST_PLACEOBJECT2) {
953 printf(" id %04d",swf_GetPlaceID(tag));
957 printf(" at depth %04d", swf_GetDepth(tag));
959 swf_SetTagPos(tag, 0);
960 if(tag->data[0]&64) {
962 swf_GetPlaceObject(tag, &po);
963 printf(" (clip to %04d)", po.clipdepth);
964 swf_PlaceObjectFree(&po);
967 printf(" name \"%s\"",swf_GetName(tag));
970 else if(tag->id == ST_REMOVEOBJECT) {
971 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
973 else if(tag->id == ST_REMOVEOBJECT2) {
974 printf(" removes object from depth %04d", swf_GetDepth(tag));
976 else if(tag->id == ST_FREECHARACTER) {
977 printf(" frees object %04d", swf_GetPlaceID(tag));
979 else if(tag->id == ST_STARTSOUND) {
982 id = swf_GetU16(tag);
983 flags = swf_GetU8(tag);
985 printf(" stops sound with id %04d", id);
987 printf(" starts sound with id %04d", id);
989 printf(" (if not already playing)");
995 printf(" looping %d times", swf_GetU16(tag));
998 else if(tag->id == ST_FRAMELABEL) {
999 int l = strlen(tag->data);
1000 printf(" \"%s\"", tag->data);
1001 if((l+1) < tag->len) {
1002 printf(" has %d extra bytes", tag->len-1-l);
1003 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1004 printf(" (ANCHOR)");
1006 if((framelabel && !issprite) ||
1007 (spriteframelabel && issprite)) {
1008 dumperror("Frame %d has more than one label",
1009 issprite?spriteframe:mainframe);
1011 if(issprite) spriteframelabel = tag->data;
1012 else framelabel = tag->data;
1014 else if(tag->id == ST_SHOWFRAME) {
1015 char*label = issprite?spriteframelabel:framelabel;
1016 int frame = issprite?spriteframe:mainframe;
1019 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1021 if(issprite) spriteframe++;
1027 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1029 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1030 timestring(frame*(256.0/(swf.frameRate+0.1))),
1031 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1034 printf(" (label \"%s\")", label);
1035 if(issprite) {spriteframe++; spriteframelabel = 0;}
1036 if(!issprite) {mainframe++; framelabel = 0;}
1039 if(tag->id == ST_SETBACKGROUNDCOLOR) {
1040 U8 r = swf_GetU8(tag);
1041 U8 g = swf_GetU8(tag);
1042 U8 b = swf_GetU8(tag);
1043 printf(" (%02x/%02x/%02x)\n",r,g,b);
1045 else if(tag->id == ST_PROTECT) {
1047 printf(" %s\n", swf_GetString(tag));
1052 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1053 tag->id == ST_DEFINEBITSLOSSLESS2) {
1054 handleDefineBits(tag);
1057 else if(tag->id == ST_DEFINESOUND) {
1058 handleDefineSound(tag);
1061 else if(tag->id == ST_VIDEOFRAME) {
1062 handleVideoFrame(tag, myprefix);
1065 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1066 handleVideoStream(tag, myprefix);
1069 else if(tag->id == ST_DEFINEEDITTEXT) {
1070 handleEditText(tag);
1073 else if(tag->id == ST_DEFINEMOVIE) {
1074 U16 id = swf_GetU16(tag);
1075 char*s = swf_GetString(tag);
1076 printf(" URL: %s\n", s);
1078 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1084 else if(tag->id == ST_PLACEOBJECT2) {
1086 else if(tag->id == ST_NAMECHARACTER) {
1088 printf(" \"%s\"\n", swf_GetString(tag));
1094 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1095 SRECT r = swf_GetDefineBBox(tag);
1096 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1103 sprintf(myprefix, " %s", prefix);
1105 if(tag->id == ST_DEFINESPRITE) {
1106 sprintf(prefix, " ");
1108 dumperror("Sprite definition inside a sprite definition");
1112 spriteframelabel = 0;
1114 else if(tag->id == ST_END) {
1117 spriteframelabel = 0;
1119 dumperror("End Tag not empty");
1121 else if(tag->id == ST_EXPORTASSETS) {
1122 handleExportAssets(tag, myprefix);
1124 else if(tag->id == ST_DOACTION && action) {
1126 actions = swf_ActionGet(tag);
1127 swf_DumpActions(actions, myprefix);
1129 else if(tag->id == ST_DOINITACTION && action) {
1131 swf_GetU16(tag); // id
1132 actions = swf_ActionGet(tag);
1133 swf_DumpActions(actions, myprefix);
1135 else if(tag->id == ST_DEFINEBUTTON && action) {
1136 dumpButtonActions(tag, myprefix);
1138 else if(tag->id == ST_DEFINEBUTTON2 && action) {
1139 dumpButton2Actions(tag, myprefix);
1141 else if(tag->id == ST_PLACEOBJECT) {
1142 handlePlaceObject(tag, myprefix);
1144 else if(tag->id == ST_PLACEOBJECT2) {
1145 handlePlaceObject2(tag, myprefix);
1147 else if(tag->id == ST_DEFINESHAPE ||
1148 tag->id == ST_DEFINESHAPE2 ||
1149 tag->id == ST_DEFINESHAPE3) {
1151 handleShape(tag, myprefix);
1154 if(tag->len && used) {
1155 int num = swf_GetNumUsedIDs(tag);
1159 used = (int*)malloc(sizeof(int)*num);
1160 swf_GetUsedIDs(tag, used);
1161 printf("%s%suses IDs: ", indent, prefix);
1162 for(t=0;t<num;t++) {
1164 swf_SetTagPos(tag, used[t]);
1165 id = swf_GetU16(tag);
1166 printf("%d%s", id, t<num-1?", ":"");
1168 dumperror("Id %04d is not yet defined.\n", id);
1175 if(tag->id == ST_FREECHARACTER) {
1177 swf_SetTagPos(tag, 0);
1178 id = swf_GetU16(tag);
1182 if(tag->len && hex) {
1183 hexdumpTag(tag, prefix);