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&1) printf(" usenetwork");
1224 if(flags&8) printf(" as3");
1225 if(flags&16) printf(" symbolclass");
1227 printf(" flags=%02x", flags);
1229 else if(tag->id == ST_DOABC) {
1230 swf_SetTagPos(tag, 0);
1231 U32 flags = swf_GetU32(tag);
1232 char*s = swf_GetString(tag);
1234 printf(" flags=%08x", flags);
1237 printf(" \"%s\"", s);
1242 printf(" lazy load");
1244 swf_SetTagPos(tag, 0);
1246 else if(tag->id == ST_STARTSOUND) {
1249 id = swf_GetU16(tag);
1250 flags = swf_GetU8(tag);
1252 printf(" stops sound with id %04d", id);
1254 printf(" starts sound with id %04d", id);
1256 printf(" (if not already playing)");
1262 printf(" looping %d times", swf_GetU16(tag));
1265 else if(tag->id == ST_FRAMELABEL) {
1266 int l = strlen(tag->data);
1267 printf(" \"%s\"", tag->data);
1268 if((l+1) < tag->len) {
1269 printf(" has %d extra bytes", tag->len-1-l);
1270 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1271 printf(" (ANCHOR)");
1273 if((framelabel && !issprite) ||
1274 (spriteframelabel && issprite)) {
1275 dumperror("Frame %d has more than one label",
1276 issprite?spriteframe:mainframe);
1278 if(issprite) spriteframelabel = tag->data;
1279 else framelabel = tag->data;
1281 else if(tag->id == ST_SHOWFRAME) {
1282 char*label = issprite?spriteframelabel:framelabel;
1283 int frame = issprite?spriteframe:mainframe;
1286 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1288 if(issprite) spriteframe++;
1294 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1296 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1297 timestring(frame*(256.0/(swf.frameRate+0.1))),
1298 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1301 printf(" (label \"%s\")", label);
1302 if(issprite) {spriteframe++; spriteframelabel = 0;}
1303 if(!issprite) {mainframe++; framelabel = 0;}
1305 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1306 U8 r = swf_GetU8(tag);
1307 U8 g = swf_GetU8(tag);
1308 U8 b = swf_GetU8(tag);
1309 printf(" (%02x/%02x/%02x)",r,g,b);
1311 else if(tag->id == ST_PROTECT) {
1313 printf(" %s", swf_GetString(tag));
1316 else if(tag->id == ST_CSMTEXTSETTINGS) {
1317 U16 id = swf_GetU16(tag);
1318 U8 flags = swf_GetU8(tag);
1321 printf("flashtype,");
1323 switch(((flags>>3)&7)) {
1324 case 0:printf("no grid,");break;
1325 case 1:printf("pixel grid,");break;
1326 case 2:printf("subpixel grid,");break;
1327 case 3:printf("unknown grid,");break;
1330 printf("unknown[%08x],", flags);
1331 float thickness = swf_GetFixed(tag);
1332 float sharpness = swf_GetFixed(tag);
1333 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1337 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1338 tag->id == ST_DEFINEBITSLOSSLESS2) {
1339 handleDefineBits(tag);
1342 else if(tag->id == ST_DEFINESOUND) {
1343 handleDefineSound(tag);
1346 else if(tag->id == ST_VIDEOFRAME) {
1347 handleVideoFrame(tag, myprefix);
1350 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1351 handleVideoStream(tag, myprefix);
1354 else if(tag->id == ST_DEFINEEDITTEXT) {
1355 handleEditText(tag);
1358 else if(tag->id == ST_DEFINEMOVIE) {
1359 U16 id = swf_GetU16(tag);
1360 char*s = swf_GetString(tag);
1361 printf(" URL: %s\n", s);
1363 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1369 else if(tag->id == ST_DEFINESCALINGGRID) {
1370 U16 id = swf_GetU16(tag);
1372 swf_GetRect(tag, &r);
1373 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1375 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1377 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1379 printf(" \"%s\"\n", swf_GetString(tag));
1385 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1386 SRECT r = swf_GetDefineBBox(tag);
1387 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1394 sprintf(myprefix, " %s", prefix);
1396 if(tag->id == ST_DEFINESPRITE) {
1397 sprintf(prefix, " ");
1399 dumperror("Sprite definition inside a sprite definition");
1403 spriteframelabel = 0;
1405 else if(tag->id == ST_END) {
1408 spriteframelabel = 0;
1410 dumperror("End Tag not empty");
1412 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1413 handleExportAssets(tag, myprefix);
1415 else if(tag->id == ST_DOACTION && action) {
1417 actions = swf_ActionGet(tag);
1418 swf_DumpActions(actions, myprefix);
1420 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1421 void*abccode = swf_ReadABC(tag);
1422 swf_DumpABC(stdout, abccode, "");
1423 swf_FreeABC(abccode);
1425 else if(tag->id == ST_DOINITACTION && action) {
1427 swf_GetU16(tag); // id
1428 actions = swf_ActionGet(tag);
1429 swf_DumpActions(actions, myprefix);
1431 else if(tag->id == ST_DEFINEBUTTON) {
1433 dumpButton(tag, myprefix);
1436 dumpButtonActions(tag, myprefix);
1439 else if(swf_isFontTag(tag) && showfonts) {
1440 dumpFont(tag, myprefix);
1442 else if(tag->id == ST_DEFINEBUTTON2) {
1444 dumpButton2Actions(tag, myprefix);
1447 else if(tag->id == ST_PLACEOBJECT) {
1448 handlePlaceObject(tag, myprefix);
1450 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1451 handlePlaceObject23(tag, myprefix);
1453 else if(tag->id == ST_DEFINEFONTNAME) {
1454 swf_SetTagPos(tag, 0);
1455 swf_GetU16(tag); //id
1456 swf_GetString(tag); //name
1457 char* copyright = swf_GetString(tag);
1458 printf("%s%s\n", myprefix, copyright);
1460 else if(tag->id == ST_DEFINESHAPE ||
1461 tag->id == ST_DEFINESHAPE2 ||
1462 tag->id == ST_DEFINESHAPE3 ||
1463 tag->id == ST_DEFINESHAPE4) {
1465 handleShape(tag, myprefix);
1468 if(tag->len && used) {
1469 int num = swf_GetNumUsedIDs(tag);
1473 used = (int*)malloc(sizeof(int)*num);
1474 swf_GetUsedIDs(tag, used);
1475 printf("%s%suses IDs: ", indent, prefix);
1476 for(t=0;t<num;t++) {
1478 swf_SetTagPos(tag, used[t]);
1479 id = swf_GetU16(tag);
1480 printf("%d%s", id, t<num-1?", ":"");
1482 dumperror("Id %04d is not yet defined.\n", id);
1489 if(tag->id == ST_FREECHARACTER) {
1491 swf_SetTagPos(tag, 0);
1492 id = swf_GetU16(tag);
1496 if(tag->len && hex) {
1497 hexdumpTag(tag, prefix);