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);
350 printf("%sencoding table:", prefix, prefix);
351 char filled0=0, lastfilled=0;
352 for(t=0;t<font->maxascii;t++) {
354 printf("\n%s%08x ", prefix, t);
357 for(s=t;s<font->maxascii;s++) {
358 if(font->ascii2glyph[s]>=0) break;
367 for(s=t;s<t+16 && s<font->maxascii;s++) {
368 if(font->ascii2glyph[s]>=0) filled0=1;
371 printf("%4d ", font->ascii2glyph[t]);
379 static int fontnum = 0;
380 static SWFFONT**fonts;
382 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
385 printf(" <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a);
386 for(t=0;t<fontnum;t++)
388 if(fonts[t]->id == fontid) {
398 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
399 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
402 if(fonts[font]->glyph2ascii[glyphs[t]])
403 a = fonts[font]->glyph2ascii[glyphs[t]];
413 printf("\\x%x", (int)a);
418 void handleText(TAG*tag, char*prefix)
422 swf_SetTagPos(tag, 0);
425 swf_ResetReadBits(tag);
427 swf_GetMatrix(tag, &m);
428 printf("%s| Matrix\n",prefix);
429 printf("%s| %5.3f %5.3f %6.2f\n", prefix, m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
430 printf("%s| %5.3f %5.3f %6.2f\n", prefix, m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
431 swf_SetTagPos(tag, 0);
434 swf_ParseDefineText(tag,textcallback, 0);
438 void handleDefineSound(TAG*tag)
440 U16 id = swf_GetU16(tag);
441 U8 flags = swf_GetU8(tag);
442 int compression = (flags>>4)&7;
443 int rate = (flags>>2)&3;
444 int bits = flags&2?16:8;
445 int stereo = flags&1;
447 if(compression == 0) printf("Raw ");
448 else if(compression == 1) printf("ADPCM ");
449 else if(compression == 2) printf("MP3 ");
450 else if(compression == 3) printf("Raw little-endian ");
451 else if(compression == 6) printf("ASAO ");
453 if(rate == 0) printf("5.5Khz ");
454 if(rate == 1) printf("11Khz ");
455 if(rate == 2) printf("22Khz ");
456 if(rate == 3) printf("44Khz ");
457 printf("%dBit ", bits);
458 if(stereo) printf("stereo");
463 void handleDefineBits(TAG*tag)
469 id = swf_GetU16(tag);
470 mode = swf_GetU8(tag);
471 width = swf_GetU16(tag);
472 height = swf_GetU16(tag);
473 printf(" image %dx%d",width,height);
474 if(mode == 3) printf(" (8 bpp)");
475 else if(mode == 4) printf(" (16 bpp)");
476 else if(mode == 5) printf(" (32 bpp)");
477 else printf(" (? bpp)");
480 void handleEditText(TAG*tag)
485 id = swf_GetU16(tag);
488 //swf_ResetReadBits(tag);
494 flags = swf_GetBits(tag,16);
495 if(flags & ET_HASFONT) {
496 swf_GetU16(tag); //font
497 swf_GetU16(tag); //fontheight
499 if(flags & ET_HASTEXTCOLOR) {
500 swf_GetU8(tag); //rgba
505 if(flags & ET_HASMAXLENGTH) {
506 swf_GetU16(tag); //maxlength
508 if(flags & ET_HASLAYOUT) {
509 swf_GetU8(tag); //align
510 swf_GetU16(tag); //left margin
511 swf_GetU16(tag); //right margin
512 swf_GetU16(tag); //indent
513 swf_GetU16(tag); //leading
515 printf(" variable \"%s\" ", &tag->data[tag->pos]);
516 if(flags & ET_HTML) printf("(html)");
517 if(flags & ET_NOSELECT) printf("(noselect)");
518 if(flags & ET_PASSWORD) printf("(password)");
519 if(flags & ET_READONLY) printf("(readonly)");
521 if(flags & (ET_X1 | ET_X3 ))
523 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
526 while(tag->data[tag->pos++]);
527 if(flags & ET_HASTEXT)
528 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
531 void printhandlerflags(U32 handlerflags)
533 if(handlerflags&1) printf("[on load]");
534 if(handlerflags&2) printf("[enter frame]");
535 if(handlerflags&4) printf("[unload]");
536 if(handlerflags&8) printf("[mouse move]");
537 if(handlerflags&16) printf("[mouse down]");
538 if(handlerflags&32) printf("[mouse up]");
539 if(handlerflags&64) printf("[key down]");
540 if(handlerflags&128) printf("[key up]");
542 if(handlerflags&256) printf("[data]");
543 if(handlerflags&512) printf("[initialize]");
544 if(handlerflags&1024) printf("[mouse press]");
545 if(handlerflags&2048) printf("[mouse release]");
546 if(handlerflags&4096) printf("[mouse release outside]");
547 if(handlerflags&8192) printf("[mouse rollover]");
548 if(handlerflags&16384) printf("[mouse rollout]");
549 if(handlerflags&32768) printf("[mouse drag over]");
551 if(handlerflags&0x10000) printf("[mouse drag out]");
552 if(handlerflags&0x20000) printf("[key press]");
553 if(handlerflags&0x40000) printf("[construct even]");
554 if(handlerflags&0xfff80000) printf("[???]");
556 void handleVideoStream(TAG*tag, char*prefix)
558 U16 id = swf_GetU16(tag);
559 U16 frames = swf_GetU16(tag);
560 U16 width = swf_GetU16(tag);
561 U16 height = swf_GetU16(tag);
562 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
563 U8 codec = swf_GetU8(tag);
564 printf(" (%d frames, %dx%d", frames, width, height);
568 printf(" sorenson h.263)");
570 printf(" codec 0x%02x)", codec);
572 void handleVideoFrame(TAG*tag, char*prefix)
574 U32 code, version, reference, sizeflags;
575 U32 width=0, height=0;
577 U16 id = swf_GetU16(tag);
578 U16 frame = swf_GetU16(tag);
579 U8 deblock,flags, tmp, bit;
581 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
582 printf(" (frame %d) ", frame);
584 /* video packet follows */
585 code = swf_GetBits(tag, 17);
586 version = swf_GetBits(tag, 5);
587 reference = swf_GetBits(tag, 8);
589 sizeflags = swf_GetBits(tag, 3);
592 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
593 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
594 case 2: width = 352; height = 288; break;
595 case 3: width = 176; height = 144; break;
596 case 4: width = 128; height = 96; break;
597 case 5: width = 320; height = 240; break;
598 case 6: width = 160; height = 120; break;
599 case 7: width = -1; height = -1;/*reserved*/ break;
601 printf("%dx%d ", width, height);
602 type = swf_GetBits(tag, 2);
603 printf("%s", types[type]);
605 deblock = swf_GetBits(tag, 1);
607 printf(" deblock ", deblock);
608 quantizer = swf_GetBits(tag, 5);
609 printf(" quant: %d ", quantizer);
612 void dumpFilter(FILTER*filter)
614 if(filter->type == FILTERTYPE_BLUR) {
615 FILTER_BLUR*f = (FILTER_BLUR*)filter;
616 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
617 printf("passes: %d\n", f->passes);
618 } if(filter->type == FILTERTYPE_GLOW) {
619 FILTER_GLOW*f = (FILTER_GLOW*)filter;
620 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
621 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
622 printf("passes: %d\n", f->passes);
623 printf("flags: %s%s%s\n",
624 f->knockout?"knockout ":"",
625 f->composite?"composite ":"",
626 f->innerglow?"innerglow":"");
627 } if(filter->type == FILTERTYPE_DROPSHADOW) {
628 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
629 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
630 printf("passes: %d\n", f->passes);
631 printf("angle: %f distance: %f\n", f->angle, f->distance);
632 printf("strength: %f passes: %d\n", f->strength, f->passes);
633 printf("flags: %s%s%s\n",
634 f->knockout?"knockout ":"",
635 f->composite?"composite ":"",
636 f->innershadow?"innershadow ":"");
637 } if(filter->type == FILTERTYPE_BEVEL) {
638 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
639 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
640 printf("passes: %d\n", f->passes);
641 printf("angle: %f distance: %f\n", f->angle, f->distance);
642 printf("strength: %f passes: %d\n", f->strength, f->passes);
643 printf("flags: %s%s%s%s\n",
645 f->knockout?"knockout ":"",
646 f->composite?"composite ":"",
647 f->innershadow?"innershadow ":"");
648 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
649 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
650 swf_DumpGradient(stdout, f->gradient);
651 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
652 printf("angle: %f distance: %f\n", f->angle, f->distance);
653 printf("strength: %f passes: %d\n", f->strength, f->passes);
654 printf("flags: %s%s%s%s\n",
655 f->knockout?"knockout ":"",
656 f->ontop?"ontop ":"",
657 f->composite?"composite ":"",
658 f->innershadow?"innershadow ":"");
663 void handlePlaceObject23(TAG*tag, char*prefix)
669 int ppos[3] = {0,0,0};
670 swf_SetTagPos(tag, 0);
671 flags = swf_GetU8(tag);
672 if(tag->id == ST_PLACEOBJECT3)
673 flags2 = swf_GetU8(tag);
674 swf_GetU16(tag); //depth
677 if(flags&2) swf_GetU16(tag); //id
679 swf_GetMatrix(tag,&m);
681 ppos[0] += sprintf(pstr[0], "| Matrix ");
682 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
683 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
687 swf_GetCXForm(tag, &cx, 1);
689 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
690 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);
691 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
695 U16 ratio = swf_GetU16(tag); //ratio
697 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
698 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
699 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
703 U16 clip = swf_GetU16(tag); //clip
705 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
706 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
707 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
710 if(flags&32) { while(swf_GetU8(tag)); }
712 if(flags2&1) { // filter list
713 U8 num = swf_GetU8(tag);
715 printf("\n%d filters\n", num);
716 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
719 FILTER*filter = swf_GetFilter(tag);
725 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
730 if(flags2&2) { // blend mode
731 U8 blendmode = swf_GetU8(tag);
735 sprintf(name, "%-5d", blendmode);
736 for(t=0;blendModeNames[t];t++) {
738 sprintf(name, "%-5s", blendModeNames[t]);
742 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
743 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
744 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
748 if(placements && ppos[0]) {
750 printf("%s %s\n", prefix, pstr[0]);
751 printf("%s %s\n", prefix, pstr[1]);
752 printf("%s %s", prefix, pstr[2]);
761 reserved = swf_GetU16(tag); // must be 0
762 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
764 printf("Unknown parameter field not zero: %04x\n", reserved);
767 printf("global flags: %04x\n", globalflags);
769 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
771 handlerflags = swf_GetU32(tag);
774 while(handlerflags) {
779 globalflags &= ~handlerflags;
780 printf("%s flags %08x ",prefix, handlerflags);
781 printhandlerflags(handlerflags);
782 length = swf_GetU32(tag);
783 printf(", %d bytes actioncode\n",length);
784 a = swf_ActionGet(tag);
785 swf_DumpActions(a,prefix);
788 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
790 if(globalflags) // should go to sterr.
791 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
793 printf(" has action code\n");
798 void handlePlaceObject(TAG*tag, char*prefix)
800 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
805 swf_SetTagPos(tag, 0);
806 id = swf_GetU16(tag);
807 depth = swf_GetU16(tag);
808 swf_GetMatrix(tag, &matrix);
809 swf_GetCXForm(tag, &cxform, 0);
811 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
812 swf_SetU16(tag2, depth);
813 swf_SetU16(tag2, id);
814 swf_SetMatrix(tag2, &matrix);
815 swf_SetCXForm(tag2, &cxform, 1);
817 handlePlaceObject23(tag2, prefix);
820 char* fillstyle2str(FILLSTYLE*style)
822 switch(style->type) {
824 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
826 case 0x10: case 0x11: case 0x12: case 0x13:
827 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
829 case 0x40: case 0x42:
830 /* TODO: display information about that bitmap */
831 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
832 /* TODO: show matrix */
833 //swf_DumpMatrix(stdout, &style->m);
835 case 0x41: case 0x43:
836 /* TODO: display information about that bitmap */
837 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
838 /* TODO: show matrix */
839 //swf_DumpMatrix(stdout, &style->m);
842 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
846 char* linestyle2str(LINESTYLE*style)
848 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
852 void handleShape(TAG*tag, char*prefix)
860 swf_ParseDefineShape(tag, &shape);
862 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
864 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
869 else printf("%s | (Neither line nor fill styles)\n", prefix);
872 printf("%s", prefix);
873 if(t < shape.numfillstyles) {
874 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
878 if(t < shape.numlinestyles) {
879 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
882 //if(shape.fillstyles[t].type&0x40) {
883 // MATRIX m = shape.fillstyles[t].m;
884 // swf_DumpMatrix(stdout, &m);
888 printf("%s |\n", prefix);
892 printf("%s | fill: %02d/%02d line:%02d - ",
897 if(line->type == moveTo) {
898 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
899 } else if(line->type == lineTo) {
900 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
901 } else if(line->type == splineTo) {
902 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
903 line->sx/20.0, line->sy/20.0,
904 line->x/20.0, line->y/20.0
909 printf("%s |\n", prefix);
912 void fontcallback1(void*self, U16 id,U8 * name)
916 void fontcallback2(void*self, U16 id,U8 * name)
918 swf_FontExtract(&swf,id,&fonts[fontnum]);
922 static U8 printable(U8 a)
924 if(a<32 || a==127) return '.';
927 void hexdumpTag(TAG*tag, char* prefix)
931 printf(" %s-=> ",prefix);
932 for(t=0;t<tag->len;t++) {
933 printf("%02x ", tag->data[t]);
934 ascii[t&15] = printable(tag->data[t]);
935 if((t && ((t&15)==15)) || (t==tag->len-1))
939 for(s=p-1;s<16;s++) {
943 printf(" %s\n", ascii);
945 printf(" %s\n %s-=> ",ascii,prefix);
950 void handleExportAssets(TAG*tag, char* prefix)
956 num = swf_GetU16(tag);
959 id = swf_GetU16(tag);
960 name = swf_GetString(tag);
961 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
965 void dumperror(const char* format, ...)
970 va_start(arglist, format);
971 vsnprintf(buf, sizeof(buf)-1, format, arglist);
975 printf("==== Error: %s ====\n", buf);
978 static char strbuf[800];
981 char* timestring(double f)
983 int hours = (int)(f/3600);
984 int minutes = (int)((f-hours*3600)/60);
985 int seconds = (int)((f-hours*3600-minutes*60));
986 int useconds = (int)((f-(int)f)*1000+0.5);
989 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
990 return &strbuf[bufpos];
993 int main (int argc,char ** argv)
1001 char issprite = 0; // are we inside a sprite definition?
1002 int spriteframe = 0;
1004 char* spriteframelabel = 0;
1005 char* framelabel = 0;
1010 memset(idtab,0,65536);
1012 processargs(argc, argv);
1016 fprintf(stderr, "You must supply a filename.\n");
1020 f = open(filename,O_RDONLY|O_BINARY);
1024 sprintf(buffer, "Couldn't open %.200s", filename);
1030 char compressed = (header[0]=='C');
1031 char isflash = (header[0]=='F' && header[1] == 'W' && header[2] == 'S') ||
1032 (header[0]=='C' && header[1] == 'W' && header[2] == 'S');
1035 int fl=strlen(filename);
1036 if(!isflash && fl>3 && !strcmp(&filename[fl-4], ".abc")) {
1037 swf_ReadABCfile(filename, &swf);
1039 f = open(filename,O_RDONLY|O_BINARY);
1040 if FAILED(swf_ReadSWF(f,&swf))
1042 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1049 if(statbuf.st_size != swf.fileSize && !compressed)
1050 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1051 statbuf.st_size, swf.fileSize);
1052 filesize = statbuf.st_size;
1057 //if(action && swf.fileVersion>=9) {
1058 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1062 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1063 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1067 printf("-X %d", xsize);
1069 if((xy&1) && (xy&6))
1073 printf("-Y %d", ysize);
1075 if((xy&3) && (xy&4))
1079 printf("-r %.2f", swf.frameRate/256.0);
1081 if((xy&7) && (xy&8))
1085 printf("-f %d", swf.frameCount);
1092 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1093 "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"};
1094 if(swf.fileVersion>10) {
1095 fprintf(stderr, "Fileversion>10\n");
1100 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1101 "<param name=\"movie\" value=\"%s\"/>\n"
1102 "<param name=\"play\" value=\"true\"/>\n"
1103 "<param name=\"loop\" value=\"false\"/>\n"
1104 "<param name=\"quality\" value=\"high\"/>\n"
1105 "<param name=\"loop\" value=\"false\"/>\n"
1106 "</object>\n\n", filename, xsize, ysize, filename);
1108 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1110 //" BGCOLOR=#ffffffff\n"?
1112 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1113 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1114 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1115 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1116 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1117 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1118 " <PARAM NAME=\"ALLOWSCRIPTACCESS\" VALUE=\"always\">\n"
1119 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1120 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1121 " TYPE=\"application/x-shockwave-flash\"\n"
1122 " ALLOWSCRIPTACCESS=\"always\"\n"
1123 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1125 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1126 filename, filename, xsize, ysize);
1130 printf("[HEADER] File version: %d\n", swf.fileVersion);
1132 printf("[HEADER] File is zlib compressed.");
1133 if(filesize && swf.fileSize)
1134 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1138 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1139 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1140 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1141 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1142 if(swf.movieSize.xmin)
1143 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1146 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1147 if(swf.movieSize.ymin)
1148 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1156 swf_FontEnumerate(&swf,&fontcallback1, 0);
1157 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1159 swf_FontEnumerate(&swf,&fontcallback2, 0);
1163 char*name = swf_TagGetName(tag);
1166 dumperror("Unknown tag:0x%03x", tag->id);
1171 name = "UNKNOWN TAG";
1174 filepos += tag->len;
1175 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1177 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1180 if(swf_isDefiningTag(tag)) {
1181 U16 id = swf_GetDefineID(tag);
1182 printf(" defines id %04d", id);
1184 dumperror("Id %04d is defined more than once.", id);
1187 else if(swf_isPseudoDefiningTag(tag)) {
1188 U16 id = swf_GetDefineID(tag);
1189 printf(" adds information to id %04d", id);
1191 dumperror("Id %04d is not yet defined.\n", id);
1193 else if(tag->id == ST_PLACEOBJECT) {
1194 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1195 if(swf_GetName(tag))
1196 printf(" name \"%s\"",swf_GetName(tag));
1198 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1205 printf(" id %04d",swf_GetPlaceID(tag));
1209 printf(" at depth %04d", swf_GetDepth(tag));
1211 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1212 printf(" as bitmap");
1214 swf_SetTagPos(tag, 0);
1215 if(tag->data[0]&64) {
1217 swf_GetPlaceObject(tag, &po);
1218 printf(" (clip to %04d)", po.clipdepth);
1219 swf_PlaceObjectFree(&po);
1221 if(swf_GetName(tag))
1222 printf(" name \"%s\"",swf_GetName(tag));
1225 else if(tag->id == ST_REMOVEOBJECT) {
1226 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1228 else if(tag->id == ST_REMOVEOBJECT2) {
1229 printf(" removes object from depth %04d", swf_GetDepth(tag));
1231 else if(tag->id == ST_FREECHARACTER) {
1232 printf(" frees object %04d", swf_GetPlaceID(tag));
1234 else if(tag->id == ST_FILEATTRIBUTES) {
1235 swf_SetTagPos(tag, 0);
1236 U32 flags = swf_GetU32(tag);
1237 if(flags&FILEATTRIBUTE_USENETWORK) printf(" usenetwork");
1238 if(flags&FILEATTRIBUTE_AS3) printf(" as3");
1239 if(flags&FILEATTRIBUTE_SYMBOLCLASS) printf(" symbolclass");
1240 if(flags&FILEATTRIBUTE_USEHARDWAREGPU) printf(" hardware-gpu");
1241 if(flags&FILEATTRIBUTE_USEACCELERATEDBLIT) printf(" accelerated-blit");
1242 if(flags&~(1|8|16|32|64))
1243 printf(" flags=%02x", flags);
1245 else if(tag->id == ST_DOABC) {
1246 swf_SetTagPos(tag, 0);
1247 U32 flags = swf_GetU32(tag);
1248 char*s = swf_GetString(tag);
1250 printf(" flags=%08x", flags);
1253 printf(" \"%s\"", s);
1258 printf(" lazy load");
1260 swf_SetTagPos(tag, 0);
1262 else if(tag->id == ST_STARTSOUND) {
1265 id = swf_GetU16(tag);
1266 flags = swf_GetU8(tag);
1268 printf(" stops sound with id %04d", id);
1270 printf(" starts sound with id %04d", id);
1272 printf(" (if not already playing)");
1278 printf(" looping %d times", swf_GetU16(tag));
1281 else if(tag->id == ST_FRAMELABEL) {
1282 int l = strlen(tag->data);
1283 printf(" \"%s\"", tag->data);
1284 if((l+1) < tag->len) {
1285 printf(" has %d extra bytes", tag->len-1-l);
1286 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1287 printf(" (ANCHOR)");
1289 if((framelabel && !issprite) ||
1290 (spriteframelabel && issprite)) {
1291 dumperror("Frame %d has more than one label",
1292 issprite?spriteframe:mainframe);
1294 if(issprite) spriteframelabel = tag->data;
1295 else framelabel = tag->data;
1297 else if(tag->id == ST_SHOWFRAME) {
1298 char*label = issprite?spriteframelabel:framelabel;
1299 int frame = issprite?spriteframe:mainframe;
1302 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1304 if(issprite) spriteframe++;
1310 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1312 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1313 timestring(frame*(256.0/(swf.frameRate+0.1))),
1314 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1317 printf(" (label \"%s\")", label);
1318 if(issprite) {spriteframe++; spriteframelabel = 0;}
1319 if(!issprite) {mainframe++; framelabel = 0;}
1321 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1322 U8 r = swf_GetU8(tag);
1323 U8 g = swf_GetU8(tag);
1324 U8 b = swf_GetU8(tag);
1325 printf(" (%02x/%02x/%02x)",r,g,b);
1327 else if(tag->id == ST_PROTECT) {
1329 printf(" %s", swf_GetString(tag));
1332 else if(tag->id == ST_CSMTEXTSETTINGS) {
1333 U16 id = swf_GetU16(tag);
1334 U8 flags = swf_GetU8(tag);
1337 printf("flashtype,");
1339 switch(((flags>>3)&7)) {
1340 case 0:printf("no grid,");break;
1341 case 1:printf("pixel grid,");break;
1342 case 2:printf("subpixel grid,");break;
1343 case 3:printf("unknown grid,");break;
1346 printf("unknown[%08x],", flags);
1347 float thickness = swf_GetFixed(tag);
1348 float sharpness = swf_GetFixed(tag);
1349 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1353 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1354 tag->id == ST_DEFINEBITSLOSSLESS2) {
1355 handleDefineBits(tag);
1358 else if(tag->id == ST_DEFINESOUND) {
1359 handleDefineSound(tag);
1362 else if(tag->id == ST_VIDEOFRAME) {
1363 handleVideoFrame(tag, myprefix);
1366 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1367 handleVideoStream(tag, myprefix);
1370 else if(tag->id == ST_DEFINEEDITTEXT) {
1371 handleEditText(tag);
1374 else if(tag->id == ST_DEFINEMOVIE) {
1375 U16 id = swf_GetU16(tag);
1376 char*s = swf_GetString(tag);
1377 printf(" URL: %s\n", s);
1379 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1380 handleText(tag, myprefix);
1382 else if(tag->id == ST_DEFINESCALINGGRID) {
1383 U16 id = swf_GetU16(tag);
1385 swf_GetRect(tag, &r);
1386 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1388 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1390 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1392 printf(" \"%s\"\n", swf_GetString(tag));
1398 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1399 SRECT r = swf_GetDefineBBox(tag);
1400 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1407 sprintf(myprefix, " %s", prefix);
1409 if(tag->id == ST_DEFINESPRITE) {
1410 sprintf(prefix, " ");
1412 dumperror("Sprite definition inside a sprite definition");
1416 spriteframelabel = 0;
1418 else if(tag->id == ST_END) {
1421 spriteframelabel = 0;
1423 dumperror("End Tag not empty");
1425 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1426 handleExportAssets(tag, myprefix);
1428 else if(tag->id == ST_DOACTION && action) {
1430 actions = swf_ActionGet(tag);
1431 swf_DumpActions(actions, myprefix);
1433 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1434 void*abccode = swf_ReadABC(tag);
1435 swf_DumpABC(stdout, abccode, "");
1436 swf_FreeABC(abccode);
1438 else if(tag->id == ST_DOINITACTION && action) {
1440 swf_GetU16(tag); // id
1441 actions = swf_ActionGet(tag);
1442 swf_DumpActions(actions, myprefix);
1444 else if(tag->id == ST_DEFINEBUTTON) {
1446 dumpButton(tag, myprefix);
1449 dumpButtonActions(tag, myprefix);
1452 else if(swf_isFontTag(tag) && showfonts) {
1453 dumpFont(tag, myprefix);
1455 else if(tag->id == ST_DEFINEBUTTON2) {
1457 dumpButton2Actions(tag, myprefix);
1460 else if(tag->id == ST_PLACEOBJECT) {
1461 handlePlaceObject(tag, myprefix);
1463 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1464 handlePlaceObject23(tag, myprefix);
1466 else if(tag->id == ST_DEFINEFONTNAME) {
1467 swf_SetTagPos(tag, 0);
1468 swf_GetU16(tag); //id
1469 swf_GetString(tag); //name
1470 char* copyright = swf_GetString(tag);
1471 printf("%s%s\n", myprefix, copyright);
1473 else if(tag->id == ST_DEFINESHAPE ||
1474 tag->id == ST_DEFINESHAPE2 ||
1475 tag->id == ST_DEFINESHAPE3 ||
1476 tag->id == ST_DEFINESHAPE4) {
1478 handleShape(tag, myprefix);
1481 if(tag->len && used) {
1482 int num = swf_GetNumUsedIDs(tag);
1486 used = (int*)malloc(sizeof(int)*num);
1487 swf_GetUsedIDs(tag, used);
1488 printf("%s%suses IDs: ", indent, prefix);
1489 for(t=0;t<num;t++) {
1491 swf_SetTagPos(tag, used[t]);
1492 id = swf_GetU16(tag);
1493 printf("%d%s", id, t<num-1?", ":"");
1495 dumperror("Id %04d is not yet defined.\n", id);
1502 if(tag->id == ST_FREECHARACTER) {
1504 swf_SetTagPos(tag, 0);
1505 id = swf_GetU16(tag);
1509 if(tag->len && hex) {
1510 hexdumpTag(tag, prefix);