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[] = {
84 int args_callback_option(char*name,char*val)
86 if(!strcmp(name, "V")) {
87 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
90 else if(name[0]=='a') {
94 else if(name[0]=='p') {
98 else if(name[0]=='t') {
102 else if(name[0]=='s') {
106 else if(name[0]=='e') {
110 else if(name[0]=='c') {
114 else if(name[0]=='E') {
119 else if(name[0]=='X') {
123 else if(name[0]=='Y') {
127 else if(name[0]=='r') {
131 else if(name[0]=='f') {
135 else if(name[0]=='F') {
139 else if(name[0]=='d') {
143 else if(name[0]=='u') {
147 else if(name[0]=='b') {
151 else if(name[0]=='D') {
152 action = placements = showtext = showshapes = 1;
156 printf("Unknown option: -%s\n", name);
162 int args_callback_longoption(char*name,char*val)
164 return args_long2shortoption(options, name, val);
166 void args_callback_usage(char *name)
169 printf("Usage: %s [-atpdu] file.swf\n", name);
171 printf("-h , --help Print short help message and exit\n");
172 printf("-D , --full Show everything. Same as -atp\n");
173 printf("-V , --version Print version info and exit\n");
174 printf("-e , --html Print out html code for embedding the file\n");
175 printf("-E , --xhtml Print out xhtml code for embedding the file\n");
176 printf("-a , --action Disassemble action tags\n");
177 printf("-t , --text Show text fields (like swfstrings).\n");
178 printf("-s , --shapes Show shape coordinates/styles\n");
179 printf("-p , --placements Show placement information\n");
180 printf("-b , --bbox Print tag's bounding boxes\n");
181 printf("-X , --width Prints out a string of the form \"-X width\".\n");
182 printf("-Y , --height Prints out a string of the form \"-Y height\".\n");
183 printf("-r , --rate Prints out a string of the form \"-r rate\".\n");
184 printf("-f , --frames Prints out a string of the form \"-f framenum\".\n");
185 printf("-d , --hex Print hex output of tag data, too.\n");
186 printf("-u , --used Show referred IDs for each Tag.\n");
189 int args_callback_command(char*name,char*val)
192 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
200 char* testfunc(char*str)
202 printf("%s: %s\n", what, str);
206 void dumpButton2Actions(TAG*tag, char*prefix)
212 oldTagPos = swf_GetTagPos(tag);
214 // scan DefineButton2 Record
216 swf_GetU16(tag); // Character ID
217 swf_GetU8(tag); // Flags;
219 offsetpos = swf_GetTagPos(tag); // first offset
222 while (swf_GetU8(tag)) // state -> parse ButtonRecord
223 { swf_GetU16(tag); // id
224 swf_GetU16(tag); // layer
225 swf_GetMatrix(tag,NULL); // matrix
226 swf_GetCXForm(tag,NULL,1); // cxform
233 if(tag->pos >= tag->len)
236 offsetpos = swf_GetU16(tag);
237 condition = swf_GetU16(tag); // condition
239 actions = swf_ActionGet(tag);
240 printf("%s condition %04x\n", prefix, condition);
241 swf_DumpActions(actions, prefix);
244 swf_SetTagPos(tag,oldTagPos);
248 void dumpButtonActions(TAG*tag, char*prefix)
251 swf_GetU16(tag); // id
252 while (swf_GetU8(tag)) // state -> parse ButtonRecord
253 { swf_GetU16(tag); // id
254 swf_GetU16(tag); // layer
255 swf_GetMatrix(tag,NULL); // matrix
257 actions = swf_ActionGet(tag);
258 swf_DumpActions(actions, prefix);
261 void dumpFont(TAG*tag, char*prefix)
263 SWFFONT* font = malloc(sizeof(SWFFONT));
264 memset(font, 0, sizeof(SWFFONT));
265 if(tag->id == ST_DEFINEFONT2) {
266 swf_FontExtract_DefineFont2(0, font, tag);
267 } else if(tag->id == ST_DEFINEFONT) {
268 swf_FontExtract_DefineFont(0, font, tag);
270 printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
272 printf("%sID: %d\n", prefix,font->id);
273 printf("%sVersion: %d\n", prefix,font->version);
274 printf("%sname: %s\n", prefix,font->name);
275 printf("%scharacters: %d\n", prefix,font->numchars);
276 printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
279 printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
280 printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
281 printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
282 printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
284 printf("%sstyle: %d\n", prefix,font->style);
285 printf("%sencoding: %02x\n", prefix,font->encoding);
286 printf("%slanguage: %02x\n", prefix,font->language);
288 for(t=0;t<font->numchars;t++) {
289 printf("%s== Glyph %d: advance=%d ==\n", prefix, t, font->glyph[t].advance);
290 SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
291 SHAPELINE*line = shape->lines;
294 if(line->type == moveTo) {
295 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
296 } else if(line->type == lineTo) {
297 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
298 } else if(line->type == splineTo) {
299 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
300 line->sx/20.0, line->sy/20.0,
301 line->x/20.0, line->y/20.0
306 swf_Shape2Free(shape);
316 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color)
319 printf(" <%2d glyphs in font %2d, color #%02x%02x%02x%02x> ",nr, fontid, color->r, color->g, color->b, color->a);
320 for(t=0;t<fontnum;t++)
322 if(fonts[t]->id == fontid) {
332 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
333 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
336 if(fonts[font]->glyph2ascii[glyphs[t]])
337 a = fonts[font]->glyph2ascii[glyphs[t]];
347 printf("\\x%x", (int)a);
352 void handleText(TAG*tag)
355 swf_ParseDefineText(tag,textcallback, 0);
358 void handleDefineSound(TAG*tag)
360 U16 id = swf_GetU16(tag);
361 U8 flags = swf_GetU8(tag);
362 int compression = (flags>>4)&7;
363 int rate = (flags>>2)&3;
364 int bits = flags&2?16:8;
365 int stereo = flags&1;
367 if(compression == 0) printf("Raw ");
368 else if(compression == 1) printf("ADPCM ");
369 else if(compression == 2) printf("MP3 ");
370 else if(compression == 3) printf("Raw little-endian ");
371 else if(compression == 6) printf("ASAO ");
373 if(rate == 0) printf("5.5Khz ");
374 if(rate == 1) printf("11Khz ");
375 if(rate == 2) printf("22Khz ");
376 if(rate == 3) printf("44Khz ");
377 printf("%dBit ", bits);
378 if(stereo) printf("stereo");
383 void handleDefineBits(TAG*tag)
389 id = swf_GetU16(tag);
390 mode = swf_GetU8(tag);
391 width = swf_GetU16(tag);
392 height = swf_GetU16(tag);
393 printf(" image %dx%d",width,height);
394 if(mode == 3) printf(" (8 bpp)");
395 else if(mode == 4) printf(" (16 bpp)");
396 else if(mode == 5) printf(" (32 bpp)");
397 else printf(" (? bpp)");
400 void handleEditText(TAG*tag)
405 id = swf_GetU16(tag);
408 //swf_ResetReadBits(tag);
414 flags = swf_GetBits(tag,16);
415 if(flags & ET_HASFONT) {
416 swf_GetU16(tag); //font
417 swf_GetU16(tag); //fontheight
419 if(flags & ET_HASTEXTCOLOR) {
420 swf_GetU8(tag); //rgba
425 if(flags & ET_HASMAXLENGTH) {
426 swf_GetU16(tag); //maxlength
428 if(flags & ET_HASLAYOUT) {
429 swf_GetU8(tag); //align
430 swf_GetU16(tag); //left margin
431 swf_GetU16(tag); //right margin
432 swf_GetU16(tag); //indent
433 swf_GetU16(tag); //leading
435 printf(" variable \"%s\" ", &tag->data[tag->pos]);
436 if(flags & ET_HTML) printf("(html)");
437 if(flags & ET_NOSELECT) printf("(noselect)");
438 if(flags & ET_PASSWORD) printf("(password)");
439 if(flags & ET_READONLY) printf("(readonly)");
441 if(flags & (ET_X1 | ET_X3 ))
443 printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
446 while(tag->data[tag->pos++]);
447 if(flags & ET_HASTEXT)
448 // printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
451 void printhandlerflags(U32 handlerflags)
453 if(handlerflags&1) printf("[on load]");
454 if(handlerflags&2) printf("[enter frame]");
455 if(handlerflags&4) printf("[unload]");
456 if(handlerflags&8) printf("[mouse move]");
457 if(handlerflags&16) printf("[mouse down]");
458 if(handlerflags&32) printf("[mouse up]");
459 if(handlerflags&64) printf("[key down]");
460 if(handlerflags&128) printf("[key up]");
462 if(handlerflags&256) printf("[data]");
463 if(handlerflags&512) printf("[initialize]");
464 if(handlerflags&1024) printf("[mouse press]");
465 if(handlerflags&2048) printf("[mouse release]");
466 if(handlerflags&4096) printf("[mouse release outside]");
467 if(handlerflags&8192) printf("[mouse rollover]");
468 if(handlerflags&16384) printf("[mouse rollout]");
469 if(handlerflags&32768) printf("[mouse drag over]");
471 if(handlerflags&0x10000) printf("[mouse drag out]");
472 if(handlerflags&0x20000) printf("[key press]");
473 if(handlerflags&0x40000) printf("[construct even]");
474 if(handlerflags&0xfff80000) printf("[???]");
476 void handleVideoStream(TAG*tag, char*prefix)
478 U16 id = swf_GetU16(tag);
479 U16 frames = swf_GetU16(tag);
480 U16 width = swf_GetU16(tag);
481 U16 height = swf_GetU16(tag);
482 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
483 U8 codec = swf_GetU8(tag);
484 printf(" (%d frames, %dx%d", frames, width, height);
488 printf(" sorenson h.263)");
490 printf(" codec 0x%02x)", codec);
492 void handleVideoFrame(TAG*tag, char*prefix)
494 U32 code, version, reference, sizeflags;
495 U32 width=0, height=0;
497 U16 id = swf_GetU16(tag);
498 U16 frame = swf_GetU16(tag);
499 U8 deblock,flags, tmp, bit;
501 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
502 printf(" (frame %d) ", frame);
504 /* video packet follows */
505 code = swf_GetBits(tag, 17);
506 version = swf_GetBits(tag, 5);
507 reference = swf_GetBits(tag, 8);
509 sizeflags = swf_GetBits(tag, 3);
512 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
513 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
514 case 2: width = 352; height = 288; break;
515 case 3: width = 176; height = 144; break;
516 case 4: width = 128; height = 96; break;
517 case 5: width = 320; height = 240; break;
518 case 6: width = 160; height = 120; break;
519 case 7: width = -1; height = -1;/*reserved*/ break;
521 printf("%dx%d ", width, height);
522 type = swf_GetBits(tag, 2);
523 printf("%s", types[type]);
525 deblock = swf_GetBits(tag, 1);
527 printf(" deblock ", deblock);
528 quantizer = swf_GetBits(tag, 5);
529 printf(" quant: %d ", quantizer);
532 void dumpFilter(FILTER*filter)
534 if(filter->type == FILTERTYPE_BLUR) {
535 FILTER_BLUR*f = (FILTER_BLUR*)filter;
536 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
537 printf("passes: %d\n", f->passes);
538 } if(filter->type == FILTERTYPE_DROPSHADOW) {
539 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
540 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
541 printf("passes: %d\n", f->passes);
542 printf("angle: %f distance: %f\n", f->angle, f->distance);
543 printf("strength: %f passes: %d\n", f->strength, f->passes);
544 printf("flags: %s%s%s\n",
545 f->knockout?"knockout ":"",
546 f->composite?"composite ":"",
547 f->innershadow?"innershadow ":"");
548 } if(filter->type == FILTERTYPE_BEVEL) {
549 FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
550 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
551 printf("passes: %d\n", f->passes);
552 printf("angle: %f distance: %f\n", f->angle, f->distance);
553 printf("strength: %f passes: %d\n", f->strength, f->passes);
554 printf("flags: %s%s%s%s\n",
556 f->knockout?"knockout ":"",
557 f->composite?"composite ":"",
558 f->innershadow?"innershadow ":"");
559 } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
560 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
561 swf_DumpGradient(stdout, f->gradient);
562 printf("blurx: %f blury: %f\n", f->blurx, f->blury);
563 printf("angle: %f distance: %f\n", f->angle, f->distance);
564 printf("strength: %f passes: %d\n", f->strength, f->passes);
565 printf("flags: %s%s%s%s\n",
566 f->knockout?"knockout ":"",
567 f->ontop?"ontop ":"",
568 f->composite?"composite ":"",
569 f->innershadow?"innershadow ":"");
574 void handlePlaceObject23(TAG*tag, char*prefix)
580 int ppos[3] = {0,0,0};
581 swf_SetTagPos(tag, 0);
582 flags = swf_GetU8(tag);
583 if(tag->id == ST_PLACEOBJECT3)
584 flags2 = swf_GetU8(tag);
585 swf_GetU16(tag); //depth
588 if(flags&2) swf_GetU16(tag); //id
590 swf_GetMatrix(tag,&m);
592 ppos[0] += sprintf(pstr[0], "| Matrix ");
593 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
594 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
598 swf_GetCXForm(tag, &cx, 1);
600 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
601 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);
602 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
606 U16 ratio = swf_GetU16(tag); //ratio
608 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
609 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
610 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
614 U16 clip = swf_GetU16(tag); //clip
616 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
617 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
618 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
621 if(flags&32) { while(swf_GetU8(tag)); }
623 if(flags2&1) { // filter list
624 U8 num = swf_GetU8(tag);
626 printf("\n%d filters\n", num);
627 char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
630 FILTER*filter = swf_GetFilter(tag);
636 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
641 if(flags2&2) { // blend mode
642 U8 blendmode = swf_GetU8(tag);
646 sprintf(name, "%-5d", blendmode);
647 for(t=0;blendModeNames[t];t++) {
649 sprintf(name, "%-5s", blendModeNames[t]);
653 ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
654 ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
655 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
659 if(placements && ppos[0]) {
661 printf("%s %s\n", prefix, pstr[0]);
662 printf("%s %s\n", prefix, pstr[1]);
663 printf("%s %s", prefix, pstr[2]);
672 reserved = swf_GetU16(tag); // must be 0
673 globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
675 printf("Unknown parameter field not zero: %04x\n", reserved);
678 printf("global flags: %04x\n", globalflags);
680 handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
682 handlerflags = swf_GetU32(tag);
685 while(handlerflags) {
690 globalflags &= ~handlerflags;
691 printf("%s flags %08x ",prefix, handlerflags);
692 printhandlerflags(handlerflags);
693 length = swf_GetU32(tag);
694 printf(", %d bytes actioncode\n",length);
695 a = swf_ActionGet(tag);
696 swf_DumpActions(a,prefix);
699 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
701 if(globalflags) // should go to sterr.
702 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
704 printf(" has action code\n");
709 void handlePlaceObject(TAG*tag, char*prefix)
711 TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
716 swf_SetTagPos(tag, 0);
717 id = swf_GetU16(tag);
718 depth = swf_GetU16(tag);
719 swf_GetMatrix(tag, &matrix);
720 swf_GetCXForm(tag, &cxform, 0);
722 swf_SetU8(tag2, 14 /* char, matrix, cxform */);
723 swf_SetU16(tag2, depth);
724 swf_SetU16(tag2, id);
725 swf_SetMatrix(tag2, &matrix);
726 swf_SetCXForm(tag2, &cxform, 1);
728 handlePlaceObject23(tag2, prefix);
731 char* fillstyle2str(FILLSTYLE*style)
733 switch(style->type) {
735 sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
737 case 0x10: case 0x11: case 0x12: case 0x13:
738 sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
740 case 0x40: case 0x42:
741 /* TODO: display information about that bitmap */
742 sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
743 /* TODO: show matrix */
745 case 0x41: case 0x43:
746 /* TODO: display information about that bitmap */
747 sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
748 /* TODO: show matrix */
751 sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
755 char* linestyle2str(LINESTYLE*style)
757 sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
761 void handleShape(TAG*tag, char*prefix)
769 swf_ParseDefineShape(tag, &shape);
771 max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
773 if(max) printf("%s | fillstyles(%02d) linestyles(%02d)\n",
778 else printf("%s | (Neither line nor fill styles)\n", prefix);
781 printf("%s", prefix);
782 if(t < shape.numfillstyles) {
783 printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
787 if(t < shape.numlinestyles) {
788 printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
793 printf("%s |\n", prefix);
797 printf("%s | fill: %02d/%02d line:%02d - ",
802 if(line->type == moveTo) {
803 printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
804 } else if(line->type == lineTo) {
805 printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
806 } else if(line->type == splineTo) {
807 printf("splineTo (%.2f %.2f) %.2f %.2f\n",
808 line->sx/20.0, line->sy/20.0,
809 line->x/20.0, line->y/20.0
814 printf("%s |\n", prefix);
817 void fontcallback1(void*self, U16 id,U8 * name)
821 void fontcallback2(void*self, U16 id,U8 * name)
823 swf_FontExtract(&swf,id,&fonts[fontnum]);
827 static U8 printable(U8 a)
829 if(a<32 || a==127) return '.';
832 void hexdumpTag(TAG*tag, char* prefix)
836 printf(" %s-=> ",prefix);
837 for(t=0;t<tag->len;t++) {
838 printf("%02x ", tag->data[t]);
839 ascii[t&15] = printable(tag->data[t]);
840 if((t && ((t&15)==15)) || (t==tag->len-1))
844 for(s=p-1;s<16;s++) {
848 printf(" %s\n", ascii);
850 printf(" %s\n %s-=> ",ascii,prefix);
855 void handleExportAssets(TAG*tag, char* prefix)
861 num = swf_GetU16(tag);
864 id = swf_GetU16(tag);
865 name = swf_GetString(tag);
866 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
870 void dumperror(const char* format, ...)
875 va_start(arglist, format);
876 vsprintf(buf, format, arglist);
880 printf("==== Error: %s ====\n", buf);
883 static char strbuf[800];
886 char* timestring(double f)
888 int hours = (int)(f/3600);
889 int minutes = (int)((f-hours*3600)/60);
890 int seconds = (int)((f-hours*3600-minutes*60));
891 int useconds = (int)((f-(int)f)*1000+0.5);
894 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
895 return &strbuf[bufpos];
898 int main (int argc,char ** argv)
906 char issprite = 0; // are we inside a sprite definition?
909 char* spriteframelabel = 0;
910 char* framelabel = 0;
915 memset(idtab,0,65536);
917 processargs(argc, argv);
921 fprintf(stderr, "You must supply a filename.\n");
925 f = open(filename,O_RDONLY|O_BINARY);
930 sprintf(buffer, "Couldn't open %s", filename);
934 if FAILED(swf_ReadSWF(f,&swf))
936 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
943 if(statbuf.st_size != swf.fileSize && !swf.compressed)
944 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
945 statbuf.st_size, swf.fileSize);
946 filesize = statbuf.st_size;
951 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
952 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
956 printf("-X %d", xsize);
962 printf("-Y %d", ysize);
968 printf("-r %.2f", swf.frameRate/256.0);
974 printf("-f %d", swf.frameCount);
981 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
982 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
983 if(swf.fileVersion>9) {
984 fprintf(stderr, "Fileversion>9\n");
989 printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
990 "<param name=\"movie\" value=\"%s\"/>\n"
991 "<param name=\"play\" value=\"true\"/>\n"
992 "<param name=\"loop\" value=\"false\"/>\n"
993 "<param name=\"quality\" value=\"high\"/>\n"
994 "<param name=\"loop\" value=\"false\"/>\n"
995 "</object>\n\n", filename, xsize, ysize, filename);
997 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
999 //" BGCOLOR=#ffffffff\n"?
1001 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1002 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1003 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1004 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
1005 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1006 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1007 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1008 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1009 " TYPE=\"application/x-shockwave-flash\"\n"
1010 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1012 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
1013 filename, filename, xsize, ysize);
1017 printf("[HEADER] File version: %d\n", swf.fileVersion);
1018 if(swf.compressed) {
1019 printf("[HEADER] File is zlib compressed.");
1020 if(filesize && swf.fileSize)
1021 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1025 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1026 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
1027 printf("[HEADER] Frame count: %d\n",swf.frameCount);
1028 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1029 if(swf.movieSize.xmin)
1030 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1033 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1034 if(swf.movieSize.ymin)
1035 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1043 swf_FontEnumerate(&swf,&fontcallback1, 0);
1044 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1046 swf_FontEnumerate(&swf,&fontcallback2, 0);
1050 char*name = swf_TagGetName(tag);
1053 dumperror("Unknown tag:0x%03x", tag->id);
1058 name = "UNKNOWN TAG";
1061 filepos += tag->len;
1062 printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1064 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1067 if(swf_isDefiningTag(tag)) {
1068 U16 id = swf_GetDefineID(tag);
1069 printf(" defines id %04d", id);
1071 dumperror("Id %04d is defined more than once.", id);
1074 else if(swf_isPseudoDefiningTag(tag)) {
1075 U16 id = swf_GetDefineID(tag);
1076 printf(" adds information to id %04d", id);
1078 dumperror("Id %04d is not yet defined.\n", id);
1080 else if(tag->id == ST_PLACEOBJECT) {
1081 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1082 if(swf_GetName(tag))
1083 printf(" name \"%s\"",swf_GetName(tag));
1085 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1092 printf(" id %04d",swf_GetPlaceID(tag));
1096 printf(" at depth %04d", swf_GetDepth(tag));
1098 if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1099 printf(" as bitmap");
1101 swf_SetTagPos(tag, 0);
1102 if(tag->data[0]&64) {
1104 swf_GetPlaceObject(tag, &po);
1105 printf(" (clip to %04d)", po.clipdepth);
1106 swf_PlaceObjectFree(&po);
1108 if(swf_GetName(tag))
1109 printf(" name \"%s\"",swf_GetName(tag));
1112 else if(tag->id == ST_REMOVEOBJECT) {
1113 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1115 else if(tag->id == ST_REMOVEOBJECT2) {
1116 printf(" removes object from depth %04d", swf_GetDepth(tag));
1118 else if(tag->id == ST_FREECHARACTER) {
1119 printf(" frees object %04d", swf_GetPlaceID(tag));
1121 else if(tag->id == ST_STARTSOUND) {
1124 id = swf_GetU16(tag);
1125 flags = swf_GetU8(tag);
1127 printf(" stops sound with id %04d", id);
1129 printf(" starts sound with id %04d", id);
1131 printf(" (if not already playing)");
1137 printf(" looping %d times", swf_GetU16(tag));
1140 else if(tag->id == ST_FRAMELABEL) {
1141 int l = strlen(tag->data);
1142 printf(" \"%s\"", tag->data);
1143 if((l+1) < tag->len) {
1144 printf(" has %d extra bytes", tag->len-1-l);
1145 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1146 printf(" (ANCHOR)");
1148 if((framelabel && !issprite) ||
1149 (spriteframelabel && issprite)) {
1150 dumperror("Frame %d has more than one label",
1151 issprite?spriteframe:mainframe);
1153 if(issprite) spriteframelabel = tag->data;
1154 else framelabel = tag->data;
1156 else if(tag->id == ST_SHOWFRAME) {
1157 char*label = issprite?spriteframelabel:framelabel;
1158 int frame = issprite?spriteframe:mainframe;
1161 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1163 if(issprite) spriteframe++;
1169 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1171 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1172 timestring(frame*(256.0/(swf.frameRate+0.1))),
1173 timestring(nframe*(256.0/(swf.frameRate+0.1)))
1176 printf(" (label \"%s\")", label);
1177 if(issprite) {spriteframe++; spriteframelabel = 0;}
1178 if(!issprite) {mainframe++; framelabel = 0;}
1181 if(tag->id == ST_SETBACKGROUNDCOLOR) {
1182 U8 r = swf_GetU8(tag);
1183 U8 g = swf_GetU8(tag);
1184 U8 b = swf_GetU8(tag);
1185 printf(" (%02x/%02x/%02x)\n",r,g,b);
1187 else if(tag->id == ST_PROTECT) {
1189 printf(" %s\n", swf_GetString(tag));
1194 else if(tag->id == ST_CSMTEXTSETTINGS) {
1195 U16 id = swf_GetU16(tag);
1196 U8 flags = swf_GetU8(tag);
1199 printf("flashtype,");
1201 switch(((flags>>3)&7)) {
1202 case 0:printf("no grid,");break;
1203 case 1:printf("pixel grid,");break;
1204 case 2:printf("subpixel grid,");break;
1205 case 3:printf("unknown grid,");break;
1208 printf("unknown[%08x],", flags);
1209 float thickness = swf_GetFixed(tag);
1210 float sharpness = swf_GetFixed(tag);
1211 printf("s=%.2f,t=%.2f)\n", thickness, sharpness);
1214 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1215 tag->id == ST_DEFINEBITSLOSSLESS2) {
1216 handleDefineBits(tag);
1219 else if(tag->id == ST_DEFINESOUND) {
1220 handleDefineSound(tag);
1223 else if(tag->id == ST_VIDEOFRAME) {
1224 handleVideoFrame(tag, myprefix);
1227 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1228 handleVideoStream(tag, myprefix);
1231 else if(tag->id == ST_DEFINEEDITTEXT) {
1232 handleEditText(tag);
1235 else if(tag->id == ST_DEFINEMOVIE) {
1236 U16 id = swf_GetU16(tag);
1237 char*s = swf_GetString(tag);
1238 printf(" URL: %s\n", s);
1240 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1246 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1248 else if(tag->id == ST_NAMECHARACTER) {
1250 printf(" \"%s\"\n", swf_GetString(tag));
1256 if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1257 SRECT r = swf_GetDefineBBox(tag);
1258 printf(" %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1265 sprintf(myprefix, " %s", prefix);
1267 if(tag->id == ST_DEFINESPRITE) {
1268 sprintf(prefix, " ");
1270 dumperror("Sprite definition inside a sprite definition");
1274 spriteframelabel = 0;
1276 else if(tag->id == ST_END) {
1279 spriteframelabel = 0;
1281 dumperror("End Tag not empty");
1283 else if(tag->id == ST_EXPORTASSETS) {
1284 handleExportAssets(tag, myprefix);
1286 else if(tag->id == ST_DOACTION && action) {
1288 actions = swf_ActionGet(tag);
1289 swf_DumpActions(actions, myprefix);
1291 else if(tag->id == ST_DOINITACTION && action) {
1293 swf_GetU16(tag); // id
1294 actions = swf_ActionGet(tag);
1295 swf_DumpActions(actions, myprefix);
1297 else if(tag->id == ST_DEFINEBUTTON && action) {
1298 dumpButtonActions(tag, myprefix);
1300 else if(swf_isFontTag(tag) && showfonts) {
1301 dumpFont(tag, myprefix);
1303 else if(tag->id == ST_DEFINEBUTTON2 && action) {
1304 dumpButton2Actions(tag, myprefix);
1306 else if(tag->id == ST_PLACEOBJECT) {
1307 handlePlaceObject(tag, myprefix);
1309 else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1310 handlePlaceObject23(tag, myprefix);
1312 else if(tag->id == ST_DEFINESHAPE ||
1313 tag->id == ST_DEFINESHAPE2 ||
1314 tag->id == ST_DEFINESHAPE3 ||
1315 tag->id == ST_DEFINESHAPE4) {
1317 handleShape(tag, myprefix);
1320 if(tag->len && used) {
1321 int num = swf_GetNumUsedIDs(tag);
1325 used = (int*)malloc(sizeof(int)*num);
1326 swf_GetUsedIDs(tag, used);
1327 printf("%s%suses IDs: ", indent, prefix);
1328 for(t=0;t<num;t++) {
1330 swf_SetTagPos(tag, used[t]);
1331 id = swf_GetU16(tag);
1332 printf("%d%s", id, t<num-1?", ":"");
1334 dumperror("Id %04d is not yet defined.\n", id);
1341 if(tag->id == ST_FREECHARACTER) {
1343 swf_SetTagPos(tag, 0);
1344 id = swf_GetU16(tag);
1348 if(tag->len && hex) {
1349 hexdumpTag(tag, prefix);