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);
268 swf_ActionFree(actions);
271 void dumpButton(TAG*tag, char*prefix)
273 swf_SetTagPos(tag, 0);
274 swf_GetU16(tag); // id
276 U8 flags = swf_GetU8(tag);
279 U16 id = swf_GetU16(tag);
280 U16 depth = swf_GetU16(tag);
282 sprintf(event, "%s%s%s%s",
283 (flags&BS_HIT)?"[hit]":"",
284 (flags&BS_DOWN)?"[down]":"",
285 (flags&BS_OVER)?"[over]":"",
286 (flags&BS_UP)?"[up]":"");
288 printf("%s | Show %d at depth %d for %s flags=%02x\n", prefix, id, depth, event, flags);
290 printf("%s | Show %d at depth %d for %s\n", prefix, id, depth, event);
292 swf_GetMatrix(tag,NULL); // matrix
296 void dumpFont(TAG*tag, char*prefix)
298 SWFFONT* font = malloc(sizeof(SWFFONT));
299 memset(font, 0, sizeof(SWFFONT));
300 if(tag->id == ST_DEFINEFONT2) {
301 swf_FontExtract_DefineFont2(0, font, tag);
302 } else if(tag->id == ST_DEFINEFONT) {
303 swf_FontExtract_DefineFont(0, font, tag);
305 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
307 printf("%sID: %d\n", prefix,font->id);
308 printf("%sVersion: %d\n", prefix,font->version);
309 printf("%sname: %s\n", prefix,font->name);
310 printf("%scharacters: %d\n", prefix,font->numchars);
311 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
314 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
315 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
316 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
317 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
319 printf("%sstyle: %d\n", prefix,font->style);
320 printf("%sencoding: %02x\n", prefix,font->encoding);
321 printf("%slanguage: %02x\n", prefix,font->language);
323 for(t=0;t<font->numchars;t++) {
324 int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
325 printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
326 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
327 SHAPELINE*line = shape->lines;
330 if(line->type == moveTo) {
331 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
332 } else if(line->type == lineTo) {
333 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
334 } else if(line->type == splineTo) {
335 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
336 line->sx/20.0, line->sy/20.0,
337 line->x/20.0, line->y/20.0
342 swf_Shape2Free(shape);
352 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
355 printf(" <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a);
356 for(t=0;t<fontnum;t++)
358 if(fonts[t]->id == fontid) {
368 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
369 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
372 if(fonts[font]->glyph2ascii[glyphs[t]])
373 a = fonts[font]->glyph2ascii[glyphs[t]];
383 printf("\\x%x", (int)a);
388 void handleText(TAG*tag)
391 swf_ParseDefineText(tag,textcallback, 0);
394 void handleDefineSound(TAG*tag)
396 U16 id = swf_GetU16(tag);
397 U8 flags = swf_GetU8(tag);
398 int compression = (flags>>4)&7;
399 int rate = (flags>>2)&3;
400 int bits = flags&2?16:8;
401 int stereo = flags&1;
403 if(compression == 0) printf("Raw ");
404 else if(compression == 1) printf("ADPCM ");
405 else if(compression == 2) printf("MP3 ");
406 else if(compression == 3) printf("Raw little-endian ");
407 else if(compression == 6) printf("ASAO ");
409 if(rate == 0) printf("5.5Khz ");
410 if(rate == 1) printf("11Khz ");
411 if(rate == 2) printf("22Khz ");
412 if(rate == 3) printf("44Khz ");
413 printf("%dBit ", bits);
414 if(stereo) printf("stereo");
419 void handleDefineBits(TAG*tag)
425 id = swf_GetU16(tag);
426 mode = swf_GetU8(tag);
427 width = swf_GetU16(tag);
428 height = swf_GetU16(tag);
429 printf(" image %dx%d",width,height);
430 if(mode == 3) printf(" (8 bpp)");
431 else if(mode == 4) printf(" (16 bpp)");
432 else if(mode == 5) printf(" (32 bpp)");
433 else printf(" (? bpp)");
436 void handleEditText(TAG*tag)
441 id = swf_GetU16(tag);
444 //swf_ResetReadBits(tag);
450 flags = swf_GetBits(tag,16);
451 if(flags & ET_HASFONT) {
452 swf_GetU16(tag); //font
453 swf_GetU16(tag); //fontheight
455 if(flags & ET_HASTEXTCOLOR) {
456 swf_GetU8(tag); //rgba
461 if(flags & ET_HASMAXLENGTH) {
462 swf_GetU16(tag); //maxlength
464 if(flags & ET_HASLAYOUT) {
465 swf_GetU8(tag); //align
466 swf_GetU16(tag); //left margin
467 swf_GetU16(tag); //right margin
468 swf_GetU16(tag); //indent
469 swf_GetU16(tag); //leading
471 printf(" variable \"%s\" ", &tag->data[tag->pos]);
472 if(flags & ET_HTML) printf("(html)");
473 if(flags & ET_NOSELECT) printf("(noselect)");
474 if(flags & ET_PASSWORD) printf("(password)");
475 if(flags & ET_READONLY) printf("(readonly)");
477 if(flags & (ET_X1 | ET_X3 ))
479 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
482 while(tag->data[tag->pos++]);
483 if(flags & ET_HASTEXT)
484 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
487 void printhandlerflags(U32 handlerflags)
489 if(handlerflags&1) printf("[on load]");
490 if(handlerflags&2) printf("[enter frame]");
491 if(handlerflags&4) printf("[unload]");
492 if(handlerflags&8) printf("[mouse move]");
493 if(handlerflags&16) printf("[mouse down]");
494 if(handlerflags&32) printf("[mouse up]");
495 if(handlerflags&64) printf("[key down]");
496 if(handlerflags&128) printf("[key up]");
498 if(handlerflags&256) printf("[data]");
499 if(handlerflags&512) printf("[initialize]");
500 if(handlerflags&1024) printf("[mouse press]");
501 if(handlerflags&2048) printf("[mouse release]");
502 if(handlerflags&4096) printf("[mouse release outside]");
503 if(handlerflags&8192) printf("[mouse rollover]");
504 if(handlerflags&16384) printf("[mouse rollout]");
505 if(handlerflags&32768) printf("[mouse drag over]");
507 if(handlerflags&0x10000) printf("[mouse drag out]");
508 if(handlerflags&0x20000) printf("[key press]");
509 if(handlerflags&0x40000) printf("[construct even]");
510 if(handlerflags&0xfff80000) printf("[???]");
512 void handleVideoStream(TAG*tag, char*prefix)
514 U16 id = swf_GetU16(tag);
515 U16 frames = swf_GetU16(tag);
516 U16 width = swf_GetU16(tag);
517 U16 height = swf_GetU16(tag);
518 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
519 U8 codec = swf_GetU8(tag);
520 printf(" (%d frames, %dx%d", frames, width, height);
524 printf(" sorenson h.263)");
526 printf(" codec 0x%02x)", codec);
528 void handleVideoFrame(TAG*tag, char*prefix)
530 U32 code, version, reference, sizeflags;
531 U32 width=0, height=0;
533 U16 id = swf_GetU16(tag);
534 U16 frame = swf_GetU16(tag);
535 U8 deblock,flags, tmp, bit;
537 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
538 printf(" (frame %d) ", frame);
540 /* video packet follows */
541 code = swf_GetBits(tag, 17);
542 version = swf_GetBits(tag, 5);
543 reference = swf_GetBits(tag, 8);
545 sizeflags = swf_GetBits(tag, 3);
548 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
549 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
550 case 2: width = 352; height = 288; break;
551 case 3: width = 176; height = 144; break;
552 case 4: width = 128; height = 96; break;
553 case 5: width = 320; height = 240; break;
554 case 6: width = 160; height = 120; break;
555 case 7: width = -1; height = -1;/*reserved*/ break;
557 printf("%dx%d ", width, height);
558 type = swf_GetBits(tag, 2);
559 printf("%s", types[type]);
561 deblock = swf_GetBits(tag, 1);
563 printf(" deblock ", deblock);
564 quantizer = swf_GetBits(tag, 5);
565 printf(" quant: %d ", quantizer);
568 void dumpFilter(FILTER*filter)
570 if(filter->type == FILTERTYPE_BLUR) {
571 FILTER_BLUR*f = (FILTER_BLUR*)filter;
572 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
573 printf("passes: %d\n", f->passes);
574 } if(filter->type == FILTERTYPE_GLOW) {
575 FILTER_GLOW*f = (FILTER_GLOW*)filter;
576 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
577 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
578 printf("passes: %d\n", f->passes);
579 printf("flags: %s%s%s\n",
580 f->knockout?"knockout ":"",
581 f->composite?"composite ":"",
582 f->innerglow?"innerglow":"");
583 } if(filter->type == FILTERTYPE_DROPSHADOW) {
584 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
585 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
586 printf("passes: %d\n", f->passes);
587 printf("angle: %f distance: %f\n", f->angle, f->distance);
588 printf("strength: %f passes: %d\n", f->strength, f->passes);
589 printf("flags: %s%s%s\n",
590 f->knockout?"knockout ":"",
591 f->composite?"composite ":"",
592 f->innershadow?"innershadow ":"");
593 } if(filter->type == FILTERTYPE_BEVEL) {
594 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
595 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
596 printf("passes: %d\n", f->passes);
597 printf("angle: %f distance: %f\n", f->angle, f->distance);
598 printf("strength: %f passes: %d\n", f->strength, f->passes);
599 printf("flags: %s%s%s%s\n",
601 f->knockout?"knockout ":"",
602 f->composite?"composite ":"",
603 f->innershadow?"innershadow ":"");
604 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
605 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
606 swf_DumpGradient(stdout, f->gradient);
607 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
608 printf("angle: %f distance: %f\n", f->angle, f->distance);
609 printf("strength: %f passes: %d\n", f->strength, f->passes);
610 printf("flags: %s%s%s%s\n",
611 f->knockout?"knockout ":"",
612 f->ontop?"ontop ":"",
613 f->composite?"composite ":"",
614 f->innershadow?"innershadow ":"");
619 void handlePlaceObject23(TAG*tag, char*prefix)
625 int ppos[3] = {0,0,0};
626 swf_SetTagPos(tag, 0);
627 flags = swf_GetU8(tag);
628 if(tag->id == ST_PLACEOBJECT3)
629 flags2 = swf_GetU8(tag);
630 swf_GetU16(tag); //depth
633 if(flags&2) swf_GetU16(tag); //id
635 swf_GetMatrix(tag,&m);
637 ppos[0] += sprintf(pstr[0], "| Matrix ");
638 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
639 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
643 swf_GetCXForm(tag, &cx, 1);
645 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
646 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);
647 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
651 U16 ratio = swf_GetU16(tag); //ratio
653 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
654 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
655 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
659 U16 clip = swf_GetU16(tag); //clip
661 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
662 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
663 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
666 if(flags&32) { while(swf_GetU8(tag)); }
668 if(flags2&1) { // filter list
669 U8 num = swf_GetU8(tag);
671 printf("\n%d filters\n", num);
672 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
675 FILTER*filter = swf_GetFilter(tag);
681 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
686 if(flags2&2) { // blend mode
687 U8 blendmode = swf_GetU8(tag);
691 sprintf(name, "%-5d", blendmode);
692 for(t=0;blendModeNames[t];t++) {
694 sprintf(name, "%-5s", blendModeNames[t]);
698 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
699 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
700 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
704 if(placements && ppos[0]) {
706 printf("%s %s\n", prefix, pstr[0]);
707 printf("%s %s\n", prefix, pstr[1]);
708 printf("%s %s", prefix, pstr[2]);
717 reserved = swf_GetU16(tag); // must be 0
718 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
720 printf("Unknown parameter field not zero: %04x\n", reserved);
723 printf("global flags: %04x\n", globalflags);
725 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
727 handlerflags = swf_GetU32(tag);
730 while(handlerflags) {
735 globalflags &= ~handlerflags;
736 printf("%s flags %08x ",prefix, handlerflags);
737 printhandlerflags(handlerflags);
738 length = swf_GetU32(tag);
739 printf(", %d bytes actioncode\n",length);
740 a = swf_ActionGet(tag);
741 swf_DumpActions(a,prefix);
744 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
746 if(globalflags) // should go to sterr.
747 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
749 printf(" has action code\n");
754 void handlePlaceObject(TAG*tag, char*prefix)
756 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
761 swf_SetTagPos(tag, 0);
762 id = swf_GetU16(tag);
763 depth = swf_GetU16(tag);
764 swf_GetMatrix(tag, &matrix);
765 swf_GetCXForm(tag, &cxform, 0);
767 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
768 swf_SetU16(tag2, depth);
769 swf_SetU16(tag2, id);
770 swf_SetMatrix(tag2, &matrix);
771 swf_SetCXForm(tag2, &cxform, 1);
773 handlePlaceObject23(tag2, prefix);
776 char* fillstyle2str(FILLSTYLE*style)
778 switch(style->type) {
780 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
782 case 0x10: case 0x11: case 0x12: case 0x13:
783 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
785 case 0x40: case 0x42:
786 /* TODO: display information about that bitmap */
787 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
788 /* TODO: show matrix */
789 //swf_DumpMatrix(stdout, &style->m);
791 case 0x41: case 0x43:
792 /* TODO: display information about that bitmap */
793 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
794 /* TODO: show matrix */
795 //swf_DumpMatrix(stdout, &style->m);
798 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
802 char* linestyle2str(LINESTYLE*style)
804 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
808 void handleShape(TAG*tag, char*prefix)
816 swf_ParseDefineShape(tag, &shape);
818 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
820 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
825 else printf("%s | (Neither line nor fill styles)\n", prefix);
828 printf("%s", prefix);
829 if(t < shape.numfillstyles) {
830 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
834 if(t < shape.numlinestyles) {
835 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
838 //if(shape.fillstyles[t].type&0x40) {
839 // MATRIX m = shape.fillstyles[t].m;
840 // swf_DumpMatrix(stdout, &m);
844 printf("%s |\n", prefix);
848 printf("%s | fill: %02d/%02d line:%02d - ",
853 if(line->type == moveTo) {
854 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
855 } else if(line->type == lineTo) {
856 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
857 } else if(line->type == splineTo) {
858 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
859 line->sx/20.0, line->sy/20.0,
860 line->x/20.0, line->y/20.0
865 printf("%s |\n", prefix);
868 void fontcallback1(void*self, U16 id,U8 * name)
872 void fontcallback2(void*self, U16 id,U8 * name)
874 swf_FontExtract(&swf,id,&fonts[fontnum]);
878 static U8 printable(U8 a)
880 if(a<32 || a==127) return '.';
883 void hexdumpTag(TAG*tag, char* prefix)
887 printf(" %s-=> ",prefix);
888 for(t=0;t<tag->len;t++) {
889 printf("%02x ", tag->data[t]);
890 ascii[t&15] = printable(tag->data[t]);
891 if((t && ((t&15)==15)) || (t==tag->len-1))
895 for(s=p-1;s<16;s++) {
899 printf(" %s\n", ascii);
901 printf(" %s\n %s-=> ",ascii,prefix);
906 void handleExportAssets(TAG*tag, char* prefix)
912 num = swf_GetU16(tag);
915 id = swf_GetU16(tag);
916 name = swf_GetString(tag);
917 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
921 void dumperror(const char* format, ...)
926 va_start(arglist, format);
927 vsprintf(buf, format, arglist);
931 printf("==== Error: %s ====\n", buf);
934 static char strbuf[800];
937 char* timestring(double f)
939 int hours = (int)(f/3600);
940 int minutes = (int)((f-hours*3600)/60);
941 int seconds = (int)((f-hours*3600-minutes*60));
942 int useconds = (int)((f-(int)f)*1000+0.5);
945 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
946 return &strbuf[bufpos];
949 int main (int argc,char ** argv)
957 char issprite = 0; // are we inside a sprite definition?
960 char* spriteframelabel = 0;
961 char* framelabel = 0;
966 memset(idtab,0,65536);
968 processargs(argc, argv);
972 fprintf(stderr, "You must supply a filename.\n");
976 f = open(filename,O_RDONLY|O_BINARY);
980 sprintf(buffer, "Couldn't open %s", filename);
986 int compressed = (header[0]=='C');
988 f = open(filename,O_RDONLY|O_BINARY);
990 if FAILED(swf_ReadSWF(f,&swf))
992 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
999 if(statbuf.st_size != swf.fileSize && !compressed)
1000 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1001 statbuf.st_size, swf.fileSize);
1002 filesize = statbuf.st_size;
1007 //if(action && swf.fileVersion>=9) {
1008 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1012 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1013 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1017 printf("-X %d", xsize);
1019 if((xy&1) && (xy&6))
1023 printf("-Y %d", ysize);
1025 if((xy&3) && (xy&4))
1029 printf("-r %.2f", swf.frameRate/256.0);
1031 if((xy&7) && (xy&8))
1035 printf("-f %d", swf.frameCount);
1042 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1043 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
1044 if(swf.fileVersion>9) {
1045 fprintf(stderr, "Fileversion>9\n");
1050 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1051 "<param name=\"movie\" value=\"%s\"/>\n"
1052 "<param name=\"play\" value=\"true\"/>\n"
1053 "<param name=\"loop\" value=\"false\"/>\n"
1054 "<param name=\"quality\" value=\"high\"/>\n"
1055 "<param name=\"loop\" value=\"false\"/>\n"
1056 "</object>\n\n", filename, xsize, ysize, filename);
1058 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1060 //" BGCOLOR=#ffffffff\n"?
1062 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1063 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1064 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1065 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1066 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1067 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1068 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1069 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1070 " TYPE=\"application/x-shockwave-flash\"\n"
1071 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1073 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1074 filename, filename, xsize, ysize);
1078 printf("[HEADER] File version: %d\n", swf.fileVersion);
1080 printf("[HEADER] File is zlib compressed.");
1081 if(filesize && swf.fileSize)
1082 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1086 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1087 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1088 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1089 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1090 if(swf.movieSize.xmin)
1091 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1094 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1095 if(swf.movieSize.ymin)
1096 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1104 swf_FontEnumerate(&swf,&fontcallback1, 0);
1105 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1107 swf_FontEnumerate(&swf,&fontcallback2, 0);
1111 char*name = swf_TagGetName(tag);
1114 dumperror("Unknown tag:0x%03x", tag->id);
1119 name = "UNKNOWN TAG";
1122 filepos += tag->len;
1123 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1125 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1128 if(swf_isDefiningTag(tag)) {
1129 U16 id = swf_GetDefineID(tag);
1130 printf(" defines id %04d", id);
1132 dumperror("Id %04d is defined more than once.", id);
1135 else if(swf_isPseudoDefiningTag(tag)) {
1136 U16 id = swf_GetDefineID(tag);
1137 printf(" adds information to id %04d", id);
1139 dumperror("Id %04d is not yet defined.\n", id);
1141 else if(tag->id == ST_PLACEOBJECT) {
1142 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1143 if(swf_GetName(tag))
1144 printf(" name \"%s\"",swf_GetName(tag));
1146 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1153 printf(" id %04d",swf_GetPlaceID(tag));
1157 printf(" at depth %04d", swf_GetDepth(tag));
1159 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1160 printf(" as bitmap");
1162 swf_SetTagPos(tag, 0);
1163 if(tag->data[0]&64) {
1165 swf_GetPlaceObject(tag, &po);
1166 printf(" (clip to %04d)", po.clipdepth);
1167 swf_PlaceObjectFree(&po);
1169 if(swf_GetName(tag))
1170 printf(" name \"%s\"",swf_GetName(tag));
1173 else if(tag->id == ST_REMOVEOBJECT) {
1174 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1176 else if(tag->id == ST_REMOVEOBJECT2) {
1177 printf(" removes object from depth %04d", swf_GetDepth(tag));
1179 else if(tag->id == ST_FREECHARACTER) {
1180 printf(" frees object %04d", swf_GetPlaceID(tag));
1182 else if(tag->id == ST_DOABC) {
1183 swf_SetTagPos(tag, 0);
1184 U32 flags = swf_GetU32(tag);
1185 char*s = swf_GetString(tag);
1187 printf(" \"%s\"", s);
1192 printf(" lazy load");
1194 swf_SetTagPos(tag, 0);
1196 else if(tag->id == ST_STARTSOUND) {
1199 id = swf_GetU16(tag);
1200 flags = swf_GetU8(tag);
1202 printf(" stops sound with id %04d", id);
1204 printf(" starts sound with id %04d", id);
1206 printf(" (if not already playing)");
1212 printf(" looping %d times", swf_GetU16(tag));
1215 else if(tag->id == ST_FRAMELABEL) {
1216 int l = strlen(tag->data);
1217 printf(" \"%s\"", tag->data);
1218 if((l+1) < tag->len) {
1219 printf(" has %d extra bytes", tag->len-1-l);
1220 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1221 printf(" (ANCHOR)");
1223 if((framelabel && !issprite) ||
1224 (spriteframelabel && issprite)) {
1225 dumperror("Frame %d has more than one label",
1226 issprite?spriteframe:mainframe);
1228 if(issprite) spriteframelabel = tag->data;
1229 else framelabel = tag->data;
1231 else if(tag->id == ST_SHOWFRAME) {
1232 char*label = issprite?spriteframelabel:framelabel;
1233 int frame = issprite?spriteframe:mainframe;
1236 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1238 if(issprite) spriteframe++;
1244 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1246 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1247 timestring(frame*(256.0/(swf.frameRate+0.1))),
1248 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1251 printf(" (label \"%s\")", label);
1252 if(issprite) {spriteframe++; spriteframelabel = 0;}
1253 if(!issprite) {mainframe++; framelabel = 0;}
1255 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1256 U8 r = swf_GetU8(tag);
1257 U8 g = swf_GetU8(tag);
1258 U8 b = swf_GetU8(tag);
1259 printf(" (%02x/%02x/%02x)",r,g,b);
1261 else if(tag->id == ST_PROTECT) {
1263 printf(" %s", swf_GetString(tag));
1266 else if(tag->id == ST_CSMTEXTSETTINGS) {
1267 U16 id = swf_GetU16(tag);
1268 U8 flags = swf_GetU8(tag);
1271 printf("flashtype,");
1273 switch(((flags>>3)&7)) {
1274 case 0:printf("no grid,");break;
1275 case 1:printf("pixel grid,");break;
1276 case 2:printf("subpixel grid,");break;
1277 case 3:printf("unknown grid,");break;
1280 printf("unknown[%08x],", flags);
1281 float thickness = swf_GetFixed(tag);
1282 float sharpness = swf_GetFixed(tag);
1283 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1287 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1288 tag->id == ST_DEFINEBITSLOSSLESS2) {
1289 handleDefineBits(tag);
1292 else if(tag->id == ST_DEFINESOUND) {
1293 handleDefineSound(tag);
1296 else if(tag->id == ST_VIDEOFRAME) {
1297 handleVideoFrame(tag, myprefix);
1300 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1301 handleVideoStream(tag, myprefix);
1304 else if(tag->id == ST_DEFINEEDITTEXT) {
1305 handleEditText(tag);
1308 else if(tag->id == ST_DEFINEMOVIE) {
1309 U16 id = swf_GetU16(tag);
1310 char*s = swf_GetString(tag);
1311 printf(" URL: %s\n", s);
1313 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1319 else if(tag->id == ST_DEFINESCALINGGRID) {
1320 U16 id = swf_GetU16(tag);
1322 swf_GetRect(tag, &r);
1323 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1325 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1327 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1329 printf(" \"%s\"\n", swf_GetString(tag));
1335 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1336 SRECT r = swf_GetDefineBBox(tag);
1337 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1344 sprintf(myprefix, " %s", prefix);
1346 if(tag->id == ST_DEFINESPRITE) {
1347 sprintf(prefix, " ");
1349 dumperror("Sprite definition inside a sprite definition");
1353 spriteframelabel = 0;
1355 else if(tag->id == ST_END) {
1358 spriteframelabel = 0;
1360 dumperror("End Tag not empty");
1362 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1363 handleExportAssets(tag, myprefix);
1365 else if(tag->id == ST_DOACTION && action) {
1367 actions = swf_ActionGet(tag);
1368 swf_DumpActions(actions, myprefix);
1370 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1371 void*abccode = swf_ReadABC(tag);
1372 swf_DumpABC(stdout, abccode, "");
1373 swf_FreeABC(abccode);
1375 else if(tag->id == ST_DOINITACTION && action) {
1377 swf_GetU16(tag); // id
1378 actions = swf_ActionGet(tag);
1379 swf_DumpActions(actions, myprefix);
1381 else if(tag->id == ST_DEFINEBUTTON) {
1383 dumpButton(tag, myprefix);
1386 dumpButtonActions(tag, myprefix);
1389 else if(swf_isFontTag(tag) && showfonts) {
1390 dumpFont(tag, myprefix);
1392 else if(tag->id == ST_DEFINEBUTTON2) {
1394 dumpButton2Actions(tag, myprefix);
1397 else if(tag->id == ST_PLACEOBJECT) {
1398 handlePlaceObject(tag, myprefix);
1400 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1401 handlePlaceObject23(tag, myprefix);
1403 else if(tag->id == ST_DEFINEFONTNAME) {
1404 swf_SetTagPos(tag, 0);
1405 swf_GetU16(tag); //id
1406 swf_GetString(tag); //name
1407 char* copyright = swf_GetString(tag);
1408 printf("%s%s\n", myprefix, copyright);
1410 else if(tag->id == ST_DEFINESHAPE ||
1411 tag->id == ST_DEFINESHAPE2 ||
1412 tag->id == ST_DEFINESHAPE3 ||
1413 tag->id == ST_DEFINESHAPE4) {
1415 handleShape(tag, myprefix);
1418 if(tag->len && used) {
1419 int num = swf_GetNumUsedIDs(tag);
1423 used = (int*)malloc(sizeof(int)*num);
1424 swf_GetUsedIDs(tag, used);
1425 printf("%s%suses IDs: ", indent, prefix);
1426 for(t=0;t<num;t++) {
1428 swf_SetTagPos(tag, used[t]);
1429 id = swf_GetU16(tag);
1430 printf("%d%s", id, t<num-1?", ":"");
1432 dumperror("Id %04d is not yet defined.\n", id);
1439 if(tag->id == ST_FREECHARACTER) {
1441 swf_SetTagPos(tag, 0);
1442 id = swf_GetU16(tag);
1446 if(tag->len && hex) {
1447 hexdumpTag(tag, prefix);