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;
63 static int showbuttons = 0;
65 static struct options_t options[] = {
87 int args_callback_option(char*name,char*val)
89 if(!strcmp(name, "V")) {
90 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
93 else if(name[0]=='a') {
97 else if(name[0]=='p') {
101 else if(name[0]=='t') {
105 else if(name[0]=='s') {
109 else if(name[0]=='e') {
113 else if(name[0]=='c') {
117 else if(name[0]=='E') {
122 else if(name[0]=='X') {
126 else if(name[0]=='Y') {
130 else if(name[0]=='r') {
134 else if(name[0]=='f') {
138 else if(name[0]=='F') {
142 else if(name[0]=='d') {
146 else if(name[0]=='u') {
150 else if(name[0]=='b') {
154 else if(name[0]=='B') {
158 else if(name[0]=='D') {
159 showbuttons = action = placements = showtext = showshapes = 1;
163 printf("Unknown option: -%s\n", name);
169 int args_callback_longoption(char*name,char*val)
171 return args_long2shortoption(options, name, val);
173 void args_callback_usage(char *name)
176 printf("Usage: %s [-atpdu] file.swf\n", name);
178 printf("-h , --help Print short help message and exit\n");
179 printf("-D , --full Show everything. Same as -atp\n");
180 printf("-V , --version Print version info and exit\n");
181 printf("-e , --html Print out html code for embedding the file\n");
182 printf("-E , --xhtml Print out xhtml code for embedding the file\n");
183 printf("-a , --action Disassemble action tags\n");
184 printf("-t , --text Show text fields (like swfstrings).\n");
185 printf("-s , --shapes Show shape coordinates/styles\n");
186 printf("-F , --fonts Show font information\n");
187 printf("-p , --placements Show placement information\n");
188 printf("-b , --bbox Print tag's bounding boxes\n");
189 printf("-X , --width Prints out a string of the form \"-X width\".\n");
190 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
191 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
192 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
193 printf("-d , --hex Print hex output of tag data, too.\n");
194 printf("-u , --used Show referred IDs for each Tag.\n");
197 int args_callback_command(char*name,char*val)
200 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
208 char* testfunc(char*str)
210 printf("%s: %s\n", what, str);
214 void dumpButton2Actions(TAG*tag, char*prefix)
220 oldTagPos = swf_GetTagPos(tag);
222 // scan DefineButton2 Record
224 swf_GetU16(tag); // Character ID
225 swf_GetU8(tag); // Flags;
227 offsetpos = swf_GetTagPos(tag); // first offset
230 while (swf_GetU8(tag)) // state -> parse ButtonRecord
231 { swf_GetU16(tag); // id
232 swf_GetU16(tag); // layer
233 swf_GetMatrix(tag,NULL); // matrix
234 swf_GetCXForm(tag,NULL,1); // cxform
241 if(tag->pos >= tag->len)
244 offsetpos = swf_GetU16(tag);
245 condition = swf_GetU16(tag); // condition
247 actions = swf_ActionGet(tag);
248 printf("%s condition %04x\n", prefix, condition);
249 swf_DumpActions(actions, prefix);
252 swf_SetTagPos(tag,oldTagPos);
256 void dumpButtonActions(TAG*tag, char*prefix)
259 swf_SetTagPos(tag, 0);
260 swf_GetU16(tag); // id
261 while (swf_GetU8(tag)) // state -> parse ButtonRecord
262 { swf_GetU16(tag); // id
263 swf_GetU16(tag); // layer
264 swf_GetMatrix(tag,NULL); // matrix
266 actions = swf_ActionGet(tag);
267 swf_DumpActions(actions, prefix);
270 void dumpButton(TAG*tag, char*prefix)
272 swf_SetTagPos(tag, 0);
273 swf_GetU16(tag); // id
275 U8 flags = swf_GetU8(tag);
278 U16 id = swf_GetU16(tag);
279 U16 depth = swf_GetU16(tag);
281 sprintf(event, "%s%s%s%s",
282 (flags&BS_HIT)?"[hit]":"",
283 (flags&BS_DOWN)?"[down]":"",
284 (flags&BS_OVER)?"[over]":"",
285 (flags&BS_UP)?"[up]":"");
287 printf("%s | Show %d at depth %d for %s flags=%02x\n", prefix, id, depth, event, flags);
289 printf("%s | Show %d at depth %d for %s\n", prefix, id, depth, event);
291 swf_GetMatrix(tag,NULL); // matrix
295 void dumpFont(TAG*tag, char*prefix)
297 SWFFONT* font = malloc(sizeof(SWFFONT));
298 memset(font, 0, sizeof(SWFFONT));
299 if(tag->id == ST_DEFINEFONT2) {
300 swf_FontExtract_DefineFont2(0, font, tag);
301 } else if(tag->id == ST_DEFINEFONT) {
302 swf_FontExtract_DefineFont(0, font, tag);
304 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
306 printf("%sID: %d\n", prefix,font->id);
307 printf("%sVersion: %d\n", prefix,font->version);
308 printf("%sname: %s\n", prefix,font->name);
309 printf("%scharacters: %d\n", prefix,font->numchars);
310 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
313 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
314 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
315 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
316 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
318 printf("%sstyle: %d\n", prefix,font->style);
319 printf("%sencoding: %02x\n", prefix,font->encoding);
320 printf("%slanguage: %02x\n", prefix,font->language);
322 for(t=0;t<font->numchars;t++) {
323 int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
324 printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
325 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
326 SHAPELINE*line = shape->lines;
329 if(line->type == moveTo) {
330 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
331 } else if(line->type == lineTo) {
332 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
333 } else if(line->type == splineTo) {
334 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
335 line->sx/20.0, line->sy/20.0,
336 line->x/20.0, line->y/20.0
341 swf_Shape2Free(shape);
351 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
354 printf(" <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a);
355 for(t=0;t<fontnum;t++)
357 if(fonts[t]->id == fontid) {
367 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
368 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
371 if(fonts[font]->glyph2ascii[glyphs[t]])
372 a = fonts[font]->glyph2ascii[glyphs[t]];
382 printf("\\x%x", (int)a);
387 void handleText(TAG*tag)
390 swf_ParseDefineText(tag,textcallback, 0);
393 void handleDefineSound(TAG*tag)
395 U16 id = swf_GetU16(tag);
396 U8 flags = swf_GetU8(tag);
397 int compression = (flags>>4)&7;
398 int rate = (flags>>2)&3;
399 int bits = flags&2?16:8;
400 int stereo = flags&1;
402 if(compression == 0) printf("Raw ");
403 else if(compression == 1) printf("ADPCM ");
404 else if(compression == 2) printf("MP3 ");
405 else if(compression == 3) printf("Raw little-endian ");
406 else if(compression == 6) printf("ASAO ");
408 if(rate == 0) printf("5.5Khz ");
409 if(rate == 1) printf("11Khz ");
410 if(rate == 2) printf("22Khz ");
411 if(rate == 3) printf("44Khz ");
412 printf("%dBit ", bits);
413 if(stereo) printf("stereo");
418 void handleDefineBits(TAG*tag)
424 id = swf_GetU16(tag);
425 mode = swf_GetU8(tag);
426 width = swf_GetU16(tag);
427 height = swf_GetU16(tag);
428 printf(" image %dx%d",width,height);
429 if(mode == 3) printf(" (8 bpp)");
430 else if(mode == 4) printf(" (16 bpp)");
431 else if(mode == 5) printf(" (32 bpp)");
432 else printf(" (? bpp)");
435 void handleEditText(TAG*tag)
440 id = swf_GetU16(tag);
443 //swf_ResetReadBits(tag);
449 flags = swf_GetBits(tag,16);
450 if(flags & ET_HASFONT) {
451 swf_GetU16(tag); //font
452 swf_GetU16(tag); //fontheight
454 if(flags & ET_HASTEXTCOLOR) {
455 swf_GetU8(tag); //rgba
460 if(flags & ET_HASMAXLENGTH) {
461 swf_GetU16(tag); //maxlength
463 if(flags & ET_HASLAYOUT) {
464 swf_GetU8(tag); //align
465 swf_GetU16(tag); //left margin
466 swf_GetU16(tag); //right margin
467 swf_GetU16(tag); //indent
468 swf_GetU16(tag); //leading
470 printf(" variable \"%s\" ", &tag->data[tag->pos]);
471 if(flags & ET_HTML) printf("(html)");
472 if(flags & ET_NOSELECT) printf("(noselect)");
473 if(flags & ET_PASSWORD) printf("(password)");
474 if(flags & ET_READONLY) printf("(readonly)");
476 if(flags & (ET_X1 | ET_X3 ))
478 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
481 while(tag->data[tag->pos++]);
482 if(flags & ET_HASTEXT)
483 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
486 void printhandlerflags(U32 handlerflags)
488 if(handlerflags&1) printf("[on load]");
489 if(handlerflags&2) printf("[enter frame]");
490 if(handlerflags&4) printf("[unload]");
491 if(handlerflags&8) printf("[mouse move]");
492 if(handlerflags&16) printf("[mouse down]");
493 if(handlerflags&32) printf("[mouse up]");
494 if(handlerflags&64) printf("[key down]");
495 if(handlerflags&128) printf("[key up]");
497 if(handlerflags&256) printf("[data]");
498 if(handlerflags&512) printf("[initialize]");
499 if(handlerflags&1024) printf("[mouse press]");
500 if(handlerflags&2048) printf("[mouse release]");
501 if(handlerflags&4096) printf("[mouse release outside]");
502 if(handlerflags&8192) printf("[mouse rollover]");
503 if(handlerflags&16384) printf("[mouse rollout]");
504 if(handlerflags&32768) printf("[mouse drag over]");
506 if(handlerflags&0x10000) printf("[mouse drag out]");
507 if(handlerflags&0x20000) printf("[key press]");
508 if(handlerflags&0x40000) printf("[construct even]");
509 if(handlerflags&0xfff80000) printf("[???]");
511 void handleVideoStream(TAG*tag, char*prefix)
513 U16 id = swf_GetU16(tag);
514 U16 frames = swf_GetU16(tag);
515 U16 width = swf_GetU16(tag);
516 U16 height = swf_GetU16(tag);
517 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
518 U8 codec = swf_GetU8(tag);
519 printf(" (%d frames, %dx%d", frames, width, height);
523 printf(" sorenson h.263)");
525 printf(" codec 0x%02x)", codec);
527 void handleVideoFrame(TAG*tag, char*prefix)
529 U32 code, version, reference, sizeflags;
530 U32 width=0, height=0;
532 U16 id = swf_GetU16(tag);
533 U16 frame = swf_GetU16(tag);
534 U8 deblock,flags, tmp, bit;
536 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
537 printf(" (frame %d) ", frame);
539 /* video packet follows */
540 code = swf_GetBits(tag, 17);
541 version = swf_GetBits(tag, 5);
542 reference = swf_GetBits(tag, 8);
544 sizeflags = swf_GetBits(tag, 3);
547 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
548 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
549 case 2: width = 352; height = 288; break;
550 case 3: width = 176; height = 144; break;
551 case 4: width = 128; height = 96; break;
552 case 5: width = 320; height = 240; break;
553 case 6: width = 160; height = 120; break;
554 case 7: width = -1; height = -1;/*reserved*/ break;
556 printf("%dx%d ", width, height);
557 type = swf_GetBits(tag, 2);
558 printf("%s", types[type]);
560 deblock = swf_GetBits(tag, 1);
562 printf(" deblock ", deblock);
563 quantizer = swf_GetBits(tag, 5);
564 printf(" quant: %d ", quantizer);
567 void dumpFilter(FILTER*filter)
569 if(filter->type == FILTERTYPE_BLUR) {
570 FILTER_BLUR*f = (FILTER_BLUR*)filter;
571 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
572 printf("passes: %d\n", f->passes);
573 } if(filter->type == FILTERTYPE_GLOW) {
574 FILTER_GLOW*f = (FILTER_GLOW*)filter;
575 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
576 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
577 printf("passes: %d\n", f->passes);
578 printf("flags: %s%s%s\n",
579 f->knockout?"knockout ":"",
580 f->composite?"composite ":"",
581 f->innerglow?"innerglow":"");
582 } if(filter->type == FILTERTYPE_DROPSHADOW) {
583 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
584 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
585 printf("passes: %d\n", f->passes);
586 printf("angle: %f distance: %f\n", f->angle, f->distance);
587 printf("strength: %f passes: %d\n", f->strength, f->passes);
588 printf("flags: %s%s%s\n",
589 f->knockout?"knockout ":"",
590 f->composite?"composite ":"",
591 f->innershadow?"innershadow ":"");
592 } if(filter->type == FILTERTYPE_BEVEL) {
593 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
594 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
595 printf("passes: %d\n", f->passes);
596 printf("angle: %f distance: %f\n", f->angle, f->distance);
597 printf("strength: %f passes: %d\n", f->strength, f->passes);
598 printf("flags: %s%s%s%s\n",
600 f->knockout?"knockout ":"",
601 f->composite?"composite ":"",
602 f->innershadow?"innershadow ":"");
603 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
604 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
605 swf_DumpGradient(stdout, f->gradient);
606 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
607 printf("angle: %f distance: %f\n", f->angle, f->distance);
608 printf("strength: %f passes: %d\n", f->strength, f->passes);
609 printf("flags: %s%s%s%s\n",
610 f->knockout?"knockout ":"",
611 f->ontop?"ontop ":"",
612 f->composite?"composite ":"",
613 f->innershadow?"innershadow ":"");
618 void handlePlaceObject23(TAG*tag, char*prefix)
624 int ppos[3] = {0,0,0};
625 swf_SetTagPos(tag, 0);
626 flags = swf_GetU8(tag);
627 if(tag->id == ST_PLACEOBJECT3)
628 flags2 = swf_GetU8(tag);
629 swf_GetU16(tag); //depth
632 if(flags&2) swf_GetU16(tag); //id
634 swf_GetMatrix(tag,&m);
636 ppos[0] += sprintf(pstr[0], "| Matrix ");
637 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
638 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
642 swf_GetCXForm(tag, &cx, 1);
644 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
645 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);
646 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
650 U16 ratio = swf_GetU16(tag); //ratio
652 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
653 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
654 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
658 U16 clip = swf_GetU16(tag); //clip
660 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
661 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
662 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
665 if(flags&32) { while(swf_GetU8(tag)); }
667 if(flags2&1) { // filter list
668 U8 num = swf_GetU8(tag);
670 printf("\n%d filters\n", num);
671 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
674 FILTER*filter = swf_GetFilter(tag);
680 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
685 if(flags2&2) { // blend mode
686 U8 blendmode = swf_GetU8(tag);
690 sprintf(name, "%-5d", blendmode);
691 for(t=0;blendModeNames[t];t++) {
693 sprintf(name, "%-5s", blendModeNames[t]);
697 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
698 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
699 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
703 if(placements && ppos[0]) {
705 printf("%s %s\n", prefix, pstr[0]);
706 printf("%s %s\n", prefix, pstr[1]);
707 printf("%s %s", prefix, pstr[2]);
716 reserved = swf_GetU16(tag); // must be 0
717 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
719 printf("Unknown parameter field not zero: %04x\n", reserved);
722 printf("global flags: %04x\n", globalflags);
724 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
726 handlerflags = swf_GetU32(tag);
729 while(handlerflags) {
734 globalflags &= ~handlerflags;
735 printf("%s flags %08x ",prefix, handlerflags);
736 printhandlerflags(handlerflags);
737 length = swf_GetU32(tag);
738 printf(", %d bytes actioncode\n",length);
739 a = swf_ActionGet(tag);
740 swf_DumpActions(a,prefix);
743 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
745 if(globalflags) // should go to sterr.
746 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
748 printf(" has action code\n");
753 void handlePlaceObject(TAG*tag, char*prefix)
755 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
760 swf_SetTagPos(tag, 0);
761 id = swf_GetU16(tag);
762 depth = swf_GetU16(tag);
763 swf_GetMatrix(tag, &matrix);
764 swf_GetCXForm(tag, &cxform, 0);
766 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
767 swf_SetU16(tag2, depth);
768 swf_SetU16(tag2, id);
769 swf_SetMatrix(tag2, &matrix);
770 swf_SetCXForm(tag2, &cxform, 1);
772 handlePlaceObject23(tag2, prefix);
775 char* fillstyle2str(FILLSTYLE*style)
777 switch(style->type) {
779 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
781 case 0x10: case 0x11: case 0x12: case 0x13:
782 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
784 case 0x40: case 0x42:
785 /* TODO: display information about that bitmap */
786 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
787 /* TODO: show matrix */
789 case 0x41: case 0x43:
790 /* TODO: display information about that bitmap */
791 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
792 /* TODO: show matrix */
795 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
799 char* linestyle2str(LINESTYLE*style)
801 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
805 void handleShape(TAG*tag, char*prefix)
813 swf_ParseDefineShape(tag, &shape);
815 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
817 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
822 else printf("%s | (Neither line nor fill styles)\n", prefix);
825 printf("%s", prefix);
826 if(t < shape.numfillstyles) {
827 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
831 if(t < shape.numlinestyles) {
832 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
835 //if(shape.fillstyles[t].type&0x40) {
836 // MATRIX m = shape.fillstyles[t].m;
837 // swf_DumpMatrix(stdout, &m);
841 printf("%s |\n", prefix);
845 printf("%s | fill: %02d/%02d line:%02d - ",
850 if(line->type == moveTo) {
851 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
852 } else if(line->type == lineTo) {
853 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
854 } else if(line->type == splineTo) {
855 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
856 line->sx/20.0, line->sy/20.0,
857 line->x/20.0, line->y/20.0
862 printf("%s |\n", prefix);
865 void fontcallback1(void*self, U16 id,U8 * name)
869 void fontcallback2(void*self, U16 id,U8 * name)
871 swf_FontExtract(&swf,id,&fonts[fontnum]);
875 static U8 printable(U8 a)
877 if(a<32 || a==127) return '.';
880 void hexdumpTag(TAG*tag, char* prefix)
884 printf(" %s-=> ",prefix);
885 for(t=0;t<tag->len;t++) {
886 printf("%02x ", tag->data[t]);
887 ascii[t&15] = printable(tag->data[t]);
888 if((t && ((t&15)==15)) || (t==tag->len-1))
892 for(s=p-1;s<16;s++) {
896 printf(" %s\n", ascii);
898 printf(" %s\n %s-=> ",ascii,prefix);
903 void handleExportAssets(TAG*tag, char* prefix)
909 num = swf_GetU16(tag);
912 id = swf_GetU16(tag);
913 name = swf_GetString(tag);
914 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
918 void dumperror(const char* format, ...)
923 va_start(arglist, format);
924 vsprintf(buf, format, arglist);
928 printf("==== Error: %s ====\n", buf);
931 static char strbuf[800];
934 char* timestring(double f)
936 int hours = (int)(f/3600);
937 int minutes = (int)((f-hours*3600)/60);
938 int seconds = (int)((f-hours*3600-minutes*60));
939 int useconds = (int)((f-(int)f)*1000+0.5);
942 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
943 return &strbuf[bufpos];
946 int main (int argc,char ** argv)
954 char issprite = 0; // are we inside a sprite definition?
957 char* spriteframelabel = 0;
958 char* framelabel = 0;
963 memset(idtab,0,65536);
965 processargs(argc, argv);
969 fprintf(stderr, "You must supply a filename.\n");
973 f = open(filename,O_RDONLY|O_BINARY);
977 sprintf(buffer, "Couldn't open %s", filename);
983 int compressed = (header[0]=='C');
985 f = open(filename,O_RDONLY|O_BINARY);
987 if FAILED(swf_ReadSWF(f,&swf))
989 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
996 if(statbuf.st_size != swf.fileSize && !compressed)
997 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
998 statbuf.st_size, swf.fileSize);
999 filesize = statbuf.st_size;
1004 //if(action && swf.fileVersion>=9) {
1005 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1009 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1010 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1014 printf("-X %d", xsize);
1016 if((xy&1) && (xy&6))
1020 printf("-Y %d", ysize);
1022 if((xy&3) && (xy&4))
1026 printf("-r %.2f", swf.frameRate/256.0);
1028 if((xy&7) && (xy&8))
1032 printf("-f %d", swf.frameCount);
1039 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1040 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
1041 if(swf.fileVersion>9) {
1042 fprintf(stderr, "Fileversion>9\n");
1047 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1048 "<param name=\"movie\" value=\"%s\"/>\n"
1049 "<param name=\"play\" value=\"true\"/>\n"
1050 "<param name=\"loop\" value=\"false\"/>\n"
1051 "<param name=\"quality\" value=\"high\"/>\n"
1052 "<param name=\"loop\" value=\"false\"/>\n"
1053 "</object>\n\n", filename, xsize, ysize, filename);
1055 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1057 //" BGCOLOR=#ffffffff\n"?
1059 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1060 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1061 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1062 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1063 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1064 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1065 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1066 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1067 " TYPE=\"application/x-shockwave-flash\"\n"
1068 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1070 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1071 filename, filename, xsize, ysize);
1075 printf("[HEADER] File version: %d\n", swf.fileVersion);
1077 printf("[HEADER] File is zlib compressed.");
1078 if(filesize && swf.fileSize)
1079 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1083 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1084 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1085 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1086 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1087 if(swf.movieSize.xmin)
1088 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1091 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1092 if(swf.movieSize.ymin)
1093 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1101 swf_FontEnumerate(&swf,&fontcallback1, 0);
1102 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1104 swf_FontEnumerate(&swf,&fontcallback2, 0);
1108 char*name = swf_TagGetName(tag);
1111 dumperror("Unknown tag:0x%03x", tag->id);
1116 name = "UNKNOWN TAG";
1119 filepos += tag->len;
1120 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1122 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1125 if(swf_isDefiningTag(tag)) {
1126 U16 id = swf_GetDefineID(tag);
1127 printf(" defines id %04d", id);
1129 dumperror("Id %04d is defined more than once.", id);
1132 else if(swf_isPseudoDefiningTag(tag)) {
1133 U16 id = swf_GetDefineID(tag);
1134 printf(" adds information to id %04d", id);
1136 dumperror("Id %04d is not yet defined.\n", id);
1138 else if(tag->id == ST_PLACEOBJECT) {
1139 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1140 if(swf_GetName(tag))
1141 printf(" name \"%s\"",swf_GetName(tag));
1143 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1150 printf(" id %04d",swf_GetPlaceID(tag));
1154 printf(" at depth %04d", swf_GetDepth(tag));
1156 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1157 printf(" as bitmap");
1159 swf_SetTagPos(tag, 0);
1160 if(tag->data[0]&64) {
1162 swf_GetPlaceObject(tag, &po);
1163 printf(" (clip to %04d)", po.clipdepth);
1164 swf_PlaceObjectFree(&po);
1166 if(swf_GetName(tag))
1167 printf(" name \"%s\"",swf_GetName(tag));
1170 else if(tag->id == ST_REMOVEOBJECT) {
1171 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1173 else if(tag->id == ST_REMOVEOBJECT2) {
1174 printf(" removes object from depth %04d", swf_GetDepth(tag));
1176 else if(tag->id == ST_FREECHARACTER) {
1177 printf(" frees object %04d", swf_GetPlaceID(tag));
1179 else if(tag->id == ST_DOABC) {
1180 swf_SetTagPos(tag, 0);
1181 U32 flags = swf_GetU32(tag);
1182 char*s = swf_GetString(tag);
1184 printf(" \"%s\"", s);
1189 printf(" lazy load");
1191 swf_SetTagPos(tag, 0);
1193 else if(tag->id == ST_STARTSOUND) {
1196 id = swf_GetU16(tag);
1197 flags = swf_GetU8(tag);
1199 printf(" stops sound with id %04d", id);
1201 printf(" starts sound with id %04d", id);
1203 printf(" (if not already playing)");
1209 printf(" looping %d times", swf_GetU16(tag));
1212 else if(tag->id == ST_FRAMELABEL) {
1213 int l = strlen(tag->data);
1214 printf(" \"%s\"", tag->data);
1215 if((l+1) < tag->len) {
1216 printf(" has %d extra bytes", tag->len-1-l);
1217 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1218 printf(" (ANCHOR)");
1220 if((framelabel && !issprite) ||
1221 (spriteframelabel && issprite)) {
1222 dumperror("Frame %d has more than one label",
1223 issprite?spriteframe:mainframe);
1225 if(issprite) spriteframelabel = tag->data;
1226 else framelabel = tag->data;
1228 else if(tag->id == ST_SHOWFRAME) {
1229 char*label = issprite?spriteframelabel:framelabel;
1230 int frame = issprite?spriteframe:mainframe;
1233 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1235 if(issprite) spriteframe++;
1241 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1243 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1244 timestring(frame*(256.0/(swf.frameRate+0.1))),
1245 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1248 printf(" (label \"%s\")", label);
1249 if(issprite) {spriteframe++; spriteframelabel = 0;}
1250 if(!issprite) {mainframe++; framelabel = 0;}
1252 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1253 U8 r = swf_GetU8(tag);
1254 U8 g = swf_GetU8(tag);
1255 U8 b = swf_GetU8(tag);
1256 printf(" (%02x/%02x/%02x)\n",r,g,b);
1258 else if(tag->id == ST_PROTECT) {
1260 printf(" %s\n", swf_GetString(tag));
1265 else if(tag->id == ST_CSMTEXTSETTINGS) {
1266 U16 id = swf_GetU16(tag);
1267 U8 flags = swf_GetU8(tag);
1270 printf("flashtype,");
1272 switch(((flags>>3)&7)) {
1273 case 0:printf("no grid,");break;
1274 case 1:printf("pixel grid,");break;
1275 case 2:printf("subpixel grid,");break;
1276 case 3:printf("unknown grid,");break;
1279 printf("unknown[%08x],", flags);
1280 float thickness = swf_GetFixed(tag);
1281 float sharpness = swf_GetFixed(tag);
1282 printf("s=%.2f,t=%.2f)\n", thickness, sharpness);
1286 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1287 tag->id == ST_DEFINEBITSLOSSLESS2) {
1288 handleDefineBits(tag);
1291 else if(tag->id == ST_DEFINESOUND) {
1292 handleDefineSound(tag);
1295 else if(tag->id == ST_VIDEOFRAME) {
1296 handleVideoFrame(tag, myprefix);
1299 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1300 handleVideoStream(tag, myprefix);
1303 else if(tag->id == ST_DEFINEEDITTEXT) {
1304 handleEditText(tag);
1307 else if(tag->id == ST_DEFINEMOVIE) {
1308 U16 id = swf_GetU16(tag);
1309 char*s = swf_GetString(tag);
1310 printf(" URL: %s\n", s);
1312 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1318 else if(tag->id == ST_DEFINESCALINGGRID) {
1319 U16 id = swf_GetU16(tag);
1321 swf_GetRect(tag, &r);
1322 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1324 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1326 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1328 printf(" \"%s\"\n", swf_GetString(tag));
1334 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1335 SRECT r = swf_GetDefineBBox(tag);
1336 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1343 sprintf(myprefix, " %s", prefix);
1345 if(tag->id == ST_DEFINESPRITE) {
1346 sprintf(prefix, " ");
1348 dumperror("Sprite definition inside a sprite definition");
1352 spriteframelabel = 0;
1354 else if(tag->id == ST_END) {
1357 spriteframelabel = 0;
1359 dumperror("End Tag not empty");
1361 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1362 handleExportAssets(tag, myprefix);
1364 else if(tag->id == ST_DOACTION && action) {
1366 actions = swf_ActionGet(tag);
1367 swf_DumpActions(actions, myprefix);
1369 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1372 else if(tag->id == ST_DOINITACTION && action) {
1374 swf_GetU16(tag); // id
1375 actions = swf_ActionGet(tag);
1376 swf_DumpActions(actions, myprefix);
1378 else if(tag->id == ST_DEFINEBUTTON) {
1380 dumpButton(tag, myprefix);
1383 dumpButtonActions(tag, myprefix);
1386 else if(swf_isFontTag(tag) && showfonts) {
1387 dumpFont(tag, myprefix);
1389 else if(tag->id == ST_DEFINEBUTTON2) {
1391 dumpButton2Actions(tag, myprefix);
1394 else if(tag->id == ST_PLACEOBJECT) {
1395 handlePlaceObject(tag, myprefix);
1397 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1398 handlePlaceObject23(tag, myprefix);
1400 else if(tag->id == ST_DEFINEFONTNAME) {
1401 swf_SetTagPos(tag, 0);
1402 swf_GetU16(tag); //id
1403 swf_GetString(tag); //name
1404 char* copyright = swf_GetString(tag);
1405 printf("%s%s\n", myprefix, copyright);
1407 else if(tag->id == ST_DEFINESHAPE ||
1408 tag->id == ST_DEFINESHAPE2 ||
1409 tag->id == ST_DEFINESHAPE3 ||
1410 tag->id == ST_DEFINESHAPE4) {
1412 handleShape(tag, myprefix);
1415 if(tag->len && used) {
1416 int num = swf_GetNumUsedIDs(tag);
1420 used = (int*)malloc(sizeof(int)*num);
1421 swf_GetUsedIDs(tag, used);
1422 printf("%s%suses IDs: ", indent, prefix);
1423 for(t=0;t<num;t++) {
1425 swf_SetTagPos(tag, used[t]);
1426 id = swf_GetU16(tag);
1427 printf("%d%s", id, t<num-1?", ":"");
1429 dumperror("Id %04d is not yet defined.\n", id);
1436 if(tag->id == ST_FREECHARACTER) {
1438 swf_SetTagPos(tag, 0);
1439 id = swf_GetU16(tag);
1443 if(tag->len && hex) {
1444 hexdumpTag(tag, prefix);