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 %.200s", filename);
986 char compressed = (header[0]=='C');
987 char isflash = header[0]=='F' && header[1] == 'W' && header[2] == 'S' ||
988 header[0]=='C' && header[1] == 'W' && header[2] == 'S';
991 int fl=strlen(filename);
992 if(!isflash && fl>3 && !strcmp(&filename[fl-4], ".abc")) {
993 swf_ReadABCfile(filename, &swf);
995 f = open(filename,O_RDONLY|O_BINARY);
996 if FAILED(swf_ReadSWF(f,&swf))
998 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1005 if(statbuf.st_size != swf.fileSize && !compressed)
1006 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1007 statbuf.st_size, swf.fileSize);
1008 filesize = statbuf.st_size;
1013 //if(action && swf.fileVersion>=9) {
1014 // fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1018 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1019 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1023 printf("-X %d", xsize);
1025 if((xy&1) && (xy&6))
1029 printf("-Y %d", ysize);
1031 if((xy&3) && (xy&4))
1035 printf("-r %.2f", swf.frameRate/256.0);
1037 if((xy&7) && (xy&8))
1041 printf("-f %d", swf.frameCount);
1048 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1049 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0","10,0,0,0"};
1050 if(swf.fileVersion>10) {
1051 fprintf(stderr, "Fileversion>10\n");
1056 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1057 "<param name=\"movie\" value=\"%s\"/>\n"
1058 "<param name=\"play\" value=\"true\"/>\n"
1059 "<param name=\"loop\" value=\"false\"/>\n"
1060 "<param name=\"quality\" value=\"high\"/>\n"
1061 "<param name=\"loop\" value=\"false\"/>\n"
1062 "</object>\n\n", filename, xsize, ysize, filename);
1064 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1066 //" BGCOLOR=#ffffffff\n"?
1068 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1069 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1070 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1071 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1072 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1073 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1074 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1075 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1076 " TYPE=\"application/x-shockwave-flash\"\n"
1077 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1079 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1080 filename, filename, xsize, ysize);
1084 printf("[HEADER] File version: %d\n", swf.fileVersion);
1086 printf("[HEADER] File is zlib compressed.");
1087 if(filesize && swf.fileSize)
1088 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1092 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1093 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1094 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1095 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1096 if(swf.movieSize.xmin)
1097 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1100 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1101 if(swf.movieSize.ymin)
1102 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1110 swf_FontEnumerate(&swf,&fontcallback1, 0);
1111 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1113 swf_FontEnumerate(&swf,&fontcallback2, 0);
1117 char*name = swf_TagGetName(tag);
1120 dumperror("Unknown tag:0x%03x", tag->id);
1125 name = "UNKNOWN TAG";
1128 filepos += tag->len;
1129 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1131 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1134 if(swf_isDefiningTag(tag)) {
1135 U16 id = swf_GetDefineID(tag);
1136 printf(" defines id %04d", id);
1138 dumperror("Id %04d is defined more than once.", id);
1141 else if(swf_isPseudoDefiningTag(tag)) {
1142 U16 id = swf_GetDefineID(tag);
1143 printf(" adds information to id %04d", id);
1145 dumperror("Id %04d is not yet defined.\n", id);
1147 else if(tag->id == ST_PLACEOBJECT) {
1148 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1149 if(swf_GetName(tag))
1150 printf(" name \"%s\"",swf_GetName(tag));
1152 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1159 printf(" id %04d",swf_GetPlaceID(tag));
1163 printf(" at depth %04d", swf_GetDepth(tag));
1165 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1166 printf(" as bitmap");
1168 swf_SetTagPos(tag, 0);
1169 if(tag->data[0]&64) {
1171 swf_GetPlaceObject(tag, &po);
1172 printf(" (clip to %04d)", po.clipdepth);
1173 swf_PlaceObjectFree(&po);
1175 if(swf_GetName(tag))
1176 printf(" name \"%s\"",swf_GetName(tag));
1179 else if(tag->id == ST_REMOVEOBJECT) {
1180 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1182 else if(tag->id == ST_REMOVEOBJECT2) {
1183 printf(" removes object from depth %04d", swf_GetDepth(tag));
1185 else if(tag->id == ST_FREECHARACTER) {
1186 printf(" frees object %04d", swf_GetPlaceID(tag));
1188 else if(tag->id == ST_FILEATTRIBUTES) {
1189 swf_SetTagPos(tag, 0);
1190 U32 flags = swf_GetU32(tag);
1191 if(flags&1) printf(" usenetwork");
1192 if(flags&8) printf(" as3");
1193 if(flags&16) printf(" symbolclass");
1195 printf(" flags=%02x", flags);
1197 else if(tag->id == ST_DOABC) {
1198 swf_SetTagPos(tag, 0);
1199 U32 flags = swf_GetU32(tag);
1200 char*s = swf_GetString(tag);
1202 printf(" flags=%08x", flags);
1205 printf(" \"%s\"", s);
1210 printf(" lazy load");
1212 swf_SetTagPos(tag, 0);
1214 else if(tag->id == ST_STARTSOUND) {
1217 id = swf_GetU16(tag);
1218 flags = swf_GetU8(tag);
1220 printf(" stops sound with id %04d", id);
1222 printf(" starts sound with id %04d", id);
1224 printf(" (if not already playing)");
1230 printf(" looping %d times", swf_GetU16(tag));
1233 else if(tag->id == ST_FRAMELABEL) {
1234 int l = strlen(tag->data);
1235 printf(" \"%s\"", tag->data);
1236 if((l+1) < tag->len) {
1237 printf(" has %d extra bytes", tag->len-1-l);
1238 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1239 printf(" (ANCHOR)");
1241 if((framelabel && !issprite) ||
1242 (spriteframelabel && issprite)) {
1243 dumperror("Frame %d has more than one label",
1244 issprite?spriteframe:mainframe);
1246 if(issprite) spriteframelabel = tag->data;
1247 else framelabel = tag->data;
1249 else if(tag->id == ST_SHOWFRAME) {
1250 char*label = issprite?spriteframelabel:framelabel;
1251 int frame = issprite?spriteframe:mainframe;
1254 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1256 if(issprite) spriteframe++;
1262 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1264 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1265 timestring(frame*(256.0/(swf.frameRate+0.1))),
1266 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1269 printf(" (label \"%s\")", label);
1270 if(issprite) {spriteframe++; spriteframelabel = 0;}
1271 if(!issprite) {mainframe++; framelabel = 0;}
1273 else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1274 U8 r = swf_GetU8(tag);
1275 U8 g = swf_GetU8(tag);
1276 U8 b = swf_GetU8(tag);
1277 printf(" (%02x/%02x/%02x)",r,g,b);
1279 else if(tag->id == ST_PROTECT) {
1281 printf(" %s", swf_GetString(tag));
1284 else if(tag->id == ST_CSMTEXTSETTINGS) {
1285 U16 id = swf_GetU16(tag);
1286 U8 flags = swf_GetU8(tag);
1289 printf("flashtype,");
1291 switch(((flags>>3)&7)) {
1292 case 0:printf("no grid,");break;
1293 case 1:printf("pixel grid,");break;
1294 case 2:printf("subpixel grid,");break;
1295 case 3:printf("unknown grid,");break;
1298 printf("unknown[%08x],", flags);
1299 float thickness = swf_GetFixed(tag);
1300 float sharpness = swf_GetFixed(tag);
1301 printf("s=%.2f,t=%.2f)", thickness, sharpness);
1305 if(tag->id == ST_DEFINEBITSLOSSLESS ||
1306 tag->id == ST_DEFINEBITSLOSSLESS2) {
1307 handleDefineBits(tag);
1310 else if(tag->id == ST_DEFINESOUND) {
1311 handleDefineSound(tag);
1314 else if(tag->id == ST_VIDEOFRAME) {
1315 handleVideoFrame(tag, myprefix);
1318 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1319 handleVideoStream(tag, myprefix);
1322 else if(tag->id == ST_DEFINEEDITTEXT) {
1323 handleEditText(tag);
1326 else if(tag->id == ST_DEFINEMOVIE) {
1327 U16 id = swf_GetU16(tag);
1328 char*s = swf_GetString(tag);
1329 printf(" URL: %s\n", s);
1331 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1337 else if(tag->id == ST_DEFINESCALINGGRID) {
1338 U16 id = swf_GetU16(tag);
1340 swf_GetRect(tag, &r);
1341 printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1343 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1345 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1347 printf(" \"%s\"\n", swf_GetString(tag));
1353 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1354 SRECT r = swf_GetDefineBBox(tag);
1355 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1362 sprintf(myprefix, " %s", prefix);
1364 if(tag->id == ST_DEFINESPRITE) {
1365 sprintf(prefix, " ");
1367 dumperror("Sprite definition inside a sprite definition");
1371 spriteframelabel = 0;
1373 else if(tag->id == ST_END) {
1376 spriteframelabel = 0;
1378 dumperror("End Tag not empty");
1380 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1381 handleExportAssets(tag, myprefix);
1383 else if(tag->id == ST_DOACTION && action) {
1385 actions = swf_ActionGet(tag);
1386 swf_DumpActions(actions, myprefix);
1388 else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1389 void*abccode = swf_ReadABC(tag);
1390 swf_DumpABC(stdout, abccode, "");
1391 swf_FreeABC(abccode);
1393 else if(tag->id == ST_DOINITACTION && action) {
1395 swf_GetU16(tag); // id
1396 actions = swf_ActionGet(tag);
1397 swf_DumpActions(actions, myprefix);
1399 else if(tag->id == ST_DEFINEBUTTON) {
1401 dumpButton(tag, myprefix);
1404 dumpButtonActions(tag, myprefix);
1407 else if(swf_isFontTag(tag) && showfonts) {
1408 dumpFont(tag, myprefix);
1410 else if(tag->id == ST_DEFINEBUTTON2) {
1412 dumpButton2Actions(tag, myprefix);
1415 else if(tag->id == ST_PLACEOBJECT) {
1416 handlePlaceObject(tag, myprefix);
1418 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1419 handlePlaceObject23(tag, myprefix);
1421 else if(tag->id == ST_DEFINEFONTNAME) {
1422 swf_SetTagPos(tag, 0);
1423 swf_GetU16(tag); //id
1424 swf_GetString(tag); //name
1425 char* copyright = swf_GetString(tag);
1426 printf("%s%s\n", myprefix, copyright);
1428 else if(tag->id == ST_DEFINESHAPE ||
1429 tag->id == ST_DEFINESHAPE2 ||
1430 tag->id == ST_DEFINESHAPE3 ||
1431 tag->id == ST_DEFINESHAPE4) {
1433 handleShape(tag, myprefix);
1436 if(tag->len && used) {
1437 int num = swf_GetNumUsedIDs(tag);
1441 used = (int*)malloc(sizeof(int)*num);
1442 swf_GetUsedIDs(tag, used);
1443 printf("%s%suses IDs: ", indent, prefix);
1444 for(t=0;t<num;t++) {
1446 swf_SetTagPos(tag, used[t]);
1447 id = swf_GetU16(tag);
1448 printf("%d%s", id, t<num-1?", ":"");
1450 dumperror("Id %04d is not yet defined.\n", id);
1457 if(tag->id == ST_FREECHARACTER) {
1459 swf_SetTagPos(tag, 0);
1460 id = swf_GetU16(tag);
1464 if(tag->len && hex) {
1465 hexdumpTag(tag, prefix);