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 || tag->id == ST_DEFINEFONT3) {
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 static void handleFontAlign1(TAG*tag)
967 swf_SetTagPos(tag, 0);
968 U16 id = swf_GetU16(tag);
969 U8 flags = swf_GetU8(tag);
970 printf(" for font %04d, ", id);
971 if((flags&3)==0) printf("thin, ");
972 else if((flags&3)==1) printf("medium, ");
973 else if((flags&3)==2) printf("thick, ");
976 while(tag->pos < tag->len) {
977 int nr = swf_GetU8(tag); // should be 2
980 printf("*** unsupported multiboxes ***, ");
984 float v1 = swf_GetF16(tag);
985 float v2 = swf_GetF16(tag);
987 U8 xyflags = swf_GetU8(tag);
990 printf(" %d glyphs", num);
993 static void handleFontAlign2(TAG*tag, char*prefix)
997 swf_SetTagPos(tag, 0);
1001 while(tag->pos < tag->len) {
1002 printf("%sglyph %d) ", prefix, num++);
1003 int nr = swf_GetU8(tag); // should be 2
1006 float v1 = swf_GetF16(tag);
1007 float v2 = swf_GetF16(tag);
1008 printf("%f/%f ", v1,v2);
1010 U8 xyflags = swf_GetU8(tag);
1011 printf("xy:%02x\n", xyflags);
1016 void dumperror(const char* format, ...)
1021 va_start(arglist, format);
1022 vsnprintf(buf, sizeof(buf)-1, format, arglist);
1026 printf("==== Error: %s ====\n", buf);
1029 static char strbuf[800];
1030 static int bufpos=0;
1032 char* timestring(double f)
1034 int hours = (int)(f/3600);
1035 int minutes = (int)((f-hours*3600)/60);
1036 int seconds = (int)((f-hours*3600-minutes*60));
1037 int useconds = (int)((f-(int)f)*1000+0.5);
1040 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
1041 return &strbuf[bufpos];
1044 int main (int argc,char ** argv)
1048 struct stat statbuf;
1052 char issprite = 0; // are we inside a sprite definition?
1053 int spriteframe = 0;
1055 char* spriteframelabel = 0;
1056 char* framelabel = 0;
1061 memset(idtab,0,65536);
1063 processargs(argc, argv);
1067 fprintf(stderr, "You must supply a filename.\n");
1071 f = open(filename,O_RDONLY|O_BINARY);
1075 sprintf(buffer, "Couldn't open %.200s", filename);
1081 char compressed = (header[0]=='C');
1082 char isflash = (header[0]=='F' && header[1] == 'W' && header[2] == 'S') ||
1083 (header[0]=='C' && header[1] == 'W' && header[2] == 'S');
1086 int fl=strlen(filename);
1087 if(!isflash && fl>3 && !strcmp(&filename[fl-4], ".abc")) {
1088 swf_ReadABCfile(filename, &swf);
1090 f = open(filename,O_RDONLY|O_BINARY);
1091 if FAILED(swf_ReadSWF(f,&swf))
1093 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1100 if(statbuf.st_size != swf.fileSize && !compressed)
1101 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1102 statbuf.st_size, swf.fileSize);
1103 filesize = statbuf.st_size;
1108 //if(action && swf.fileVersion>=9) {
1109 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1113 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1114 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1118 printf("-X %d", xsize);
1120 if((xy&1) && (xy&6))
1124 printf("-Y %d", ysize);
1126 if((xy&3) && (xy&4))
1130 printf("-r %.2f", swf.frameRate/256.0);
1132 if((xy&7) && (xy&8))
1136 printf("-f %d", swf.frameCount);
1143 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1144 "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"};
1145 if(swf.fileVersion>10) {
1146 fprintf(stderr, "Fileversion>10\n");
1151 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1152 "<param name=\"movie\" value=\"%s\"/>\n"
1153 "<param name=\"play\" value=\"true\"/>\n"
1154 "<param name=\"loop\" value=\"false\"/>\n"
1155 "<param name=\"quality\" value=\"high\"/>\n"
1156 "<param name=\"loop\" value=\"false\"/>\n"
1157 "</object>\n\n", filename, xsize, ysize, filename);
1159 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1161 //" BGCOLOR=#ffffffff\n"?
1163 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1164 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1165 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1166 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1167 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1168 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1169 " <PARAM NAME=\"ALLOWSCRIPTACCESS\" VALUE=\"always\">\n"
1170 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1171 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1172 " TYPE=\"application/x-shockwave-flash\"\n"
1173 " ALLOWSCRIPTACCESS=\"always\"\n"
1174 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1176 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1177 filename, filename, xsize, ysize);
1181 printf("[HEADER] File version: %d\n", swf.fileVersion);
1183 printf("[HEADER] File is zlib compressed.");
1184 if(filesize && swf.fileSize)
1185 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1189 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1190 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1191 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1192 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1193 if(swf.movieSize.xmin)
1194 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1197 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1198 if(swf.movieSize.ymin)
1199 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1207 swf_FontEnumerate(&swf,&fontcallback1, 0);
1208 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1210 swf_FontEnumerate(&swf,&fontcallback2, 0);
1214 char*name = swf_TagGetName(tag);
1217 dumperror("Unknown tag:0x%03x", tag->id);
1222 name = "UNKNOWN TAG";
1225 filepos += tag->len;
1226 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1228 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1231 if(tag->id == ST_PLACEOBJECT) {
1232 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1233 if(swf_GetName(tag))
1234 printf(" name \"%s\"",swf_GetName(tag));
1236 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1243 printf(" id %04d",swf_GetPlaceID(tag));
1247 printf(" at depth %04d", swf_GetDepth(tag));
1249 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1250 printf(" as bitmap");
1252 swf_SetTagPos(tag, 0);
1253 if(tag->data[0]&64) {
1255 swf_GetPlaceObject(tag, &po);
1256 printf(" (clip to %04d)", po.clipdepth);
1257 swf_PlaceObjectFree(&po);
1259 if(swf_GetName(tag))
1260 printf(" name \"%s\"",swf_GetName(tag));
1263 else if(tag->id == ST_REMOVEOBJECT) {
1264 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1266 else if(tag->id == ST_REMOVEOBJECT2) {
1267 printf(" removes object from depth %04d", swf_GetDepth(tag));
1269 else if(tag->id == ST_FREECHARACTER) {
1270 printf(" frees object %04d", swf_GetPlaceID(tag));
1272 else if(tag->id == ST_FILEATTRIBUTES) {
1273 swf_SetTagPos(tag, 0);
1274 U32 flags = swf_GetU32(tag);
1275 if(flags&FILEATTRIBUTE_USENETWORK) printf(" usenetwork");
1276 if(flags&FILEATTRIBUTE_AS3) printf(" as3");
1277 if(flags&FILEATTRIBUTE_SYMBOLCLASS) printf(" symbolclass");
1278 if(flags&FILEATTRIBUTE_USEHARDWAREGPU) printf(" hardware-gpu");
1279 if(flags&FILEATTRIBUTE_USEACCELERATEDBLIT) printf(" accelerated-blit");
1280 if(flags&~(1|8|16|32|64))
1281 printf(" flags=%02x", flags);
1283 else if(tag->id == ST_DOABC) {
1284 swf_SetTagPos(tag, 0);
1285 U32 flags = swf_GetU32(tag);
1286 char*s = swf_GetString(tag);
1288 printf(" flags=%08x", flags);
1291 printf(" \"%s\"", s);
1296 printf(" lazy load");
1298 swf_SetTagPos(tag, 0);
1300 else if(tag->id == ST_STARTSOUND) {
1303 id = swf_GetU16(tag);
1304 flags = swf_GetU8(tag);
1306 printf(" stops sound with id %04d", id);
1308 printf(" starts sound with id %04d", id);
1310 printf(" (if not already playing)");
1316 printf(" looping %d times", swf_GetU16(tag));
1319 else if(tag->id == ST_FRAMELABEL) {
1320 int l = strlen((char*)tag->data);
1321 printf(" \"%s\"", tag->data);
1322 if((l+1) < tag->len) {
1323 printf(" has %d extra bytes", tag->len-1-l);
1324 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1325 printf(" (ANCHOR)");
1327 if((framelabel && !issprite) ||
1328 (spriteframelabel && issprite)) {
1329 dumperror("Frame %d has more than one label",
1330 issprite?spriteframe:mainframe);
1332 if(issprite) spriteframelabel = (char*)tag->data;
1333 else framelabel = (char*)tag->data;
1335 else if(tag->id == ST_SHOWFRAME) {
1336 char*label = issprite?spriteframelabel:framelabel;
1337 int frame = issprite?spriteframe:mainframe;
1340 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1342 if(issprite) spriteframe++;
1348 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1350 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1351 timestring(frame*(256.0/(swf.frameRate+0.1))),
1352 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1355 printf(" (label \"%s\")", label);
1356 if(issprite) {spriteframe++; spriteframelabel = 0;}
1357 if(!issprite) {mainframe++; framelabel = 0;}
1359 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1360 U8 r = swf_GetU8(tag);
1361 U8 g = swf_GetU8(tag);
1362 U8 b = swf_GetU8(tag);
1363 printf(" (%02x/%02x/%02x)",r,g,b);
1365 else if(tag->id == ST_PROTECT) {
1367 printf(" %s", swf_GetString(tag));
1370 else if(tag->id == ST_DEFINEFONTALIGNZONES) {
1371 handleFontAlign1(tag);
1373 else if(tag->id == ST_CSMTEXTSETTINGS) {
1374 U16 id = swf_GetU16(tag);
1375 U8 flags = swf_GetU8(tag);
1378 printf("flashtype,");
1380 switch(((flags>>3)&7)) {
1381 case 0:printf("no grid,");break;
1382 case 1:printf("pixel grid,");break;
1383 case 2:printf("subpixel grid,");break;
1384 case 3:printf("unknown grid,");break;
1387 printf("unknown[%08x],", flags);
1388 float thickness = swf_GetFixed(tag);
1389 float sharpness = swf_GetFixed(tag);
1390 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1393 else if(swf_isDefiningTag(tag)) {
1394 U16 id = swf_GetDefineID(tag);
1395 printf(" defines id %04d", id);
1397 dumperror("Id %04d is defined more than once.", id);
1400 else if(swf_isPseudoDefiningTag(tag)) {
1401 U16 id = swf_GetDefineID(tag);
1402 printf(" adds information to id %04d", id);
1404 dumperror("Id %04d is not yet defined.\n", id);
1407 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1408 tag->id == ST_DEFINEBITSLOSSLESS2) {
1409 handleDefineBits(tag);
1412 else if(tag->id == ST_DEFINESOUND) {
1413 handleDefineSound(tag);
1416 else if(tag->id == ST_VIDEOFRAME) {
1417 handleVideoFrame(tag, myprefix);
1420 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1421 handleVideoStream(tag, myprefix);
1424 else if(tag->id == ST_DEFINEEDITTEXT) {
1425 handleEditText(tag);
1428 else if(tag->id == ST_DEFINEMOVIE) {
1429 U16 id = swf_GetU16(tag);
1430 char*s = swf_GetString(tag);
1431 printf(" URL: %s\n", s);
1433 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1434 handleText(tag, myprefix);
1436 else if(tag->id == ST_DEFINESCALINGGRID) {
1437 U16 id = swf_GetU16(tag);
1439 swf_GetRect(tag, &r);
1440 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1442 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1444 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1446 printf(" \"%s\"\n", swf_GetString(tag));
1452 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1453 SRECT r = swf_GetDefineBBox(tag);
1454 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1461 sprintf(myprefix, " %s", prefix);
1463 if(tag->id == ST_DEFINESPRITE) {
1464 sprintf(prefix, " ");
1466 dumperror("Sprite definition inside a sprite definition");
1470 spriteframelabel = 0;
1472 else if(tag->id == ST_END) {
1475 spriteframelabel = 0;
1477 dumperror("End Tag not empty");
1479 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1480 handleExportAssets(tag, myprefix);
1482 else if(tag->id == ST_DOACTION && action) {
1484 actions = swf_ActionGet(tag);
1485 swf_DumpActions(actions, myprefix);
1487 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1488 void*abccode = swf_ReadABC(tag);
1489 swf_DumpABC(stdout, abccode, "");
1490 swf_FreeABC(abccode);
1492 else if(tag->id == ST_DOINITACTION && action) {
1494 swf_GetU16(tag); // id
1495 actions = swf_ActionGet(tag);
1496 swf_DumpActions(actions, myprefix);
1498 else if(tag->id == ST_DEFINEBUTTON) {
1500 dumpButton(tag, myprefix);
1503 dumpButtonActions(tag, myprefix);
1506 else if(swf_isFontTag(tag) && showfonts) {
1507 dumpFont(tag, myprefix);
1509 else if(tag->id == ST_DEFINEBUTTON2) {
1511 dumpButton2Actions(tag, myprefix);
1514 else if(tag->id == ST_PLACEOBJECT) {
1515 handlePlaceObject(tag, myprefix);
1517 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1518 handlePlaceObject23(tag, myprefix);
1520 else if(tag->id == ST_DEFINEFONTALIGNZONES) {
1521 handleFontAlign2(tag, myprefix);
1523 else if(tag->id == ST_DEFINEFONTNAME) {
1524 swf_SetTagPos(tag, 0);
1525 swf_GetU16(tag); //id
1526 swf_GetString(tag); //name
1527 char* copyright = swf_GetString(tag);
1528 printf("%s%s\n", myprefix, copyright);
1530 else if(tag->id == ST_DEFINESHAPE ||
1531 tag->id == ST_DEFINESHAPE2 ||
1532 tag->id == ST_DEFINESHAPE3 ||
1533 tag->id == ST_DEFINESHAPE4) {
1535 handleShape(tag, myprefix);
1538 if(tag->len && used) {
1539 int num = swf_GetNumUsedIDs(tag);
1543 used = (int*)malloc(sizeof(int)*num);
1544 swf_GetUsedIDs(tag, used);
1545 printf("%s%suses IDs: ", indent, prefix);
1546 for(t=0;t<num;t++) {
1548 swf_SetTagPos(tag, used[t]);
1549 id = swf_GetU16(tag);
1550 printf("%d%s", id, t<num-1?", ":"");
1552 dumperror("Id %04d is not yet defined.\n", id);
1559 if(tag->id == ST_FREECHARACTER) {
1561 swf_SetTagPos(tag, 0);
1562 id = swf_GetU16(tag);
1566 if(tag->len && hex) {
1567 hexdumpTag(tag, prefix);