2 Shows the structure of a swf file
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22 #include "../config.h"
24 #ifdef HAVE_SYS_STAT_H
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
40 #include "../lib/rfxswf.h"
41 #include "../lib/args.h"
43 static char * filename = 0;
45 /* idtab stores the ids which are defined in the file. This allows us
46 to detect errors in the file. (i.e. ids which are defined more than
48 static char idtab[65536];
49 static char * indent = " ";
51 static int placements = 0;
52 static int action = 0;
56 static int showtext = 0;
57 static int showshapes = 0;
61 static int cumulative = 0;
62 static int showfonts = 0;
63 static int showbuttons = 0;
65 static struct options_t options[] = {
87 int args_callback_option(char*name,char*val)
89 if(!strcmp(name, "V")) {
90 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
93 else if(name[0]=='a') {
97 else if(name[0]=='p') {
101 else if(name[0]=='t') {
105 else if(name[0]=='s') {
109 else if(name[0]=='e') {
113 else if(name[0]=='c') {
117 else if(name[0]=='E') {
122 else if(name[0]=='X') {
126 else if(name[0]=='Y') {
130 else if(name[0]=='r') {
134 else if(name[0]=='f') {
138 else if(name[0]=='F') {
142 else if(name[0]=='d') {
146 else if(name[0]=='u') {
150 else if(name[0]=='b') {
154 else if(name[0]=='B') {
158 else if(name[0]=='D') {
159 showbuttons = action = placements = showtext = showshapes = 1;
163 printf("Unknown option: -%s\n", name);
169 int args_callback_longoption(char*name,char*val)
171 return args_long2shortoption(options, name, val);
173 void args_callback_usage(char *name)
176 printf("Usage: %s [-atpdu] file.swf\n", name);
178 printf("-h , --help Print short help message and exit\n");
179 printf("-D , --full Show everything. Same as -atp\n");
180 printf("-V , --version Print version info and exit\n");
181 printf("-e , --html Print out html code for embedding the file\n");
182 printf("-E , --xhtml Print out xhtml code for embedding the file\n");
183 printf("-a , --action Disassemble action tags\n");
184 printf("-t , --text Show text fields (like swfstrings).\n");
185 printf("-s , --shapes Show shape coordinates/styles\n");
186 printf("-F , --fonts Show font information\n");
187 printf("-p , --placements Show placement information\n");
188 printf("-B , --buttons Show button information\n");
189 printf("-b , --bbox Print tag's bounding boxes\n");
190 printf("-X , --width Prints out a string of the form \"-X width\".\n");
191 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
192 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
193 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
194 printf("-d , --hex Print hex output of tag data, too.\n");
195 printf("-u , --used Show referred IDs for each Tag.\n");
198 int args_callback_command(char*name,char*val)
201 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
209 char* testfunc(char*str)
211 printf("%s: %s\n", what, str);
215 void dumpButton2Actions(TAG*tag, char*prefix)
221 oldTagPos = swf_GetTagPos(tag);
223 // scan DefineButton2 Record
225 swf_GetU16(tag); // Character ID
226 swf_GetU8(tag); // Flags;
228 offsetpos = swf_GetTagPos(tag); // first offset
231 while (swf_GetU8(tag)) // state -> parse ButtonRecord
232 { swf_GetU16(tag); // id
233 swf_GetU16(tag); // layer
234 swf_GetMatrix(tag,NULL); // matrix
235 swf_GetCXForm(tag,NULL,1); // cxform
242 if(tag->pos >= tag->len)
245 offsetpos = swf_GetU16(tag);
246 condition = swf_GetU16(tag); // condition
248 actions = swf_ActionGet(tag);
249 printf("%s condition %04x\n", prefix, condition);
250 swf_DumpActions(actions, prefix);
253 swf_SetTagPos(tag,oldTagPos);
257 void dumpButtonActions(TAG*tag, char*prefix)
260 swf_SetTagPos(tag, 0);
261 swf_GetU16(tag); // id
262 while (swf_GetU8(tag)) // state -> parse ButtonRecord
263 { swf_GetU16(tag); // id
264 swf_GetU16(tag); // layer
265 swf_GetMatrix(tag,NULL); // matrix
267 actions = swf_ActionGet(tag);
268 swf_DumpActions(actions, prefix);
269 swf_ActionFree(actions);
272 void dumpButton(TAG*tag, char*prefix)
274 swf_SetTagPos(tag, 0);
275 swf_GetU16(tag); // id
277 U8 flags = swf_GetU8(tag);
280 U16 id = swf_GetU16(tag);
281 U16 depth = swf_GetU16(tag);
283 sprintf(event, "%s%s%s%s",
284 (flags&BS_HIT)?"[hit]":"",
285 (flags&BS_DOWN)?"[down]":"",
286 (flags&BS_OVER)?"[over]":"",
287 (flags&BS_UP)?"[up]":"");
289 printf("%s | Show %d at depth %d for %s flags=%02x\n", prefix, id, depth, event, flags);
291 printf("%s | Show %d at depth %d for %s\n", prefix, id, depth, event);
293 swf_GetMatrix(tag,NULL); // matrix
297 void dumpFont(TAG*tag, char*prefix)
299 SWFFONT* font = malloc(sizeof(SWFFONT));
300 memset(font, 0, sizeof(SWFFONT));
301 if(tag->id == ST_DEFINEFONT2) {
302 swf_FontExtract_DefineFont2(0, font, tag);
303 } else if(tag->id == ST_DEFINEFONT) {
304 swf_FontExtract_DefineFont(0, font, tag);
306 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
308 printf("%sID: %d\n", prefix,font->id);
309 printf("%sVersion: %d\n", prefix,font->version);
310 printf("%sname: %s\n", prefix,font->name);
311 printf("%scharacters: %d\n", prefix,font->numchars);
312 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
315 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
316 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
317 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
318 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
320 printf("%sstyle: %d\n", prefix,font->style);
321 printf("%sencoding: %02x\n", prefix,font->encoding);
322 printf("%slanguage: %02x\n", prefix,font->language);
324 for(t=0;t<font->numchars;t++) {
325 int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
326 printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
327 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
328 SHAPELINE*line = shape->lines;
331 if(line->type == moveTo) {
332 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
333 } else if(line->type == lineTo) {
334 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
335 } else if(line->type == splineTo) {
336 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
337 line->sx/20.0, line->sy/20.0,
338 line->x/20.0, line->y/20.0
343 swf_Shape2Free(shape);
350 printf("%sencoding table:", prefix, prefix);
351 char filled0=0, lastfilled=0;
352 for(t=0;t<font->maxascii;t++) {
354 printf("\n%s%08x ", prefix, t);
357 for(s=t;s<font->maxascii;s++) {
358 if(font->ascii2glyph[s]>=0) break;
367 for(s=t;s<t+16 && s<font->maxascii;s++) {
368 if(font->ascii2glyph[s]>=0) filled0=1;
371 printf("%4d ", font->ascii2glyph[t]);
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)
421 swf_ParseDefineText(tag,textcallback, 0);
424 void handleDefineSound(TAG*tag)
426 U16 id = swf_GetU16(tag);
427 U8 flags = swf_GetU8(tag);
428 int compression = (flags>>4)&7;
429 int rate = (flags>>2)&3;
430 int bits = flags&2?16:8;
431 int stereo = flags&1;
433 if(compression == 0) printf("Raw ");
434 else if(compression == 1) printf("ADPCM ");
435 else if(compression == 2) printf("MP3 ");
436 else if(compression == 3) printf("Raw little-endian ");
437 else if(compression == 6) printf("ASAO ");
439 if(rate == 0) printf("5.5Khz ");
440 if(rate == 1) printf("11Khz ");
441 if(rate == 2) printf("22Khz ");
442 if(rate == 3) printf("44Khz ");
443 printf("%dBit ", bits);
444 if(stereo) printf("stereo");
449 void handleDefineBits(TAG*tag)
455 id = swf_GetU16(tag);
456 mode = swf_GetU8(tag);
457 width = swf_GetU16(tag);
458 height = swf_GetU16(tag);
459 printf(" image %dx%d",width,height);
460 if(mode == 3) printf(" (8 bpp)");
461 else if(mode == 4) printf(" (16 bpp)");
462 else if(mode == 5) printf(" (32 bpp)");
463 else printf(" (? bpp)");
466 void handleEditText(TAG*tag)
471 id = swf_GetU16(tag);
474 //swf_ResetReadBits(tag);
480 flags = swf_GetBits(tag,16);
481 if(flags & ET_HASFONT) {
482 swf_GetU16(tag); //font
483 swf_GetU16(tag); //fontheight
485 if(flags & ET_HASTEXTCOLOR) {
486 swf_GetU8(tag); //rgba
491 if(flags & ET_HASMAXLENGTH) {
492 swf_GetU16(tag); //maxlength
494 if(flags & ET_HASLAYOUT) {
495 swf_GetU8(tag); //align
496 swf_GetU16(tag); //left margin
497 swf_GetU16(tag); //right margin
498 swf_GetU16(tag); //indent
499 swf_GetU16(tag); //leading
501 printf(" variable \"%s\" ", &tag->data[tag->pos]);
502 if(flags & ET_HTML) printf("(html)");
503 if(flags & ET_NOSELECT) printf("(noselect)");
504 if(flags & ET_PASSWORD) printf("(password)");
505 if(flags & ET_READONLY) printf("(readonly)");
507 if(flags & (ET_X1 | ET_X3 ))
509 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
512 while(tag->data[tag->pos++]);
513 if(flags & ET_HASTEXT)
514 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
517 void printhandlerflags(U32 handlerflags)
519 if(handlerflags&1) printf("[on load]");
520 if(handlerflags&2) printf("[enter frame]");
521 if(handlerflags&4) printf("[unload]");
522 if(handlerflags&8) printf("[mouse move]");
523 if(handlerflags&16) printf("[mouse down]");
524 if(handlerflags&32) printf("[mouse up]");
525 if(handlerflags&64) printf("[key down]");
526 if(handlerflags&128) printf("[key up]");
528 if(handlerflags&256) printf("[data]");
529 if(handlerflags&512) printf("[initialize]");
530 if(handlerflags&1024) printf("[mouse press]");
531 if(handlerflags&2048) printf("[mouse release]");
532 if(handlerflags&4096) printf("[mouse release outside]");
533 if(handlerflags&8192) printf("[mouse rollover]");
534 if(handlerflags&16384) printf("[mouse rollout]");
535 if(handlerflags&32768) printf("[mouse drag over]");
537 if(handlerflags&0x10000) printf("[mouse drag out]");
538 if(handlerflags&0x20000) printf("[key press]");
539 if(handlerflags&0x40000) printf("[construct even]");
540 if(handlerflags&0xfff80000) printf("[???]");
542 void handleVideoStream(TAG*tag, char*prefix)
544 U16 id = swf_GetU16(tag);
545 U16 frames = swf_GetU16(tag);
546 U16 width = swf_GetU16(tag);
547 U16 height = swf_GetU16(tag);
548 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
549 U8 codec = swf_GetU8(tag);
550 printf(" (%d frames, %dx%d", frames, width, height);
554 printf(" sorenson h.263)");
556 printf(" codec 0x%02x)", codec);
558 void handleVideoFrame(TAG*tag, char*prefix)
560 U32 code, version, reference, sizeflags;
561 U32 width=0, height=0;
563 U16 id = swf_GetU16(tag);
564 U16 frame = swf_GetU16(tag);
565 U8 deblock,flags, tmp, bit;
567 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
568 printf(" (frame %d) ", frame);
570 /* video packet follows */
571 code = swf_GetBits(tag, 17);
572 version = swf_GetBits(tag, 5);
573 reference = swf_GetBits(tag, 8);
575 sizeflags = swf_GetBits(tag, 3);
578 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
579 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
580 case 2: width = 352; height = 288; break;
581 case 3: width = 176; height = 144; break;
582 case 4: width = 128; height = 96; break;
583 case 5: width = 320; height = 240; break;
584 case 6: width = 160; height = 120; break;
585 case 7: width = -1; height = -1;/*reserved*/ break;
587 printf("%dx%d ", width, height);
588 type = swf_GetBits(tag, 2);
589 printf("%s", types[type]);
591 deblock = swf_GetBits(tag, 1);
593 printf(" deblock ", deblock);
594 quantizer = swf_GetBits(tag, 5);
595 printf(" quant: %d ", quantizer);
598 void dumpFilter(FILTER*filter)
600 if(filter->type == FILTERTYPE_BLUR) {
601 FILTER_BLUR*f = (FILTER_BLUR*)filter;
602 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
603 printf("passes: %d\n", f->passes);
604 } if(filter->type == FILTERTYPE_GLOW) {
605 FILTER_GLOW*f = (FILTER_GLOW*)filter;
606 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
607 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
608 printf("passes: %d\n", f->passes);
609 printf("flags: %s%s%s\n",
610 f->knockout?"knockout ":"",
611 f->composite?"composite ":"",
612 f->innerglow?"innerglow":"");
613 } if(filter->type == FILTERTYPE_DROPSHADOW) {
614 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
615 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
616 printf("passes: %d\n", f->passes);
617 printf("angle: %f distance: %f\n", f->angle, f->distance);
618 printf("strength: %f passes: %d\n", f->strength, f->passes);
619 printf("flags: %s%s%s\n",
620 f->knockout?"knockout ":"",
621 f->composite?"composite ":"",
622 f->innershadow?"innershadow ":"");
623 } if(filter->type == FILTERTYPE_BEVEL) {
624 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
625 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
626 printf("passes: %d\n", f->passes);
627 printf("angle: %f distance: %f\n", f->angle, f->distance);
628 printf("strength: %f passes: %d\n", f->strength, f->passes);
629 printf("flags: %s%s%s%s\n",
631 f->knockout?"knockout ":"",
632 f->composite?"composite ":"",
633 f->innershadow?"innershadow ":"");
634 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
635 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
636 swf_DumpGradient(stdout, f->gradient);
637 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
638 printf("angle: %f distance: %f\n", f->angle, f->distance);
639 printf("strength: %f passes: %d\n", f->strength, f->passes);
640 printf("flags: %s%s%s%s\n",
641 f->knockout?"knockout ":"",
642 f->ontop?"ontop ":"",
643 f->composite?"composite ":"",
644 f->innershadow?"innershadow ":"");
649 void handlePlaceObject23(TAG*tag, char*prefix)
655 int ppos[3] = {0,0,0};
656 swf_SetTagPos(tag, 0);
657 flags = swf_GetU8(tag);
658 if(tag->id == ST_PLACEOBJECT3)
659 flags2 = swf_GetU8(tag);
660 swf_GetU16(tag); //depth
663 if(flags&2) swf_GetU16(tag); //id
665 swf_GetMatrix(tag,&m);
667 ppos[0] += sprintf(pstr[0], "| Matrix ");
668 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
669 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
673 swf_GetCXForm(tag, &cx, 1);
675 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
676 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);
677 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
681 U16 ratio = swf_GetU16(tag); //ratio
683 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
684 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
685 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
689 U16 clip = swf_GetU16(tag); //clip
691 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
692 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
693 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
696 if(flags&32) { while(swf_GetU8(tag)); }
698 if(flags2&1) { // filter list
699 U8 num = swf_GetU8(tag);
701 printf("\n%d filters\n", num);
702 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
705 FILTER*filter = swf_GetFilter(tag);
711 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
716 if(flags2&2) { // blend mode
717 U8 blendmode = swf_GetU8(tag);
721 sprintf(name, "%-5d", blendmode);
722 for(t=0;blendModeNames[t];t++) {
724 sprintf(name, "%-5s", blendModeNames[t]);
728 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
729 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
730 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
734 if(placements && ppos[0]) {
736 printf("%s %s\n", prefix, pstr[0]);
737 printf("%s %s\n", prefix, pstr[1]);
738 printf("%s %s", prefix, pstr[2]);
747 reserved = swf_GetU16(tag); // must be 0
748 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
750 printf("Unknown parameter field not zero: %04x\n", reserved);
753 printf("global flags: %04x\n", globalflags);
755 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
757 handlerflags = swf_GetU32(tag);
760 while(handlerflags) {
765 globalflags &= ~handlerflags;
766 printf("%s flags %08x ",prefix, handlerflags);
767 printhandlerflags(handlerflags);
768 length = swf_GetU32(tag);
769 printf(", %d bytes actioncode\n",length);
770 a = swf_ActionGet(tag);
771 swf_DumpActions(a,prefix);
774 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
776 if(globalflags) // should go to sterr.
777 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
779 printf(" has action code\n");
784 void handlePlaceObject(TAG*tag, char*prefix)
786 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
791 swf_SetTagPos(tag, 0);
792 id = swf_GetU16(tag);
793 depth = swf_GetU16(tag);
794 swf_GetMatrix(tag, &matrix);
795 swf_GetCXForm(tag, &cxform, 0);
797 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
798 swf_SetU16(tag2, depth);
799 swf_SetU16(tag2, id);
800 swf_SetMatrix(tag2, &matrix);
801 swf_SetCXForm(tag2, &cxform, 1);
803 handlePlaceObject23(tag2, prefix);
806 char* fillstyle2str(FILLSTYLE*style)
808 switch(style->type) {
810 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
812 case 0x10: case 0x11: case 0x12: case 0x13:
813 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
815 case 0x40: case 0x42:
816 /* TODO: display information about that bitmap */
817 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
818 /* TODO: show matrix */
819 //swf_DumpMatrix(stdout, &style->m);
821 case 0x41: case 0x43:
822 /* TODO: display information about that bitmap */
823 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
824 /* TODO: show matrix */
825 //swf_DumpMatrix(stdout, &style->m);
828 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
832 char* linestyle2str(LINESTYLE*style)
834 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
838 void handleShape(TAG*tag, char*prefix)
846 swf_ParseDefineShape(tag, &shape);
848 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
850 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
855 else printf("%s | (Neither line nor fill styles)\n", prefix);
858 printf("%s", prefix);
859 if(t < shape.numfillstyles) {
860 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
864 if(t < shape.numlinestyles) {
865 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
868 //if(shape.fillstyles[t].type&0x40) {
869 // MATRIX m = shape.fillstyles[t].m;
870 // swf_DumpMatrix(stdout, &m);
874 printf("%s |\n", prefix);
878 printf("%s | fill: %02d/%02d line:%02d - ",
883 if(line->type == moveTo) {
884 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
885 } else if(line->type == lineTo) {
886 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
887 } else if(line->type == splineTo) {
888 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
889 line->sx/20.0, line->sy/20.0,
890 line->x/20.0, line->y/20.0
895 printf("%s |\n", prefix);
898 void fontcallback1(void*self, U16 id,U8 * name)
902 void fontcallback2(void*self, U16 id,U8 * name)
904 swf_FontExtract(&swf,id,&fonts[fontnum]);
908 static U8 printable(U8 a)
910 if(a<32 || a==127) return '.';
913 void hexdumpTag(TAG*tag, char* prefix)
917 printf(" %s-=> ",prefix);
918 for(t=0;t<tag->len;t++) {
919 printf("%02x ", tag->data[t]);
920 ascii[t&15] = printable(tag->data[t]);
921 if((t && ((t&15)==15)) || (t==tag->len-1))
925 for(s=p-1;s<16;s++) {
929 printf(" %s\n", ascii);
931 printf(" %s\n %s-=> ",ascii,prefix);
936 void handleExportAssets(TAG*tag, char* prefix)
942 num = swf_GetU16(tag);
945 id = swf_GetU16(tag);
946 name = swf_GetString(tag);
947 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
951 void dumperror(const char* format, ...)
956 va_start(arglist, format);
957 vsnprintf(buf, sizeof(buf)-1, format, arglist);
961 printf("==== Error: %s ====\n", buf);
964 static char strbuf[800];
967 char* timestring(double f)
969 int hours = (int)(f/3600);
970 int minutes = (int)((f-hours*3600)/60);
971 int seconds = (int)((f-hours*3600-minutes*60));
972 int useconds = (int)((f-(int)f)*1000+0.5);
975 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
976 return &strbuf[bufpos];
979 int main (int argc,char ** argv)
987 char issprite = 0; // are we inside a sprite definition?
990 char* spriteframelabel = 0;
991 char* framelabel = 0;
996 memset(idtab,0,65536);
998 processargs(argc, argv);
1002 fprintf(stderr, "You must supply a filename.\n");
1006 f = open(filename,O_RDONLY|O_BINARY);
1010 sprintf(buffer, "Couldn't open %.200s", filename);
1016 char compressed = (header[0]=='C');
1017 char isflash = (header[0]=='F' && header[1] == 'W' && header[2] == 'S') ||
1018 (header[0]=='C' && header[1] == 'W' && header[2] == 'S');
1021 int fl=strlen(filename);
1022 if(!isflash && fl>3 && !strcmp(&filename[fl-4], ".abc")) {
1023 swf_ReadABCfile(filename, &swf);
1025 f = open(filename,O_RDONLY|O_BINARY);
1026 if FAILED(swf_ReadSWF(f,&swf))
1028 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1035 if(statbuf.st_size != swf.fileSize && !compressed)
1036 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1037 statbuf.st_size, swf.fileSize);
1038 filesize = statbuf.st_size;
1043 //if(action && swf.fileVersion>=9) {
1044 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1048 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1049 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1053 printf("-X %d", xsize);
1055 if((xy&1) && (xy&6))
1059 printf("-Y %d", ysize);
1061 if((xy&3) && (xy&4))
1065 printf("-r %.2f", swf.frameRate/256.0);
1067 if((xy&7) && (xy&8))
1071 printf("-f %d", swf.frameCount);
1078 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1079 "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"};
1080 if(swf.fileVersion>10) {
1081 fprintf(stderr, "Fileversion>10\n");
1086 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1087 "<param name=\"movie\" value=\"%s\"/>\n"
1088 "<param name=\"play\" value=\"true\"/>\n"
1089 "<param name=\"loop\" value=\"false\"/>\n"
1090 "<param name=\"quality\" value=\"high\"/>\n"
1091 "<param name=\"loop\" value=\"false\"/>\n"
1092 "</object>\n\n", filename, xsize, ysize, filename);
1094 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1096 //" BGCOLOR=#ffffffff\n"?
1098 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1099 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1100 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1101 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1102 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1103 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1104 " <PARAM NAME=\"ALLOWSCRIPTACCESS\" VALUE=\"always\">\n"
1105 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1106 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1107 " TYPE=\"application/x-shockwave-flash\"\n"
1108 " ALLOWSCRIPTACCESS=\"always\"\n"
1109 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1111 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1112 filename, filename, xsize, ysize);
1116 printf("[HEADER] File version: %d\n", swf.fileVersion);
1118 printf("[HEADER] File is zlib compressed.");
1119 if(filesize && swf.fileSize)
1120 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1124 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1125 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1126 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1127 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1128 if(swf.movieSize.xmin)
1129 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1132 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1133 if(swf.movieSize.ymin)
1134 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1142 swf_FontEnumerate(&swf,&fontcallback1, 0);
1143 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1145 swf_FontEnumerate(&swf,&fontcallback2, 0);
1149 char*name = swf_TagGetName(tag);
1152 dumperror("Unknown tag:0x%03x", tag->id);
1157 name = "UNKNOWN TAG";
1160 filepos += tag->len;
1161 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1163 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1166 if(swf_isDefiningTag(tag)) {
1167 U16 id = swf_GetDefineID(tag);
1168 printf(" defines id %04d", id);
1170 dumperror("Id %04d is defined more than once.", id);
1173 else if(swf_isPseudoDefiningTag(tag)) {
1174 U16 id = swf_GetDefineID(tag);
1175 printf(" adds information to id %04d", id);
1177 dumperror("Id %04d is not yet defined.\n", id);
1179 else if(tag->id == ST_PLACEOBJECT) {
1180 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1181 if(swf_GetName(tag))
1182 printf(" name \"%s\"",swf_GetName(tag));
1184 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1191 printf(" id %04d",swf_GetPlaceID(tag));
1195 printf(" at depth %04d", swf_GetDepth(tag));
1197 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1198 printf(" as bitmap");
1200 swf_SetTagPos(tag, 0);
1201 if(tag->data[0]&64) {
1203 swf_GetPlaceObject(tag, &po);
1204 printf(" (clip to %04d)", po.clipdepth);
1205 swf_PlaceObjectFree(&po);
1207 if(swf_GetName(tag))
1208 printf(" name \"%s\"",swf_GetName(tag));
1211 else if(tag->id == ST_REMOVEOBJECT) {
1212 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1214 else if(tag->id == ST_REMOVEOBJECT2) {
1215 printf(" removes object from depth %04d", swf_GetDepth(tag));
1217 else if(tag->id == ST_FREECHARACTER) {
1218 printf(" frees object %04d", swf_GetPlaceID(tag));
1220 else if(tag->id == ST_FILEATTRIBUTES) {
1221 swf_SetTagPos(tag, 0);
1222 U32 flags = swf_GetU32(tag);
1223 if(flags&FILEATTRIBUTE_USENETWORK) printf(" usenetwork");
1224 if(flags&FILEATTRIBUTE_AS3) printf(" as3");
1225 if(flags&FILEATTRIBUTE_SYMBOLCLASS) printf(" symbolclass");
1226 if(flags&FILEATTRIBUTE_USEHARDWAREGPU) printf(" hardware-gpu");
1227 if(flags&FILEATTRIBUTE_USEACCELERATEDBLIT) printf(" accelerated-blit");
1228 if(flags&~(1|8|16|32|64))
1229 printf(" flags=%02x", flags);
1231 else if(tag->id == ST_DOABC) {
1232 swf_SetTagPos(tag, 0);
1233 U32 flags = swf_GetU32(tag);
1234 char*s = swf_GetString(tag);
1236 printf(" flags=%08x", flags);
1239 printf(" \"%s\"", s);
1244 printf(" lazy load");
1246 swf_SetTagPos(tag, 0);
1248 else if(tag->id == ST_STARTSOUND) {
1251 id = swf_GetU16(tag);
1252 flags = swf_GetU8(tag);
1254 printf(" stops sound with id %04d", id);
1256 printf(" starts sound with id %04d", id);
1258 printf(" (if not already playing)");
1264 printf(" looping %d times", swf_GetU16(tag));
1267 else if(tag->id == ST_FRAMELABEL) {
1268 int l = strlen(tag->data);
1269 printf(" \"%s\"", tag->data);
1270 if((l+1) < tag->len) {
1271 printf(" has %d extra bytes", tag->len-1-l);
1272 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1273 printf(" (ANCHOR)");
1275 if((framelabel && !issprite) ||
1276 (spriteframelabel && issprite)) {
1277 dumperror("Frame %d has more than one label",
1278 issprite?spriteframe:mainframe);
1280 if(issprite) spriteframelabel = tag->data;
1281 else framelabel = tag->data;
1283 else if(tag->id == ST_SHOWFRAME) {
1284 char*label = issprite?spriteframelabel:framelabel;
1285 int frame = issprite?spriteframe:mainframe;
1288 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1290 if(issprite) spriteframe++;
1296 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1298 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1299 timestring(frame*(256.0/(swf.frameRate+0.1))),
1300 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1303 printf(" (label \"%s\")", label);
1304 if(issprite) {spriteframe++; spriteframelabel = 0;}
1305 if(!issprite) {mainframe++; framelabel = 0;}
1307 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1308 U8 r = swf_GetU8(tag);
1309 U8 g = swf_GetU8(tag);
1310 U8 b = swf_GetU8(tag);
1311 printf(" (%02x/%02x/%02x)",r,g,b);
1313 else if(tag->id == ST_PROTECT) {
1315 printf(" %s", swf_GetString(tag));
1318 else if(tag->id == ST_CSMTEXTSETTINGS) {
1319 U16 id = swf_GetU16(tag);
1320 U8 flags = swf_GetU8(tag);
1323 printf("flashtype,");
1325 switch(((flags>>3)&7)) {
1326 case 0:printf("no grid,");break;
1327 case 1:printf("pixel grid,");break;
1328 case 2:printf("subpixel grid,");break;
1329 case 3:printf("unknown grid,");break;
1332 printf("unknown[%08x],", flags);
1333 float thickness = swf_GetFixed(tag);
1334 float sharpness = swf_GetFixed(tag);
1335 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1339 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1340 tag->id == ST_DEFINEBITSLOSSLESS2) {
1341 handleDefineBits(tag);
1344 else if(tag->id == ST_DEFINESOUND) {
1345 handleDefineSound(tag);
1348 else if(tag->id == ST_VIDEOFRAME) {
1349 handleVideoFrame(tag, myprefix);
1352 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1353 handleVideoStream(tag, myprefix);
1356 else if(tag->id == ST_DEFINEEDITTEXT) {
1357 handleEditText(tag);
1360 else if(tag->id == ST_DEFINEMOVIE) {
1361 U16 id = swf_GetU16(tag);
1362 char*s = swf_GetString(tag);
1363 printf(" URL: %s\n", s);
1365 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1371 else if(tag->id == ST_DEFINESCALINGGRID) {
1372 U16 id = swf_GetU16(tag);
1374 swf_GetRect(tag, &r);
1375 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1377 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1379 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1381 printf(" \"%s\"\n", swf_GetString(tag));
1387 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1388 SRECT r = swf_GetDefineBBox(tag);
1389 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1396 sprintf(myprefix, " %s", prefix);
1398 if(tag->id == ST_DEFINESPRITE) {
1399 sprintf(prefix, " ");
1401 dumperror("Sprite definition inside a sprite definition");
1405 spriteframelabel = 0;
1407 else if(tag->id == ST_END) {
1410 spriteframelabel = 0;
1412 dumperror("End Tag not empty");
1414 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1415 handleExportAssets(tag, myprefix);
1417 else if(tag->id == ST_DOACTION && action) {
1419 actions = swf_ActionGet(tag);
1420 swf_DumpActions(actions, myprefix);
1422 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1423 void*abccode = swf_ReadABC(tag);
1424 swf_DumpABC(stdout, abccode, "");
1425 swf_FreeABC(abccode);
1427 else if(tag->id == ST_DOINITACTION && action) {
1429 swf_GetU16(tag); // id
1430 actions = swf_ActionGet(tag);
1431 swf_DumpActions(actions, myprefix);
1433 else if(tag->id == ST_DEFINEBUTTON) {
1435 dumpButton(tag, myprefix);
1438 dumpButtonActions(tag, myprefix);
1441 else if(swf_isFontTag(tag) && showfonts) {
1442 dumpFont(tag, myprefix);
1444 else if(tag->id == ST_DEFINEBUTTON2) {
1446 dumpButton2Actions(tag, myprefix);
1449 else if(tag->id == ST_PLACEOBJECT) {
1450 handlePlaceObject(tag, myprefix);
1452 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1453 handlePlaceObject23(tag, myprefix);
1455 else if(tag->id == ST_DEFINEFONTNAME) {
1456 swf_SetTagPos(tag, 0);
1457 swf_GetU16(tag); //id
1458 swf_GetString(tag); //name
1459 char* copyright = swf_GetString(tag);
1460 printf("%s%s\n", myprefix, copyright);
1462 else if(tag->id == ST_DEFINESHAPE ||
1463 tag->id == ST_DEFINESHAPE2 ||
1464 tag->id == ST_DEFINESHAPE3 ||
1465 tag->id == ST_DEFINESHAPE4) {
1467 handleShape(tag, myprefix);
1470 if(tag->len && used) {
1471 int num = swf_GetNumUsedIDs(tag);
1475 used = (int*)malloc(sizeof(int)*num);
1476 swf_GetUsedIDs(tag, used);
1477 printf("%s%suses IDs: ", indent, prefix);
1478 for(t=0;t<num;t++) {
1480 swf_SetTagPos(tag, used[t]);
1481 id = swf_GetU16(tag);
1482 printf("%d%s", id, t<num-1?", ":"");
1484 dumperror("Id %04d is not yet defined.\n", id);
1491 if(tag->id == ST_FREECHARACTER) {
1493 swf_SetTagPos(tag, 0);
1494 id = swf_GetU16(tag);
1498 if(tag->len && hex) {
1499 hexdumpTag(tag, prefix);