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;
64 static struct options_t options[] = {
85 int args_callback_option(char*name,char*val)
87 if(!strcmp(name, "V")) {
88 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
91 else if(name[0]=='a') {
95 else if(name[0]=='p') {
99 else if(name[0]=='t') {
103 else if(name[0]=='s') {
107 else if(name[0]=='e') {
111 else if(name[0]=='c') {
115 else if(name[0]=='E') {
120 else if(name[0]=='X') {
124 else if(name[0]=='Y') {
128 else if(name[0]=='r') {
132 else if(name[0]=='f') {
136 else if(name[0]=='F') {
140 else if(name[0]=='d') {
144 else if(name[0]=='u') {
148 else if(name[0]=='b') {
152 else if(name[0]=='D') {
153 action = placements = showtext = showshapes = 1;
157 printf("Unknown option: -%s\n", name);
163 int args_callback_longoption(char*name,char*val)
165 return args_long2shortoption(options, name, val);
167 void args_callback_usage(char *name)
170 printf("Usage: %s [-atpdu] file.swf\n", name);
172 printf("-h , --help Print short help message and exit\n");
173 printf("-D , --full Show everything. Same as -atp\n");
174 printf("-V , --version Print version info and exit\n");
175 printf("-e , --html Print out html code for embedding the file\n");
176 printf("-E , --xhtml Print out xhtml code for embedding the file\n");
177 printf("-a , --action Disassemble action tags\n");
178 printf("-t , --text Show text fields (like swfstrings).\n");
179 printf("-s , --shapes Show shape coordinates/styles\n");
180 printf("-F , --fonts Show font information\n");
181 printf("-p , --placements Show placement information\n");
182 printf("-b , --bbox Print tag's bounding boxes\n");
183 printf("-X , --width Prints out a string of the form \"-X width\".\n");
184 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
185 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
186 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
187 printf("-d , --hex Print hex output of tag data, too.\n");
188 printf("-u , --used Show referred IDs for each Tag.\n");
191 int args_callback_command(char*name,char*val)
194 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
202 char* testfunc(char*str)
204 printf("%s: %s\n", what, str);
208 void dumpButton2Actions(TAG*tag, char*prefix)
214 oldTagPos = swf_GetTagPos(tag);
216 // scan DefineButton2 Record
218 swf_GetU16(tag); // Character ID
219 swf_GetU8(tag); // Flags;
221 offsetpos = swf_GetTagPos(tag); // first offset
224 while (swf_GetU8(tag)) // state -> parse ButtonRecord
225 { swf_GetU16(tag); // id
226 swf_GetU16(tag); // layer
227 swf_GetMatrix(tag,NULL); // matrix
228 swf_GetCXForm(tag,NULL,1); // cxform
235 if(tag->pos >= tag->len)
238 offsetpos = swf_GetU16(tag);
239 condition = swf_GetU16(tag); // condition
241 actions = swf_ActionGet(tag);
242 printf("%s condition %04x\n", prefix, condition);
243 swf_DumpActions(actions, prefix);
246 swf_SetTagPos(tag,oldTagPos);
250 void dumpButtonActions(TAG*tag, char*prefix)
253 swf_GetU16(tag); // id
254 while (swf_GetU8(tag)) // state -> parse ButtonRecord
255 { swf_GetU16(tag); // id
256 swf_GetU16(tag); // layer
257 swf_GetMatrix(tag,NULL); // matrix
259 actions = swf_ActionGet(tag);
260 swf_DumpActions(actions, prefix);
263 void dumpFont(TAG*tag, char*prefix)
265 SWFFONT* font = malloc(sizeof(SWFFONT));
266 memset(font, 0, sizeof(SWFFONT));
267 if(tag->id == ST_DEFINEFONT2) {
268 swf_FontExtract_DefineFont2(0, font, tag);
269 } else if(tag->id == ST_DEFINEFONT) {
270 swf_FontExtract_DefineFont(0, font, tag);
272 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
274 printf("%sID: %d\n", prefix,font->id);
275 printf("%sVersion: %d\n", prefix,font->version);
276 printf("%sname: %s\n", prefix,font->name);
277 printf("%scharacters: %d\n", prefix,font->numchars);
278 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
281 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
282 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
283 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
284 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
286 printf("%sstyle: %d\n", prefix,font->style);
287 printf("%sencoding: %02x\n", prefix,font->encoding);
288 printf("%slanguage: %02x\n", prefix,font->language);
290 for(t=0;t<font->numchars;t++) {
291 int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
292 printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
293 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
294 SHAPELINE*line = shape->lines;
297 if(line->type == moveTo) {
298 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
299 } else if(line->type == lineTo) {
300 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
301 } else if(line->type == splineTo) {
302 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
303 line->sx/20.0, line->sy/20.0,
304 line->x/20.0, line->y/20.0
309 swf_Shape2Free(shape);
319 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
322 printf(" <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a);
323 for(t=0;t<fontnum;t++)
325 if(fonts[t]->id == fontid) {
335 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
336 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
339 if(fonts[font]->glyph2ascii[glyphs[t]])
340 a = fonts[font]->glyph2ascii[glyphs[t]];
350 printf("\\x%x", (int)a);
355 void handleText(TAG*tag)
358 swf_ParseDefineText(tag,textcallback, 0);
361 void handleDefineSound(TAG*tag)
363 U16 id = swf_GetU16(tag);
364 U8 flags = swf_GetU8(tag);
365 int compression = (flags>>4)&7;
366 int rate = (flags>>2)&3;
367 int bits = flags&2?16:8;
368 int stereo = flags&1;
370 if(compression == 0) printf("Raw ");
371 else if(compression == 1) printf("ADPCM ");
372 else if(compression == 2) printf("MP3 ");
373 else if(compression == 3) printf("Raw little-endian ");
374 else if(compression == 6) printf("ASAO ");
376 if(rate == 0) printf("5.5Khz ");
377 if(rate == 1) printf("11Khz ");
378 if(rate == 2) printf("22Khz ");
379 if(rate == 3) printf("44Khz ");
380 printf("%dBit ", bits);
381 if(stereo) printf("stereo");
386 void handleDefineBits(TAG*tag)
392 id = swf_GetU16(tag);
393 mode = swf_GetU8(tag);
394 width = swf_GetU16(tag);
395 height = swf_GetU16(tag);
396 printf(" image %dx%d",width,height);
397 if(mode == 3) printf(" (8 bpp)");
398 else if(mode == 4) printf(" (16 bpp)");
399 else if(mode == 5) printf(" (32 bpp)");
400 else printf(" (? bpp)");
403 void handleEditText(TAG*tag)
408 id = swf_GetU16(tag);
411 //swf_ResetReadBits(tag);
417 flags = swf_GetBits(tag,16);
418 if(flags & ET_HASFONT) {
419 swf_GetU16(tag); //font
420 swf_GetU16(tag); //fontheight
422 if(flags & ET_HASTEXTCOLOR) {
423 swf_GetU8(tag); //rgba
428 if(flags & ET_HASMAXLENGTH) {
429 swf_GetU16(tag); //maxlength
431 if(flags & ET_HASLAYOUT) {
432 swf_GetU8(tag); //align
433 swf_GetU16(tag); //left margin
434 swf_GetU16(tag); //right margin
435 swf_GetU16(tag); //indent
436 swf_GetU16(tag); //leading
438 printf(" variable \"%s\" ", &tag->data[tag->pos]);
439 if(flags & ET_HTML) printf("(html)");
440 if(flags & ET_NOSELECT) printf("(noselect)");
441 if(flags & ET_PASSWORD) printf("(password)");
442 if(flags & ET_READONLY) printf("(readonly)");
444 if(flags & (ET_X1 | ET_X3 ))
446 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
449 while(tag->data[tag->pos++]);
450 if(flags & ET_HASTEXT)
451 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
454 void printhandlerflags(U32 handlerflags)
456 if(handlerflags&1) printf("[on load]");
457 if(handlerflags&2) printf("[enter frame]");
458 if(handlerflags&4) printf("[unload]");
459 if(handlerflags&8) printf("[mouse move]");
460 if(handlerflags&16) printf("[mouse down]");
461 if(handlerflags&32) printf("[mouse up]");
462 if(handlerflags&64) printf("[key down]");
463 if(handlerflags&128) printf("[key up]");
465 if(handlerflags&256) printf("[data]");
466 if(handlerflags&512) printf("[initialize]");
467 if(handlerflags&1024) printf("[mouse press]");
468 if(handlerflags&2048) printf("[mouse release]");
469 if(handlerflags&4096) printf("[mouse release outside]");
470 if(handlerflags&8192) printf("[mouse rollover]");
471 if(handlerflags&16384) printf("[mouse rollout]");
472 if(handlerflags&32768) printf("[mouse drag over]");
474 if(handlerflags&0x10000) printf("[mouse drag out]");
475 if(handlerflags&0x20000) printf("[key press]");
476 if(handlerflags&0x40000) printf("[construct even]");
477 if(handlerflags&0xfff80000) printf("[???]");
479 void handleVideoStream(TAG*tag, char*prefix)
481 U16 id = swf_GetU16(tag);
482 U16 frames = swf_GetU16(tag);
483 U16 width = swf_GetU16(tag);
484 U16 height = swf_GetU16(tag);
485 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
486 U8 codec = swf_GetU8(tag);
487 printf(" (%d frames, %dx%d", frames, width, height);
491 printf(" sorenson h.263)");
493 printf(" codec 0x%02x)", codec);
495 void handleVideoFrame(TAG*tag, char*prefix)
497 U32 code, version, reference, sizeflags;
498 U32 width=0, height=0;
500 U16 id = swf_GetU16(tag);
501 U16 frame = swf_GetU16(tag);
502 U8 deblock,flags, tmp, bit;
504 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
505 printf(" (frame %d) ", frame);
507 /* video packet follows */
508 code = swf_GetBits(tag, 17);
509 version = swf_GetBits(tag, 5);
510 reference = swf_GetBits(tag, 8);
512 sizeflags = swf_GetBits(tag, 3);
515 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
516 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
517 case 2: width = 352; height = 288; break;
518 case 3: width = 176; height = 144; break;
519 case 4: width = 128; height = 96; break;
520 case 5: width = 320; height = 240; break;
521 case 6: width = 160; height = 120; break;
522 case 7: width = -1; height = -1;/*reserved*/ break;
524 printf("%dx%d ", width, height);
525 type = swf_GetBits(tag, 2);
526 printf("%s", types[type]);
528 deblock = swf_GetBits(tag, 1);
530 printf(" deblock ", deblock);
531 quantizer = swf_GetBits(tag, 5);
532 printf(" quant: %d ", quantizer);
535 void dumpFilter(FILTER*filter)
537 if(filter->type == FILTERTYPE_BLUR) {
538 FILTER_BLUR*f = (FILTER_BLUR*)filter;
539 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
540 printf("passes: %d\n", f->passes);
541 } if(filter->type == FILTERTYPE_GLOW) {
542 FILTER_GLOW*f = (FILTER_GLOW*)filter;
543 printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
544 printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
545 printf("passes: %d\n", f->passes);
546 printf("flags: %s%s%s\n",
547 f->knockout?"knockout ":"",
548 f->composite?"composite ":"",
549 f->innerglow?"innerglow":"");
550 } if(filter->type == FILTERTYPE_DROPSHADOW) {
551 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
552 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
553 printf("passes: %d\n", f->passes);
554 printf("angle: %f distance: %f\n", f->angle, f->distance);
555 printf("strength: %f passes: %d\n", f->strength, f->passes);
556 printf("flags: %s%s%s\n",
557 f->knockout?"knockout ":"",
558 f->composite?"composite ":"",
559 f->innershadow?"innershadow ":"");
560 } if(filter->type == FILTERTYPE_BEVEL) {
561 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
562 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
563 printf("passes: %d\n", f->passes);
564 printf("angle: %f distance: %f\n", f->angle, f->distance);
565 printf("strength: %f passes: %d\n", f->strength, f->passes);
566 printf("flags: %s%s%s%s\n",
568 f->knockout?"knockout ":"",
569 f->composite?"composite ":"",
570 f->innershadow?"innershadow ":"");
571 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
572 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
573 swf_DumpGradient(stdout, f->gradient);
574 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
575 printf("angle: %f distance: %f\n", f->angle, f->distance);
576 printf("strength: %f passes: %d\n", f->strength, f->passes);
577 printf("flags: %s%s%s%s\n",
578 f->knockout?"knockout ":"",
579 f->ontop?"ontop ":"",
580 f->composite?"composite ":"",
581 f->innershadow?"innershadow ":"");
586 void handlePlaceObject23(TAG*tag, char*prefix)
592 int ppos[3] = {0,0,0};
593 swf_SetTagPos(tag, 0);
594 flags = swf_GetU8(tag);
595 if(tag->id == ST_PLACEOBJECT3)
596 flags2 = swf_GetU8(tag);
597 swf_GetU16(tag); //depth
600 if(flags&2) swf_GetU16(tag); //id
602 swf_GetMatrix(tag,&m);
604 ppos[0] += sprintf(pstr[0], "| Matrix ");
605 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
606 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
610 swf_GetCXForm(tag, &cx, 1);
612 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
613 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);
614 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
618 U16 ratio = swf_GetU16(tag); //ratio
620 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
621 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
622 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
626 U16 clip = swf_GetU16(tag); //clip
628 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
629 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
630 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
633 if(flags&32) { while(swf_GetU8(tag)); }
635 if(flags2&1) { // filter list
636 U8 num = swf_GetU8(tag);
638 printf("\n%d filters\n", num);
639 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
642 FILTER*filter = swf_GetFilter(tag);
648 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
653 if(flags2&2) { // blend mode
654 U8 blendmode = swf_GetU8(tag);
658 sprintf(name, "%-5d", blendmode);
659 for(t=0;blendModeNames[t];t++) {
661 sprintf(name, "%-5s", blendModeNames[t]);
665 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
666 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
667 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
671 if(placements && ppos[0]) {
673 printf("%s %s\n", prefix, pstr[0]);
674 printf("%s %s\n", prefix, pstr[1]);
675 printf("%s %s", prefix, pstr[2]);
684 reserved = swf_GetU16(tag); // must be 0
685 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
687 printf("Unknown parameter field not zero: %04x\n", reserved);
690 printf("global flags: %04x\n", globalflags);
692 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
694 handlerflags = swf_GetU32(tag);
697 while(handlerflags) {
702 globalflags &= ~handlerflags;
703 printf("%s flags %08x ",prefix, handlerflags);
704 printhandlerflags(handlerflags);
705 length = swf_GetU32(tag);
706 printf(", %d bytes actioncode\n",length);
707 a = swf_ActionGet(tag);
708 swf_DumpActions(a,prefix);
711 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
713 if(globalflags) // should go to sterr.
714 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
716 printf(" has action code\n");
721 void handlePlaceObject(TAG*tag, char*prefix)
723 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
728 swf_SetTagPos(tag, 0);
729 id = swf_GetU16(tag);
730 depth = swf_GetU16(tag);
731 swf_GetMatrix(tag, &matrix);
732 swf_GetCXForm(tag, &cxform, 0);
734 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
735 swf_SetU16(tag2, depth);
736 swf_SetU16(tag2, id);
737 swf_SetMatrix(tag2, &matrix);
738 swf_SetCXForm(tag2, &cxform, 1);
740 handlePlaceObject23(tag2, prefix);
743 char* fillstyle2str(FILLSTYLE*style)
745 switch(style->type) {
747 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
749 case 0x10: case 0x11: case 0x12: case 0x13:
750 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
752 case 0x40: case 0x42:
753 /* TODO: display information about that bitmap */
754 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
755 /* TODO: show matrix */
757 case 0x41: case 0x43:
758 /* TODO: display information about that bitmap */
759 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
760 /* TODO: show matrix */
763 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
767 char* linestyle2str(LINESTYLE*style)
769 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
773 void handleShape(TAG*tag, char*prefix)
781 swf_ParseDefineShape(tag, &shape);
783 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
785 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
790 else printf("%s | (Neither line nor fill styles)\n", prefix);
793 printf("%s", prefix);
794 if(t < shape.numfillstyles) {
795 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
799 if(t < shape.numlinestyles) {
800 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
805 printf("%s |\n", prefix);
809 printf("%s | fill: %02d/%02d line:%02d - ",
814 if(line->type == moveTo) {
815 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
816 } else if(line->type == lineTo) {
817 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
818 } else if(line->type == splineTo) {
819 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
820 line->sx/20.0, line->sy/20.0,
821 line->x/20.0, line->y/20.0
826 printf("%s |\n", prefix);
829 void fontcallback1(void*self, U16 id,U8 * name)
833 void fontcallback2(void*self, U16 id,U8 * name)
835 swf_FontExtract(&swf,id,&fonts[fontnum]);
839 static U8 printable(U8 a)
841 if(a<32 || a==127) return '.';
844 void hexdumpTag(TAG*tag, char* prefix)
848 printf(" %s-=> ",prefix);
849 for(t=0;t<tag->len;t++) {
850 printf("%02x ", tag->data[t]);
851 ascii[t&15] = printable(tag->data[t]);
852 if((t && ((t&15)==15)) || (t==tag->len-1))
856 for(s=p-1;s<16;s++) {
860 printf(" %s\n", ascii);
862 printf(" %s\n %s-=> ",ascii,prefix);
867 void handleExportAssets(TAG*tag, char* prefix)
873 num = swf_GetU16(tag);
876 id = swf_GetU16(tag);
877 name = swf_GetString(tag);
878 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
882 void dumperror(const char* format, ...)
887 va_start(arglist, format);
888 vsprintf(buf, format, arglist);
892 printf("==== Error: %s ====\n", buf);
895 static char strbuf[800];
898 char* timestring(double f)
900 int hours = (int)(f/3600);
901 int minutes = (int)((f-hours*3600)/60);
902 int seconds = (int)((f-hours*3600-minutes*60));
903 int useconds = (int)((f-(int)f)*1000+0.5);
906 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
907 return &strbuf[bufpos];
910 int main (int argc,char ** argv)
918 char issprite = 0; // are we inside a sprite definition?
921 char* spriteframelabel = 0;
922 char* framelabel = 0;
927 memset(idtab,0,65536);
929 processargs(argc, argv);
933 fprintf(stderr, "You must supply a filename.\n");
937 f = open(filename,O_RDONLY|O_BINARY);
941 sprintf(buffer, "Couldn't open %s", filename);
947 int compressed = (header[0]=='C');
949 f = open(filename,O_RDONLY|O_BINARY);
951 if FAILED(swf_ReadSWF(f,&swf))
953 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
960 if(statbuf.st_size != swf.fileSize && !compressed)
961 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
962 statbuf.st_size, swf.fileSize);
963 filesize = statbuf.st_size;
968 if(action && swf.fileVersion>=9) {
969 fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
973 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
974 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
978 printf("-X %d", xsize);
984 printf("-Y %d", ysize);
990 printf("-r %.2f", swf.frameRate/256.0);
996 printf("-f %d", swf.frameCount);
1003 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1004 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
1005 if(swf.fileVersion>9) {
1006 fprintf(stderr, "Fileversion>9\n");
1011 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1012 "<param name=\"movie\" value=\"%s\"/>\n"
1013 "<param name=\"play\" value=\"true\"/>\n"
1014 "<param name=\"loop\" value=\"false\"/>\n"
1015 "<param name=\"quality\" value=\"high\"/>\n"
1016 "<param name=\"loop\" value=\"false\"/>\n"
1017 "</object>\n\n", filename, xsize, ysize, filename);
1019 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1021 //" BGCOLOR=#ffffffff\n"?
1023 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1024 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1025 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1026 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1027 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1028 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1029 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1030 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1031 " TYPE=\"application/x-shockwave-flash\"\n"
1032 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1034 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1035 filename, filename, xsize, ysize);
1039 printf("[HEADER] File version: %d\n", swf.fileVersion);
1041 printf("[HEADER] File is zlib compressed.");
1042 if(filesize && swf.fileSize)
1043 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1047 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1048 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1049 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1050 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1051 if(swf.movieSize.xmin)
1052 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1055 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1056 if(swf.movieSize.ymin)
1057 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1065 swf_FontEnumerate(&swf,&fontcallback1, 0);
1066 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1068 swf_FontEnumerate(&swf,&fontcallback2, 0);
1072 char*name = swf_TagGetName(tag);
1075 dumperror("Unknown tag:0x%03x", tag->id);
1080 name = "UNKNOWN TAG";
1083 filepos += tag->len;
1084 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1086 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1089 if(swf_isDefiningTag(tag)) {
1090 U16 id = swf_GetDefineID(tag);
1091 printf(" defines id %04d", id);
1093 dumperror("Id %04d is defined more than once.", id);
1096 else if(swf_isPseudoDefiningTag(tag)) {
1097 U16 id = swf_GetDefineID(tag);
1098 printf(" adds information to id %04d", id);
1100 dumperror("Id %04d is not yet defined.\n", id);
1102 else if(tag->id == ST_PLACEOBJECT) {
1103 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1104 if(swf_GetName(tag))
1105 printf(" name \"%s\"",swf_GetName(tag));
1107 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1114 printf(" id %04d",swf_GetPlaceID(tag));
1118 printf(" at depth %04d", swf_GetDepth(tag));
1120 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1121 printf(" as bitmap");
1123 swf_SetTagPos(tag, 0);
1124 if(tag->data[0]&64) {
1126 swf_GetPlaceObject(tag, &po);
1127 printf(" (clip to %04d)", po.clipdepth);
1128 swf_PlaceObjectFree(&po);
1130 if(swf_GetName(tag))
1131 printf(" name \"%s\"",swf_GetName(tag));
1134 else if(tag->id == ST_REMOVEOBJECT) {
1135 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1137 else if(tag->id == ST_REMOVEOBJECT2) {
1138 printf(" removes object from depth %04d", swf_GetDepth(tag));
1140 else if(tag->id == ST_FREECHARACTER) {
1141 printf(" frees object %04d", swf_GetPlaceID(tag));
1143 else if(tag->id == ST_STARTSOUND) {
1146 id = swf_GetU16(tag);
1147 flags = swf_GetU8(tag);
1149 printf(" stops sound with id %04d", id);
1151 printf(" starts sound with id %04d", id);
1153 printf(" (if not already playing)");
1159 printf(" looping %d times", swf_GetU16(tag));
1162 else if(tag->id == ST_FRAMELABEL) {
1163 int l = strlen(tag->data);
1164 printf(" \"%s\"", tag->data);
1165 if((l+1) < tag->len) {
1166 printf(" has %d extra bytes", tag->len-1-l);
1167 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1168 printf(" (ANCHOR)");
1170 if((framelabel && !issprite) ||
1171 (spriteframelabel && issprite)) {
1172 dumperror("Frame %d has more than one label",
1173 issprite?spriteframe:mainframe);
1175 if(issprite) spriteframelabel = tag->data;
1176 else framelabel = tag->data;
1178 else if(tag->id == ST_SHOWFRAME) {
1179 char*label = issprite?spriteframelabel:framelabel;
1180 int frame = issprite?spriteframe:mainframe;
1183 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1185 if(issprite) spriteframe++;
1191 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1193 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1194 timestring(frame*(256.0/(swf.frameRate+0.1))),
1195 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1198 printf(" (label \"%s\")", label);
1199 if(issprite) {spriteframe++; spriteframelabel = 0;}
1200 if(!issprite) {mainframe++; framelabel = 0;}
1203 if(tag->id == ST_SETBACKGROUNDCOLOR) {
1204 U8 r = swf_GetU8(tag);
1205 U8 g = swf_GetU8(tag);
1206 U8 b = swf_GetU8(tag);
1207 printf(" (%02x/%02x/%02x)\n",r,g,b);
1209 else if(tag->id == ST_PROTECT) {
1211 printf(" %s\n", swf_GetString(tag));
1216 else if(tag->id == ST_CSMTEXTSETTINGS) {
1217 U16 id = swf_GetU16(tag);
1218 U8 flags = swf_GetU8(tag);
1221 printf("flashtype,");
1223 switch(((flags>>3)&7)) {
1224 case 0:printf("no grid,");break;
1225 case 1:printf("pixel grid,");break;
1226 case 2:printf("subpixel grid,");break;
1227 case 3:printf("unknown grid,");break;
1230 printf("unknown[%08x],", flags);
1231 float thickness = swf_GetFixed(tag);
1232 float sharpness = swf_GetFixed(tag);
1233 printf("s=%.2f,t=%.2f)\n", thickness, sharpness);
1236 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1237 tag->id == ST_DEFINEBITSLOSSLESS2) {
1238 handleDefineBits(tag);
1241 else if(tag->id == ST_DEFINESOUND) {
1242 handleDefineSound(tag);
1245 else if(tag->id == ST_VIDEOFRAME) {
1246 handleVideoFrame(tag, myprefix);
1249 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1250 handleVideoStream(tag, myprefix);
1253 else if(tag->id == ST_DEFINEEDITTEXT) {
1254 handleEditText(tag);
1257 else if(tag->id == ST_DEFINEMOVIE) {
1258 U16 id = swf_GetU16(tag);
1259 char*s = swf_GetString(tag);
1260 printf(" URL: %s\n", s);
1262 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1268 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1270 else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1272 printf(" \"%s\"\n", swf_GetString(tag));
1278 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1279 SRECT r = swf_GetDefineBBox(tag);
1280 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1287 sprintf(myprefix, " %s", prefix);
1289 if(tag->id == ST_DEFINESPRITE) {
1290 sprintf(prefix, " ");
1292 dumperror("Sprite definition inside a sprite definition");
1296 spriteframelabel = 0;
1298 else if(tag->id == ST_END) {
1301 spriteframelabel = 0;
1303 dumperror("End Tag not empty");
1305 else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1306 handleExportAssets(tag, myprefix);
1308 else if(tag->id == ST_DOACTION && action) {
1310 actions = swf_ActionGet(tag);
1311 swf_DumpActions(actions, myprefix);
1313 else if(tag->id == ST_DOINITACTION && action) {
1315 swf_GetU16(tag); // id
1316 actions = swf_ActionGet(tag);
1317 swf_DumpActions(actions, myprefix);
1319 else if(tag->id == ST_DEFINEBUTTON && action) {
1320 dumpButtonActions(tag, myprefix);
1322 else if(swf_isFontTag(tag) && showfonts) {
1323 dumpFont(tag, myprefix);
1325 else if(tag->id == ST_DEFINEBUTTON2 && action) {
1326 dumpButton2Actions(tag, myprefix);
1328 else if(tag->id == ST_PLACEOBJECT) {
1329 handlePlaceObject(tag, myprefix);
1331 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1332 handlePlaceObject23(tag, myprefix);
1334 else if(tag->id == ST_DEFINEFONTNAME) {
1335 swf_SetTagPos(tag, 0);
1336 swf_GetU16(tag); //id
1337 swf_GetString(tag); //name
1338 char* copyright = swf_GetString(tag);
1339 printf("%s%s\n", myprefix, copyright);
1341 else if(tag->id == ST_DEFINESHAPE ||
1342 tag->id == ST_DEFINESHAPE2 ||
1343 tag->id == ST_DEFINESHAPE3 ||
1344 tag->id == ST_DEFINESHAPE4) {
1346 handleShape(tag, myprefix);
1349 if(tag->len && used) {
1350 int num = swf_GetNumUsedIDs(tag);
1354 used = (int*)malloc(sizeof(int)*num);
1355 swf_GetUsedIDs(tag, used);
1356 printf("%s%suses IDs: ", indent, prefix);
1357 for(t=0;t<num;t++) {
1359 swf_SetTagPos(tag, used[t]);
1360 id = swf_GetU16(tag);
1361 printf("%d%s", id, t<num-1?", ":"");
1363 dumperror("Id %04d is not yet defined.\n", id);
1370 if(tag->id == ST_FREECHARACTER) {
1372 swf_SetTagPos(tag, 0);
1373 id = swf_GetU16(tag);
1377 if(tag->len && hex) {
1378 hexdumpTag(tag, prefix);