font fix
[swftools.git] / src / swfdump.c
1 /* swfdump.c
2    Shows the structure of a swf file
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
7
8    This file is distributed under the GPL, see file COPYING for details */
9
10 #include "../config.h"
11
12 #ifdef HAVE_SYS_STAT_H
13 #include <sys/stat.h>
14 #else
15 #undef HAVE_STAT
16 #endif
17
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #else
21 #undef HAVE_STAT
22 #endif
23
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <stdarg.h>
28 #include "../lib/rfxswf.h"
29 #include "../lib/args.h"
30
31 static char * filename = 0;
32
33 /* idtab stores the ids which are defined in the file. This allows us
34    to detect errors in the file. (i.e. ids which are defined more than 
35    once */
36 static char idtab[65536];
37 static char * indent = "                ";
38
39 static int placements = 0;
40 static int action = 0;
41 static int html = 0;
42 static int xy = 0;
43 static int showtext = 0;
44 static int hex = 0;
45 static int used = 0;
46
47 struct options_t options[] =
48 {
49  {"D","full"},
50  {"a","action"},
51  {"t","text"},
52  {"X","width"},
53  {"Y","height"},
54  {"f","frames"},
55  {"r","rate"},
56  {"e","html"},
57  {"p","placements"},
58  {"u","used"},
59  {"v","verbose"},
60  {"V","version"},
61  {"d","hex"},
62  {0,0}
63 };
64
65
66 int args_callback_option(char*name,char*val)
67 {
68     if(!strcmp(name, "V")) {
69         printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
70         exit(0);
71     } 
72     else if(name[0]=='a') {
73         action = 1;
74         return 0;
75     }
76     else if(name[0]=='p') {
77         placements = 1;
78         return 0;
79     }
80     else if(name[0]=='t') {
81         showtext = 1;
82         return 0;
83     }
84     else if(name[0]=='e') {
85         html = 1;
86         return 0;
87     }
88     else if(name[0]=='X') {
89         xy |= 1;
90         return 0;
91     }
92     else if(name[0]=='Y') {
93         xy |= 2;
94         return 0;
95     }
96     else if(name[0]=='r') {
97         xy |= 4;
98         return 0;
99     }
100     else if(name[0]=='f') {
101         xy |= 8;
102         return 0;
103     }
104     else if(name[0]=='d') {
105         hex = 1;
106         return 0;
107     }
108     else if(name[0]=='u') {
109         used = 1;
110         return 0;
111     }
112     else if(name[0]=='D') {
113         action = placements = showtext = 1;
114         return 0;
115     }
116     else {
117         printf("Unknown option: -%s\n", name);
118         exit(1);
119     }
120
121     return 0;
122 }
123 int args_callback_longoption(char*name,char*val)
124 {
125     return args_long2shortoption(options, name, val);
126 }
127 void args_callback_usage(char*name)
128 {    
129     printf("Usage: %s [-at] file.swf\n", name);
130     printf("\t-h , --help\t\t Print help and exit\n");
131     printf("\t-D , --full\t\t Show everything. The same as -atp\n");
132     printf("\t-e , --html\t\t Create html output embedding the file (simple, but useful)\n");
133     printf("\t-X , --width\t\t Prints out a string of the form \"-X width\"\n");
134     printf("\t-Y , --height\t\t Prints out a string of the form \"-Y height\"\n");
135     printf("\t-r , --rate\t\t Prints out a string of the form \"-r rate\"\n");
136     printf("\t-f , --frames\t\t Prints out a string of the form \"-f framenum\"\n");
137     printf("\t-a , --action\t\t Disassemble action tags\n");
138     printf("\t-p , --placements\t\t Show extra placement information\n");
139     printf("\t-t , --text\t\t Show text data\n");
140     printf("\t-d , --hex\t\t Print hex output of tag data, too\n");
141     printf("\t-u , --used\t\t Show referred IDs for each Tag\n");
142     printf("\t-V , --version\t\t Print program version and exit\n");
143 }
144 int args_callback_command(char*name,char*val)
145 {
146     if(filename) {
147         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
148                  filename, name);
149     }
150     filename = name;
151     return 0;
152 }
153
154 char* what;
155 char* testfunc(char*str)
156 {
157     printf("%s: %s\n", what, str);
158     return 0;
159 }
160
161 void dumpButton2Actions(TAG*tag, char*prefix)
162 {
163     U32 oldTagPos;
164     U32 offsetpos;
165     U32 condition;
166
167     oldTagPos = swf_GetTagPos(tag);
168
169     // scan DefineButton2 Record
170     
171     swf_GetU16(tag);          // Character ID
172     swf_GetU8(tag);           // Flags;
173
174     offsetpos = swf_GetTagPos(tag);  // first offset
175     swf_GetU16(tag);
176
177     while (swf_GetU8(tag))      // state  -> parse ButtonRecord
178     { swf_GetU16(tag);          // id
179       swf_GetU16(tag);          // layer
180       swf_GetMatrix(tag,NULL);  // matrix
181       swf_GetCXForm(tag,NULL,1);  // cxform
182     }
183
184     while(offsetpos)
185     { U8 a;
186       ActionTAG*actions;
187
188       if(tag->pos >= tag->len)
189           break;
190         
191       offsetpos = swf_GetU16(tag);
192       condition = swf_GetU16(tag);                // condition
193       
194       actions = swf_ActionGet(tag);
195       printf("%s condition %04x\n", prefix, condition);
196       swf_DumpActions(actions, prefix);
197     }
198     
199     swf_SetTagPos(tag,oldTagPos);
200     return;
201 }
202
203 void dumpButtonActions(TAG*tag, char*prefix)
204 {
205     ActionTAG*actions;
206     swf_GetU16(tag); // id
207     while (swf_GetU8(tag))      // state  -> parse ButtonRecord
208     { swf_GetU16(tag);          // id
209       swf_GetU16(tag);          // layer
210       swf_GetMatrix(tag,NULL);  // matrix
211     }
212     actions = swf_ActionGet(tag);
213     swf_DumpActions(actions, prefix);
214 }
215
216 #define ET_HASTEXT 32768
217 #define ET_WORDWRAP 16384
218 #define ET_MULTILINE 8192
219 #define ET_PASSWORD 4096
220 #define ET_READONLY 2048
221 #define ET_HASTEXTCOLOR 1024
222 #define ET_HASMAXLENGTH 512
223 #define ET_HASFONT 256
224 #define ET_X3 128
225 #define ET_X2 64
226 #define ET_HASLAYOUT 32
227 #define ET_NOSELECT 16
228 #define ET_BORDER 8
229 #define ET_X1 4
230 #define ET_X0 2
231 #define ET_USEOUTLINES 1
232
233 SWF swf;
234 int fontnum = 0;
235 SWFFONT**fonts;
236
237 void textcallback(int*glyphs, int nr, int fontid) 
238 {
239     int font=-1,t;
240     printf("                <%2d glyphs in font %2d> ",nr, fontid);
241     for(t=0;t<fontnum;t++)
242     {
243         if(fonts[t]->id == fontid) {
244             font = t;
245             break;
246         }
247     }
248
249     for(t=0;t<nr;t++)
250     {
251         unsigned char a; 
252         if(font>=0) {
253             if(glyphs[t] >= fonts[font]->numchars  /*glyph is in range*/
254                     || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
255               )
256                 continue;
257             a = fonts[font]->glyph2ascii[glyphs[t]];
258         } else {
259             a = glyphs[t];
260         }
261         if(a>=32)
262             printf("%c", a);
263         else
264             printf("\\x%x", (int)a);
265     }
266     printf("\n");
267 }
268
269 void handleText(TAG*tag) 
270 {
271   printf("\n");
272   swf_FontExtract_DefineTextCallback(-1,0,tag,4, textcallback);
273 }
274             
275 void handleDefineSound(TAG*tag)
276 {
277     U16 id = swf_GetU16(tag);
278     U8 flags = swf_GetU8(tag);
279     int compression = (flags>>4)&3;
280     int rate = (flags>>2)&3;
281     int bits = flags&2?16:8;
282     int stereo = flags&1;
283     printf(" (");
284     if(compression == 0) printf("Raw ");
285     else if(compression == 1) printf("ADPCM ");
286     else if(compression == 2) printf("MP3 ");
287     else printf("? ");
288     if(rate == 0) printf("5.5Khz ");
289     if(rate == 1) printf("11Khz ");
290     if(rate == 2) printf("22Khz ");
291     if(rate == 3) printf("44Khz ");
292     printf("%dBit ", bits);
293     if(stereo) printf("stereo");
294     else printf("mono");
295     printf(")");
296 }
297
298 void handleDefineBits(TAG*tag)
299 {
300     U16 id;
301     U8 mode;
302     U16 width,height;
303     int bpp;
304     id = swf_GetU16(tag);
305     mode = swf_GetU8(tag);
306     width = swf_GetU16(tag);
307     height = swf_GetU16(tag);
308     printf(" image %dx%d",width,height);
309     if(mode == 3) printf(" (8 bpp)");
310     else if(mode == 4) printf(" (16 bpp)");
311     else if(mode == 5) printf(" (32 bpp)");
312     else printf(" (? bpp)");
313 }
314
315 void handleEditText(TAG*tag)
316 {
317     U16 id ;
318     U16 flags;
319     int t;
320     id = swf_GetU16(tag);
321     swf_GetRect(tag,0);
322     //swf_ResetReadBits(tag);
323     if (tag->readBit)  
324     { tag->pos++; 
325       tag->readBit = 0; 
326     }
327     flags = swf_GetBits(tag,16);
328     if(flags & ET_HASFONT) {
329         swf_GetU16(tag); //font
330         swf_GetU16(tag); //fontheight
331     }
332     if(flags & ET_HASTEXTCOLOR) {
333         swf_GetU8(tag); //rgba
334         swf_GetU8(tag);
335         swf_GetU8(tag);
336         swf_GetU8(tag);
337     }
338     if(flags & ET_HASMAXLENGTH) {
339         swf_GetU16(tag); //maxlength
340     }
341     if(flags & ET_HASLAYOUT) {
342         swf_GetU8(tag); //align
343         swf_GetU16(tag); //left margin
344         swf_GetU16(tag); //right margin
345         swf_GetU16(tag); //indent
346         swf_GetU16(tag); //leading
347     }
348     printf(" variable \"%s\"", &tag->data[tag->pos]);
349
350     if(flags & (ET_X1 | ET_X2 | ET_X3 | ET_X0))
351     {
352         printf(" undefined flags: %d%d%d%d", 
353                 (flags&ET_X0?1:0),
354                 (flags&ET_X1?1:0),
355                 (flags&ET_X2?1:0),
356                 (flags&ET_X3?1:0));
357     }
358     
359     while(tag->data[tag->pos++]);
360     if(flags & ET_HASTEXT)
361    //  printf(" text \"%s\"\n", &tag->data[tag->pos])
362         ;
363 }
364 void printhandlerflags(U16 handlerflags) 
365 {
366     if(handlerflags&1) printf("[on load]");
367     if(handlerflags&2) printf("[enter frame]");
368     if(handlerflags&4) printf("[unload]");
369     if(handlerflags&8) printf("[mouse move]");
370     if(handlerflags&16) printf("[mouse down]");
371     if(handlerflags&32) printf("[mouse up]");
372     if(handlerflags&64) printf("[key down]");
373     if(handlerflags&128) printf("[key up]");
374     if(handlerflags&256) printf("[data]");
375     if(handlerflags&0xfe00) printf("[???]");
376 }
377 void handlePlaceObject2(TAG*tag, char*prefix)
378 {
379     U8 flags = swf_GetU8(tag);
380     MATRIX m;
381     CXFORM cx;
382     char pstr[3][160];
383     int ppos[3] = {0,0,0};
384     swf_GetU16(tag); //depth
385     //flags&1: move
386     if(flags&2) swf_GetU16(tag); //id
387     if(flags&4) {
388         swf_GetMatrix(tag,&m);
389         if(placements) {
390             ppos[0] += sprintf(pstr[0], "| Matrix             ");
391             ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
392             ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
393         }
394     }
395     if(flags&8) {
396         swf_GetCXForm(tag, &cx, 1);
397         if(placements) {
398             ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm    r    g    b    a ");
399             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);
400             ppos[2] += sprintf(pstr[2]+ppos[2], "| add    %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
401         }
402     }
403     if(flags&16) {
404         U16 ratio = swf_GetU16(tag); //ratio
405         if(placements) {
406             ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
407             ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
408             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
409         }
410     }
411     if(flags&64) {
412         U16 clip = swf_GetU16(tag); //clip
413         if(placements) {
414             ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip  ");
415             ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", clip);
416             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
417         }
418     }
419     if(flags&32) { while(swf_GetU8(tag)); }
420     if(placements && ppos[0]) {
421         printf("\n");
422         printf("%s %s\n", prefix, pstr[0]);
423         printf("%s %s\n", prefix, pstr[1]);
424         printf("%s %s", prefix, pstr[2]);
425     }
426     if(flags&128) {
427       if (action) {
428         U16 unknown;
429         U32 globalflags;
430         U32 handlerflags;
431         char is32 = 0;
432         printf("\n");
433         unknown = swf_GetU16(tag);
434         globalflags = swf_GetU16(tag);
435         if(unknown) {
436             printf("Unknown parameter field not zero: %04x\n", unknown);
437             return;
438         }
439         printf("global flags: %04x\n", globalflags);
440         handlerflags = swf_GetU16(tag);
441         if(!handlerflags) {
442             handlerflags = swf_GetU32(tag);
443             is32 = 1;
444         }
445         while(handlerflags)  {
446             int length;
447             int t;
448             ActionTAG*a;
449
450             globalflags &= ~handlerflags;
451             printf("%s flags %08x ",prefix, handlerflags);
452             printhandlerflags(handlerflags);
453             length = swf_GetU32(tag);
454             printf(", %d bytes actioncode\n",length);
455             a = swf_ActionGet(tag);
456             swf_DumpActions(a,prefix);
457             swf_ActionFree(a);
458
459             handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag);
460         }
461         if(globalflags) // should go to sterr.
462             printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
463     } else {
464       printf(" has action code\n");
465     }
466     } else printf("\n");
467 }
468
469 void handlePlaceObject(TAG*tag, char*prefix)
470 {
471     /*TODO*/
472 }
473     
474 void fontcallback1(U16 id,U8 * name)
475 { fontnum++;
476 }
477
478 void fontcallback2(U16 id,U8 * name)
479
480   swf_FontExtract(&swf,id,&fonts[fontnum]);
481   fontnum++;
482 }
483
484 void hexdumpTag(TAG*tag, char* prefix)
485 {
486     int t;
487     printf("                %s-=> ",prefix);
488     for(t=0;t<tag->len;t++) {
489         printf("%02x ", tag->data[t]);
490         if((t && ((t&15)==15)) || (t==tag->len-1))
491         {
492             if(t==tag->len-1)
493                 printf("\n");
494             else
495                 printf("\n                %s-=> ",prefix);
496         }
497     }
498 }
499
500 void handleExportAssets(TAG*tag, char* prefix)
501 {
502     int num;
503     U16 id;
504     char* name;
505     int t;
506     num = swf_GetU16(tag);
507     for(t=0;t<num;t++)
508     {
509         id = swf_GetU16(tag);
510         name = swf_GetString(tag);
511         printf("%sexports %04d as \"%s\"\n", prefix, id, name);
512     }
513 }
514
515 void dumperror(const char* format, ...)
516 {
517     char buf[1024];
518     va_list arglist;
519
520     va_start(arglist, format);
521     vsprintf(buf, format, arglist);
522     va_end(arglist);
523
524     if(!html && !xy)
525         printf("==== Error: %s ====\n", buf);
526 }
527
528 static char strbuf[800];
529 static int bufpos=0;
530
531 char* timestring(double f)
532 {
533     int hours   = (int)(f/3600);
534     int minutes = (int)((f-hours*3600)/60);
535     int seconds = (int)((f-hours*3600-minutes*60));
536     int useconds = (int)((f-(int)f)*1000+0.5);
537     bufpos+=100;
538     bufpos%=800;
539     sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
540     return &strbuf[bufpos];
541 }
542
543 int main (int argc,char ** argv)
544
545     TAG*tag;
546 #ifdef HAVE_STAT
547     struct stat statbuf;
548 #endif
549     int f;
550     int xsize,ysize;
551     char issprite = 0; // are we inside a sprite definition?
552     int spriteframe = 0;
553     int mainframe=0;
554     char* spriteframelabel = 0;
555     char* framelabel = 0;
556     char prefix[128];
557     int filesize = 0;
558     prefix[0] = 0;
559     memset(idtab,0,65536);
560
561     processargs(argc, argv);
562
563     if(!filename)
564     {
565         fprintf(stderr, "You must supply a filename.\n");
566         return 1;
567     }
568
569     f = open(filename,O_RDONLY);
570
571     if (f<0)
572     { 
573         perror("Couldn't open file: ");
574         exit(1);
575     }
576     if FAILED(swf_ReadSWF(f,&swf))
577     { 
578         fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
579         close(f);
580         exit(1);
581     }
582
583 #ifdef HAVE_STAT
584     fstat(f, &statbuf);
585     if(statbuf.st_size != swf.fileSize && !swf.compressed)
586         dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
587                 statbuf.st_size, swf.fileSize);
588     filesize = statbuf.st_size;
589 #endif
590
591     close(f);
592
593     xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
594     ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
595     if(xy)
596     {
597         if(xy&1)
598         printf("-X %d", xsize);
599
600         if((xy&1) && (xy&6))
601         printf(" ");
602
603         if(xy&2)
604         printf("-Y %d", ysize);
605         
606         if((xy&3) && (xy&4))
607         printf(" ");
608
609         if(xy&4)
610         printf("-r %d", swf.frameRate*100/256);
611         
612         if((xy&7) && (xy&8))
613         printf(" ");
614         
615         if(xy&8)
616         printf("-f %d", swf.frameCount);
617         
618         printf("\n");
619         return 0;
620     }
621     if(html)
622     {
623         char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
624                                "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0"};
625         if(swf.fileVersion>8) {
626             fprintf(stderr, "Fileversion>8\n");
627             exit(1);
628         }
629         printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
630                " WIDTH=\"%d\"\n"
631                //" BGCOLOR=#ffffffff\n"?
632                " HEIGHT=\"%d\"\n"
633                //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
634                " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
635                "  <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
636                "  <PARAM NAME=\"PLAY\" VALUE=\"true\">\n" 
637                "  <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
638                "  <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
639                "  <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
640                "   PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
641                "   TYPE=\"application/x-shockwave-flash\"\n"
642                "   PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
643                "  </EMBED>\n" 
644                "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion], 
645                               filename, filename, xsize, ysize);
646         return 0;
647     } 
648     printf("[HEADER]        File version: %d\n", swf.fileVersion);
649     if(swf.compressed) {
650         printf("[HEADER]        File is zlib compressed.");
651         if(filesize && swf.fileSize)
652             printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
653         else
654             printf("\n");
655     }
656     printf("[HEADER]        File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
657     printf("[HEADER]        Frame rate: %f\n",swf.frameRate/256.0);
658     printf("[HEADER]        Frame count: %d\n",swf.frameCount);
659     printf("[HEADER]        Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
660     if(swf.movieSize.xmin)
661         printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
662     else 
663         printf("\n");
664     printf("[HEADER]        Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
665     if(swf.movieSize.ymin)
666         printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
667     else 
668         printf("\n");
669
670     tag = swf.firstTag;
671    
672     if(showtext) {
673         fontnum = 0;
674         swf_FontEnumerate(&swf,&fontcallback1);
675         fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
676         fontnum = 0;
677         swf_FontEnumerate(&swf,&fontcallback2);
678     }
679
680     while(tag) {
681         char*name = swf_TagGetName(tag);
682         char myprefix[128];
683         if(!name) {
684             dumperror("Unknown tag:0x%03x", tag->id);
685             tag = tag->next;
686             continue;
687         }
688         printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
689         
690         if(tag->id == ST_FREECHARACTER) {
691             U16 id = swf_GetU16(tag);
692             idtab[id] = 0;
693         }
694
695         if(swf_isDefiningTag(tag)) {
696             U16 id = swf_GetDefineID(tag);
697             printf(" defines id %04d", id);
698             if(idtab[id])
699                 dumperror("Id %04d is defined more than once.", id);
700             idtab[id] = 1;
701         }
702         else if(swf_isPseudoDefiningTag(tag)) {
703             U16 id = swf_GetDefineID(tag);
704             printf(" adds information to id %04d", id);
705             if(!idtab[id])
706                 dumperror("Id %04d is not yet defined.\n", id);
707         }
708         else if(tag->id == ST_PLACEOBJECT) {
709             printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
710             if(swf_GetName(tag))
711                 printf(" name \"%s\"",swf_GetName(tag));
712             handlePlaceObject(tag, myprefix);
713         }
714         else if(tag->id == ST_PLACEOBJECT2) {
715             if(tag->data[0]&1)
716                 printf(" moves");
717             else
718                 printf(" places");
719             
720             if(tag->data[0]&2)
721                 printf(" id %04d",swf_GetPlaceID(tag));
722             else
723                 printf(" object");
724
725             printf(" at depth %04d", swf_GetDepth(tag));
726             if(swf_GetName(tag))
727                 printf(" name \"%s\"",swf_GetName(tag));
728         }
729         else if(tag->id == ST_REMOVEOBJECT) {
730             printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
731         }
732         else if(tag->id == ST_REMOVEOBJECT2) {
733             printf(" removes object from depth %04d", swf_GetDepth(tag));
734         }
735         else if(tag->id == ST_FREECHARACTER) {
736             printf(" frees object %04d", swf_GetPlaceID(tag));
737         }
738         else if(tag->id == ST_STARTSOUND) {
739             U8 flags;
740             U16 id;
741             id = swf_GetU16(tag);
742             flags = swf_GetU8(tag);
743             if(flags & 32)
744                 printf(" stops sound with id %04d", id);
745             else
746                 printf(" starts sound with id %04d", id);
747             if(flags & 16)
748                 printf(" (if not already playing)");
749             if(flags & 1)
750                 swf_GetU32(tag);
751             if(flags & 2)
752                 swf_GetU32(tag);
753             if(flags & 4) {
754                 printf(" looping %d times", swf_GetU16(tag));
755             }
756         }
757         else if(tag->id == ST_FRAMELABEL) {
758             int l = strlen(tag->data);
759             printf(" \"%s\"", tag->data);
760             if(l < tag->len-1) {
761                 printf(" has %d extra bytes", tag->len-1-l);
762                 if(tag ->len-1-l == 1 && tag->data[tag->len-1] == 1)
763                     printf(" (ANCHOR)");
764             }
765             if((framelabel && !issprite) ||
766                (spriteframelabel && issprite)) {
767                 dumperror("Frame %d has more than one label", 
768                         issprite?spriteframe:mainframe);
769             }
770             if(issprite) spriteframelabel = tag->data;
771             else framelabel = tag->data;
772         }
773         else if(tag->id == ST_SHOWFRAME) {
774             char*label = issprite?spriteframelabel:framelabel;
775             int frame = issprite?spriteframe:mainframe;
776             int nframe = frame;
777             if(!label) {
778                 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
779                     tag = tag->next;
780                     if(issprite) spriteframe++;
781                     else mainframe++;
782                     nframe++;
783                 }
784             }
785             if(nframe == frame)
786                 printf(" %d (%s)", frame, timestring(frame*(256.0/(swf.frameRate+0.1))));
787             else
788                 printf(" %d-%d (%s-%s)", frame, nframe,
789                         timestring(frame*(256.0/(swf.frameRate+0.1))),
790                         timestring(nframe*(256.0/(swf.frameRate+0.1)))
791                         );
792             if(label)
793                 printf(" (label \"%s\")", label);
794             if(issprite) {spriteframe++; spriteframelabel = 0;}
795             if(!issprite) {mainframe++; framelabel = 0;}
796         }
797
798         if(tag->id == ST_SETBACKGROUNDCOLOR) {
799             U8 r = swf_GetU8(tag);
800             U8 g = swf_GetU8(tag);
801             U8 b = swf_GetU8(tag);
802             printf(" (%02x/%02x/%02x)\n",r,g,b);
803         }
804         else if(tag->id == ST_DEFINEBITSLOSSLESS ||
805            tag->id == ST_DEFINEBITSLOSSLESS2) {
806             handleDefineBits(tag);
807             printf("\n");
808         }
809         else if(tag->id == ST_DEFINESOUND) {
810             handleDefineSound(tag);
811             printf("\n");
812         }
813         else if(tag->id == ST_DEFINEEDITTEXT) {
814             handleEditText(tag);
815             printf("\n");
816         }
817         else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
818             if(showtext)
819                 handleText(tag);
820             else
821                 printf("\n");
822         }
823         else if(tag->id == ST_PLACEOBJECT2) {
824         }
825         else if(tag->id == ST_NAMECHARACTER) {
826             swf_GetU16(tag);
827             printf(" \"%s\"\n", swf_GetString(tag));
828         }
829         else {
830             printf("\n");
831         }
832         
833         sprintf(myprefix, "                %s", prefix);
834
835         if(tag->id == ST_DEFINESPRITE) {
836             sprintf(prefix, "         ");
837             if(issprite) {
838                 dumperror("Sprite definition inside a sprite definition");
839             }
840             issprite = 1;
841             spriteframe = 0;
842             spriteframelabel = 0;
843         }
844         else if(tag->id == ST_END) {
845             *prefix = 0;
846             issprite = 0;
847             spriteframelabel = 0;
848             if(tag->len)
849                 dumperror("End Tag not empty");
850         }
851         else if(tag->id == ST_EXPORTASSETS) {
852             handleExportAssets(tag, myprefix);
853         }
854         else if(tag->id == ST_DOACTION && action) {
855             ActionTAG*actions;
856             actions = swf_ActionGet(tag);
857             swf_DumpActions(actions, myprefix);
858         }
859         else if(tag->id == ST_DEFINEBUTTON && action) {
860             dumpButtonActions(tag, myprefix);
861         }
862         else if(tag->id == ST_DEFINEBUTTON2 && action) {
863             dumpButton2Actions(tag, myprefix);
864         }
865         else if(tag->id == ST_PLACEOBJECT2) {
866             handlePlaceObject2(tag, myprefix);
867         }
868
869         if(tag->len && used) {
870             int num = swf_GetNumUsedIDs(tag);
871             int* used;
872             int t;
873             if(num) {
874                 used = (int*)malloc(sizeof(int)*num);
875                 swf_GetUsedIDs(tag, used);
876                 printf("%s%suses IDs: ", indent, prefix);
877                 for(t=0;t<num;t++) {
878                     swf_SetTagPos(tag, used[t]);
879                     printf("%d%s", swf_GetU16(tag), t<num-1?", ":"");
880                 }
881                 printf("\n");
882             }
883         }
884
885         if(tag->len && hex) {
886             hexdumpTag(tag, prefix);
887         }
888         tag = tag->next;
889         fflush(stdout);
890     }
891
892     swf_FreeTags(&swf);
893     return 0;
894 }
895
896