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 ", 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);
1026 float v = swf_GetF16(tag);
1027 printf("+%f ", v*1024.0);
1029 U8 xyflags = swf_GetU8(tag);
1030 printf("xy:%02x\n", xyflags);
1032 #ifdef ALIGN_WITH_GLYPHS
1033 if(font && num<font->numchars) {
1034 SHAPE2* shape = swf_ShapeToShape2(font->glyph[num].shape);
1035 SHAPELINE*line = shape->lines;
1037 if(line->type == moveTo) {
1038 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
1039 } else if(line->type == lineTo) {
1040 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
1041 } else if(line->type == splineTo) {
1042 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
1043 line->sx/20.0, line->sy/20.0,
1044 line->x/20.0, line->y/20.0
1049 swf_Shape2Free(shape);
1052 if(num==font->numchars-1) break;
1059 void dumperror(const char* format, ...)
1064 va_start(arglist, format);
1065 vsnprintf(buf, sizeof(buf)-1, format, arglist);
1069 printf("==== Error: %s ====\n", buf);
1072 static char strbuf[800];
1073 static int bufpos=0;
1075 char* timestring(double f)
1077 int hours = (int)(f/3600);
1078 int minutes = (int)((f-hours*3600)/60);
1079 int seconds = (int)((f-hours*3600-minutes*60));
1080 int useconds = (int)((f-(int)f)*1000+0.5);
1083 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
1084 return &strbuf[bufpos];
1087 int main (int argc,char ** argv)
1091 struct stat statbuf;
1095 char issprite = 0; // are we inside a sprite definition?
1096 int spriteframe = 0;
1098 char* spriteframelabel = 0;
1099 char* framelabel = 0;
1104 memset(idtab,0,65536);
1106 processargs(argc, argv);
1110 fprintf(stderr, "You must supply a filename.\n");
1114 f = open(filename,O_RDONLY|O_BINARY);
1118 sprintf(buffer, "Couldn't open %.200s", filename);
1124 char compressed = (header[0]=='C');
1125 char isflash = (header[0]=='F' && header[1] == 'W' && header[2] == 'S') ||
1126 (header[0]=='C' && header[1] == 'W' && header[2] == 'S');
1129 int fl=strlen(filename);
1130 if(!isflash && fl>3 && !strcmp(&filename[fl-4], ".abc")) {
1131 swf_ReadABCfile(filename, &swf);
1133 f = open(filename,O_RDONLY|O_BINARY);
1134 if FAILED(swf_ReadSWF(f,&swf))
1136 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1143 if(statbuf.st_size != swf.fileSize && !compressed)
1144 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1145 statbuf.st_size, swf.fileSize);
1146 filesize = statbuf.st_size;
1151 //if(action && swf.fileVersion>=9) {
1152 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1156 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1157 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1161 printf("-X %d", xsize);
1163 if((xy&1) && (xy&6))
1167 printf("-Y %d", ysize);
1169 if((xy&3) && (xy&4))
1173 printf("-r %.2f", swf.frameRate/256.0);
1175 if((xy&7) && (xy&8))
1179 printf("-f %d", swf.frameCount);
1186 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1187 "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"};
1188 if(swf.fileVersion>10) {
1189 fprintf(stderr, "Fileversion>10\n");
1194 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1195 "<param name=\"movie\" value=\"%s\"/>\n"
1196 "<param name=\"play\" value=\"true\"/>\n"
1197 "<param name=\"loop\" value=\"false\"/>\n"
1198 "<param name=\"quality\" value=\"high\"/>\n"
1199 "<param name=\"loop\" value=\"false\"/>\n"
1200 "</object>\n\n", filename, xsize, ysize, filename);
1202 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1204 //" BGCOLOR=#ffffffff\n"?
1206 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1207 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1208 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1209 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1210 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1211 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1212 " <PARAM NAME=\"ALLOWSCRIPTACCESS\" VALUE=\"always\">\n"
1213 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1214 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1215 " TYPE=\"application/x-shockwave-flash\"\n"
1216 " ALLOWSCRIPTACCESS=\"always\"\n"
1217 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1219 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1220 filename, filename, xsize, ysize);
1224 printf("[HEADER] File version: %d\n", swf.fileVersion);
1226 printf("[HEADER] File is zlib compressed.");
1227 if(filesize && swf.fileSize)
1228 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1232 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1233 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1234 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1235 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1236 if(swf.movieSize.xmin)
1237 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1240 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1241 if(swf.movieSize.ymin)
1242 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1250 swf_FontEnumerate(&swf,&fontcallback1, 0);
1251 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1253 swf_FontEnumerate(&swf,&fontcallback2, 0);
1257 char*name = swf_TagGetName(tag);
1260 dumperror("Unknown tag:0x%03x", tag->id);
1265 name = "UNKNOWN TAG";
1268 filepos += tag->len;
1269 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1271 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1274 if(tag->id == ST_PLACEOBJECT) {
1275 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1276 if(swf_GetName(tag))
1277 printf(" name \"%s\"",swf_GetName(tag));
1279 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1286 printf(" id %04d",swf_GetPlaceID(tag));
1290 printf(" at depth %04d", swf_GetDepth(tag));
1292 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1293 printf(" as bitmap");
1295 swf_SetTagPos(tag, 0);
1296 if(tag->data[0]&64) {
1298 swf_GetPlaceObject(tag, &po);
1299 printf(" (clip to %04d)", po.clipdepth);
1300 swf_PlaceObjectFree(&po);
1302 if(swf_GetName(tag))
1303 printf(" name \"%s\"",swf_GetName(tag));
1306 else if(tag->id == ST_REMOVEOBJECT) {
1307 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1309 else if(tag->id == ST_REMOVEOBJECT2) {
1310 printf(" removes object from depth %04d", swf_GetDepth(tag));
1312 else if(tag->id == ST_FREECHARACTER) {
1313 printf(" frees object %04d", swf_GetPlaceID(tag));
1315 else if(tag->id == ST_FILEATTRIBUTES) {
1316 swf_SetTagPos(tag, 0);
1317 U32 flags = swf_GetU32(tag);
1318 if(flags&FILEATTRIBUTE_USENETWORK) printf(" usenetwork");
1319 if(flags&FILEATTRIBUTE_AS3) printf(" as3");
1320 if(flags&FILEATTRIBUTE_SYMBOLCLASS) printf(" symbolclass");
1321 if(flags&FILEATTRIBUTE_USEHARDWAREGPU) printf(" hardware-gpu");
1322 if(flags&FILEATTRIBUTE_USEACCELERATEDBLIT) printf(" accelerated-blit");
1323 if(flags&~(1|8|16|32|64))
1324 printf(" flags=%02x", flags);
1326 else if(tag->id == ST_DOABC) {
1327 swf_SetTagPos(tag, 0);
1328 U32 flags = swf_GetU32(tag);
1329 char*s = swf_GetString(tag);
1331 printf(" flags=%08x", flags);
1334 printf(" \"%s\"", s);
1339 printf(" lazy load");
1341 swf_SetTagPos(tag, 0);
1343 else if(tag->id == ST_STARTSOUND) {
1346 id = swf_GetU16(tag);
1347 flags = swf_GetU8(tag);
1349 printf(" stops sound with id %04d", id);
1351 printf(" starts sound with id %04d", id);
1353 printf(" (if not already playing)");
1359 printf(" looping %d times", swf_GetU16(tag));
1362 else if(tag->id == ST_FRAMELABEL) {
1363 int l = strlen((char*)tag->data);
1364 printf(" \"%s\"", tag->data);
1365 if((l+1) < tag->len) {
1366 printf(" has %d extra bytes", tag->len-1-l);
1367 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1368 printf(" (ANCHOR)");
1370 if((framelabel && !issprite) ||
1371 (spriteframelabel && issprite)) {
1372 dumperror("Frame %d has more than one label",
1373 issprite?spriteframe:mainframe);
1375 if(issprite) spriteframelabel = (char*)tag->data;
1376 else framelabel = (char*)tag->data;
1378 else if(tag->id == ST_SHOWFRAME) {
1379 char*label = issprite?spriteframelabel:framelabel;
1380 int frame = issprite?spriteframe:mainframe;
1383 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1385 if(issprite) spriteframe++;
1391 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1393 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1394 timestring(frame*(256.0/(swf.frameRate+0.1))),
1395 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1398 printf(" (label \"%s\")", label);
1399 if(issprite) {spriteframe++; spriteframelabel = 0;}
1400 if(!issprite) {mainframe++; framelabel = 0;}
1402 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1403 U8 r = swf_GetU8(tag);
1404 U8 g = swf_GetU8(tag);
1405 U8 b = swf_GetU8(tag);
1406 printf(" (%02x/%02x/%02x)",r,g,b);
1408 else if(tag->id == ST_PROTECT) {
1410 printf(" %s", swf_GetString(tag));
1413 else if(tag->id == ST_DEFINEFONTALIGNZONES) {
1414 handleFontAlign1(tag);
1416 else if(tag->id == ST_CSMTEXTSETTINGS) {
1417 U16 id = swf_GetU16(tag);
1418 U8 flags = swf_GetU8(tag);
1421 printf("flashtype,");
1423 switch(((flags>>3)&7)) {
1424 case 0:printf("no grid,");break;
1425 case 1:printf("pixel grid,");break;
1426 case 2:printf("subpixel grid,");break;
1427 case 3:printf("unknown grid,");break;
1430 printf("unknown[%08x],", flags);
1431 float thickness = swf_GetFixed(tag);
1432 float sharpness = swf_GetFixed(tag);
1433 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1436 else if(swf_isDefiningTag(tag)) {
1437 U16 id = swf_GetDefineID(tag);
1438 printf(" defines id %04d", id);
1440 dumperror("Id %04d is defined more than once.", id);
1443 else if(swf_isPseudoDefiningTag(tag)) {
1444 U16 id = swf_GetDefineID(tag);
1445 printf(" adds information to id %04d", id);
1447 dumperror("Id %04d is not yet defined.\n", id);
1450 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1451 tag->id == ST_DEFINEBITSLOSSLESS2) {
1452 handleDefineBits(tag);
1455 else if(tag->id == ST_DEFINESOUND) {
1456 handleDefineSound(tag);
1459 else if(tag->id == ST_VIDEOFRAME) {
1460 handleVideoFrame(tag, myprefix);
1463 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1464 handleVideoStream(tag, myprefix);
1467 else if(tag->id == ST_DEFINEEDITTEXT) {
1468 handleEditText(tag);
1471 else if(tag->id == ST_DEFINEMOVIE) {
1472 U16 id = swf_GetU16(tag);
1473 char*s = swf_GetString(tag);
1474 printf(" URL: %s\n", s);
1476 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1477 handleText(tag, myprefix);
1479 else if(tag->id == ST_DEFINESCALINGGRID) {
1480 U16 id = swf_GetU16(tag);
1482 swf_GetRect(tag, &r);
1483 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1485 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1487 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1489 printf(" \"%s\"\n", swf_GetString(tag));
1495 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1496 SRECT r = swf_GetDefineBBox(tag);
1497 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1504 sprintf(myprefix, " %s", prefix);
1506 if(tag->id == ST_DEFINESPRITE) {
1507 sprintf(prefix, " ");
1509 dumperror("Sprite definition inside a sprite definition");
1513 spriteframelabel = 0;
1515 else if(tag->id == ST_END) {
1518 spriteframelabel = 0;
1520 dumperror("End Tag not empty");
1522 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1523 handleExportAssets(tag, myprefix);
1525 else if(tag->id == ST_DOACTION && action) {
1527 actions = swf_ActionGet(tag);
1528 swf_DumpActions(actions, myprefix);
1530 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1531 void*abccode = swf_ReadABC(tag);
1532 swf_DumpABC(stdout, abccode, "");
1533 swf_FreeABC(abccode);
1535 else if(tag->id == ST_DOINITACTION && action) {
1537 swf_GetU16(tag); // id
1538 actions = swf_ActionGet(tag);
1539 swf_DumpActions(actions, myprefix);
1541 else if(tag->id == ST_DEFINEBUTTON) {
1543 dumpButton(tag, myprefix);
1546 dumpButtonActions(tag, myprefix);
1549 else if(swf_isFontTag(tag) && showfonts) {
1550 dumpFont(tag, myprefix);
1552 else if(tag->id == ST_DEFINEBUTTON2) {
1554 dumpButton2Actions(tag, myprefix);
1557 else if(tag->id == ST_PLACEOBJECT) {
1558 handlePlaceObject(tag, myprefix);
1560 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1561 handlePlaceObject23(tag, myprefix);
1563 else if(tag->id == ST_DEFINEFONTALIGNZONES) {
1564 handleFontAlign2(tag, myprefix);
1566 else if(tag->id == ST_DEFINEFONTNAME) {
1567 swf_SetTagPos(tag, 0);
1568 swf_GetU16(tag); //id
1569 swf_GetString(tag); //name
1570 char* copyright = swf_GetString(tag);
1571 printf("%s%s\n", myprefix, copyright);
1573 else if(tag->id == ST_DEFINESHAPE ||
1574 tag->id == ST_DEFINESHAPE2 ||
1575 tag->id == ST_DEFINESHAPE3 ||
1576 tag->id == ST_DEFINESHAPE4) {
1578 handleShape(tag, myprefix);
1581 if(tag->len && used) {
1582 int num = swf_GetNumUsedIDs(tag);
1586 used = (int*)malloc(sizeof(int)*num);
1587 swf_GetUsedIDs(tag, used);
1588 printf("%s%suses IDs: ", indent, prefix);
1589 for(t=0;t<num;t++) {
1591 swf_SetTagPos(tag, used[t]);
1592 id = swf_GetU16(tag);
1593 printf("%d%s", id, t<num-1?", ":"");
1595 dumperror("Id %04d is not yet defined.\n", id);
1602 if(tag->id == ST_FREECHARACTER) {
1604 swf_SetTagPos(tag, 0);
1605 id = swf_GetU16(tag);
1609 if(tag->len && hex) {
1610 hexdumpTag(tag, prefix);