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 , --buttons Show button information\n");
189 printf("-b , --bbox Print tag's bounding boxes\n");
190 printf("-X , --width Prints out a string of the form \"-X width\".\n");
191 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
192 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
193 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
194 printf("-d , --hex Print hex output of tag data, too.\n");
195 printf("-u , --used Show referred IDs for each Tag.\n");
198 int args_callback_command(char*name,char*val)
201 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
209 char* testfunc(char*str)
211 printf("%s: %s\n", what, str);
215 void dumpButton2Actions(TAG*tag, char*prefix)
221 oldTagPos = swf_GetTagPos(tag);
223 // scan DefineButton2 Record
225 swf_GetU16(tag); // Character ID
226 swf_GetU8(tag); // Flags;
228 offsetpos = swf_GetTagPos(tag); // first offset
231 while (swf_GetU8(tag)) // state -> parse ButtonRecord
232 { swf_GetU16(tag); // id
233 swf_GetU16(tag); // layer
234 swf_GetMatrix(tag,NULL); // matrix
235 swf_GetCXForm(tag,NULL,1); // cxform
242 if(tag->pos >= tag->len)
245 offsetpos = swf_GetU16(tag);
246 condition = swf_GetU16(tag); // condition
248 actions = swf_ActionGet(tag);
249 printf("%s condition %04x\n", prefix, condition);
250 swf_DumpActions(actions, prefix);
253 swf_SetTagPos(tag,oldTagPos);
257 void dumpButtonActions(TAG*tag, char*prefix)
260 swf_SetTagPos(tag, 0);
261 swf_GetU16(tag); // id
262 while (swf_GetU8(tag)) // state -> parse ButtonRecord
263 { swf_GetU16(tag); // id
264 swf_GetU16(tag); // layer
265 swf_GetMatrix(tag,NULL); // matrix
267 actions = swf_ActionGet(tag);
268 swf_DumpActions(actions, prefix);
269 swf_ActionFree(actions);
272 void dumpButton(TAG*tag, char*prefix)
274 swf_SetTagPos(tag, 0);
275 swf_GetU16(tag); // id
277 U8 flags = swf_GetU8(tag);
280 U16 id = swf_GetU16(tag);
281 U16 depth = swf_GetU16(tag);
283 sprintf(event, "%s%s%s%s",
284 (flags&BS_HIT)?"[hit]":"",
285 (flags&BS_DOWN)?"[down]":"",
286 (flags&BS_OVER)?"[over]":"",
287 (flags&BS_UP)?"[up]":"");
289 printf("%s | Show %d at depth %d for %s flags=%02x\n", prefix, id, depth, event, flags);
291 printf("%s | Show %d at depth %d for %s\n", prefix, id, depth, event);
293 swf_GetMatrix(tag,NULL); // matrix
297 void dumpFont(TAG*tag, char*prefix)
299 SWFFONT* font = malloc(sizeof(SWFFONT));
300 memset(font, 0, sizeof(SWFFONT));
301 if(tag->id == ST_DEFINEFONT2) {
302 swf_FontExtract_DefineFont2(0, font, tag);
303 } else if(tag->id == ST_DEFINEFONT) {
304 swf_FontExtract_DefineFont(0, font, tag);
306 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
308 printf("%sID: %d\n", prefix,font->id);
309 printf("%sVersion: %d\n", prefix,font->version);
310 printf("%sname: %s\n", prefix,font->name);
311 printf("%scharacters: %d\n", prefix,font->numchars);
312 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
315 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
316 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
317 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
318 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
320 printf("%sstyle: %d\n", prefix,font->style);
321 printf("%sencoding: %02x\n", prefix,font->encoding);
322 printf("%slanguage: %02x\n", prefix,font->language);
324 for(t=0;t<font->numchars;t++) {
325 int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
326 printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
327 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
328 SHAPELINE*line = shape->lines;
331 if(line->type == moveTo) {
332 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
333 } else if(line->type == lineTo) {
334 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
335 } else if(line->type == splineTo) {
336 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
337 line->sx/20.0, line->sy/20.0,
338 line->x/20.0, line->y/20.0
343 swf_Shape2Free(shape);
353 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
356 printf(" <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a);
357 for(t=0;t<fontnum;t++)
359 if(fonts[t]->id == fontid) {
369 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
370 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
373 if(fonts[font]->glyph2ascii[glyphs[t]])
374 a = fonts[font]->glyph2ascii[glyphs[t]];
384 printf("\\x%x", (int)a);
389 void handleText(TAG*tag)
392 swf_ParseDefineText(tag,textcallback, 0);
395 void handleDefineSound(TAG*tag)
397 U16 id = swf_GetU16(tag);
398 U8 flags = swf_GetU8(tag);
399 int compression = (flags>>4)&7;
400 int rate = (flags>>2)&3;
401 int bits = flags&2?16:8;
402 int stereo = flags&1;
404 if(compression == 0) printf("Raw ");
405 else if(compression == 1) printf("ADPCM ");
406 else if(compression == 2) printf("MP3 ");
407 else if(compression == 3) printf("Raw little-endian ");
408 else if(compression == 6) printf("ASAO ");
410 if(rate == 0) printf("5.5Khz ");
411 if(rate == 1) printf("11Khz ");
412 if(rate == 2) printf("22Khz ");
413 if(rate == 3) printf("44Khz ");
414 printf("%dBit ", bits);
415 if(stereo) printf("stereo");
420 void handleDefineBits(TAG*tag)
426 id = swf_GetU16(tag);
427 mode = swf_GetU8(tag);
428 width = swf_GetU16(tag);
429 height = swf_GetU16(tag);
430 printf(" image %dx%d",width,height);
431 if(mode == 3) printf(" (8 bpp)");
432 else if(mode == 4) printf(" (16 bpp)");
433 else if(mode == 5) printf(" (32 bpp)");
434 else printf(" (? bpp)");
437 void handleEditText(TAG*tag)
442 id = swf_GetU16(tag);
445 //swf_ResetReadBits(tag);
451 flags = swf_GetBits(tag,16);
452 if(flags & ET_HASFONT) {
453 swf_GetU16(tag); //font
454 swf_GetU16(tag); //fontheight
456 if(flags & ET_HASTEXTCOLOR) {
457 swf_GetU8(tag); //rgba
462 if(flags & ET_HASMAXLENGTH) {
463 swf_GetU16(tag); //maxlength
465 if(flags & ET_HASLAYOUT) {
466 swf_GetU8(tag); //align
467 swf_GetU16(tag); //left margin
468 swf_GetU16(tag); //right margin
469 swf_GetU16(tag); //indent
470 swf_GetU16(tag); //leading
472 printf(" variable \"%s\" ", &tag->data[tag->pos]);
473 if(flags & ET_HTML) printf("(html)");
474 if(flags & ET_NOSELECT) printf("(noselect)");
475 if(flags & ET_PASSWORD) printf("(password)");
476 if(flags & ET_READONLY) printf("(readonly)");
478 if(flags & (ET_X1 | ET_X3 ))
480 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
483 while(tag->data[tag->pos++]);
484 if(flags & ET_HASTEXT)
485 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
488 void printhandlerflags(U32 handlerflags)
490 if(handlerflags&1) printf("[on load]");
491 if(handlerflags&2) printf("[enter frame]");
492 if(handlerflags&4) printf("[unload]");
493 if(handlerflags&8) printf("[mouse move]");
494 if(handlerflags&16) printf("[mouse down]");
495 if(handlerflags&32) printf("[mouse up]");
496 if(handlerflags&64) printf("[key down]");
497 if(handlerflags&128) printf("[key up]");
499 if(handlerflags&256) printf("[data]");
500 if(handlerflags&512) printf("[initialize]");
501 if(handlerflags&1024) printf("[mouse press]");
502 if(handlerflags&2048) printf("[mouse release]");
503 if(handlerflags&4096) printf("[mouse release outside]");
504 if(handlerflags&8192) printf("[mouse rollover]");
505 if(handlerflags&16384) printf("[mouse rollout]");
506 if(handlerflags&32768) printf("[mouse drag over]");
508 if(handlerflags&0x10000) printf("[mouse drag out]");
509 if(handlerflags&0x20000) printf("[key press]");
510 if(handlerflags&0x40000) printf("[construct even]");
511 if(handlerflags&0xfff80000) printf("[???]");
513 void handleVideoStream(TAG*tag, char*prefix)
515 U16 id = swf_GetU16(tag);
516 U16 frames = swf_GetU16(tag);
517 U16 width = swf_GetU16(tag);
518 U16 height = swf_GetU16(tag);
519 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
520 U8 codec = swf_GetU8(tag);
521 printf(" (%d frames, %dx%d", frames, width, height);
525 printf(" sorenson h.263)");
527 printf(" codec 0x%02x)", codec);
529 void handleVideoFrame(TAG*tag, char*prefix)
531 U32 code, version, reference, sizeflags;
532 U32 width=0, height=0;
534 U16 id = swf_GetU16(tag);
535 U16 frame = swf_GetU16(tag);
536 U8 deblock,flags, tmp, bit;
538 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
539 printf(" (frame %d) ", frame);
541 /* video packet follows */
542 code = swf_GetBits(tag, 17);
543 version = swf_GetBits(tag, 5);
544 reference = swf_GetBits(tag, 8);
546 sizeflags = swf_GetBits(tag, 3);
549 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
550 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
551 case 2: width = 352; height = 288; break;
552 case 3: width = 176; height = 144; break;
553 case 4: width = 128; height = 96; break;
554 case 5: width = 320; height = 240; break;
555 case 6: width = 160; height = 120; break;
556 case 7: width = -1; height = -1;/*reserved*/ break;
558 printf("%dx%d ", width, height);
559 type = swf_GetBits(tag, 2);
560 printf("%s", types[type]);
562 deblock = swf_GetBits(tag, 1);
564 printf(" deblock ", deblock);
565 quantizer = swf_GetBits(tag, 5);
566 printf(" quant: %d ", quantizer);
569 void dumpFilter(FILTER*filter)
571 if(filter->type == FILTERTYPE_BLUR) {
572 FILTER_BLUR*f = (FILTER_BLUR*)filter;
573 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
574 printf("passes: %d\n", f->passes);
575 } if(filter->type == FILTERTYPE_GLOW) {
576 FILTER_GLOW*f = (FILTER_GLOW*)filter;
577 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
578 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
579 printf("passes: %d\n", f->passes);
580 printf("flags: %s%s%s\n",
581 f->knockout?"knockout ":"",
582 f->composite?"composite ":"",
583 f->innerglow?"innerglow":"");
584 } if(filter->type == FILTERTYPE_DROPSHADOW) {
585 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
586 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
587 printf("passes: %d\n", f->passes);
588 printf("angle: %f distance: %f\n", f->angle, f->distance);
589 printf("strength: %f passes: %d\n", f->strength, f->passes);
590 printf("flags: %s%s%s\n",
591 f->knockout?"knockout ":"",
592 f->composite?"composite ":"",
593 f->innershadow?"innershadow ":"");
594 } if(filter->type == FILTERTYPE_BEVEL) {
595 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
596 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
597 printf("passes: %d\n", f->passes);
598 printf("angle: %f distance: %f\n", f->angle, f->distance);
599 printf("strength: %f passes: %d\n", f->strength, f->passes);
600 printf("flags: %s%s%s%s\n",
602 f->knockout?"knockout ":"",
603 f->composite?"composite ":"",
604 f->innershadow?"innershadow ":"");
605 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
606 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
607 swf_DumpGradient(stdout, f->gradient);
608 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
609 printf("angle: %f distance: %f\n", f->angle, f->distance);
610 printf("strength: %f passes: %d\n", f->strength, f->passes);
611 printf("flags: %s%s%s%s\n",
612 f->knockout?"knockout ":"",
613 f->ontop?"ontop ":"",
614 f->composite?"composite ":"",
615 f->innershadow?"innershadow ":"");
620 void handlePlaceObject23(TAG*tag, char*prefix)
626 int ppos[3] = {0,0,0};
627 swf_SetTagPos(tag, 0);
628 flags = swf_GetU8(tag);
629 if(tag->id == ST_PLACEOBJECT3)
630 flags2 = swf_GetU8(tag);
631 swf_GetU16(tag); //depth
634 if(flags&2) swf_GetU16(tag); //id
636 swf_GetMatrix(tag,&m);
638 ppos[0] += sprintf(pstr[0], "| Matrix ");
639 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
640 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
644 swf_GetCXForm(tag, &cx, 1);
646 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
647 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);
648 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
652 U16 ratio = swf_GetU16(tag); //ratio
654 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
655 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
656 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
660 U16 clip = swf_GetU16(tag); //clip
662 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
663 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
664 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
667 if(flags&32) { while(swf_GetU8(tag)); }
669 if(flags2&1) { // filter list
670 U8 num = swf_GetU8(tag);
672 printf("\n%d filters\n", num);
673 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
676 FILTER*filter = swf_GetFilter(tag);
682 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
687 if(flags2&2) { // blend mode
688 U8 blendmode = swf_GetU8(tag);
692 sprintf(name, "%-5d", blendmode);
693 for(t=0;blendModeNames[t];t++) {
695 sprintf(name, "%-5s", blendModeNames[t]);
699 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
700 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
701 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
705 if(placements && ppos[0]) {
707 printf("%s %s\n", prefix, pstr[0]);
708 printf("%s %s\n", prefix, pstr[1]);
709 printf("%s %s", prefix, pstr[2]);
718 reserved = swf_GetU16(tag); // must be 0
719 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
721 printf("Unknown parameter field not zero: %04x\n", reserved);
724 printf("global flags: %04x\n", globalflags);
726 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
728 handlerflags = swf_GetU32(tag);
731 while(handlerflags) {
736 globalflags &= ~handlerflags;
737 printf("%s flags %08x ",prefix, handlerflags);
738 printhandlerflags(handlerflags);
739 length = swf_GetU32(tag);
740 printf(", %d bytes actioncode\n",length);
741 a = swf_ActionGet(tag);
742 swf_DumpActions(a,prefix);
745 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
747 if(globalflags) // should go to sterr.
748 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
750 printf(" has action code\n");
755 void handlePlaceObject(TAG*tag, char*prefix)
757 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
762 swf_SetTagPos(tag, 0);
763 id = swf_GetU16(tag);
764 depth = swf_GetU16(tag);
765 swf_GetMatrix(tag, &matrix);
766 swf_GetCXForm(tag, &cxform, 0);
768 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
769 swf_SetU16(tag2, depth);
770 swf_SetU16(tag2, id);
771 swf_SetMatrix(tag2, &matrix);
772 swf_SetCXForm(tag2, &cxform, 1);
774 handlePlaceObject23(tag2, prefix);
777 char* fillstyle2str(FILLSTYLE*style)
779 switch(style->type) {
781 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
783 case 0x10: case 0x11: case 0x12: case 0x13:
784 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
786 case 0x40: case 0x42:
787 /* TODO: display information about that bitmap */
788 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
789 /* TODO: show matrix */
790 //swf_DumpMatrix(stdout, &style->m);
792 case 0x41: case 0x43:
793 /* TODO: display information about that bitmap */
794 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
795 /* TODO: show matrix */
796 //swf_DumpMatrix(stdout, &style->m);
799 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
803 char* linestyle2str(LINESTYLE*style)
805 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
809 void handleShape(TAG*tag, char*prefix)
817 swf_ParseDefineShape(tag, &shape);
819 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
821 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
826 else printf("%s | (Neither line nor fill styles)\n", prefix);
829 printf("%s", prefix);
830 if(t < shape.numfillstyles) {
831 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
835 if(t < shape.numlinestyles) {
836 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
839 //if(shape.fillstyles[t].type&0x40) {
840 // MATRIX m = shape.fillstyles[t].m;
841 // swf_DumpMatrix(stdout, &m);
845 printf("%s |\n", prefix);
849 printf("%s | fill: %02d/%02d line:%02d - ",
854 if(line->type == moveTo) {
855 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
856 } else if(line->type == lineTo) {
857 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
858 } else if(line->type == splineTo) {
859 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
860 line->sx/20.0, line->sy/20.0,
861 line->x/20.0, line->y/20.0
866 printf("%s |\n", prefix);
869 void fontcallback1(void*self, U16 id,U8 * name)
873 void fontcallback2(void*self, U16 id,U8 * name)
875 swf_FontExtract(&swf,id,&fonts[fontnum]);
879 static U8 printable(U8 a)
881 if(a<32 || a==127) return '.';
884 void hexdumpTag(TAG*tag, char* prefix)
888 printf(" %s-=> ",prefix);
889 for(t=0;t<tag->len;t++) {
890 printf("%02x ", tag->data[t]);
891 ascii[t&15] = printable(tag->data[t]);
892 if((t && ((t&15)==15)) || (t==tag->len-1))
896 for(s=p-1;s<16;s++) {
900 printf(" %s\n", ascii);
902 printf(" %s\n %s-=> ",ascii,prefix);
907 void handleExportAssets(TAG*tag, char* prefix)
913 num = swf_GetU16(tag);
916 id = swf_GetU16(tag);
917 name = swf_GetString(tag);
918 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
922 void dumperror(const char* format, ...)
927 va_start(arglist, format);
928 vsprintf(buf, format, arglist);
932 printf("==== Error: %s ====\n", buf);
935 static char strbuf[800];
938 char* timestring(double f)
940 int hours = (int)(f/3600);
941 int minutes = (int)((f-hours*3600)/60);
942 int seconds = (int)((f-hours*3600-minutes*60));
943 int useconds = (int)((f-(int)f)*1000+0.5);
946 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
947 return &strbuf[bufpos];
950 int main (int argc,char ** argv)
958 char issprite = 0; // are we inside a sprite definition?
961 char* spriteframelabel = 0;
962 char* framelabel = 0;
967 memset(idtab,0,65536);
969 processargs(argc, argv);
973 fprintf(stderr, "You must supply a filename.\n");
977 f = open(filename,O_RDONLY|O_BINARY);
981 sprintf(buffer, "Couldn't open %.200s", filename);
987 char compressed = (header[0]=='C');
988 char isflash = header[0]=='F' && header[1] == 'W' && header[2] == 'S' ||
989 header[0]=='C' && header[1] == 'W' && header[2] == 'S';
992 int fl=strlen(filename);
993 if(!isflash && fl>3 && !strcmp(&filename[fl-4], ".abc")) {
994 swf_ReadABCfile(filename, &swf);
996 f = open(filename,O_RDONLY|O_BINARY);
997 if FAILED(swf_ReadSWF(f,&swf))
999 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1006 if(statbuf.st_size != swf.fileSize && !compressed)
1007 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1008 statbuf.st_size, swf.fileSize);
1009 filesize = statbuf.st_size;
1014 //if(action && swf.fileVersion>=9) {
1015 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1019 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1020 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1024 printf("-X %d", xsize);
1026 if((xy&1) && (xy&6))
1030 printf("-Y %d", ysize);
1032 if((xy&3) && (xy&4))
1036 printf("-r %.2f", swf.frameRate/256.0);
1038 if((xy&7) && (xy&8))
1042 printf("-f %d", swf.frameCount);
1049 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1050 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0","10,0,0,0", "11,0,0,0", "12,0,0,0"};
1051 if(swf.fileVersion>10) {
1052 fprintf(stderr, "Fileversion>10\n");
1057 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1058 "<param name=\"movie\" value=\"%s\"/>\n"
1059 "<param name=\"play\" value=\"true\"/>\n"
1060 "<param name=\"loop\" value=\"false\"/>\n"
1061 "<param name=\"quality\" value=\"high\"/>\n"
1062 "<param name=\"loop\" value=\"false\"/>\n"
1063 "</object>\n\n", filename, xsize, ysize, filename);
1065 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1067 //" BGCOLOR=#ffffffff\n"?
1069 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1070 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1071 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1072 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1073 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1074 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1075 " <PARAM NAME=\"ALLOWSCRIPTACCESS\" VALUE=\"always\">\n"
1076 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1077 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1078 " TYPE=\"application/x-shockwave-flash\"\n"
1079 " ALLOWSCRIPTACCESS=\"always\"\n"
1080 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1082 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1083 filename, filename, xsize, ysize);
1087 printf("[HEADER] File version: %d\n", swf.fileVersion);
1089 printf("[HEADER] File is zlib compressed.");
1090 if(filesize && swf.fileSize)
1091 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1095 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1096 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1097 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1098 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1099 if(swf.movieSize.xmin)
1100 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1103 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1104 if(swf.movieSize.ymin)
1105 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1113 swf_FontEnumerate(&swf,&fontcallback1, 0);
1114 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1116 swf_FontEnumerate(&swf,&fontcallback2, 0);
1120 char*name = swf_TagGetName(tag);
1123 dumperror("Unknown tag:0x%03x", tag->id);
1128 name = "UNKNOWN TAG";
1131 filepos += tag->len;
1132 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1134 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1137 if(swf_isDefiningTag(tag)) {
1138 U16 id = swf_GetDefineID(tag);
1139 printf(" defines id %04d", id);
1141 dumperror("Id %04d is defined more than once.", id);
1144 else if(swf_isPseudoDefiningTag(tag)) {
1145 U16 id = swf_GetDefineID(tag);
1146 printf(" adds information to id %04d", id);
1148 dumperror("Id %04d is not yet defined.\n", id);
1150 else if(tag->id == ST_PLACEOBJECT) {
1151 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1152 if(swf_GetName(tag))
1153 printf(" name \"%s\"",swf_GetName(tag));
1155 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1162 printf(" id %04d",swf_GetPlaceID(tag));
1166 printf(" at depth %04d", swf_GetDepth(tag));
1168 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1169 printf(" as bitmap");
1171 swf_SetTagPos(tag, 0);
1172 if(tag->data[0]&64) {
1174 swf_GetPlaceObject(tag, &po);
1175 printf(" (clip to %04d)", po.clipdepth);
1176 swf_PlaceObjectFree(&po);
1178 if(swf_GetName(tag))
1179 printf(" name \"%s\"",swf_GetName(tag));
1182 else if(tag->id == ST_REMOVEOBJECT) {
1183 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1185 else if(tag->id == ST_REMOVEOBJECT2) {
1186 printf(" removes object from depth %04d", swf_GetDepth(tag));
1188 else if(tag->id == ST_FREECHARACTER) {
1189 printf(" frees object %04d", swf_GetPlaceID(tag));
1191 else if(tag->id == ST_FILEATTRIBUTES) {
1192 swf_SetTagPos(tag, 0);
1193 U32 flags = swf_GetU32(tag);
1194 if(flags&1) printf(" usenetwork");
1195 if(flags&8) printf(" as3");
1196 if(flags&16) printf(" symbolclass");
1198 printf(" flags=%02x", flags);
1200 else if(tag->id == ST_DOABC) {
1201 swf_SetTagPos(tag, 0);
1202 U32 flags = swf_GetU32(tag);
1203 char*s = swf_GetString(tag);
1205 printf(" flags=%08x", flags);
1208 printf(" \"%s\"", s);
1213 printf(" lazy load");
1215 swf_SetTagPos(tag, 0);
1217 else if(tag->id == ST_STARTSOUND) {
1220 id = swf_GetU16(tag);
1221 flags = swf_GetU8(tag);
1223 printf(" stops sound with id %04d", id);
1225 printf(" starts sound with id %04d", id);
1227 printf(" (if not already playing)");
1233 printf(" looping %d times", swf_GetU16(tag));
1236 else if(tag->id == ST_FRAMELABEL) {
1237 int l = strlen(tag->data);
1238 printf(" \"%s\"", tag->data);
1239 if((l+1) < tag->len) {
1240 printf(" has %d extra bytes", tag->len-1-l);
1241 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1242 printf(" (ANCHOR)");
1244 if((framelabel && !issprite) ||
1245 (spriteframelabel && issprite)) {
1246 dumperror("Frame %d has more than one label",
1247 issprite?spriteframe:mainframe);
1249 if(issprite) spriteframelabel = tag->data;
1250 else framelabel = tag->data;
1252 else if(tag->id == ST_SHOWFRAME) {
1253 char*label = issprite?spriteframelabel:framelabel;
1254 int frame = issprite?spriteframe:mainframe;
1257 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1259 if(issprite) spriteframe++;
1265 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1267 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1268 timestring(frame*(256.0/(swf.frameRate+0.1))),
1269 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1272 printf(" (label \"%s\")", label);
1273 if(issprite) {spriteframe++; spriteframelabel = 0;}
1274 if(!issprite) {mainframe++; framelabel = 0;}
1276 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1277 U8 r = swf_GetU8(tag);
1278 U8 g = swf_GetU8(tag);
1279 U8 b = swf_GetU8(tag);
1280 printf(" (%02x/%02x/%02x)",r,g,b);
1282 else if(tag->id == ST_PROTECT) {
1284 printf(" %s", swf_GetString(tag));
1287 else if(tag->id == ST_CSMTEXTSETTINGS) {
1288 U16 id = swf_GetU16(tag);
1289 U8 flags = swf_GetU8(tag);
1292 printf("flashtype,");
1294 switch(((flags>>3)&7)) {
1295 case 0:printf("no grid,");break;
1296 case 1:printf("pixel grid,");break;
1297 case 2:printf("subpixel grid,");break;
1298 case 3:printf("unknown grid,");break;
1301 printf("unknown[%08x],", flags);
1302 float thickness = swf_GetFixed(tag);
1303 float sharpness = swf_GetFixed(tag);
1304 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1308 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1309 tag->id == ST_DEFINEBITSLOSSLESS2) {
1310 handleDefineBits(tag);
1313 else if(tag->id == ST_DEFINESOUND) {
1314 handleDefineSound(tag);
1317 else if(tag->id == ST_VIDEOFRAME) {
1318 handleVideoFrame(tag, myprefix);
1321 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1322 handleVideoStream(tag, myprefix);
1325 else if(tag->id == ST_DEFINEEDITTEXT) {
1326 handleEditText(tag);
1329 else if(tag->id == ST_DEFINEMOVIE) {
1330 U16 id = swf_GetU16(tag);
1331 char*s = swf_GetString(tag);
1332 printf(" URL: %s\n", s);
1334 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1340 else if(tag->id == ST_DEFINESCALINGGRID) {
1341 U16 id = swf_GetU16(tag);
1343 swf_GetRect(tag, &r);
1344 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1346 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1348 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1350 printf(" \"%s\"\n", swf_GetString(tag));
1356 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1357 SRECT r = swf_GetDefineBBox(tag);
1358 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1365 sprintf(myprefix, " %s", prefix);
1367 if(tag->id == ST_DEFINESPRITE) {
1368 sprintf(prefix, " ");
1370 dumperror("Sprite definition inside a sprite definition");
1374 spriteframelabel = 0;
1376 else if(tag->id == ST_END) {
1379 spriteframelabel = 0;
1381 dumperror("End Tag not empty");
1383 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1384 handleExportAssets(tag, myprefix);
1386 else if(tag->id == ST_DOACTION && action) {
1388 actions = swf_ActionGet(tag);
1389 swf_DumpActions(actions, myprefix);
1391 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1392 void*abccode = swf_ReadABC(tag);
1393 swf_DumpABC(stdout, abccode, "");
1394 swf_FreeABC(abccode);
1396 else if(tag->id == ST_DOINITACTION && action) {
1398 swf_GetU16(tag); // id
1399 actions = swf_ActionGet(tag);
1400 swf_DumpActions(actions, myprefix);
1402 else if(tag->id == ST_DEFINEBUTTON) {
1404 dumpButton(tag, myprefix);
1407 dumpButtonActions(tag, myprefix);
1410 else if(swf_isFontTag(tag) && showfonts) {
1411 dumpFont(tag, myprefix);
1413 else if(tag->id == ST_DEFINEBUTTON2) {
1415 dumpButton2Actions(tag, myprefix);
1418 else if(tag->id == ST_PLACEOBJECT) {
1419 handlePlaceObject(tag, myprefix);
1421 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1422 handlePlaceObject23(tag, myprefix);
1424 else if(tag->id == ST_DEFINEFONTNAME) {
1425 swf_SetTagPos(tag, 0);
1426 swf_GetU16(tag); //id
1427 swf_GetString(tag); //name
1428 char* copyright = swf_GetString(tag);
1429 printf("%s%s\n", myprefix, copyright);
1431 else if(tag->id == ST_DEFINESHAPE ||
1432 tag->id == ST_DEFINESHAPE2 ||
1433 tag->id == ST_DEFINESHAPE3 ||
1434 tag->id == ST_DEFINESHAPE4) {
1436 handleShape(tag, myprefix);
1439 if(tag->len && used) {
1440 int num = swf_GetNumUsedIDs(tag);
1444 used = (int*)malloc(sizeof(int)*num);
1445 swf_GetUsedIDs(tag, used);
1446 printf("%s%suses IDs: ", indent, prefix);
1447 for(t=0;t<num;t++) {
1449 swf_SetTagPos(tag, used[t]);
1450 id = swf_GetU16(tag);
1451 printf("%d%s", id, t<num-1?", ":"");
1453 dumperror("Id %04d is not yet defined.\n", id);
1460 if(tag->id == ST_FREECHARACTER) {
1462 swf_SetTagPos(tag, 0);
1463 id = swf_GetU16(tag);
1467 if(tag->len && hex) {
1468 hexdumpTag(tag, prefix);