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 , --bbox Print tag's bounding boxes\n");
189 printf("-X , --width Prints out a string of the form \"-X width\".\n");
190 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
191 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
192 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
193 printf("-d , --hex Print hex output of tag data, too.\n");
194 printf("-u , --used Show referred IDs for each Tag.\n");
197 int args_callback_command(char*name,char*val)
200 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
208 char* testfunc(char*str)
210 printf("%s: %s\n", what, str);
214 void dumpButton2Actions(TAG*tag, char*prefix)
220 oldTagPos = swf_GetTagPos(tag);
222 // scan DefineButton2 Record
224 swf_GetU16(tag); // Character ID
225 swf_GetU8(tag); // Flags;
227 offsetpos = swf_GetTagPos(tag); // first offset
230 while (swf_GetU8(tag)) // state -> parse ButtonRecord
231 { swf_GetU16(tag); // id
232 swf_GetU16(tag); // layer
233 swf_GetMatrix(tag,NULL); // matrix
234 swf_GetCXForm(tag,NULL,1); // cxform
241 if(tag->pos >= tag->len)
244 offsetpos = swf_GetU16(tag);
245 condition = swf_GetU16(tag); // condition
247 actions = swf_ActionGet(tag);
248 printf("%s condition %04x\n", prefix, condition);
249 swf_DumpActions(actions, prefix);
252 swf_SetTagPos(tag,oldTagPos);
256 void dumpButtonActions(TAG*tag, char*prefix)
259 swf_SetTagPos(tag, 0);
260 swf_GetU16(tag); // id
261 while (swf_GetU8(tag)) // state -> parse ButtonRecord
262 { swf_GetU16(tag); // id
263 swf_GetU16(tag); // layer
264 swf_GetMatrix(tag,NULL); // matrix
266 actions = swf_ActionGet(tag);
267 swf_DumpActions(actions, prefix);
270 void dumpButton(TAG*tag, char*prefix)
272 swf_SetTagPos(tag, 0);
273 swf_GetU16(tag); // id
275 U8 flags = swf_GetU8(tag);
278 U16 id = swf_GetU16(tag);
279 U16 depth = swf_GetU16(tag);
281 sprintf(event, "%s%s%s%s",
282 (flags&BS_HIT)?"[hit]":"",
283 (flags&BS_DOWN)?"[down]":"",
284 (flags&BS_OVER)?"[over]":"",
285 (flags&BS_UP)?"[up]":"");
287 printf("%s | Show %d at depth %d for %s flags=%02x\n", prefix, id, depth, event, flags);
289 printf("%s | Show %d at depth %d for %s\n", prefix, id, depth, event);
291 swf_GetMatrix(tag,NULL); // matrix
295 void dumpFont(TAG*tag, char*prefix)
297 SWFFONT* font = malloc(sizeof(SWFFONT));
298 memset(font, 0, sizeof(SWFFONT));
299 if(tag->id == ST_DEFINEFONT2) {
300 swf_FontExtract_DefineFont2(0, font, tag);
301 } else if(tag->id == ST_DEFINEFONT) {
302 swf_FontExtract_DefineFont(0, font, tag);
304 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
306 printf("%sID: %d\n", prefix,font->id);
307 printf("%sVersion: %d\n", prefix,font->version);
308 printf("%sname: %s\n", prefix,font->name);
309 printf("%scharacters: %d\n", prefix,font->numchars);
310 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
313 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
314 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
315 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
316 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
318 printf("%sstyle: %d\n", prefix,font->style);
319 printf("%sencoding: %02x\n", prefix,font->encoding);
320 printf("%slanguage: %02x\n", prefix,font->language);
322 for(t=0;t<font->numchars;t++) {
323 int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
324 printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
325 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
326 SHAPELINE*line = shape->lines;
329 if(line->type == moveTo) {
330 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
331 } else if(line->type == lineTo) {
332 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
333 } else if(line->type == splineTo) {
334 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
335 line->sx/20.0, line->sy/20.0,
336 line->x/20.0, line->y/20.0
341 swf_Shape2Free(shape);
351 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
354 printf(" <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a);
355 for(t=0;t<fontnum;t++)
357 if(fonts[t]->id == fontid) {
367 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
368 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
371 if(fonts[font]->glyph2ascii[glyphs[t]])
372 a = fonts[font]->glyph2ascii[glyphs[t]];
382 printf("\\x%x", (int)a);
387 void handleText(TAG*tag)
390 swf_ParseDefineText(tag,textcallback, 0);
393 void handleDefineSound(TAG*tag)
395 U16 id = swf_GetU16(tag);
396 U8 flags = swf_GetU8(tag);
397 int compression = (flags>>4)&7;
398 int rate = (flags>>2)&3;
399 int bits = flags&2?16:8;
400 int stereo = flags&1;
402 if(compression == 0) printf("Raw ");
403 else if(compression == 1) printf("ADPCM ");
404 else if(compression == 2) printf("MP3 ");
405 else if(compression == 3) printf("Raw little-endian ");
406 else if(compression == 6) printf("ASAO ");
408 if(rate == 0) printf("5.5Khz ");
409 if(rate == 1) printf("11Khz ");
410 if(rate == 2) printf("22Khz ");
411 if(rate == 3) printf("44Khz ");
412 printf("%dBit ", bits);
413 if(stereo) printf("stereo");
418 void handleDefineBits(TAG*tag)
424 id = swf_GetU16(tag);
425 mode = swf_GetU8(tag);
426 width = swf_GetU16(tag);
427 height = swf_GetU16(tag);
428 printf(" image %dx%d",width,height);
429 if(mode == 3) printf(" (8 bpp)");
430 else if(mode == 4) printf(" (16 bpp)");
431 else if(mode == 5) printf(" (32 bpp)");
432 else printf(" (? bpp)");
435 void handleEditText(TAG*tag)
440 id = swf_GetU16(tag);
443 //swf_ResetReadBits(tag);
449 flags = swf_GetBits(tag,16);
450 if(flags & ET_HASFONT) {
451 swf_GetU16(tag); //font
452 swf_GetU16(tag); //fontheight
454 if(flags & ET_HASTEXTCOLOR) {
455 swf_GetU8(tag); //rgba
460 if(flags & ET_HASMAXLENGTH) {
461 swf_GetU16(tag); //maxlength
463 if(flags & ET_HASLAYOUT) {
464 swf_GetU8(tag); //align
465 swf_GetU16(tag); //left margin
466 swf_GetU16(tag); //right margin
467 swf_GetU16(tag); //indent
468 swf_GetU16(tag); //leading
470 printf(" variable \"%s\" ", &tag->data[tag->pos]);
471 if(flags & ET_HTML) printf("(html)");
472 if(flags & ET_NOSELECT) printf("(noselect)");
473 if(flags & ET_PASSWORD) printf("(password)");
474 if(flags & ET_READONLY) printf("(readonly)");
476 if(flags & (ET_X1 | ET_X3 ))
478 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
481 while(tag->data[tag->pos++]);
482 if(flags & ET_HASTEXT)
483 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
486 void printhandlerflags(U32 handlerflags)
488 if(handlerflags&1) printf("[on load]");
489 if(handlerflags&2) printf("[enter frame]");
490 if(handlerflags&4) printf("[unload]");
491 if(handlerflags&8) printf("[mouse move]");
492 if(handlerflags&16) printf("[mouse down]");
493 if(handlerflags&32) printf("[mouse up]");
494 if(handlerflags&64) printf("[key down]");
495 if(handlerflags&128) printf("[key up]");
497 if(handlerflags&256) printf("[data]");
498 if(handlerflags&512) printf("[initialize]");
499 if(handlerflags&1024) printf("[mouse press]");
500 if(handlerflags&2048) printf("[mouse release]");
501 if(handlerflags&4096) printf("[mouse release outside]");
502 if(handlerflags&8192) printf("[mouse rollover]");
503 if(handlerflags&16384) printf("[mouse rollout]");
504 if(handlerflags&32768) printf("[mouse drag over]");
506 if(handlerflags&0x10000) printf("[mouse drag out]");
507 if(handlerflags&0x20000) printf("[key press]");
508 if(handlerflags&0x40000) printf("[construct even]");
509 if(handlerflags&0xfff80000) printf("[???]");
511 void handleVideoStream(TAG*tag, char*prefix)
513 U16 id = swf_GetU16(tag);
514 U16 frames = swf_GetU16(tag);
515 U16 width = swf_GetU16(tag);
516 U16 height = swf_GetU16(tag);
517 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
518 U8 codec = swf_GetU8(tag);
519 printf(" (%d frames, %dx%d", frames, width, height);
523 printf(" sorenson h.263)");
525 printf(" codec 0x%02x)", codec);
527 void handleVideoFrame(TAG*tag, char*prefix)
529 U32 code, version, reference, sizeflags;
530 U32 width=0, height=0;
532 U16 id = swf_GetU16(tag);
533 U16 frame = swf_GetU16(tag);
534 U8 deblock,flags, tmp, bit;
536 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
537 printf(" (frame %d) ", frame);
539 /* video packet follows */
540 code = swf_GetBits(tag, 17);
541 version = swf_GetBits(tag, 5);
542 reference = swf_GetBits(tag, 8);
544 sizeflags = swf_GetBits(tag, 3);
547 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
548 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
549 case 2: width = 352; height = 288; break;
550 case 3: width = 176; height = 144; break;
551 case 4: width = 128; height = 96; break;
552 case 5: width = 320; height = 240; break;
553 case 6: width = 160; height = 120; break;
554 case 7: width = -1; height = -1;/*reserved*/ break;
556 printf("%dx%d ", width, height);
557 type = swf_GetBits(tag, 2);
558 printf("%s", types[type]);
560 deblock = swf_GetBits(tag, 1);
562 printf(" deblock ", deblock);
563 quantizer = swf_GetBits(tag, 5);
564 printf(" quant: %d ", quantizer);
567 void dumpFilter(FILTER*filter)
569 if(filter->type == FILTERTYPE_BLUR) {
570 FILTER_BLUR*f = (FILTER_BLUR*)filter;
571 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
572 printf("passes: %d\n", f->passes);
573 } if(filter->type == FILTERTYPE_GLOW) {
574 FILTER_GLOW*f = (FILTER_GLOW*)filter;
575 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
576 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
577 printf("passes: %d\n", f->passes);
578 printf("flags: %s%s%s\n",
579 f->knockout?"knockout ":"",
580 f->composite?"composite ":"",
581 f->innerglow?"innerglow":"");
582 } if(filter->type == FILTERTYPE_DROPSHADOW) {
583 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
584 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
585 printf("passes: %d\n", f->passes);
586 printf("angle: %f distance: %f\n", f->angle, f->distance);
587 printf("strength: %f passes: %d\n", f->strength, f->passes);
588 printf("flags: %s%s%s\n",
589 f->knockout?"knockout ":"",
590 f->composite?"composite ":"",
591 f->innershadow?"innershadow ":"");
592 } if(filter->type == FILTERTYPE_BEVEL) {
593 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
594 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
595 printf("passes: %d\n", f->passes);
596 printf("angle: %f distance: %f\n", f->angle, f->distance);
597 printf("strength: %f passes: %d\n", f->strength, f->passes);
598 printf("flags: %s%s%s%s\n",
600 f->knockout?"knockout ":"",
601 f->composite?"composite ":"",
602 f->innershadow?"innershadow ":"");
603 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
604 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
605 swf_DumpGradient(stdout, f->gradient);
606 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
607 printf("angle: %f distance: %f\n", f->angle, f->distance);
608 printf("strength: %f passes: %d\n", f->strength, f->passes);
609 printf("flags: %s%s%s%s\n",
610 f->knockout?"knockout ":"",
611 f->ontop?"ontop ":"",
612 f->composite?"composite ":"",
613 f->innershadow?"innershadow ":"");
618 void handlePlaceObject23(TAG*tag, char*prefix)
624 int ppos[3] = {0,0,0};
625 swf_SetTagPos(tag, 0);
626 flags = swf_GetU8(tag);
627 if(tag->id == ST_PLACEOBJECT3)
628 flags2 = swf_GetU8(tag);
629 swf_GetU16(tag); //depth
632 if(flags&2) swf_GetU16(tag); //id
634 swf_GetMatrix(tag,&m);
636 ppos[0] += sprintf(pstr[0], "| Matrix ");
637 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
638 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
642 swf_GetCXForm(tag, &cx, 1);
644 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
645 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);
646 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
650 U16 ratio = swf_GetU16(tag); //ratio
652 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
653 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
654 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
658 U16 clip = swf_GetU16(tag); //clip
660 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
661 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
662 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
665 if(flags&32) { while(swf_GetU8(tag)); }
667 if(flags2&1) { // filter list
668 U8 num = swf_GetU8(tag);
670 printf("\n%d filters\n", num);
671 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
674 FILTER*filter = swf_GetFilter(tag);
680 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
685 if(flags2&2) { // blend mode
686 U8 blendmode = swf_GetU8(tag);
690 sprintf(name, "%-5d", blendmode);
691 for(t=0;blendModeNames[t];t++) {
693 sprintf(name, "%-5s", blendModeNames[t]);
697 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
698 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
699 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
703 if(placements && ppos[0]) {
705 printf("%s %s\n", prefix, pstr[0]);
706 printf("%s %s\n", prefix, pstr[1]);
707 printf("%s %s", prefix, pstr[2]);
716 reserved = swf_GetU16(tag); // must be 0
717 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
719 printf("Unknown parameter field not zero: %04x\n", reserved);
722 printf("global flags: %04x\n", globalflags);
724 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
726 handlerflags = swf_GetU32(tag);
729 while(handlerflags) {
734 globalflags &= ~handlerflags;
735 printf("%s flags %08x ",prefix, handlerflags);
736 printhandlerflags(handlerflags);
737 length = swf_GetU32(tag);
738 printf(", %d bytes actioncode\n",length);
739 a = swf_ActionGet(tag);
740 swf_DumpActions(a,prefix);
743 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
745 if(globalflags) // should go to sterr.
746 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
748 printf(" has action code\n");
753 void handlePlaceObject(TAG*tag, char*prefix)
755 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
760 swf_SetTagPos(tag, 0);
761 id = swf_GetU16(tag);
762 depth = swf_GetU16(tag);
763 swf_GetMatrix(tag, &matrix);
764 swf_GetCXForm(tag, &cxform, 0);
766 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
767 swf_SetU16(tag2, depth);
768 swf_SetU16(tag2, id);
769 swf_SetMatrix(tag2, &matrix);
770 swf_SetCXForm(tag2, &cxform, 1);
772 handlePlaceObject23(tag2, prefix);
775 char* fillstyle2str(FILLSTYLE*style)
777 switch(style->type) {
779 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
781 case 0x10: case 0x11: case 0x12: case 0x13:
782 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
784 case 0x40: case 0x42:
785 /* TODO: display information about that bitmap */
786 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
787 /* TODO: show matrix */
788 //swf_DumpMatrix(stdout, &style->m);
790 case 0x41: case 0x43:
791 /* TODO: display information about that bitmap */
792 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
793 /* TODO: show matrix */
794 //swf_DumpMatrix(stdout, &style->m);
797 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
801 char* linestyle2str(LINESTYLE*style)
803 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
807 void handleShape(TAG*tag, char*prefix)
815 swf_ParseDefineShape(tag, &shape);
817 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
819 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
824 else printf("%s | (Neither line nor fill styles)\n", prefix);
827 printf("%s", prefix);
828 if(t < shape.numfillstyles) {
829 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
833 if(t < shape.numlinestyles) {
834 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
837 //if(shape.fillstyles[t].type&0x40) {
838 // MATRIX m = shape.fillstyles[t].m;
839 // swf_DumpMatrix(stdout, &m);
843 printf("%s |\n", prefix);
847 printf("%s | fill: %02d/%02d line:%02d - ",
852 if(line->type == moveTo) {
853 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
854 } else if(line->type == lineTo) {
855 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
856 } else if(line->type == splineTo) {
857 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
858 line->sx/20.0, line->sy/20.0,
859 line->x/20.0, line->y/20.0
864 printf("%s |\n", prefix);
867 void fontcallback1(void*self, U16 id,U8 * name)
871 void fontcallback2(void*self, U16 id,U8 * name)
873 swf_FontExtract(&swf,id,&fonts[fontnum]);
877 static U8 printable(U8 a)
879 if(a<32 || a==127) return '.';
882 void hexdumpTag(TAG*tag, char* prefix)
886 printf(" %s-=> ",prefix);
887 for(t=0;t<tag->len;t++) {
888 printf("%02x ", tag->data[t]);
889 ascii[t&15] = printable(tag->data[t]);
890 if((t && ((t&15)==15)) || (t==tag->len-1))
894 for(s=p-1;s<16;s++) {
898 printf(" %s\n", ascii);
900 printf(" %s\n %s-=> ",ascii,prefix);
905 void handleExportAssets(TAG*tag, char* prefix)
911 num = swf_GetU16(tag);
914 id = swf_GetU16(tag);
915 name = swf_GetString(tag);
916 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
920 void dumperror(const char* format, ...)
925 va_start(arglist, format);
926 vsprintf(buf, format, arglist);
930 printf("==== Error: %s ====\n", buf);
933 static char strbuf[800];
936 char* timestring(double f)
938 int hours = (int)(f/3600);
939 int minutes = (int)((f-hours*3600)/60);
940 int seconds = (int)((f-hours*3600-minutes*60));
941 int useconds = (int)((f-(int)f)*1000+0.5);
944 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
945 return &strbuf[bufpos];
948 int main (int argc,char ** argv)
956 char issprite = 0; // are we inside a sprite definition?
959 char* spriteframelabel = 0;
960 char* framelabel = 0;
965 memset(idtab,0,65536);
967 processargs(argc, argv);
971 fprintf(stderr, "You must supply a filename.\n");
975 f = open(filename,O_RDONLY|O_BINARY);
979 sprintf(buffer, "Couldn't open %s", filename);
985 int compressed = (header[0]=='C');
987 f = open(filename,O_RDONLY|O_BINARY);
989 if FAILED(swf_ReadSWF(f,&swf))
991 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
998 if(statbuf.st_size != swf.fileSize && !compressed)
999 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1000 statbuf.st_size, swf.fileSize);
1001 filesize = statbuf.st_size;
1006 //if(action && swf.fileVersion>=9) {
1007 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1011 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1012 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1016 printf("-X %d", xsize);
1018 if((xy&1) && (xy&6))
1022 printf("-Y %d", ysize);
1024 if((xy&3) && (xy&4))
1028 printf("-r %.2f", swf.frameRate/256.0);
1030 if((xy&7) && (xy&8))
1034 printf("-f %d", swf.frameCount);
1041 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1042 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
1043 if(swf.fileVersion>9) {
1044 fprintf(stderr, "Fileversion>9\n");
1049 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1050 "<param name=\"movie\" value=\"%s\"/>\n"
1051 "<param name=\"play\" value=\"true\"/>\n"
1052 "<param name=\"loop\" value=\"false\"/>\n"
1053 "<param name=\"quality\" value=\"high\"/>\n"
1054 "<param name=\"loop\" value=\"false\"/>\n"
1055 "</object>\n\n", filename, xsize, ysize, filename);
1057 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1059 //" BGCOLOR=#ffffffff\n"?
1061 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1062 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1063 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1064 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1065 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1066 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1067 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1068 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1069 " TYPE=\"application/x-shockwave-flash\"\n"
1070 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1072 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1073 filename, filename, xsize, ysize);
1077 printf("[HEADER] File version: %d\n", swf.fileVersion);
1079 printf("[HEADER] File is zlib compressed.");
1080 if(filesize && swf.fileSize)
1081 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1085 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1086 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1087 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1088 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1089 if(swf.movieSize.xmin)
1090 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1093 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1094 if(swf.movieSize.ymin)
1095 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1103 swf_FontEnumerate(&swf,&fontcallback1, 0);
1104 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1106 swf_FontEnumerate(&swf,&fontcallback2, 0);
1110 char*name = swf_TagGetName(tag);
1113 dumperror("Unknown tag:0x%03x", tag->id);
1118 name = "UNKNOWN TAG";
1121 filepos += tag->len;
1122 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1124 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1127 if(swf_isDefiningTag(tag)) {
1128 U16 id = swf_GetDefineID(tag);
1129 printf(" defines id %04d", id);
1131 dumperror("Id %04d is defined more than once.", id);
1134 else if(swf_isPseudoDefiningTag(tag)) {
1135 U16 id = swf_GetDefineID(tag);
1136 printf(" adds information to id %04d", id);
1138 dumperror("Id %04d is not yet defined.\n", id);
1140 else if(tag->id == ST_PLACEOBJECT) {
1141 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1142 if(swf_GetName(tag))
1143 printf(" name \"%s\"",swf_GetName(tag));
1145 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1152 printf(" id %04d",swf_GetPlaceID(tag));
1156 printf(" at depth %04d", swf_GetDepth(tag));
1158 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1159 printf(" as bitmap");
1161 swf_SetTagPos(tag, 0);
1162 if(tag->data[0]&64) {
1164 swf_GetPlaceObject(tag, &po);
1165 printf(" (clip to %04d)", po.clipdepth);
1166 swf_PlaceObjectFree(&po);
1168 if(swf_GetName(tag))
1169 printf(" name \"%s\"",swf_GetName(tag));
1172 else if(tag->id == ST_REMOVEOBJECT) {
1173 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1175 else if(tag->id == ST_REMOVEOBJECT2) {
1176 printf(" removes object from depth %04d", swf_GetDepth(tag));
1178 else if(tag->id == ST_FREECHARACTER) {
1179 printf(" frees object %04d", swf_GetPlaceID(tag));
1181 else if(tag->id == ST_DOABC) {
1182 swf_SetTagPos(tag, 0);
1183 U32 flags = swf_GetU32(tag);
1184 char*s = swf_GetString(tag);
1186 printf(" \"%s\"", s);
1191 printf(" lazy load");
1193 swf_SetTagPos(tag, 0);
1195 else if(tag->id == ST_STARTSOUND) {
1198 id = swf_GetU16(tag);
1199 flags = swf_GetU8(tag);
1201 printf(" stops sound with id %04d", id);
1203 printf(" starts sound with id %04d", id);
1205 printf(" (if not already playing)");
1211 printf(" looping %d times", swf_GetU16(tag));
1214 else if(tag->id == ST_FRAMELABEL) {
1215 int l = strlen(tag->data);
1216 printf(" \"%s\"", tag->data);
1217 if((l+1) < tag->len) {
1218 printf(" has %d extra bytes", tag->len-1-l);
1219 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1220 printf(" (ANCHOR)");
1222 if((framelabel && !issprite) ||
1223 (spriteframelabel && issprite)) {
1224 dumperror("Frame %d has more than one label",
1225 issprite?spriteframe:mainframe);
1227 if(issprite) spriteframelabel = tag->data;
1228 else framelabel = tag->data;
1230 else if(tag->id == ST_SHOWFRAME) {
1231 char*label = issprite?spriteframelabel:framelabel;
1232 int frame = issprite?spriteframe:mainframe;
1235 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1237 if(issprite) spriteframe++;
1243 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1245 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1246 timestring(frame*(256.0/(swf.frameRate+0.1))),
1247 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1250 printf(" (label \"%s\")", label);
1251 if(issprite) {spriteframe++; spriteframelabel = 0;}
1252 if(!issprite) {mainframe++; framelabel = 0;}
1254 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1255 U8 r = swf_GetU8(tag);
1256 U8 g = swf_GetU8(tag);
1257 U8 b = swf_GetU8(tag);
1258 printf(" (%02x/%02x/%02x)",r,g,b);
1260 else if(tag->id == ST_PROTECT) {
1262 printf(" %s", swf_GetString(tag));
1265 else if(tag->id == ST_CSMTEXTSETTINGS) {
1266 U16 id = swf_GetU16(tag);
1267 U8 flags = swf_GetU8(tag);
1270 printf("flashtype,");
1272 switch(((flags>>3)&7)) {
1273 case 0:printf("no grid,");break;
1274 case 1:printf("pixel grid,");break;
1275 case 2:printf("subpixel grid,");break;
1276 case 3:printf("unknown grid,");break;
1279 printf("unknown[%08x],", flags);
1280 float thickness = swf_GetFixed(tag);
1281 float sharpness = swf_GetFixed(tag);
1282 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1286 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1287 tag->id == ST_DEFINEBITSLOSSLESS2) {
1288 handleDefineBits(tag);
1291 else if(tag->id == ST_DEFINESOUND) {
1292 handleDefineSound(tag);
1295 else if(tag->id == ST_VIDEOFRAME) {
1296 handleVideoFrame(tag, myprefix);
1299 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1300 handleVideoStream(tag, myprefix);
1303 else if(tag->id == ST_DEFINEEDITTEXT) {
1304 handleEditText(tag);
1307 else if(tag->id == ST_DEFINEMOVIE) {
1308 U16 id = swf_GetU16(tag);
1309 char*s = swf_GetString(tag);
1310 printf(" URL: %s\n", s);
1312 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1318 else if(tag->id == ST_DEFINESCALINGGRID) {
1319 U16 id = swf_GetU16(tag);
1321 swf_GetRect(tag, &r);
1322 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1324 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1326 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1328 printf(" \"%s\"\n", swf_GetString(tag));
1334 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1335 SRECT r = swf_GetDefineBBox(tag);
1336 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1343 sprintf(myprefix, " %s", prefix);
1345 if(tag->id == ST_DEFINESPRITE) {
1346 sprintf(prefix, " ");
1348 dumperror("Sprite definition inside a sprite definition");
1352 spriteframelabel = 0;
1354 else if(tag->id == ST_END) {
1357 spriteframelabel = 0;
1359 dumperror("End Tag not empty");
1361 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1362 handleExportAssets(tag, myprefix);
1364 else if(tag->id == ST_DOACTION && action) {
1366 actions = swf_ActionGet(tag);
1367 swf_DumpActions(actions, myprefix);
1369 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1370 void*abccode = swf_ReadABC(tag);
1371 swf_DumpABC(stdout, abccode, "");
1372 swf_FreeABC(abccode);
1374 else if(tag->id == ST_DOINITACTION && action) {
1376 swf_GetU16(tag); // id
1377 actions = swf_ActionGet(tag);
1378 swf_DumpActions(actions, myprefix);
1380 else if(tag->id == ST_DEFINEBUTTON) {
1382 dumpButton(tag, myprefix);
1385 dumpButtonActions(tag, myprefix);
1388 else if(swf_isFontTag(tag) && showfonts) {
1389 dumpFont(tag, myprefix);
1391 else if(tag->id == ST_DEFINEBUTTON2) {
1393 dumpButton2Actions(tag, myprefix);
1396 else if(tag->id == ST_PLACEOBJECT) {
1397 handlePlaceObject(tag, myprefix);
1399 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1400 handlePlaceObject23(tag, myprefix);
1402 else if(tag->id == ST_DEFINEFONTNAME) {
1403 swf_SetTagPos(tag, 0);
1404 swf_GetU16(tag); //id
1405 swf_GetString(tag); //name
1406 char* copyright = swf_GetString(tag);
1407 printf("%s%s\n", myprefix, copyright);
1409 else if(tag->id == ST_DEFINESHAPE ||
1410 tag->id == ST_DEFINESHAPE2 ||
1411 tag->id == ST_DEFINESHAPE3 ||
1412 tag->id == ST_DEFINESHAPE4) {
1414 handleShape(tag, myprefix);
1417 if(tag->len && used) {
1418 int num = swf_GetNumUsedIDs(tag);
1422 used = (int*)malloc(sizeof(int)*num);
1423 swf_GetUsedIDs(tag, used);
1424 printf("%s%suses IDs: ", indent, prefix);
1425 for(t=0;t<num;t++) {
1427 swf_SetTagPos(tag, used[t]);
1428 id = swf_GetU16(tag);
1429 printf("%d%s", id, t<num-1?", ":"");
1431 dumperror("Id %04d is not yet defined.\n", id);
1438 if(tag->id == ST_FREECHARACTER) {
1440 swf_SetTagPos(tag, 0);
1441 id = swf_GetU16(tag);
1445 if(tag->len && hex) {
1446 hexdumpTag(tag, prefix);