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;
62 static int showfonts = 0;
64 static struct options_t options[] = {
84 int args_callback_option(char*name,char*val)
86 if(!strcmp(name, "V")) {
87 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
90 else if(name[0]=='a') {
94 else if(name[0]=='p') {
98 else if(name[0]=='t') {
102 else if(name[0]=='s') {
106 else if(name[0]=='e') {
110 else if(name[0]=='c') {
114 else if(name[0]=='E') {
119 else if(name[0]=='X') {
123 else if(name[0]=='Y') {
127 else if(name[0]=='r') {
131 else if(name[0]=='f') {
135 else if(name[0]=='F') {
139 else if(name[0]=='d') {
143 else if(name[0]=='u') {
147 else if(name[0]=='b') {
151 else if(name[0]=='D') {
152 action = placements = showtext = showshapes = 1;
156 printf("Unknown option: -%s\n", name);
162 int args_callback_longoption(char*name,char*val)
164 return args_long2shortoption(options, name, val);
166 void args_callback_usage(char *name)
169 printf("Usage: %s [-atpdu] file.swf\n", name);
171 printf("-h , --help Print short help message and exit\n");
172 printf("-D , --full Show everything. Same as -atp\n");
173 printf("-V , --version Print version info and exit\n");
174 printf("-e , --html Print out html code for embedding the file\n");
175 printf("-E , --xhtml Print out xhtml code for embedding the file\n");
176 printf("-a , --action Disassemble action tags\n");
177 printf("-t , --text Show text fields (like swfstrings).\n");
178 printf("-s , --shapes Show shape coordinates/styles\n");
179 printf("-p , --placements Show placement information\n");
180 printf("-b , --bbox Print tag's bounding boxes\n");
181 printf("-X , --width Prints out a string of the form \"-X width\".\n");
182 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
183 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
184 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
185 printf("-d , --hex Print hex output of tag data, too.\n");
186 printf("-u , --used Show referred IDs for each Tag.\n");
189 int args_callback_command(char*name,char*val)
192 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
200 char* testfunc(char*str)
202 printf("%s: %s\n", what, str);
206 void dumpButton2Actions(TAG*tag, char*prefix)
212 oldTagPos = swf_GetTagPos(tag);
214 // scan DefineButton2 Record
216 swf_GetU16(tag); // Character ID
217 swf_GetU8(tag); // Flags;
219 offsetpos = swf_GetTagPos(tag); // first offset
222 while (swf_GetU8(tag)) // state -> parse ButtonRecord
223 { swf_GetU16(tag); // id
224 swf_GetU16(tag); // layer
225 swf_GetMatrix(tag,NULL); // matrix
226 swf_GetCXForm(tag,NULL,1); // cxform
233 if(tag->pos >= tag->len)
236 offsetpos = swf_GetU16(tag);
237 condition = swf_GetU16(tag); // condition
239 actions = swf_ActionGet(tag);
240 printf("%s condition %04x\n", prefix, condition);
241 swf_DumpActions(actions, prefix);
244 swf_SetTagPos(tag,oldTagPos);
248 void dumpButtonActions(TAG*tag, char*prefix)
251 swf_GetU16(tag); // id
252 while (swf_GetU8(tag)) // state -> parse ButtonRecord
253 { swf_GetU16(tag); // id
254 swf_GetU16(tag); // layer
255 swf_GetMatrix(tag,NULL); // matrix
257 actions = swf_ActionGet(tag);
258 swf_DumpActions(actions, prefix);
261 void dumpFont(TAG*tag, char*prefix)
263 SWFFONT* font = malloc(sizeof(SWFFONT));
264 memset(font, 0, sizeof(SWFFONT));
265 if(tag->id == ST_DEFINEFONT2) {
266 swf_FontExtract_DefineFont2(0, font, tag);
267 } else if(tag->id == ST_DEFINEFONT) {
268 swf_FontExtract_DefineFont(0, font, tag);
270 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
272 printf("%sID: %d\n", prefix,font->id);
273 printf("%sVersion: %d\n", prefix,font->version);
274 printf("%sname: %s\n", prefix,font->name);
275 printf("%scharacters: %d\n", prefix,font->numchars);
276 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
279 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
280 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
281 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
282 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
284 printf("%sstyle: %d\n", prefix,font->style);
285 printf("%sencoding: %02x\n", prefix,font->encoding);
286 printf("%slanguage: %02x\n", prefix,font->language);
288 for(t=0;t<font->numchars;t++) {
289 int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
290 printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
291 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
292 SHAPELINE*line = shape->lines;
295 if(line->type == moveTo) {
296 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
297 } else if(line->type == lineTo) {
298 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
299 } else if(line->type == splineTo) {
300 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
301 line->sx/20.0, line->sy/20.0,
302 line->x/20.0, line->y/20.0
307 swf_Shape2Free(shape);
317 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
320 printf(" <%2d glyphs in font %2d, color #%02x%02x%02x%02x> ",nr, fontid, color->r, color->g, color->b, color->a);
321 for(t=0;t<fontnum;t++)
323 if(fonts[t]->id == fontid) {
333 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
334 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
337 if(fonts[font]->glyph2ascii[glyphs[t]])
338 a = fonts[font]->glyph2ascii[glyphs[t]];
348 printf("\\x%x", (int)a);
353 void handleText(TAG*tag)
356 swf_ParseDefineText(tag,textcallback, 0);
359 void handleDefineSound(TAG*tag)
361 U16 id = swf_GetU16(tag);
362 U8 flags = swf_GetU8(tag);
363 int compression = (flags>>4)&7;
364 int rate = (flags>>2)&3;
365 int bits = flags&2?16:8;
366 int stereo = flags&1;
368 if(compression == 0) printf("Raw ");
369 else if(compression == 1) printf("ADPCM ");
370 else if(compression == 2) printf("MP3 ");
371 else if(compression == 3) printf("Raw little-endian ");
372 else if(compression == 6) printf("ASAO ");
374 if(rate == 0) printf("5.5Khz ");
375 if(rate == 1) printf("11Khz ");
376 if(rate == 2) printf("22Khz ");
377 if(rate == 3) printf("44Khz ");
378 printf("%dBit ", bits);
379 if(stereo) printf("stereo");
384 void handleDefineBits(TAG*tag)
390 id = swf_GetU16(tag);
391 mode = swf_GetU8(tag);
392 width = swf_GetU16(tag);
393 height = swf_GetU16(tag);
394 printf(" image %dx%d",width,height);
395 if(mode == 3) printf(" (8 bpp)");
396 else if(mode == 4) printf(" (16 bpp)");
397 else if(mode == 5) printf(" (32 bpp)");
398 else printf(" (? bpp)");
401 void handleEditText(TAG*tag)
406 id = swf_GetU16(tag);
409 //swf_ResetReadBits(tag);
415 flags = swf_GetBits(tag,16);
416 if(flags & ET_HASFONT) {
417 swf_GetU16(tag); //font
418 swf_GetU16(tag); //fontheight
420 if(flags & ET_HASTEXTCOLOR) {
421 swf_GetU8(tag); //rgba
426 if(flags & ET_HASMAXLENGTH) {
427 swf_GetU16(tag); //maxlength
429 if(flags & ET_HASLAYOUT) {
430 swf_GetU8(tag); //align
431 swf_GetU16(tag); //left margin
432 swf_GetU16(tag); //right margin
433 swf_GetU16(tag); //indent
434 swf_GetU16(tag); //leading
436 printf(" variable \"%s\" ", &tag->data[tag->pos]);
437 if(flags & ET_HTML) printf("(html)");
438 if(flags & ET_NOSELECT) printf("(noselect)");
439 if(flags & ET_PASSWORD) printf("(password)");
440 if(flags & ET_READONLY) printf("(readonly)");
442 if(flags & (ET_X1 | ET_X3 ))
444 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
447 while(tag->data[tag->pos++]);
448 if(flags & ET_HASTEXT)
449 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
452 void printhandlerflags(U32 handlerflags)
454 if(handlerflags&1) printf("[on load]");
455 if(handlerflags&2) printf("[enter frame]");
456 if(handlerflags&4) printf("[unload]");
457 if(handlerflags&8) printf("[mouse move]");
458 if(handlerflags&16) printf("[mouse down]");
459 if(handlerflags&32) printf("[mouse up]");
460 if(handlerflags&64) printf("[key down]");
461 if(handlerflags&128) printf("[key up]");
463 if(handlerflags&256) printf("[data]");
464 if(handlerflags&512) printf("[initialize]");
465 if(handlerflags&1024) printf("[mouse press]");
466 if(handlerflags&2048) printf("[mouse release]");
467 if(handlerflags&4096) printf("[mouse release outside]");
468 if(handlerflags&8192) printf("[mouse rollover]");
469 if(handlerflags&16384) printf("[mouse rollout]");
470 if(handlerflags&32768) printf("[mouse drag over]");
472 if(handlerflags&0x10000) printf("[mouse drag out]");
473 if(handlerflags&0x20000) printf("[key press]");
474 if(handlerflags&0x40000) printf("[construct even]");
475 if(handlerflags&0xfff80000) printf("[???]");
477 void handleVideoStream(TAG*tag, char*prefix)
479 U16 id = swf_GetU16(tag);
480 U16 frames = swf_GetU16(tag);
481 U16 width = swf_GetU16(tag);
482 U16 height = swf_GetU16(tag);
483 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
484 U8 codec = swf_GetU8(tag);
485 printf(" (%d frames, %dx%d", frames, width, height);
489 printf(" sorenson h.263)");
491 printf(" codec 0x%02x)", codec);
493 void handleVideoFrame(TAG*tag, char*prefix)
495 U32 code, version, reference, sizeflags;
496 U32 width=0, height=0;
498 U16 id = swf_GetU16(tag);
499 U16 frame = swf_GetU16(tag);
500 U8 deblock,flags, tmp, bit;
502 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
503 printf(" (frame %d) ", frame);
505 /* video packet follows */
506 code = swf_GetBits(tag, 17);
507 version = swf_GetBits(tag, 5);
508 reference = swf_GetBits(tag, 8);
510 sizeflags = swf_GetBits(tag, 3);
513 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
514 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
515 case 2: width = 352; height = 288; break;
516 case 3: width = 176; height = 144; break;
517 case 4: width = 128; height = 96; break;
518 case 5: width = 320; height = 240; break;
519 case 6: width = 160; height = 120; break;
520 case 7: width = -1; height = -1;/*reserved*/ break;
522 printf("%dx%d ", width, height);
523 type = swf_GetBits(tag, 2);
524 printf("%s", types[type]);
526 deblock = swf_GetBits(tag, 1);
528 printf(" deblock ", deblock);
529 quantizer = swf_GetBits(tag, 5);
530 printf(" quant: %d ", quantizer);
533 void dumpFilter(FILTER*filter)
535 if(filter->type == FILTERTYPE_BLUR) {
536 FILTER_BLUR*f = (FILTER_BLUR*)filter;
537 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
538 printf("passes: %d\n", f->passes);
539 } if(filter->type == FILTERTYPE_DROPSHADOW) {
540 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
541 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
542 printf("passes: %d\n", f->passes);
543 printf("angle: %f distance: %f\n", f->angle, f->distance);
544 printf("strength: %f passes: %d\n", f->strength, f->passes);
545 printf("flags: %s%s%s\n",
546 f->knockout?"knockout ":"",
547 f->composite?"composite ":"",
548 f->innershadow?"innershadow ":"");
549 } if(filter->type == FILTERTYPE_BEVEL) {
550 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
551 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
552 printf("passes: %d\n", f->passes);
553 printf("angle: %f distance: %f\n", f->angle, f->distance);
554 printf("strength: %f passes: %d\n", f->strength, f->passes);
555 printf("flags: %s%s%s%s\n",
557 f->knockout?"knockout ":"",
558 f->composite?"composite ":"",
559 f->innershadow?"innershadow ":"");
560 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
561 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
562 swf_DumpGradient(stdout, f->gradient);
563 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
564 printf("angle: %f distance: %f\n", f->angle, f->distance);
565 printf("strength: %f passes: %d\n", f->strength, f->passes);
566 printf("flags: %s%s%s%s\n",
567 f->knockout?"knockout ":"",
568 f->ontop?"ontop ":"",
569 f->composite?"composite ":"",
570 f->innershadow?"innershadow ":"");
575 void handlePlaceObject23(TAG*tag, char*prefix)
581 int ppos[3] = {0,0,0};
582 swf_SetTagPos(tag, 0);
583 flags = swf_GetU8(tag);
584 if(tag->id == ST_PLACEOBJECT3)
585 flags2 = swf_GetU8(tag);
586 swf_GetU16(tag); //depth
589 if(flags&2) swf_GetU16(tag); //id
591 swf_GetMatrix(tag,&m);
593 ppos[0] += sprintf(pstr[0], "| Matrix ");
594 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
595 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
599 swf_GetCXForm(tag, &cx, 1);
601 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
602 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);
603 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
607 U16 ratio = swf_GetU16(tag); //ratio
609 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
610 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
611 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
615 U16 clip = swf_GetU16(tag); //clip
617 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
618 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
619 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
622 if(flags&32) { while(swf_GetU8(tag)); }
624 if(flags2&1) { // filter list
625 U8 num = swf_GetU8(tag);
627 printf("\n%d filters\n", num);
628 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
631 FILTER*filter = swf_GetFilter(tag);
637 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
642 if(flags2&2) { // blend mode
643 U8 blendmode = swf_GetU8(tag);
647 sprintf(name, "%-5d", blendmode);
648 for(t=0;blendModeNames[t];t++) {
650 sprintf(name, "%-5s", blendModeNames[t]);
654 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
655 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
656 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
660 if(placements && ppos[0]) {
662 printf("%s %s\n", prefix, pstr[0]);
663 printf("%s %s\n", prefix, pstr[1]);
664 printf("%s %s", prefix, pstr[2]);
673 reserved = swf_GetU16(tag); // must be 0
674 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
676 printf("Unknown parameter field not zero: %04x\n", reserved);
679 printf("global flags: %04x\n", globalflags);
681 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
683 handlerflags = swf_GetU32(tag);
686 while(handlerflags) {
691 globalflags &= ~handlerflags;
692 printf("%s flags %08x ",prefix, handlerflags);
693 printhandlerflags(handlerflags);
694 length = swf_GetU32(tag);
695 printf(", %d bytes actioncode\n",length);
696 a = swf_ActionGet(tag);
697 swf_DumpActions(a,prefix);
700 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
702 if(globalflags) // should go to sterr.
703 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
705 printf(" has action code\n");
710 void handlePlaceObject(TAG*tag, char*prefix)
712 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
717 swf_SetTagPos(tag, 0);
718 id = swf_GetU16(tag);
719 depth = swf_GetU16(tag);
720 swf_GetMatrix(tag, &matrix);
721 swf_GetCXForm(tag, &cxform, 0);
723 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
724 swf_SetU16(tag2, depth);
725 swf_SetU16(tag2, id);
726 swf_SetMatrix(tag2, &matrix);
727 swf_SetCXForm(tag2, &cxform, 1);
729 handlePlaceObject23(tag2, prefix);
732 char* fillstyle2str(FILLSTYLE*style)
734 switch(style->type) {
736 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
738 case 0x10: case 0x11: case 0x12: case 0x13:
739 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
741 case 0x40: case 0x42:
742 /* TODO: display information about that bitmap */
743 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
744 /* TODO: show matrix */
746 case 0x41: case 0x43:
747 /* TODO: display information about that bitmap */
748 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
749 /* TODO: show matrix */
752 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
756 char* linestyle2str(LINESTYLE*style)
758 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
762 void handleShape(TAG*tag, char*prefix)
770 swf_ParseDefineShape(tag, &shape);
772 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
774 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
779 else printf("%s | (Neither line nor fill styles)\n", prefix);
782 printf("%s", prefix);
783 if(t < shape.numfillstyles) {
784 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
788 if(t < shape.numlinestyles) {
789 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
794 printf("%s |\n", prefix);
798 printf("%s | fill: %02d/%02d line:%02d - ",
803 if(line->type == moveTo) {
804 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
805 } else if(line->type == lineTo) {
806 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
807 } else if(line->type == splineTo) {
808 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
809 line->sx/20.0, line->sy/20.0,
810 line->x/20.0, line->y/20.0
815 printf("%s |\n", prefix);
818 void fontcallback1(void*self, U16 id,U8 * name)
822 void fontcallback2(void*self, U16 id,U8 * name)
824 swf_FontExtract(&swf,id,&fonts[fontnum]);
828 static U8 printable(U8 a)
830 if(a<32 || a==127) return '.';
833 void hexdumpTag(TAG*tag, char* prefix)
837 printf(" %s-=> ",prefix);
838 for(t=0;t<tag->len;t++) {
839 printf("%02x ", tag->data[t]);
840 ascii[t&15] = printable(tag->data[t]);
841 if((t && ((t&15)==15)) || (t==tag->len-1))
845 for(s=p-1;s<16;s++) {
849 printf(" %s\n", ascii);
851 printf(" %s\n %s-=> ",ascii,prefix);
856 void handleExportAssets(TAG*tag, char* prefix)
862 num = swf_GetU16(tag);
865 id = swf_GetU16(tag);
866 name = swf_GetString(tag);
867 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
871 void dumperror(const char* format, ...)
876 va_start(arglist, format);
877 vsprintf(buf, format, arglist);
881 printf("==== Error: %s ====\n", buf);
884 static char strbuf[800];
887 char* timestring(double f)
889 int hours = (int)(f/3600);
890 int minutes = (int)((f-hours*3600)/60);
891 int seconds = (int)((f-hours*3600-minutes*60));
892 int useconds = (int)((f-(int)f)*1000+0.5);
895 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
896 return &strbuf[bufpos];
899 int main (int argc,char ** argv)
907 char issprite = 0; // are we inside a sprite definition?
910 char* spriteframelabel = 0;
911 char* framelabel = 0;
916 memset(idtab,0,65536);
918 processargs(argc, argv);
922 fprintf(stderr, "You must supply a filename.\n");
926 f = open(filename,O_RDONLY|O_BINARY);
931 sprintf(buffer, "Couldn't open %s", filename);
935 if FAILED(swf_ReadSWF(f,&swf))
937 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
944 if(statbuf.st_size != swf.fileSize && !swf.compressed)
945 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
946 statbuf.st_size, swf.fileSize);
947 filesize = statbuf.st_size;
952 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
953 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
957 printf("-X %d", xsize);
963 printf("-Y %d", ysize);
969 printf("-r %.2f", swf.frameRate/256.0);
975 printf("-f %d", swf.frameCount);
982 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
983 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
984 if(swf.fileVersion>9) {
985 fprintf(stderr, "Fileversion>9\n");
990 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
991 "<param name=\"movie\" value=\"%s\"/>\n"
992 "<param name=\"play\" value=\"true\"/>\n"
993 "<param name=\"loop\" value=\"false\"/>\n"
994 "<param name=\"quality\" value=\"high\"/>\n"
995 "<param name=\"loop\" value=\"false\"/>\n"
996 "</object>\n\n", filename, xsize, ysize, filename);
998 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1000 //" BGCOLOR=#ffffffff\n"?
1002 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1003 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1004 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1005 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1006 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1007 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1008 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1009 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1010 " TYPE=\"application/x-shockwave-flash\"\n"
1011 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1013 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1014 filename, filename, xsize, ysize);
1018 printf("[HEADER] File version: %d\n", swf.fileVersion);
1019 if(swf.compressed) {
1020 printf("[HEADER] File is zlib compressed.");
1021 if(filesize && swf.fileSize)
1022 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1026 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1027 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1028 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1029 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1030 if(swf.movieSize.xmin)
1031 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1034 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1035 if(swf.movieSize.ymin)
1036 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1044 swf_FontEnumerate(&swf,&fontcallback1, 0);
1045 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1047 swf_FontEnumerate(&swf,&fontcallback2, 0);
1051 char*name = swf_TagGetName(tag);
1054 dumperror("Unknown tag:0x%03x", tag->id);
1059 name = "UNKNOWN TAG";
1062 filepos += tag->len;
1063 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1065 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1068 if(swf_isDefiningTag(tag)) {
1069 U16 id = swf_GetDefineID(tag);
1070 printf(" defines id %04d", id);
1072 dumperror("Id %04d is defined more than once.", id);
1075 else if(swf_isPseudoDefiningTag(tag)) {
1076 U16 id = swf_GetDefineID(tag);
1077 printf(" adds information to id %04d", id);
1079 dumperror("Id %04d is not yet defined.\n", id);
1081 else if(tag->id == ST_PLACEOBJECT) {
1082 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1083 if(swf_GetName(tag))
1084 printf(" name \"%s\"",swf_GetName(tag));
1086 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1093 printf(" id %04d",swf_GetPlaceID(tag));
1097 printf(" at depth %04d", swf_GetDepth(tag));
1099 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1100 printf(" as bitmap");
1102 swf_SetTagPos(tag, 0);
1103 if(tag->data[0]&64) {
1105 swf_GetPlaceObject(tag, &po);
1106 printf(" (clip to %04d)", po.clipdepth);
1107 swf_PlaceObjectFree(&po);
1109 if(swf_GetName(tag))
1110 printf(" name \"%s\"",swf_GetName(tag));
1113 else if(tag->id == ST_REMOVEOBJECT) {
1114 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1116 else if(tag->id == ST_REMOVEOBJECT2) {
1117 printf(" removes object from depth %04d", swf_GetDepth(tag));
1119 else if(tag->id == ST_FREECHARACTER) {
1120 printf(" frees object %04d", swf_GetPlaceID(tag));
1122 else if(tag->id == ST_STARTSOUND) {
1125 id = swf_GetU16(tag);
1126 flags = swf_GetU8(tag);
1128 printf(" stops sound with id %04d", id);
1130 printf(" starts sound with id %04d", id);
1132 printf(" (if not already playing)");
1138 printf(" looping %d times", swf_GetU16(tag));
1141 else if(tag->id == ST_FRAMELABEL) {
1142 int l = strlen(tag->data);
1143 printf(" \"%s\"", tag->data);
1144 if((l+1) < tag->len) {
1145 printf(" has %d extra bytes", tag->len-1-l);
1146 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1147 printf(" (ANCHOR)");
1149 if((framelabel && !issprite) ||
1150 (spriteframelabel && issprite)) {
1151 dumperror("Frame %d has more than one label",
1152 issprite?spriteframe:mainframe);
1154 if(issprite) spriteframelabel = tag->data;
1155 else framelabel = tag->data;
1157 else if(tag->id == ST_SHOWFRAME) {
1158 char*label = issprite?spriteframelabel:framelabel;
1159 int frame = issprite?spriteframe:mainframe;
1162 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1164 if(issprite) spriteframe++;
1170 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1172 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1173 timestring(frame*(256.0/(swf.frameRate+0.1))),
1174 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1177 printf(" (label \"%s\")", label);
1178 if(issprite) {spriteframe++; spriteframelabel = 0;}
1179 if(!issprite) {mainframe++; framelabel = 0;}
1182 if(tag->id == ST_SETBACKGROUNDCOLOR) {
1183 U8 r = swf_GetU8(tag);
1184 U8 g = swf_GetU8(tag);
1185 U8 b = swf_GetU8(tag);
1186 printf(" (%02x/%02x/%02x)\n",r,g,b);
1188 else if(tag->id == ST_PROTECT) {
1190 printf(" %s\n", swf_GetString(tag));
1195 else if(tag->id == ST_CSMTEXTSETTINGS) {
1196 U16 id = swf_GetU16(tag);
1197 U8 flags = swf_GetU8(tag);
1200 printf("flashtype,");
1202 switch(((flags>>3)&7)) {
1203 case 0:printf("no grid,");break;
1204 case 1:printf("pixel grid,");break;
1205 case 2:printf("subpixel grid,");break;
1206 case 3:printf("unknown grid,");break;
1209 printf("unknown[%08x],", flags);
1210 float thickness = swf_GetFixed(tag);
1211 float sharpness = swf_GetFixed(tag);
1212 printf("s=%.2f,t=%.2f)\n", thickness, sharpness);
1215 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1216 tag->id == ST_DEFINEBITSLOSSLESS2) {
1217 handleDefineBits(tag);
1220 else if(tag->id == ST_DEFINESOUND) {
1221 handleDefineSound(tag);
1224 else if(tag->id == ST_VIDEOFRAME) {
1225 handleVideoFrame(tag, myprefix);
1228 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1229 handleVideoStream(tag, myprefix);
1232 else if(tag->id == ST_DEFINEEDITTEXT) {
1233 handleEditText(tag);
1236 else if(tag->id == ST_DEFINEMOVIE) {
1237 U16 id = swf_GetU16(tag);
1238 char*s = swf_GetString(tag);
1239 printf(" URL: %s\n", s);
1241 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1247 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1249 else if(tag->id == ST_NAMECHARACTER) {
1251 printf(" \"%s\"\n", swf_GetString(tag));
1257 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1258 SRECT r = swf_GetDefineBBox(tag);
1259 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1266 sprintf(myprefix, " %s", prefix);
1268 if(tag->id == ST_DEFINESPRITE) {
1269 sprintf(prefix, " ");
1271 dumperror("Sprite definition inside a sprite definition");
1275 spriteframelabel = 0;
1277 else if(tag->id == ST_END) {
1280 spriteframelabel = 0;
1282 dumperror("End Tag not empty");
1284 else if(tag->id == ST_EXPORTASSETS) {
1285 handleExportAssets(tag, myprefix);
1287 else if(tag->id == ST_DOACTION && action) {
1289 actions = swf_ActionGet(tag);
1290 swf_DumpActions(actions, myprefix);
1292 else if(tag->id == ST_DOINITACTION && action) {
1294 swf_GetU16(tag); // id
1295 actions = swf_ActionGet(tag);
1296 swf_DumpActions(actions, myprefix);
1298 else if(tag->id == ST_DEFINEBUTTON && action) {
1299 dumpButtonActions(tag, myprefix);
1301 else if(swf_isFontTag(tag) && showfonts) {
1302 dumpFont(tag, myprefix);
1304 else if(tag->id == ST_DEFINEBUTTON2 && action) {
1305 dumpButton2Actions(tag, myprefix);
1307 else if(tag->id == ST_PLACEOBJECT) {
1308 handlePlaceObject(tag, myprefix);
1310 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1311 handlePlaceObject23(tag, myprefix);
1313 else if(tag->id == ST_DEFINESHAPE ||
1314 tag->id == ST_DEFINESHAPE2 ||
1315 tag->id == ST_DEFINESHAPE3 ||
1316 tag->id == ST_DEFINESHAPE4) {
1318 handleShape(tag, myprefix);
1321 if(tag->len && used) {
1322 int num = swf_GetNumUsedIDs(tag);
1326 used = (int*)malloc(sizeof(int)*num);
1327 swf_GetUsedIDs(tag, used);
1328 printf("%s%suses IDs: ", indent, prefix);
1329 for(t=0;t<num;t++) {
1331 swf_SetTagPos(tag, used[t]);
1332 id = swf_GetU16(tag);
1333 printf("%d%s", id, t<num-1?", ":"");
1335 dumperror("Id %04d is not yet defined.\n", id);
1342 if(tag->id == ST_FREECHARACTER) {
1344 swf_SetTagPos(tag, 0);
1345 id = swf_GetU16(tag);
1349 if(tag->len && hex) {
1350 hexdumpTag(tag, prefix);