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;
327 if(u>=32) sprintf(ustr, " '%c'", u);
328 else sprintf(ustr, " 0x%02x", u);
329 printf("%s== Glyph %d: advance=%d encoding=%d%s ==\n", prefix, t, font->glyph[t].advance, u, ustr);
330 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
331 SHAPELINE*line = shape->lines;
334 if(line->type == moveTo) {
335 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
336 } else if(line->type == lineTo) {
337 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
338 } else if(line->type == splineTo) {
339 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
340 line->sx/20.0, line->sy/20.0,
341 line->x/20.0, line->y/20.0
346 swf_Shape2Free(shape);
353 printf("%sencoding table:", prefix, prefix);
354 char filled0=0, lastfilled=0;
355 for(t=0;t<font->maxascii;t++) {
357 printf("\n%s%08x ", prefix, t);
360 for(s=t;s<font->maxascii;s++) {
361 if(font->ascii2glyph[s]>=0) break;
370 for(s=t;s<t+16 && s<font->maxascii;s++) {
371 if(font->ascii2glyph[s]>=0) filled0=1;
374 printf("%4d ", font->ascii2glyph[t]);
382 static int fontnum = 0;
383 static SWFFONT**fonts;
385 void textcallback(void*self, int*glyphs, int*xpos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
390 printf(" <%2d glyphs in font %04d size %d, color #%02x%02x%02x%02x at %.2f,%.2f> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a, (startx+xpos[0])/20.0, starty/20.0);
391 for(t=0;t<fontnum;t++)
393 if(fonts[t]->id == fontid) {
403 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
404 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
407 if(fonts[font]->glyph2ascii[glyphs[t]])
408 a = fonts[font]->glyph2ascii[glyphs[t]];
418 printf("\\x%x", (int)a);
423 void handleText(TAG*tag, char*prefix)
427 swf_SetTagPos(tag, 0);
430 swf_ResetReadBits(tag);
432 swf_GetMatrix(tag, &m);
433 printf("%s| Matrix\n",prefix);
434 printf("%s| %5.3f %5.3f %6.2f\n", prefix, m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
435 printf("%s| %5.3f %5.3f %6.2f\n", prefix, m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
436 swf_SetTagPos(tag, 0);
439 swf_ParseDefineText(tag,textcallback, 0);
443 void handleDefineSound(TAG*tag)
445 U16 id = swf_GetU16(tag);
446 U8 flags = swf_GetU8(tag);
447 int compression = (flags>>4)&7;
448 int rate = (flags>>2)&3;
449 int bits = flags&2?16:8;
450 int stereo = flags&1;
452 if(compression == 0) printf("Raw ");
453 else if(compression == 1) printf("ADPCM ");
454 else if(compression == 2) printf("MP3 ");
455 else if(compression == 3) printf("Raw little-endian ");
456 else if(compression == 6) printf("ASAO ");
458 if(rate == 0) printf("5.5Khz ");
459 if(rate == 1) printf("11Khz ");
460 if(rate == 2) printf("22Khz ");
461 if(rate == 3) printf("44Khz ");
462 printf("%dBit ", bits);
463 if(stereo) printf("stereo");
468 void handleDefineBits(TAG*tag)
474 id = swf_GetU16(tag);
475 mode = swf_GetU8(tag);
476 width = swf_GetU16(tag);
477 height = swf_GetU16(tag);
478 printf(" image %dx%d",width,height);
479 if(mode == 3) printf(" (8 bpp)");
480 else if(mode == 4) printf(" (16 bpp)");
481 else if(mode == 5) printf(" (32 bpp)");
482 else printf(" (? bpp)");
485 void handleEditText(TAG*tag)
490 id = swf_GetU16(tag);
493 //swf_ResetReadBits(tag);
499 flags = swf_GetBits(tag,16);
500 if(flags & ET_HASFONT) {
501 swf_GetU16(tag); //font
502 swf_GetU16(tag); //fontheight
504 if(flags & ET_HASTEXTCOLOR) {
505 swf_GetU8(tag); //rgba
510 if(flags & ET_HASMAXLENGTH) {
511 swf_GetU16(tag); //maxlength
513 if(flags & ET_HASLAYOUT) {
514 swf_GetU8(tag); //align
515 swf_GetU16(tag); //left margin
516 swf_GetU16(tag); //right margin
517 swf_GetU16(tag); //indent
518 swf_GetU16(tag); //leading
520 printf(" variable \"%s\" ", &tag->data[tag->pos]);
521 if(flags & ET_HTML) printf("(html)");
522 if(flags & ET_NOSELECT) printf("(noselect)");
523 if(flags & ET_PASSWORD) printf("(password)");
524 if(flags & ET_READONLY) printf("(readonly)");
526 if(flags & (ET_X1 | ET_X3 ))
528 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
531 while(tag->data[tag->pos++]);
532 if(flags & ET_HASTEXT)
533 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
536 void printhandlerflags(U32 handlerflags)
538 if(handlerflags&1) printf("[on load]");
539 if(handlerflags&2) printf("[enter frame]");
540 if(handlerflags&4) printf("[unload]");
541 if(handlerflags&8) printf("[mouse move]");
542 if(handlerflags&16) printf("[mouse down]");
543 if(handlerflags&32) printf("[mouse up]");
544 if(handlerflags&64) printf("[key down]");
545 if(handlerflags&128) printf("[key up]");
547 if(handlerflags&256) printf("[data]");
548 if(handlerflags&512) printf("[initialize]");
549 if(handlerflags&1024) printf("[mouse press]");
550 if(handlerflags&2048) printf("[mouse release]");
551 if(handlerflags&4096) printf("[mouse release outside]");
552 if(handlerflags&8192) printf("[mouse rollover]");
553 if(handlerflags&16384) printf("[mouse rollout]");
554 if(handlerflags&32768) printf("[mouse drag over]");
556 if(handlerflags&0x10000) printf("[mouse drag out]");
557 if(handlerflags&0x20000) printf("[key press]");
558 if(handlerflags&0x40000) printf("[construct even]");
559 if(handlerflags&0xfff80000) printf("[???]");
561 void handleVideoStream(TAG*tag, char*prefix)
563 U16 id = swf_GetU16(tag);
564 U16 frames = swf_GetU16(tag);
565 U16 width = swf_GetU16(tag);
566 U16 height = swf_GetU16(tag);
567 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
568 U8 codec = swf_GetU8(tag);
569 printf(" (%d frames, %dx%d", frames, width, height);
573 printf(" sorenson h.263)");
575 printf(" codec 0x%02x)", codec);
577 void handleVideoFrame(TAG*tag, char*prefix)
579 U32 code, version, reference, sizeflags;
580 U32 width=0, height=0;
582 U16 id = swf_GetU16(tag);
583 U16 frame = swf_GetU16(tag);
584 U8 deblock,flags, tmp, bit;
586 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
587 printf(" (frame %d) ", frame);
589 /* video packet follows */
590 code = swf_GetBits(tag, 17);
591 version = swf_GetBits(tag, 5);
592 reference = swf_GetBits(tag, 8);
594 sizeflags = swf_GetBits(tag, 3);
597 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
598 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
599 case 2: width = 352; height = 288; break;
600 case 3: width = 176; height = 144; break;
601 case 4: width = 128; height = 96; break;
602 case 5: width = 320; height = 240; break;
603 case 6: width = 160; height = 120; break;
604 case 7: width = -1; height = -1;/*reserved*/ break;
606 printf("%dx%d ", width, height);
607 type = swf_GetBits(tag, 2);
608 printf("%s", types[type]);
610 deblock = swf_GetBits(tag, 1);
612 printf(" deblock %d ", deblock);
613 quantizer = swf_GetBits(tag, 5);
614 printf(" quant: %d ", quantizer);
617 void dumpFilter(FILTER*filter)
619 if(filter->type == FILTERTYPE_BLUR) {
620 FILTER_BLUR*f = (FILTER_BLUR*)filter;
621 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
622 printf("passes: %d\n", f->passes);
623 } if(filter->type == FILTERTYPE_GLOW) {
624 FILTER_GLOW*f = (FILTER_GLOW*)filter;
625 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
626 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
627 printf("passes: %d\n", f->passes);
628 printf("flags: %s%s%s\n",
629 f->knockout?"knockout ":"",
630 f->composite?"composite ":"",
631 f->innerglow?"innerglow":"");
632 } if(filter->type == FILTERTYPE_DROPSHADOW) {
633 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
634 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
635 printf("passes: %d\n", f->passes);
636 printf("angle: %f distance: %f\n", f->angle, f->distance);
637 printf("strength: %f passes: %d\n", f->strength, f->passes);
638 printf("flags: %s%s%s\n",
639 f->knockout?"knockout ":"",
640 f->composite?"composite ":"",
641 f->innershadow?"innershadow ":"");
642 } if(filter->type == FILTERTYPE_BEVEL) {
643 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
644 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
645 printf("passes: %d\n", f->passes);
646 printf("angle: %f distance: %f\n", f->angle, f->distance);
647 printf("strength: %f passes: %d\n", f->strength, f->passes);
648 printf("flags: %s%s%s%s\n",
650 f->knockout?"knockout ":"",
651 f->composite?"composite ":"",
652 f->innershadow?"innershadow ":"");
653 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
654 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
655 swf_DumpGradient(stdout, f->gradient);
656 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
657 printf("angle: %f distance: %f\n", f->angle, f->distance);
658 printf("strength: %f passes: %d\n", f->strength, f->passes);
659 printf("flags: %s%s%s%s\n",
660 f->knockout?"knockout ":"",
661 f->ontop?"ontop ":"",
662 f->composite?"composite ":"",
663 f->innershadow?"innershadow ":"");
668 void handlePlaceObject23(TAG*tag, char*prefix)
674 int ppos[3] = {0,0,0};
675 swf_SetTagPos(tag, 0);
676 flags = swf_GetU8(tag);
677 if(tag->id == ST_PLACEOBJECT3)
678 flags2 = swf_GetU8(tag);
679 swf_GetU16(tag); //depth
682 if(flags&2) swf_GetU16(tag); //id
684 swf_GetMatrix(tag,&m);
686 ppos[0] += sprintf(pstr[0], "| Matrix ");
687 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
688 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
692 swf_GetCXForm(tag, &cx, 1);
694 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
695 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);
696 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
700 U16 ratio = swf_GetU16(tag); //ratio
702 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
703 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
704 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
708 U16 clip = swf_GetU16(tag); //clip
710 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
711 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
712 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
715 if(flags&32) { while(swf_GetU8(tag)); }
717 if(flags2&1) { // filter list
718 U8 num = swf_GetU8(tag);
720 printf("\n%d filters\n", num);
721 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
724 FILTER*filter = swf_GetFilter(tag);
730 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
735 if(flags2&2) { // blend mode
736 U8 blendmode = swf_GetU8(tag);
740 sprintf(name, "%-5d", blendmode);
741 for(t=0;blendModeNames[t];t++) {
743 sprintf(name, "%-5s", blendModeNames[t]);
747 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
748 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
749 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
753 if(placements && ppos[0]) {
755 printf("%s %s\n", prefix, pstr[0]);
756 printf("%s %s\n", prefix, pstr[1]);
757 printf("%s %s", prefix, pstr[2]);
766 reserved = swf_GetU16(tag); // must be 0
767 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
769 printf("Unknown parameter field not zero: %04x\n", reserved);
772 printf("global flags: %04x\n", globalflags);
774 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
776 handlerflags = swf_GetU32(tag);
779 while(handlerflags) {
784 globalflags &= ~handlerflags;
785 printf("%s flags %08x ",prefix, handlerflags);
786 printhandlerflags(handlerflags);
787 length = swf_GetU32(tag);
788 printf(", %d bytes actioncode\n",length);
789 a = swf_ActionGet(tag);
790 swf_DumpActions(a,prefix);
793 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
795 if(globalflags) // should go to sterr.
796 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
798 printf(" has action code\n");
803 void handlePlaceObject(TAG*tag, char*prefix)
805 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
810 swf_SetTagPos(tag, 0);
811 id = swf_GetU16(tag);
812 depth = swf_GetU16(tag);
813 swf_GetMatrix(tag, &matrix);
814 swf_GetCXForm(tag, &cxform, 0);
816 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
817 swf_SetU16(tag2, depth);
818 swf_SetU16(tag2, id);
819 swf_SetMatrix(tag2, &matrix);
820 swf_SetCXForm(tag2, &cxform, 1);
822 handlePlaceObject23(tag2, prefix);
825 char* fillstyle2str(FILLSTYLE*style)
827 switch(style->type) {
829 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
831 case 0x10: case 0x11: case 0x12: case 0x13:
832 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
834 case 0x40: case 0x42:
835 /* TODO: display information about that bitmap */
836 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
837 /* TODO: show matrix */
838 //swf_DumpMatrix(stdout, &style->m);
840 case 0x41: case 0x43:
841 /* TODO: display information about that bitmap */
842 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
843 /* TODO: show matrix */
844 //swf_DumpMatrix(stdout, &style->m);
847 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
851 char* linestyle2str(LINESTYLE*style)
853 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
857 void handleShape(TAG*tag, char*prefix)
865 swf_ParseDefineShape(tag, &shape);
867 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
869 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
874 else printf("%s | (Neither line nor fill styles)\n", prefix);
877 printf("%s", prefix);
878 if(t < shape.numfillstyles) {
879 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
883 if(t < shape.numlinestyles) {
884 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
887 //if(shape.fillstyles[t].type&0x40) {
888 // MATRIX m = shape.fillstyles[t].m;
889 // swf_DumpMatrix(stdout, &m);
893 printf("%s |\n", prefix);
897 printf("%s | fill: %02d/%02d line:%02d - ",
902 if(line->type == moveTo) {
903 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
904 } else if(line->type == lineTo) {
905 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
906 } else if(line->type == splineTo) {
907 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
908 line->sx/20.0, line->sy/20.0,
909 line->x/20.0, line->y/20.0
914 printf("%s |\n", prefix);
917 void fontcallback1(void*self, U16 id,U8 * name)
921 void fontcallback2(void*self, U16 id,U8 * name)
923 swf_FontExtract(&swf,id,&fonts[fontnum]);
927 static U8 printable(U8 a)
929 if(a<32 || a==127) return '.';
932 void hexdumpTag(TAG*tag, char* prefix)
936 printf(" %s-=> ",prefix);
937 for(t=0;t<tag->len;t++) {
938 printf("%02x ", tag->data[t]);
939 ascii[t&15] = printable(tag->data[t]);
940 if((t && ((t&15)==15)) || (t==tag->len-1))
944 for(s=p-1;s<16;s++) {
948 printf(" %s\n", ascii);
950 printf(" %s\n %s-=> ",ascii,prefix);
955 void handleExportAssets(TAG*tag, char* prefix)
961 num = swf_GetU16(tag);
964 id = swf_GetU16(tag);
965 name = swf_GetString(tag);
966 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
970 static void handleFontAlign1(TAG*tag)
972 swf_SetTagPos(tag, 0);
973 U16 id = swf_GetU16(tag);
974 U8 flags = swf_GetU8(tag);
975 printf(" for font %04d, ", id);
976 if((flags&3)==0) printf("thin, ");
977 else if((flags&3)==1) printf("medium, ");
978 else if((flags&3)==2) printf("thick, ");
981 while(tag->pos < tag->len) {
982 int nr = swf_GetU8(tag); // should be 2
985 printf("*** unsupported multiboxes ***, ");
989 float v1 = swf_GetF16(tag);
990 float v2 = swf_GetF16(tag);
992 U8 xyflags = swf_GetU8(tag);
995 printf(" %d glyphs", num);
998 #define ALIGN_WITH_GLYPHS
999 static void handleFontAlign2(TAG*tag, char*prefix)
1003 swf_SetTagPos(tag, 0);
1004 U16 id = swf_GetU16(tag);
1007 #ifdef ALIGN_WITH_GLYPHS
1010 while(swf.firstTag->prev) swf.firstTag = swf.firstTag->prev;
1012 swf_FontExtract(&swf, id, &font);
1014 swf_SetTagPos(tag, 3);
1015 while(tag->pos < tag->len) {
1016 printf("%sglyph %d) ", prefix, num);
1017 int nr = swf_GetU8(tag); // should be 2
1021 float v = swf_GetF16(tag);
1022 printf("%f ", v*1024.0);
1025 for(s=0;s<nr-1;s++) {
1028 float v = swf_GetF16(tag);
1029 printf("+%f ", v*1024.0);
1032 U8 xyflags = swf_GetU8(tag);
1033 printf("xy:%02x\n", xyflags);
1035 #ifdef ALIGN_WITH_GLYPHS
1036 if(font && num<font->numchars) {
1037 SHAPE2* shape = swf_ShapeToShape2(font->glyph[num].shape);
1038 SHAPELINE*line = shape->lines;
1040 if(line->type == moveTo) {
1041 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
1042 } else if(line->type == lineTo) {
1043 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
1044 } else if(line->type == splineTo) {
1045 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
1046 line->sx/20.0, line->sy/20.0,
1047 line->x/20.0, line->y/20.0
1052 swf_Shape2Free(shape);
1055 if(num==font->numchars-1) break;
1062 void dumperror(const char* format, ...)
1067 va_start(arglist, format);
1068 vsnprintf(buf, sizeof(buf)-1, format, arglist);
1072 printf("==== Error: %s ====\n", buf);
1075 static char strbuf[800];
1076 static int bufpos=0;
1078 char* timestring(double f)
1080 int hours = (int)(f/3600);
1081 int minutes = (int)((f-hours*3600)/60);
1082 int seconds = (int)((f-hours*3600-minutes*60));
1083 int useconds = (int)((f-(int)f)*1000+0.5);
1086 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
1087 return &strbuf[bufpos];
1090 int main (int argc,char ** argv)
1094 struct stat statbuf;
1098 char issprite = 0; // are we inside a sprite definition?
1099 int spriteframe = 0;
1101 char* spriteframelabel = 0;
1102 char* framelabel = 0;
1107 memset(idtab,0,65536);
1109 processargs(argc, argv);
1113 fprintf(stderr, "You must supply a filename.\n");
1117 f = open(filename,O_RDONLY|O_BINARY);
1121 sprintf(buffer, "Couldn't open %.200s", filename);
1127 char compressed = (header[0]=='C');
1128 char isflash = (header[0]=='F' && header[1] == 'W' && header[2] == 'S') ||
1129 (header[0]=='C' && header[1] == 'W' && header[2] == 'S');
1132 int fl=strlen(filename);
1133 if(!isflash && fl>3 && !strcmp(&filename[fl-4], ".abc")) {
1134 swf_ReadABCfile(filename, &swf);
1136 f = open(filename,O_RDONLY|O_BINARY);
1137 if FAILED(swf_ReadSWF(f,&swf))
1139 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1146 if(statbuf.st_size != swf.fileSize && !compressed)
1147 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1148 statbuf.st_size, swf.fileSize);
1149 filesize = statbuf.st_size;
1154 //if(action && swf.fileVersion>=9) {
1155 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1159 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1160 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1164 printf("-X %d", xsize);
1166 if((xy&1) && (xy&6))
1170 printf("-Y %d", ysize);
1172 if((xy&3) && (xy&4))
1176 printf("-r %.2f", swf.frameRate/256.0);
1178 if((xy&7) && (xy&8))
1182 printf("-f %d", swf.frameCount);
1189 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1190 "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"};
1191 if(swf.fileVersion>10) {
1192 fprintf(stderr, "Fileversion>10\n");
1197 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1198 "<param name=\"movie\" value=\"%s\"/>\n"
1199 "<param name=\"play\" value=\"true\"/>\n"
1200 "<param name=\"loop\" value=\"false\"/>\n"
1201 "<param name=\"quality\" value=\"high\"/>\n"
1202 "<param name=\"loop\" value=\"false\"/>\n"
1203 "</object>\n\n", filename, xsize, ysize, filename);
1205 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1207 //" BGCOLOR=#ffffffff\n"?
1209 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1210 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1211 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1212 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1213 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1214 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1215 " <PARAM NAME=\"ALLOWSCRIPTACCESS\" VALUE=\"always\">\n"
1216 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1217 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1218 " TYPE=\"application/x-shockwave-flash\"\n"
1219 " ALLOWSCRIPTACCESS=\"always\"\n"
1220 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1222 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1223 filename, filename, xsize, ysize);
1227 printf("[HEADER] File version: %d\n", swf.fileVersion);
1229 printf("[HEADER] File is zlib compressed.");
1230 if(filesize && swf.fileSize)
1231 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1235 printf("[HEADER] File size: %d%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1236 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1237 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1238 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1239 if(swf.movieSize.xmin)
1240 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1243 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1244 if(swf.movieSize.ymin)
1245 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1253 swf_FontEnumerate(&swf,&fontcallback1, 0);
1254 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1256 swf_FontEnumerate(&swf,&fontcallback2, 0);
1260 char*name = swf_TagGetName(tag);
1263 dumperror("Unknown tag:0x%03x", tag->id);
1268 name = "UNKNOWN TAG";
1271 filepos += tag->len;
1272 printf("[%03x] %9d %9d %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1274 printf("[%03x] %9d %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1277 if(tag->id == ST_PLACEOBJECT) {
1278 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1279 if(swf_GetName(tag))
1280 printf(" name \"%s\"",swf_GetName(tag));
1282 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1289 printf(" id %04d",swf_GetPlaceID(tag));
1293 printf(" at depth %04d", swf_GetDepth(tag));
1295 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1296 printf(" as bitmap");
1298 swf_SetTagPos(tag, 0);
1299 if(tag->data[0]&64) {
1301 swf_GetPlaceObject(tag, &po);
1302 printf(" (clip to %04d)", po.clipdepth);
1303 swf_PlaceObjectFree(&po);
1305 if(swf_GetName(tag))
1306 printf(" name \"%s\"",swf_GetName(tag));
1309 else if(tag->id == ST_REMOVEOBJECT) {
1310 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1312 else if(tag->id == ST_REMOVEOBJECT2) {
1313 printf(" removes object from depth %04d", swf_GetDepth(tag));
1315 else if(tag->id == ST_FREECHARACTER) {
1316 printf(" frees object %04d", swf_GetPlaceID(tag));
1318 else if(tag->id == ST_FILEATTRIBUTES) {
1319 swf_SetTagPos(tag, 0);
1320 U32 flags = swf_GetU32(tag);
1321 if(flags&FILEATTRIBUTE_USENETWORK) printf(" usenetwork");
1322 if(flags&FILEATTRIBUTE_AS3) printf(" as3");
1323 if(flags&FILEATTRIBUTE_SYMBOLCLASS) printf(" symbolclass");
1324 if(flags&FILEATTRIBUTE_USEHARDWAREGPU) printf(" hardware-gpu");
1325 if(flags&FILEATTRIBUTE_USEACCELERATEDBLIT) printf(" accelerated-blit");
1326 if(flags&~(1|8|16|32|64))
1327 printf(" flags=%02x", flags);
1329 else if(tag->id == ST_DOABC) {
1330 swf_SetTagPos(tag, 0);
1331 U32 flags = swf_GetU32(tag);
1332 char*s = swf_GetString(tag);
1334 printf(" flags=%08x", flags);
1337 printf(" \"%s\"", s);
1342 printf(" lazy load");
1344 swf_SetTagPos(tag, 0);
1346 else if(tag->id == ST_STARTSOUND) {
1349 id = swf_GetU16(tag);
1350 flags = swf_GetU8(tag);
1352 printf(" stops sound with id %04d", id);
1354 printf(" starts sound with id %04d", id);
1356 printf(" (if not already playing)");
1362 printf(" looping %d times", swf_GetU16(tag));
1365 else if(tag->id == ST_FRAMELABEL) {
1366 int l = strlen((char*)tag->data);
1367 printf(" \"%s\"", tag->data);
1368 if((l+1) < tag->len) {
1369 printf(" has %d extra bytes", tag->len-1-l);
1370 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1371 printf(" (ANCHOR)");
1373 if((framelabel && !issprite) ||
1374 (spriteframelabel && issprite)) {
1375 dumperror("Frame %d has more than one label",
1376 issprite?spriteframe:mainframe);
1378 if(issprite) spriteframelabel = (char*)tag->data;
1379 else framelabel = (char*)tag->data;
1381 else if(tag->id == ST_SHOWFRAME) {
1382 char*label = issprite?spriteframelabel:framelabel;
1383 int frame = issprite?spriteframe:mainframe;
1386 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1388 if(issprite) spriteframe++;
1394 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1396 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1397 timestring(frame*(256.0/(swf.frameRate+0.1))),
1398 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1401 printf(" (label \"%s\")", label);
1402 if(issprite) {spriteframe++; spriteframelabel = 0;}
1403 if(!issprite) {mainframe++; framelabel = 0;}
1405 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1406 U8 r = swf_GetU8(tag);
1407 U8 g = swf_GetU8(tag);
1408 U8 b = swf_GetU8(tag);
1409 printf(" (%02x/%02x/%02x)",r,g,b);
1411 else if(tag->id == ST_PROTECT) {
1413 printf(" %s", swf_GetString(tag));
1416 else if(tag->id == ST_DEFINEFONTALIGNZONES) {
1417 handleFontAlign1(tag);
1419 else if(tag->id == ST_CSMTEXTSETTINGS) {
1420 U16 id = swf_GetU16(tag);
1421 U8 flags = swf_GetU8(tag);
1424 printf("flashtype,");
1426 switch(((flags>>3)&7)) {
1427 case 0:printf("no grid,");break;
1428 case 1:printf("pixel grid,");break;
1429 case 2:printf("subpixel grid,");break;
1430 case 3:printf("unknown grid,");break;
1433 printf("unknown[%08x],", flags);
1434 float thickness = swf_GetFixed(tag);
1435 float sharpness = swf_GetFixed(tag);
1436 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1439 else if(swf_isDefiningTag(tag)) {
1440 U16 id = swf_GetDefineID(tag);
1441 printf(" defines id %04d", id);
1443 dumperror("Id %04d is defined more than once.", id);
1446 else if(swf_isPseudoDefiningTag(tag)) {
1447 U16 id = swf_GetDefineID(tag);
1448 printf(" adds information to id %04d", id);
1450 dumperror("Id %04d is not yet defined.\n", id);
1453 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1454 tag->id == ST_DEFINEBITSLOSSLESS2) {
1455 handleDefineBits(tag);
1458 else if(tag->id == ST_DEFINESOUND) {
1459 handleDefineSound(tag);
1462 else if(tag->id == ST_VIDEOFRAME) {
1463 handleVideoFrame(tag, myprefix);
1466 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1467 handleVideoStream(tag, myprefix);
1470 else if(tag->id == ST_DEFINEEDITTEXT) {
1471 handleEditText(tag);
1474 else if(tag->id == ST_DEFINEMOVIE) {
1475 U16 id = swf_GetU16(tag);
1476 char*s = swf_GetString(tag);
1477 printf(" URL: %s\n", s);
1479 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1480 handleText(tag, myprefix);
1482 else if(tag->id == ST_DEFINESCALINGGRID) {
1483 U16 id = swf_GetU16(tag);
1485 swf_GetRect(tag, &r);
1486 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1488 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1490 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1492 printf(" \"%s\"\n", swf_GetString(tag));
1498 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1499 SRECT r = swf_GetDefineBBox(tag);
1500 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1507 sprintf(myprefix, " %s", prefix);
1509 if(tag->id == ST_DEFINESPRITE) {
1510 sprintf(prefix, " ");
1512 dumperror("Sprite definition inside a sprite definition");
1516 spriteframelabel = 0;
1518 else if(tag->id == ST_END) {
1521 spriteframelabel = 0;
1523 dumperror("End Tag not empty");
1525 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1526 handleExportAssets(tag, myprefix);
1528 else if(tag->id == ST_DOACTION && action) {
1530 actions = swf_ActionGet(tag);
1531 swf_DumpActions(actions, myprefix);
1533 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1534 void*abccode = swf_ReadABC(tag);
1535 swf_DumpABC(stdout, abccode, "");
1536 swf_FreeABC(abccode);
1538 else if(tag->id == ST_DOINITACTION && action) {
1540 swf_GetU16(tag); // id
1541 actions = swf_ActionGet(tag);
1542 swf_DumpActions(actions, myprefix);
1544 else if(tag->id == ST_DEFINEBUTTON) {
1546 dumpButton(tag, myprefix);
1549 dumpButtonActions(tag, myprefix);
1552 else if(swf_isFontTag(tag) && showfonts) {
1553 dumpFont(tag, myprefix);
1555 else if(tag->id == ST_DEFINEBUTTON2) {
1557 dumpButton2Actions(tag, myprefix);
1560 else if(tag->id == ST_PLACEOBJECT) {
1561 handlePlaceObject(tag, myprefix);
1563 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1564 handlePlaceObject23(tag, myprefix);
1566 else if(tag->id == ST_DEFINEFONTALIGNZONES) {
1567 handleFontAlign2(tag, myprefix);
1569 else if(tag->id == ST_DEFINEFONTNAME) {
1570 swf_SetTagPos(tag, 0);
1571 swf_GetU16(tag); //id
1572 swf_GetString(tag); //name
1573 char* copyright = swf_GetString(tag);
1574 printf("%s%s\n", myprefix, copyright);
1576 else if(tag->id == ST_DEFINESHAPE ||
1577 tag->id == ST_DEFINESHAPE2 ||
1578 tag->id == ST_DEFINESHAPE3 ||
1579 tag->id == ST_DEFINESHAPE4) {
1581 handleShape(tag, myprefix);
1584 if(tag->len && used) {
1585 int num = swf_GetNumUsedIDs(tag);
1589 used = (int*)malloc(sizeof(int)*num);
1590 swf_GetUsedIDs(tag, used);
1591 printf("%s%suses IDs: ", indent, prefix);
1592 for(t=0;t<num;t++) {
1594 swf_SetTagPos(tag, used[t]);
1595 id = swf_GetU16(tag);
1596 printf("%d%s", id, t<num-1?", ":"");
1598 dumperror("Id %04d is not yet defined.\n", id);
1605 if(tag->id == ST_FREECHARACTER) {
1607 swf_SetTagPos(tag, 0);
1608 id = swf_GetU16(tag);
1612 if(tag->len && hex) {
1613 hexdumpTag(tag, prefix);