added -F option
[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 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.
12
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.
17
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 */
21
22 #include "../config.h"
23
24 #ifdef HAVE_SYS_STAT_H
25 #include <sys/stat.h>
26 #else
27 #undef HAVE_STAT
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #else
33 #undef HAVE_STAT
34 #endif
35
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <stdarg.h>
40 #include "../lib/rfxswf.h"
41 #include "../lib/args.h"
42
43 static char * filename = 0;
44
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 
47    once */
48 static char idtab[65536];
49 static char * indent = "                ";
50
51 static int placements = 0;
52 static int action = 0;
53 static int html = 0;
54 static int xhtml = 0;
55 static int xy = 0;
56 static int showtext = 0;
57 static int showshapes = 0;
58 static int hex = 0;
59 static int used = 0;
60 static int bbox = 0;
61 static int cumulative = 0;
62 static int showfonts = 0;
63
64 static struct options_t options[] = {
65 {"h", "help"},
66 {"D", "full"},
67 {"V", "version"},
68 {"e", "html"},
69 {"E", "xhtml"},
70 {"a", "action"},
71 {"t", "text"},
72 {"s", "shapes"},
73 {"p", "placements"},
74 {"b", "bbox"},
75 {"X", "width"},
76 {"Y", "height"},
77 {"r", "rate"},
78 {"f", "frames"},
79 {"d", "hex"},
80 {"u", "used"},
81 {0,0}
82 };
83
84 int args_callback_option(char*name,char*val)
85 {
86     if(!strcmp(name, "V")) {
87         printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
88         exit(0);
89     } 
90     else if(name[0]=='a') {
91         action = 1;
92         return 0;
93     }
94     else if(name[0]=='p') {
95         placements = 1;
96         return 0;
97     }
98     else if(name[0]=='t') {
99         showtext = 1;
100         return 0;
101     }
102     else if(name[0]=='s') {
103         showshapes = 1;
104         return 0;
105     }
106     else if(name[0]=='e') {
107         html = 1;
108         return 0;
109     }
110     else if(name[0]=='c') {
111         cumulative = 1;
112         return 0;
113     }
114     else if(name[0]=='E') {
115         html = 1;
116         xhtml = 1;
117         return 0;
118     }
119     else if(name[0]=='X') {
120         xy |= 1;
121         return 0;
122     }
123     else if(name[0]=='Y') {
124         xy |= 2;
125         return 0;
126     }
127     else if(name[0]=='r') {
128         xy |= 4;
129         return 0;
130     }
131     else if(name[0]=='f') {
132         xy |= 8;
133         return 0;
134     }
135     else if(name[0]=='F') {
136         showfonts = 1;
137         return 0;
138     }
139     else if(name[0]=='d') {
140         hex = 1;
141         return 0;
142     }
143     else if(name[0]=='u') {
144         used = 1;
145         return 0;
146     }
147     else if(name[0]=='b') {
148         bbox = 1;
149         return 0;
150     }
151     else if(name[0]=='D') {
152         action = placements = showtext = showshapes = 1;
153         return 0;
154     }
155     else {
156         printf("Unknown option: -%s\n", name);
157         exit(1);
158     }
159
160     return 0;
161 }
162 int args_callback_longoption(char*name,char*val)
163 {
164     return args_long2shortoption(options, name, val);
165 }
166 void args_callback_usage(char *name)
167 {
168     printf("\n");
169     printf("Usage: %s [-atpdu] file.swf\n", name);
170     printf("\n");
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");
187     printf("\n");
188 }
189 int args_callback_command(char*name,char*val)
190 {
191     if(filename) {
192         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
193                  filename, name);
194     }
195     filename = name;
196     return 0;
197 }
198
199 char* what;
200 char* testfunc(char*str)
201 {
202     printf("%s: %s\n", what, str);
203     return 0;
204 }
205
206 void dumpButton2Actions(TAG*tag, char*prefix)
207 {
208     U32 oldTagPos;
209     U32 offsetpos;
210     U32 condition;
211
212     oldTagPos = swf_GetTagPos(tag);
213
214     // scan DefineButton2 Record
215     
216     swf_GetU16(tag);          // Character ID
217     swf_GetU8(tag);           // Flags;
218
219     offsetpos = swf_GetTagPos(tag);  // first offset
220     swf_GetU16(tag);
221
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
227     }
228
229     while(offsetpos)
230     { U8 a;
231       ActionTAG*actions;
232
233       if(tag->pos >= tag->len)
234           break;
235         
236       offsetpos = swf_GetU16(tag);
237       condition = swf_GetU16(tag);                // condition
238       
239       actions = swf_ActionGet(tag);
240       printf("%s condition %04x\n", prefix, condition);
241       swf_DumpActions(actions, prefix);
242     }
243     
244     swf_SetTagPos(tag,oldTagPos);
245     return;
246 }
247
248 void dumpButtonActions(TAG*tag, char*prefix)
249 {
250     ActionTAG*actions;
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
256     }
257     actions = swf_ActionGet(tag);
258     swf_DumpActions(actions, prefix);
259 }
260
261 void dumpFont(TAG*tag, char*prefix)
262 {
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);
269     } else {
270         printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
271     }
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);
277     if(font->layout)
278     {
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);
283     }
284     printf("%sstyle: %d\n", prefix,font->style);
285     printf("%sencoding: %02x\n", prefix,font->encoding);
286     printf("%slanguage: %02x\n", prefix,font->language);
287     int t;
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;
292
293         while(line) {
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
302                         );
303             }
304             line = line->next;
305         }
306         swf_Shape2Free(shape);
307         free(shape);
308     }
309     swf_FontFree(font);
310 }
311
312 SWF swf;
313 int fontnum = 0;
314 SWFFONT**fonts;
315
316 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color) 
317 {
318     int font=-1,t;
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++)
321     {
322         if(fonts[t]->id == fontid) {
323             font = t;
324             break;
325         }
326     }
327
328     for(t=0;t<nr;t++)
329     {
330         unsigned char a; 
331         if(font>=0) {
332             if(glyphs[t] >= fonts[font]->numchars  /*glyph is in range*/
333                     || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
334               ) a = glyphs[t];
335             else {
336                 if(fonts[font]->glyph2ascii[glyphs[t]])
337                     a = fonts[font]->glyph2ascii[glyphs[t]];
338                 else
339                     a = glyphs[t];
340             }
341         } else {
342             a = glyphs[t];
343         }
344         if(a>=32)
345             printf("%c", a);
346         else
347             printf("\\x%x", (int)a);
348     }
349     printf("\n");
350 }
351
352 void handleText(TAG*tag) 
353 {
354   printf("\n");
355   swf_ParseDefineText(tag,textcallback, 0);
356 }
357             
358 void handleDefineSound(TAG*tag)
359 {
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;
366     printf(" (");
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 ");
372     else printf("? ");
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");
379     else printf("mono");
380     printf(")");
381 }
382
383 void handleDefineBits(TAG*tag)
384 {
385     U16 id;
386     U8 mode;
387     U16 width,height;
388     int bpp;
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)");
398 }
399
400 void handleEditText(TAG*tag)
401 {
402     U16 id ;
403     U16 flags;
404     int t;
405     id = swf_GetU16(tag);
406     swf_GetRect(tag,0);
407     
408     //swf_ResetReadBits(tag);
409
410     if (tag->readBit)  
411     { tag->pos++; 
412       tag->readBit = 0; 
413     }
414     flags = swf_GetBits(tag,16);
415     if(flags & ET_HASFONT) {
416         swf_GetU16(tag); //font
417         swf_GetU16(tag); //fontheight
418     }
419     if(flags & ET_HASTEXTCOLOR) {
420         swf_GetU8(tag); //rgba
421         swf_GetU8(tag);
422         swf_GetU8(tag);
423         swf_GetU8(tag);
424     }
425     if(flags & ET_HASMAXLENGTH) {
426         swf_GetU16(tag); //maxlength
427     }
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
434     }
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)");
440
441     if(flags & (ET_X1 | ET_X3 ))
442     {
443         printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
444     }
445     
446     while(tag->data[tag->pos++]);
447     if(flags & ET_HASTEXT)
448    //  printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
449         ;
450 }
451 void printhandlerflags(U32 handlerflags) 
452 {
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]");
461
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]");
470
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("[???]");
475 }
476 void handleVideoStream(TAG*tag, char*prefix)
477 {
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);
485     if(flags&1)
486         printf(" smoothed");
487     if(codec == 2)
488         printf(" sorenson h.263)");
489     else
490         printf(" codec 0x%02x)", codec);
491 }
492 void handleVideoFrame(TAG*tag, char*prefix)
493 {
494     U32 code, version, reference, sizeflags;
495     U32 width=0, height=0;
496     U8 type;
497     U16 id = swf_GetU16(tag);
498     U16 frame = swf_GetU16(tag);
499     U8 deblock,flags, tmp, bit;
500     U32 quantizer;
501     char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
502     printf(" (frame %d) ", frame);
503
504     /* video packet follows */
505     code = swf_GetBits(tag, 17);
506     version = swf_GetBits(tag, 5);
507     reference = swf_GetBits(tag, 8);
508
509     sizeflags = swf_GetBits(tag, 3);
510     switch(sizeflags)
511     {
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;
520     }
521     printf("%dx%d ", width, height);
522     type = swf_GetBits(tag, 2);
523     printf("%s", types[type]);
524
525     deblock = swf_GetBits(tag, 1);
526     if(deblock)
527         printf(" deblock ", deblock);
528     quantizer = swf_GetBits(tag, 5);
529     printf(" quant: %d ", quantizer);
530 }
531
532 void dumpFilter(FILTER*filter)
533 {
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", 
555                 f->ontop?"ontop":"",
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 ":"");
570     }
571     rfx_free(filter);
572 }
573
574 void handlePlaceObject23(TAG*tag, char*prefix)
575 {
576     U8 flags,flags2=0;
577     MATRIX m;
578     CXFORM cx;
579     char pstr[3][256];
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
586
587     //flags&1: move
588     if(flags&2) swf_GetU16(tag); //id
589     if(flags&4) {
590         swf_GetMatrix(tag,&m);
591         if(placements) {
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);
595         }
596     }
597     if(flags&8) {
598         swf_GetCXForm(tag, &cx, 1);
599         if(placements) {
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);
603         }
604     }
605     if(flags&16) {
606         U16 ratio = swf_GetU16(tag); //ratio
607         if(placements) {
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], "|       ");
611         }
612     }
613     if(flags&64) {
614         U16 clip = swf_GetU16(tag); //clip
615         if(placements) {
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], "|       ");
619         }
620     }
621     if(flags&32) { while(swf_GetU8(tag)); }
622
623     if(flags2&1) { // filter list
624         U8 num = swf_GetU8(tag);
625         if(placements)
626             printf("\n%d filters\n", num);
627         char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
628         int t;
629         for(t=0;t<num;t++) {
630             FILTER*filter = swf_GetFilter(tag);
631             if(!filter) {
632                 printf("\n"); 
633                 return;
634             }
635             if(placements) {
636                 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
637                 dumpFilter(filter);
638             }
639         }
640     }
641     if(flags2&2) { // blend mode
642         U8 blendmode = swf_GetU8(tag);
643         if(placements) {
644             int t;
645             char name[80];
646             sprintf(name, "%-5d", blendmode);
647             for(t=0;blendModeNames[t];t++) {
648                 if(blendmode==t) {
649                     sprintf(name, "%-5s", blendModeNames[t]);
650                     break;
651                 }
652             }
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], "|       ");
656         }
657     }
658
659     if(placements && ppos[0]) {
660         printf("\n");
661         printf("%s %s\n", prefix, pstr[0]);
662         printf("%s %s\n", prefix, pstr[1]);
663         printf("%s %s", prefix, pstr[2]);
664     }
665     if(flags&128) {
666       if (action) {
667         U16 reserved;
668         U32 globalflags;
669         U32 handlerflags;
670         char is32 = 0;
671         printf("\n");
672         reserved = swf_GetU16(tag); // must be 0
673         globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
674         if(reserved) {
675             printf("Unknown parameter field not zero: %04x\n", reserved);
676             return;
677         }
678         printf("global flags: %04x\n", globalflags);
679
680         handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
681         if(!handlerflags) {
682             handlerflags = swf_GetU32(tag);
683             is32 = 1;
684         }
685         while(handlerflags)  {
686             int length;
687             int t;
688             ActionTAG*a;
689
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);
697             swf_ActionFree(a);
698
699             handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
700         }
701         if(globalflags) // should go to sterr.
702             printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
703     } else {
704       printf(" has action code\n");
705     }
706     } else printf("\n");
707 }
708
709 void handlePlaceObject(TAG*tag, char*prefix)
710 {
711     TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
712     U16 id, depth;
713     MATRIX matrix; 
714     CXFORM cxform;
715
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);
721
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);
727
728     handlePlaceObject23(tag2, prefix);
729 }
730 char stylebuf[256];
731 char* fillstyle2str(FILLSTYLE*style)
732 {
733     switch(style->type) {
734         case 0x00:
735             sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
736             break;
737         case 0x10: case 0x11: case 0x12: case 0x13:
738             sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
739             break;
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 */
744             break;
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 */
749             break;
750         default:
751             sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
752     }
753     return stylebuf;
754 }
755 char* linestyle2str(LINESTYLE*style)
756 {
757     sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
758     return stylebuf;
759 }
760
761 void handleShape(TAG*tag, char*prefix)
762 {
763     SHAPE2 shape;
764     SHAPELINE*line;
765     int t,max;
766
767     tag->pos = 0;
768     tag->readBit = 0;
769     swf_ParseDefineShape(tag, &shape);
770
771     max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
772
773     if(max) printf("%s | fillstyles(%02d)        linestyles(%02d)\n", 
774             prefix,
775             shape.numfillstyles,
776             shape.numlinestyles
777             );
778     else    printf("%s | (Neither line nor fill styles)\n", prefix);
779
780     for(t=0;t<max;t++) {
781         printf("%s", prefix);
782         if(t < shape.numfillstyles) {
783             printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
784         } else {
785             printf("                         ");
786         }
787         if(t < shape.numlinestyles) {
788             printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
789         }
790         printf("\n");
791     }
792
793     printf("%s |\n", prefix);
794
795     line = shape.lines;
796     while(line) {
797         printf("%s | fill: %02d/%02d line:%02d - ",
798                 prefix, 
799                 line->fillstyle0,
800                 line->fillstyle1,
801                 line->linestyle);
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
810                     );
811         }
812         line = line->next;
813     }
814     printf("%s |\n", prefix);
815 }
816     
817 void fontcallback1(void*self, U16 id,U8 * name)
818 { fontnum++;
819 }
820
821 void fontcallback2(void*self, U16 id,U8 * name)
822
823   swf_FontExtract(&swf,id,&fonts[fontnum]);
824   fontnum++;
825 }
826
827 static U8 printable(U8 a)
828 {
829     if(a<32 || a==127) return '.';
830     else return a;
831 }
832 void hexdumpTag(TAG*tag, char* prefix)
833 {
834     int t;
835     char ascii[32];
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))
841         {
842             int s,p=((t)&15)+1;
843             ascii[p] = 0;
844             for(s=p-1;s<16;s++) {
845                 printf("   ");
846             }
847             if(t==tag->len-1)
848                 printf(" %s\n", ascii);
849             else
850                 printf(" %s\n                %s-=> ",ascii,prefix);
851         }
852     }
853 }
854
855 void handleExportAssets(TAG*tag, char* prefix)
856 {
857     int num;
858     U16 id;
859     char* name;
860     int t;
861     num = swf_GetU16(tag);
862     for(t=0;t<num;t++)
863     {
864         id = swf_GetU16(tag);
865         name = swf_GetString(tag);
866         printf("%sexports %04d as \"%s\"\n", prefix, id, name);
867     }
868 }
869
870 void dumperror(const char* format, ...)
871 {
872     char buf[1024];
873     va_list arglist;
874
875     va_start(arglist, format);
876     vsprintf(buf, format, arglist);
877     va_end(arglist);
878
879     if(!html && !xy)
880         printf("==== Error: %s ====\n", buf);
881 }
882
883 static char strbuf[800];
884 static int bufpos=0;
885
886 char* timestring(double f)
887 {
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);
892     bufpos+=100;
893     bufpos%=800;
894     sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
895     return &strbuf[bufpos];
896 }
897
898 int main (int argc,char ** argv)
899
900     TAG*tag;
901 #ifdef HAVE_STAT
902     struct stat statbuf;
903 #endif
904     int f;
905     int xsize,ysize;
906     char issprite = 0; // are we inside a sprite definition?
907     int spriteframe = 0;
908     int mainframe=0;
909     char* spriteframelabel = 0;
910     char* framelabel = 0;
911     char prefix[128];
912     int filesize = 0;
913     int filepos = 0;
914     prefix[0] = 0;
915     memset(idtab,0,65536);
916
917     processargs(argc, argv);
918
919     if(!filename)
920     {
921         fprintf(stderr, "You must supply a filename.\n");
922         return 1;
923     }
924
925     f = open(filename,O_RDONLY|O_BINARY);
926
927     if (f<0)
928     { 
929         char buffer[256];
930         sprintf(buffer, "Couldn't open %s", filename);
931         perror(buffer);
932         exit(1);
933     }
934     if FAILED(swf_ReadSWF(f,&swf))
935     { 
936         fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
937         close(f);
938         exit(1);
939     }
940
941 #ifdef HAVE_STAT
942     fstat(f, &statbuf);
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;
947 #endif
948
949     close(f);
950
951     xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
952     ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
953     if(xy)
954     {
955         if(xy&1)
956         printf("-X %d", xsize);
957
958         if((xy&1) && (xy&6))
959         printf(" ");
960
961         if(xy&2)
962         printf("-Y %d", ysize);
963         
964         if((xy&3) && (xy&4))
965         printf(" ");
966
967         if(xy&4)
968         printf("-r %.2f", swf.frameRate/256.0);
969         
970         if((xy&7) && (xy&8))
971         printf(" ");
972         
973         if(xy&8)
974         printf("-f %d", swf.frameCount);
975         
976         printf("\n");
977         return 0;
978     }
979     if(html)
980     {
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");
985             exit(1);
986         }
987
988         if(xhtml) {
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);
996         } else {
997             printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
998                    " WIDTH=\"%d\"\n"
999                    //" BGCOLOR=#ffffffff\n"?
1000                    " HEIGHT=\"%d\"\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"
1011                    "  </EMBED>\n" 
1012                    "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion], 
1013                                   filename, filename, xsize, ysize);
1014         }
1015         return 0;
1016     } 
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));
1022         else
1023             printf("\n");
1024     }
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);
1031     else 
1032         printf("\n");
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);
1036     else 
1037         printf("\n");
1038
1039     tag = swf.firstTag;
1040    
1041     if(showtext) {
1042         fontnum = 0;
1043         swf_FontEnumerate(&swf,&fontcallback1, 0);
1044         fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1045         fontnum = 0;
1046         swf_FontEnumerate(&swf,&fontcallback2, 0);
1047     }
1048
1049     while(tag) {
1050         char*name = swf_TagGetName(tag);
1051         char myprefix[128];
1052         if(!name) {
1053             dumperror("Unknown tag:0x%03x", tag->id);
1054             //tag = tag->next;
1055             //continue;
1056         }
1057         if(!name) {
1058             name = "UNKNOWN TAG";
1059         }
1060         if(cumulative) {
1061             filepos += tag->len;
1062             printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1063         } else {
1064             printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1065         }
1066         
1067         if(swf_isDefiningTag(tag)) {
1068             U16 id = swf_GetDefineID(tag);
1069             printf(" defines id %04d", id);
1070             if(idtab[id])
1071                 dumperror("Id %04d is defined more than once.", id);
1072             idtab[id] = 1;
1073         }
1074         else if(swf_isPseudoDefiningTag(tag)) {
1075             U16 id = swf_GetDefineID(tag);
1076             printf(" adds information to id %04d", id);
1077             if(!idtab[id])
1078                 dumperror("Id %04d is not yet defined.\n", id);
1079         }
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));
1084         }
1085         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1086             if(tag->data[0]&1)
1087                 printf(" moves");
1088             else
1089                 printf(" places");
1090             
1091             if(tag->data[0]&2)
1092                 printf(" id %04d",swf_GetPlaceID(tag));
1093             else
1094                 printf(" object");
1095
1096             printf(" at depth %04d", swf_GetDepth(tag));
1097
1098             if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1099                 printf(" as bitmap");
1100            
1101             swf_SetTagPos(tag, 0);
1102             if(tag->data[0]&64) {
1103                 SWFPLACEOBJECT po;
1104                 swf_GetPlaceObject(tag, &po);
1105                 printf(" (clip to %04d)", po.clipdepth);
1106                 swf_PlaceObjectFree(&po);
1107             }
1108             if(swf_GetName(tag))
1109                 printf(" name \"%s\"",swf_GetName(tag));
1110
1111         }
1112         else if(tag->id == ST_REMOVEOBJECT) {
1113             printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1114         }
1115         else if(tag->id == ST_REMOVEOBJECT2) {
1116             printf(" removes object from depth %04d", swf_GetDepth(tag));
1117         }
1118         else if(tag->id == ST_FREECHARACTER) {
1119             printf(" frees object %04d", swf_GetPlaceID(tag));
1120         }
1121         else if(tag->id == ST_STARTSOUND) {
1122             U8 flags;
1123             U16 id;
1124             id = swf_GetU16(tag);
1125             flags = swf_GetU8(tag);
1126             if(flags & 32)
1127                 printf(" stops sound with id %04d", id);
1128             else
1129                 printf(" starts sound with id %04d", id);
1130             if(flags & 16)
1131                 printf(" (if not already playing)");
1132             if(flags & 1)
1133                 swf_GetU32(tag);
1134             if(flags & 2)
1135                 swf_GetU32(tag);
1136             if(flags & 4) {
1137                 printf(" looping %d times", swf_GetU16(tag));
1138             }
1139         }
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)");
1147             }
1148             if((framelabel && !issprite) ||
1149                (spriteframelabel && issprite)) {
1150                 dumperror("Frame %d has more than one label", 
1151                         issprite?spriteframe:mainframe);
1152             }
1153             if(issprite) spriteframelabel = tag->data;
1154             else framelabel = tag->data;
1155         }
1156         else if(tag->id == ST_SHOWFRAME) {
1157             char*label = issprite?spriteframelabel:framelabel;
1158             int frame = issprite?spriteframe:mainframe;
1159             int nframe = frame;
1160             if(!label) {
1161                 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1162                     tag = tag->next;
1163                     if(issprite) spriteframe++;
1164                     else mainframe++;
1165                     nframe++;
1166                 }
1167             }
1168             if(nframe == frame)
1169                 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1170             else
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)))
1174                         );
1175             if(label)
1176                 printf(" (label \"%s\")", label);
1177             if(issprite) {spriteframe++; spriteframelabel = 0;}
1178             if(!issprite) {mainframe++; framelabel = 0;}
1179         }
1180
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);
1186         }
1187         else if(tag->id == ST_PROTECT) {
1188             if(tag->len>0) {
1189                 printf(" %s\n", swf_GetString(tag));
1190             } else {
1191                 printf("\n");
1192             }
1193         }
1194         else if(tag->id == ST_CSMTEXTSETTINGS) {
1195             U16 id = swf_GetU16(tag);
1196             U8 flags = swf_GetU8(tag);
1197             printf(" (");
1198             if(flags&0x40) {
1199                 printf("flashtype,");
1200             }
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;
1206             }
1207             if(flags&0x87) 
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);
1212             swf_GetU8(tag);
1213         }
1214         else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1215            tag->id == ST_DEFINEBITSLOSSLESS2) {
1216             handleDefineBits(tag);
1217             printf("\n");
1218         }
1219         else if(tag->id == ST_DEFINESOUND) {
1220             handleDefineSound(tag);
1221             printf("\n");
1222         }
1223         else if(tag->id == ST_VIDEOFRAME) {
1224             handleVideoFrame(tag, myprefix);
1225             printf("\n");
1226         }
1227         else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1228             handleVideoStream(tag, myprefix);
1229             printf("\n");
1230         }
1231         else if(tag->id == ST_DEFINEEDITTEXT) {
1232             handleEditText(tag);
1233             printf("\n");
1234         }
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);
1239         }
1240         else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1241             if(showtext)
1242                 handleText(tag);
1243             else
1244                 printf("\n");
1245         }
1246         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1247         }
1248         else if(tag->id == ST_NAMECHARACTER) {
1249             swf_GetU16(tag);
1250             printf(" \"%s\"\n", swf_GetString(tag));
1251         }
1252         else {
1253             printf("\n");
1254         }
1255
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,
1259                     r.xmin/20.0,
1260                     r.ymin/20.0,
1261                     r.xmax/20.0,
1262                     r.ymax/20.0);
1263         }
1264         
1265         sprintf(myprefix, "                %s", prefix);
1266
1267         if(tag->id == ST_DEFINESPRITE) {
1268             sprintf(prefix, "         ");
1269             if(issprite) {
1270                 dumperror("Sprite definition inside a sprite definition");
1271             }
1272             issprite = 1;
1273             spriteframe = 0;
1274             spriteframelabel = 0;
1275         }
1276         else if(tag->id == ST_END) {
1277             *prefix = 0;
1278             issprite = 0;
1279             spriteframelabel = 0;
1280             if(tag->len)
1281                 dumperror("End Tag not empty");
1282         }
1283         else if(tag->id == ST_EXPORTASSETS) {
1284             handleExportAssets(tag, myprefix);
1285         }
1286         else if(tag->id == ST_DOACTION && action) {
1287             ActionTAG*actions;
1288             actions = swf_ActionGet(tag);
1289             swf_DumpActions(actions, myprefix);
1290         }
1291         else if(tag->id == ST_DOINITACTION && action) {
1292             ActionTAG*actions;
1293             swf_GetU16(tag); // id
1294             actions = swf_ActionGet(tag);
1295             swf_DumpActions(actions, myprefix);
1296         }
1297         else if(tag->id == ST_DEFINEBUTTON && action) {
1298             dumpButtonActions(tag, myprefix);
1299         }
1300         else if(swf_isFontTag(tag) && showfonts) {
1301             dumpFont(tag, myprefix);
1302         }
1303         else if(tag->id == ST_DEFINEBUTTON2 && action) {
1304             dumpButton2Actions(tag, myprefix);
1305         }
1306         else if(tag->id == ST_PLACEOBJECT) {
1307             handlePlaceObject(tag, myprefix);
1308         }
1309         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1310             handlePlaceObject23(tag, myprefix);
1311         }
1312         else if(tag->id == ST_DEFINESHAPE ||
1313                 tag->id == ST_DEFINESHAPE2 ||
1314                 tag->id == ST_DEFINESHAPE3 ||
1315                 tag->id == ST_DEFINESHAPE4) {
1316             if(showshapes)
1317                 handleShape(tag, myprefix);
1318         }
1319
1320         if(tag->len && used) {
1321             int num = swf_GetNumUsedIDs(tag);
1322             int* used;
1323             int t;
1324             if(num) {
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++) {
1329                     int id;
1330                     swf_SetTagPos(tag, used[t]);
1331                     id = swf_GetU16(tag);
1332                     printf("%d%s", id, t<num-1?", ":"");
1333                     if(!idtab[id]) {
1334                         dumperror("Id %04d is not yet defined.\n", id);
1335                     }
1336                 }
1337                 printf("\n");
1338             }
1339         }
1340         
1341         if(tag->id == ST_FREECHARACTER) {
1342             U16 id;
1343             swf_SetTagPos(tag, 0);
1344             id = swf_GetU16(tag);
1345             idtab[id] = 0;
1346         }
1347
1348         if(tag->len && hex) {
1349             hexdumpTag(tag, prefix);
1350         }
1351         tag = tag->next;
1352         fflush(stdout);
1353     }
1354
1355     swf_FreeTags(&swf);
1356     return 0;
1357 }
1358
1359