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)",r,g,b);
1258 else if(tag->id == ST_PROTECT) {
1260 printf(" %s", swf_GetString(tag));
1263 else if(tag->id == ST_CSMTEXTSETTINGS) {
1264 U16 id = swf_GetU16(tag);
1265 U8 flags = swf_GetU8(tag);
1268 printf("flashtype,");
1270 switch(((flags>>3)&7)) {
1271 case 0:printf("no grid,");break;
1272 case 1:printf("pixel grid,");break;
1273 case 2:printf("subpixel grid,");break;
1274 case 3:printf("unknown grid,");break;
1277 printf("unknown[%08x],", flags);
1278 float thickness = swf_GetFixed(tag);
1279 float sharpness = swf_GetFixed(tag);
1280 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1284 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1285 tag->id == ST_DEFINEBITSLOSSLESS2) {
1286 handleDefineBits(tag);
1289 else if(tag->id == ST_DEFINESOUND) {
1290 handleDefineSound(tag);
1293 else if(tag->id == ST_VIDEOFRAME) {
1294 handleVideoFrame(tag, myprefix);
1297 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1298 handleVideoStream(tag, myprefix);
1301 else if(tag->id == ST_DEFINEEDITTEXT) {
1302 handleEditText(tag);
1305 else if(tag->id == ST_DEFINEMOVIE) {
1306 U16 id = swf_GetU16(tag);
1307 char*s = swf_GetString(tag);
1308 printf(" URL: %s\n", s);
1310 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1316 else if(tag->id == ST_DEFINESCALINGGRID) {
1317 U16 id = swf_GetU16(tag);
1319 swf_GetRect(tag, &r);
1320 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1322 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1324 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1326 printf(" \"%s\"\n", swf_GetString(tag));
1332 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1333 SRECT r = swf_GetDefineBBox(tag);
1334 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1341 sprintf(myprefix, " %s", prefix);
1343 if(tag->id == ST_DEFINESPRITE) {
1344 sprintf(prefix, " ");
1346 dumperror("Sprite definition inside a sprite definition");
1350 spriteframelabel = 0;
1352 else if(tag->id == ST_END) {
1355 spriteframelabel = 0;
1357 dumperror("End Tag not empty");
1359 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1360 handleExportAssets(tag, myprefix);
1362 else if(tag->id == ST_DOACTION && action) {
1364 actions = swf_ActionGet(tag);
1365 swf_DumpActions(actions, myprefix);
1367 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1370 else if(tag->id == ST_DOINITACTION && action) {
1372 swf_GetU16(tag); // id
1373 actions = swf_ActionGet(tag);
1374 swf_DumpActions(actions, myprefix);
1376 else if(tag->id == ST_DEFINEBUTTON) {
1378 dumpButton(tag, myprefix);
1381 dumpButtonActions(tag, myprefix);
1384 else if(swf_isFontTag(tag) && showfonts) {
1385 dumpFont(tag, myprefix);
1387 else if(tag->id == ST_DEFINEBUTTON2) {
1389 dumpButton2Actions(tag, myprefix);
1392 else if(tag->id == ST_PLACEOBJECT) {
1393 handlePlaceObject(tag, myprefix);
1395 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1396 handlePlaceObject23(tag, myprefix);
1398 else if(tag->id == ST_DEFINEFONTNAME) {
1399 swf_SetTagPos(tag, 0);
1400 swf_GetU16(tag); //id
1401 swf_GetString(tag); //name
1402 char* copyright = swf_GetString(tag);
1403 printf("%s%s\n", myprefix, copyright);
1405 else if(tag->id == ST_DEFINESHAPE ||
1406 tag->id == ST_DEFINESHAPE2 ||
1407 tag->id == ST_DEFINESHAPE3 ||
1408 tag->id == ST_DEFINESHAPE4) {
1410 handleShape(tag, myprefix);
1413 if(tag->len && used) {
1414 int num = swf_GetNumUsedIDs(tag);
1418 used = (int*)malloc(sizeof(int)*num);
1419 swf_GetUsedIDs(tag, used);
1420 printf("%s%suses IDs: ", indent, prefix);
1421 for(t=0;t<num;t++) {
1423 swf_SetTagPos(tag, used[t]);
1424 id = swf_GetU16(tag);
1425 printf("%d%s", id, t<num-1?", ":"");
1427 dumperror("Id %04d is not yet defined.\n", id);
1434 if(tag->id == ST_FREECHARACTER) {
1436 swf_SetTagPos(tag, 0);
1437 id = swf_GetU16(tag);
1441 if(tag->len && hex) {
1442 hexdumpTag(tag, prefix);