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_STARTSOUND) {
1182 id = swf_GetU16(tag);
1183 flags = swf_GetU8(tag);
1185 printf(" stops sound with id %04d", id);
1187 printf(" starts sound with id %04d", id);
1189 printf(" (if not already playing)");
1195 printf(" looping %d times", swf_GetU16(tag));
1198 else if(tag->id == ST_FRAMELABEL) {
1199 int l = strlen(tag->data);
1200 printf(" \"%s\"", tag->data);
1201 if((l+1) < tag->len) {
1202 printf(" has %d extra bytes", tag->len-1-l);
1203 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1204 printf(" (ANCHOR)");
1206 if((framelabel && !issprite) ||
1207 (spriteframelabel && issprite)) {
1208 dumperror("Frame %d has more than one label",
1209 issprite?spriteframe:mainframe);
1211 if(issprite) spriteframelabel = tag->data;
1212 else framelabel = tag->data;
1214 else if(tag->id == ST_SHOWFRAME) {
1215 char*label = issprite?spriteframelabel:framelabel;
1216 int frame = issprite?spriteframe:mainframe;
1219 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1221 if(issprite) spriteframe++;
1227 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1229 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1230 timestring(frame*(256.0/(swf.frameRate+0.1))),
1231 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1234 printf(" (label \"%s\")", label);
1235 if(issprite) {spriteframe++; spriteframelabel = 0;}
1236 if(!issprite) {mainframe++; framelabel = 0;}
1239 if(tag->id == ST_SETBACKGROUNDCOLOR) {
1240 U8 r = swf_GetU8(tag);
1241 U8 g = swf_GetU8(tag);
1242 U8 b = swf_GetU8(tag);
1243 printf(" (%02x/%02x/%02x)\n",r,g,b);
1245 else if(tag->id == ST_PROTECT) {
1247 printf(" %s\n", swf_GetString(tag));
1252 else if(tag->id == ST_CSMTEXTSETTINGS) {
1253 U16 id = swf_GetU16(tag);
1254 U8 flags = swf_GetU8(tag);
1257 printf("flashtype,");
1259 switch(((flags>>3)&7)) {
1260 case 0:printf("no grid,");break;
1261 case 1:printf("pixel grid,");break;
1262 case 2:printf("subpixel grid,");break;
1263 case 3:printf("unknown grid,");break;
1266 printf("unknown[%08x],", flags);
1267 float thickness = swf_GetFixed(tag);
1268 float sharpness = swf_GetFixed(tag);
1269 printf("s=%.2f,t=%.2f)\n", thickness, sharpness);
1272 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1273 tag->id == ST_DEFINEBITSLOSSLESS2) {
1274 handleDefineBits(tag);
1277 else if(tag->id == ST_DEFINESOUND) {
1278 handleDefineSound(tag);
1281 else if(tag->id == ST_VIDEOFRAME) {
1282 handleVideoFrame(tag, myprefix);
1285 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1286 handleVideoStream(tag, myprefix);
1289 else if(tag->id == ST_DEFINEEDITTEXT) {
1290 handleEditText(tag);
1293 else if(tag->id == ST_DEFINEMOVIE) {
1294 U16 id = swf_GetU16(tag);
1295 char*s = swf_GetString(tag);
1296 printf(" URL: %s\n", s);
1298 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1304 else if(tag->id == ST_DEFINESCALINGGRID) {
1305 U16 id = swf_GetU16(tag);
1307 swf_GetRect(tag, &r);
1308 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1310 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1312 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1314 printf(" \"%s\"\n", swf_GetString(tag));
1320 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1321 SRECT r = swf_GetDefineBBox(tag);
1322 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1329 sprintf(myprefix, " %s", prefix);
1331 if(tag->id == ST_DEFINESPRITE) {
1332 sprintf(prefix, " ");
1334 dumperror("Sprite definition inside a sprite definition");
1338 spriteframelabel = 0;
1340 else if(tag->id == ST_END) {
1343 spriteframelabel = 0;
1345 dumperror("End Tag not empty");
1347 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1348 handleExportAssets(tag, myprefix);
1350 else if(tag->id == ST_DOACTION && action) {
1352 actions = swf_ActionGet(tag);
1353 swf_DumpActions(actions, myprefix);
1355 else if(tag->id == ST_DOABC && action) {
1358 else if(tag->id == ST_DOINITACTION && action) {
1360 swf_GetU16(tag); // id
1361 actions = swf_ActionGet(tag);
1362 swf_DumpActions(actions, myprefix);
1364 else if(tag->id == ST_DEFINEBUTTON) {
1366 dumpButton(tag, myprefix);
1369 dumpButtonActions(tag, myprefix);
1372 else if(swf_isFontTag(tag) && showfonts) {
1373 dumpFont(tag, myprefix);
1375 else if(tag->id == ST_DEFINEBUTTON2) {
1377 dumpButton2Actions(tag, myprefix);
1380 else if(tag->id == ST_PLACEOBJECT) {
1381 handlePlaceObject(tag, myprefix);
1383 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1384 handlePlaceObject23(tag, myprefix);
1386 else if(tag->id == ST_DEFINEFONTNAME) {
1387 swf_SetTagPos(tag, 0);
1388 swf_GetU16(tag); //id
1389 swf_GetString(tag); //name
1390 char* copyright = swf_GetString(tag);
1391 printf("%s%s\n", myprefix, copyright);
1393 else if(tag->id == ST_DEFINESHAPE ||
1394 tag->id == ST_DEFINESHAPE2 ||
1395 tag->id == ST_DEFINESHAPE3 ||
1396 tag->id == ST_DEFINESHAPE4) {
1398 handleShape(tag, myprefix);
1401 if(tag->len && used) {
1402 int num = swf_GetNumUsedIDs(tag);
1406 used = (int*)malloc(sizeof(int)*num);
1407 swf_GetUsedIDs(tag, used);
1408 printf("%s%suses IDs: ", indent, prefix);
1409 for(t=0;t<num;t++) {
1411 swf_SetTagPos(tag, used[t]);
1412 id = swf_GetU16(tag);
1413 printf("%d%s", id, t<num-1?", ":"");
1415 dumperror("Id %04d is not yet defined.\n", id);
1422 if(tag->id == ST_FREECHARACTER) {
1424 swf_SetTagPos(tag, 0);
1425 id = swf_GetU16(tag);
1429 if(tag->len && hex) {
1430 hexdumpTag(tag, prefix);