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"};
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 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1076 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1077 " TYPE=\"application/x-shockwave-flash\"\n"
1078 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1080 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1081 filename, filename, xsize, ysize);
1085 printf("[HEADER] File version: %d\n", swf.fileVersion);
1087 printf("[HEADER] File is zlib compressed.");
1088 if(filesize && swf.fileSize)
1089 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1093 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1094 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1095 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1096 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1097 if(swf.movieSize.xmin)
1098 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1101 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1102 if(swf.movieSize.ymin)
1103 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1111 swf_FontEnumerate(&swf,&fontcallback1, 0);
1112 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1114 swf_FontEnumerate(&swf,&fontcallback2, 0);
1118 char*name = swf_TagGetName(tag);
1121 dumperror("Unknown tag:0x%03x", tag->id);
1126 name = "UNKNOWN TAG";
1129 filepos += tag->len;
1130 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1132 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1135 if(swf_isDefiningTag(tag)) {
1136 U16 id = swf_GetDefineID(tag);
1137 printf(" defines id %04d", id);
1139 dumperror("Id %04d is defined more than once.", id);
1142 else if(swf_isPseudoDefiningTag(tag)) {
1143 U16 id = swf_GetDefineID(tag);
1144 printf(" adds information to id %04d", id);
1146 dumperror("Id %04d is not yet defined.\n", id);
1148 else if(tag->id == ST_PLACEOBJECT) {
1149 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1150 if(swf_GetName(tag))
1151 printf(" name \"%s\"",swf_GetName(tag));
1153 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1160 printf(" id %04d",swf_GetPlaceID(tag));
1164 printf(" at depth %04d", swf_GetDepth(tag));
1166 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1167 printf(" as bitmap");
1169 swf_SetTagPos(tag, 0);
1170 if(tag->data[0]&64) {
1172 swf_GetPlaceObject(tag, &po);
1173 printf(" (clip to %04d)", po.clipdepth);
1174 swf_PlaceObjectFree(&po);
1176 if(swf_GetName(tag))
1177 printf(" name \"%s\"",swf_GetName(tag));
1180 else if(tag->id == ST_REMOVEOBJECT) {
1181 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1183 else if(tag->id == ST_REMOVEOBJECT2) {
1184 printf(" removes object from depth %04d", swf_GetDepth(tag));
1186 else if(tag->id == ST_FREECHARACTER) {
1187 printf(" frees object %04d", swf_GetPlaceID(tag));
1189 else if(tag->id == ST_FILEATTRIBUTES) {
1190 swf_SetTagPos(tag, 0);
1191 U32 flags = swf_GetU32(tag);
1192 if(flags&1) printf(" usenetwork");
1193 if(flags&8) printf(" as3");
1194 if(flags&16) printf(" symbolclass");
1196 printf(" flags=%02x", flags);
1198 else if(tag->id == ST_DOABC) {
1199 swf_SetTagPos(tag, 0);
1200 U32 flags = swf_GetU32(tag);
1201 char*s = swf_GetString(tag);
1203 printf(" flags=%08x", flags);
1206 printf(" \"%s\"", s);
1211 printf(" lazy load");
1213 swf_SetTagPos(tag, 0);
1215 else if(tag->id == ST_STARTSOUND) {
1218 id = swf_GetU16(tag);
1219 flags = swf_GetU8(tag);
1221 printf(" stops sound with id %04d", id);
1223 printf(" starts sound with id %04d", id);
1225 printf(" (if not already playing)");
1231 printf(" looping %d times", swf_GetU16(tag));
1234 else if(tag->id == ST_FRAMELABEL) {
1235 int l = strlen(tag->data);
1236 printf(" \"%s\"", tag->data);
1237 if((l+1) < tag->len) {
1238 printf(" has %d extra bytes", tag->len-1-l);
1239 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1240 printf(" (ANCHOR)");
1242 if((framelabel && !issprite) ||
1243 (spriteframelabel && issprite)) {
1244 dumperror("Frame %d has more than one label",
1245 issprite?spriteframe:mainframe);
1247 if(issprite) spriteframelabel = tag->data;
1248 else framelabel = tag->data;
1250 else if(tag->id == ST_SHOWFRAME) {
1251 char*label = issprite?spriteframelabel:framelabel;
1252 int frame = issprite?spriteframe:mainframe;
1255 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1257 if(issprite) spriteframe++;
1263 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1265 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1266 timestring(frame*(256.0/(swf.frameRate+0.1))),
1267 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1270 printf(" (label \"%s\")", label);
1271 if(issprite) {spriteframe++; spriteframelabel = 0;}
1272 if(!issprite) {mainframe++; framelabel = 0;}
1274 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1275 U8 r = swf_GetU8(tag);
1276 U8 g = swf_GetU8(tag);
1277 U8 b = swf_GetU8(tag);
1278 printf(" (%02x/%02x/%02x)",r,g,b);
1280 else if(tag->id == ST_PROTECT) {
1282 printf(" %s", swf_GetString(tag));
1285 else if(tag->id == ST_CSMTEXTSETTINGS) {
1286 U16 id = swf_GetU16(tag);
1287 U8 flags = swf_GetU8(tag);
1290 printf("flashtype,");
1292 switch(((flags>>3)&7)) {
1293 case 0:printf("no grid,");break;
1294 case 1:printf("pixel grid,");break;
1295 case 2:printf("subpixel grid,");break;
1296 case 3:printf("unknown grid,");break;
1299 printf("unknown[%08x],", flags);
1300 float thickness = swf_GetFixed(tag);
1301 float sharpness = swf_GetFixed(tag);
1302 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1306 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1307 tag->id == ST_DEFINEBITSLOSSLESS2) {
1308 handleDefineBits(tag);
1311 else if(tag->id == ST_DEFINESOUND) {
1312 handleDefineSound(tag);
1315 else if(tag->id == ST_VIDEOFRAME) {
1316 handleVideoFrame(tag, myprefix);
1319 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1320 handleVideoStream(tag, myprefix);
1323 else if(tag->id == ST_DEFINEEDITTEXT) {
1324 handleEditText(tag);
1327 else if(tag->id == ST_DEFINEMOVIE) {
1328 U16 id = swf_GetU16(tag);
1329 char*s = swf_GetString(tag);
1330 printf(" URL: %s\n", s);
1332 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1338 else if(tag->id == ST_DEFINESCALINGGRID) {
1339 U16 id = swf_GetU16(tag);
1341 swf_GetRect(tag, &r);
1342 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1344 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1346 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1348 printf(" \"%s\"\n", swf_GetString(tag));
1354 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1355 SRECT r = swf_GetDefineBBox(tag);
1356 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1363 sprintf(myprefix, " %s", prefix);
1365 if(tag->id == ST_DEFINESPRITE) {
1366 sprintf(prefix, " ");
1368 dumperror("Sprite definition inside a sprite definition");
1372 spriteframelabel = 0;
1374 else if(tag->id == ST_END) {
1377 spriteframelabel = 0;
1379 dumperror("End Tag not empty");
1381 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1382 handleExportAssets(tag, myprefix);
1384 else if(tag->id == ST_DOACTION && action) {
1386 actions = swf_ActionGet(tag);
1387 swf_DumpActions(actions, myprefix);
1389 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1390 void*abccode = swf_ReadABC(tag);
1391 swf_DumpABC(stdout, abccode, "");
1392 swf_FreeABC(abccode);
1394 else if(tag->id == ST_DOINITACTION && action) {
1396 swf_GetU16(tag); // id
1397 actions = swf_ActionGet(tag);
1398 swf_DumpActions(actions, myprefix);
1400 else if(tag->id == ST_DEFINEBUTTON) {
1402 dumpButton(tag, myprefix);
1405 dumpButtonActions(tag, myprefix);
1408 else if(swf_isFontTag(tag) && showfonts) {
1409 dumpFont(tag, myprefix);
1411 else if(tag->id == ST_DEFINEBUTTON2) {
1413 dumpButton2Actions(tag, myprefix);
1416 else if(tag->id == ST_PLACEOBJECT) {
1417 handlePlaceObject(tag, myprefix);
1419 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1420 handlePlaceObject23(tag, myprefix);
1422 else if(tag->id == ST_DEFINEFONTNAME) {
1423 swf_SetTagPos(tag, 0);
1424 swf_GetU16(tag); //id
1425 swf_GetString(tag); //name
1426 char* copyright = swf_GetString(tag);
1427 printf("%s%s\n", myprefix, copyright);
1429 else if(tag->id == ST_DEFINESHAPE ||
1430 tag->id == ST_DEFINESHAPE2 ||
1431 tag->id == ST_DEFINESHAPE3 ||
1432 tag->id == ST_DEFINESHAPE4) {
1434 handleShape(tag, myprefix);
1437 if(tag->len && used) {
1438 int num = swf_GetNumUsedIDs(tag);
1442 used = (int*)malloc(sizeof(int)*num);
1443 swf_GetUsedIDs(tag, used);
1444 printf("%s%suses IDs: ", indent, prefix);
1445 for(t=0;t<num;t++) {
1447 swf_SetTagPos(tag, used[t]);
1448 id = swf_GetU16(tag);
1449 printf("%d%s", id, t<num-1?", ":"");
1451 dumperror("Id %04d is not yet defined.\n", id);
1458 if(tag->id == ST_FREECHARACTER) {
1460 swf_SetTagPos(tag, 0);
1461 id = swf_GetU16(tag);
1465 if(tag->len && hex) {
1466 hexdumpTag(tag, prefix);