use definetext2 instead of definetext
[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         int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
290         printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
291         SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
292         SHAPELINE*line = shape->lines;
293
294         while(line) {
295             if(line->type == moveTo) {
296                 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
297             } else if(line->type == lineTo) {
298                 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
299             } else if(line->type == splineTo) {
300                 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
301                         line->sx/20.0, line->sy/20.0,
302                         line->x/20.0, line->y/20.0
303                         );
304             }
305             line = line->next;
306         }
307         swf_Shape2Free(shape);
308         free(shape);
309     }
310     swf_FontFree(font);
311 }
312
313 SWF swf;
314 int fontnum = 0;
315 SWFFONT**fonts;
316
317 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color) 
318 {
319     int font=-1,t;
320     printf("                <%2d glyphs in font %2d, color #%02x%02x%02x%02x> ",nr, fontid, color->r, color->g, color->b, color->a);
321     for(t=0;t<fontnum;t++)
322     {
323         if(fonts[t]->id == fontid) {
324             font = t;
325             break;
326         }
327     }
328
329     for(t=0;t<nr;t++)
330     {
331         unsigned char a; 
332         if(font>=0) {
333             if(glyphs[t] >= fonts[font]->numchars  /*glyph is in range*/
334                     || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
335               ) a = glyphs[t];
336             else {
337                 if(fonts[font]->glyph2ascii[glyphs[t]])
338                     a = fonts[font]->glyph2ascii[glyphs[t]];
339                 else
340                     a = glyphs[t];
341             }
342         } else {
343             a = glyphs[t];
344         }
345         if(a>=32)
346             printf("%c", a);
347         else
348             printf("\\x%x", (int)a);
349     }
350     printf("\n");
351 }
352
353 void handleText(TAG*tag) 
354 {
355   printf("\n");
356   swf_ParseDefineText(tag,textcallback, 0);
357 }
358             
359 void handleDefineSound(TAG*tag)
360 {
361     U16 id = swf_GetU16(tag);
362     U8 flags = swf_GetU8(tag);
363     int compression = (flags>>4)&7;
364     int rate = (flags>>2)&3;
365     int bits = flags&2?16:8;
366     int stereo = flags&1;
367     printf(" (");
368     if(compression == 0) printf("Raw ");
369     else if(compression == 1) printf("ADPCM ");
370     else if(compression == 2) printf("MP3 ");
371     else if(compression == 3) printf("Raw little-endian ");
372     else if(compression == 6) printf("ASAO ");
373     else printf("? ");
374     if(rate == 0) printf("5.5Khz ");
375     if(rate == 1) printf("11Khz ");
376     if(rate == 2) printf("22Khz ");
377     if(rate == 3) printf("44Khz ");
378     printf("%dBit ", bits);
379     if(stereo) printf("stereo");
380     else printf("mono");
381     printf(")");
382 }
383
384 void handleDefineBits(TAG*tag)
385 {
386     U16 id;
387     U8 mode;
388     U16 width,height;
389     int bpp;
390     id = swf_GetU16(tag);
391     mode = swf_GetU8(tag);
392     width = swf_GetU16(tag);
393     height = swf_GetU16(tag);
394     printf(" image %dx%d",width,height);
395     if(mode == 3) printf(" (8 bpp)");
396     else if(mode == 4) printf(" (16 bpp)");
397     else if(mode == 5) printf(" (32 bpp)");
398     else printf(" (? bpp)");
399 }
400
401 void handleEditText(TAG*tag)
402 {
403     U16 id ;
404     U16 flags;
405     int t;
406     id = swf_GetU16(tag);
407     swf_GetRect(tag,0);
408     
409     //swf_ResetReadBits(tag);
410
411     if (tag->readBit)  
412     { tag->pos++; 
413       tag->readBit = 0; 
414     }
415     flags = swf_GetBits(tag,16);
416     if(flags & ET_HASFONT) {
417         swf_GetU16(tag); //font
418         swf_GetU16(tag); //fontheight
419     }
420     if(flags & ET_HASTEXTCOLOR) {
421         swf_GetU8(tag); //rgba
422         swf_GetU8(tag);
423         swf_GetU8(tag);
424         swf_GetU8(tag);
425     }
426     if(flags & ET_HASMAXLENGTH) {
427         swf_GetU16(tag); //maxlength
428     }
429     if(flags & ET_HASLAYOUT) {
430         swf_GetU8(tag); //align
431         swf_GetU16(tag); //left margin
432         swf_GetU16(tag); //right margin
433         swf_GetU16(tag); //indent
434         swf_GetU16(tag); //leading
435     }
436     printf(" variable \"%s\" ", &tag->data[tag->pos]);
437     if(flags & ET_HTML) printf("(html)");
438     if(flags & ET_NOSELECT) printf("(noselect)");
439     if(flags & ET_PASSWORD) printf("(password)");
440     if(flags & ET_READONLY) printf("(readonly)");
441
442     if(flags & (ET_X1 | ET_X3 ))
443     {
444         printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
445     }
446     
447     while(tag->data[tag->pos++]);
448     if(flags & ET_HASTEXT)
449    //  printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
450         ;
451 }
452 void printhandlerflags(U32 handlerflags) 
453 {
454     if(handlerflags&1) printf("[on load]");
455     if(handlerflags&2) printf("[enter frame]");
456     if(handlerflags&4) printf("[unload]");
457     if(handlerflags&8) printf("[mouse move]");
458     if(handlerflags&16) printf("[mouse down]");
459     if(handlerflags&32) printf("[mouse up]");
460     if(handlerflags&64) printf("[key down]");
461     if(handlerflags&128) printf("[key up]");
462
463     if(handlerflags&256) printf("[data]");
464     if(handlerflags&512) printf("[initialize]");
465     if(handlerflags&1024) printf("[mouse press]");
466     if(handlerflags&2048) printf("[mouse release]");
467     if(handlerflags&4096) printf("[mouse release outside]");
468     if(handlerflags&8192) printf("[mouse rollover]");
469     if(handlerflags&16384) printf("[mouse rollout]");
470     if(handlerflags&32768) printf("[mouse drag over]");
471
472     if(handlerflags&0x10000) printf("[mouse drag out]");
473     if(handlerflags&0x20000) printf("[key press]");
474     if(handlerflags&0x40000) printf("[construct even]");
475     if(handlerflags&0xfff80000) printf("[???]");
476 }
477 void handleVideoStream(TAG*tag, char*prefix)
478 {
479     U16 id = swf_GetU16(tag);
480     U16 frames = swf_GetU16(tag);
481     U16 width = swf_GetU16(tag);
482     U16 height = swf_GetU16(tag);
483     U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
484     U8 codec = swf_GetU8(tag);
485     printf(" (%d frames, %dx%d", frames, width, height);
486     if(flags&1)
487         printf(" smoothed");
488     if(codec == 2)
489         printf(" sorenson h.263)");
490     else
491         printf(" codec 0x%02x)", codec);
492 }
493 void handleVideoFrame(TAG*tag, char*prefix)
494 {
495     U32 code, version, reference, sizeflags;
496     U32 width=0, height=0;
497     U8 type;
498     U16 id = swf_GetU16(tag);
499     U16 frame = swf_GetU16(tag);
500     U8 deblock,flags, tmp, bit;
501     U32 quantizer;
502     char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
503     printf(" (frame %d) ", frame);
504
505     /* video packet follows */
506     code = swf_GetBits(tag, 17);
507     version = swf_GetBits(tag, 5);
508     reference = swf_GetBits(tag, 8);
509
510     sizeflags = swf_GetBits(tag, 3);
511     switch(sizeflags)
512     {
513         case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
514         case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
515         case 2: width = 352; height = 288; break;
516         case 3: width = 176; height = 144; break;
517         case 4: width = 128; height = 96; break;
518         case 5: width = 320; height = 240; break;
519         case 6: width = 160; height = 120; break;
520         case 7: width = -1; height = -1;/*reserved*/ break;
521     }
522     printf("%dx%d ", width, height);
523     type = swf_GetBits(tag, 2);
524     printf("%s", types[type]);
525
526     deblock = swf_GetBits(tag, 1);
527     if(deblock)
528         printf(" deblock ", deblock);
529     quantizer = swf_GetBits(tag, 5);
530     printf(" quant: %d ", quantizer);
531 }
532
533 void dumpFilter(FILTER*filter)
534 {
535     if(filter->type == FILTERTYPE_BLUR) {
536         FILTER_BLUR*f = (FILTER_BLUR*)filter;
537         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
538         printf("passes: %d\n", f->passes);
539     } if(filter->type == FILTERTYPE_DROPSHADOW) {
540         FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
541         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
542         printf("passes: %d\n", f->passes);
543         printf("angle: %f distance: %f\n", f->angle, f->distance);
544         printf("strength: %f passes: %d\n", f->strength, f->passes);
545         printf("flags: %s%s%s\n", 
546                 f->knockout?"knockout ":"",
547                 f->composite?"composite ":"",
548                 f->innershadow?"innershadow ":"");
549     } if(filter->type == FILTERTYPE_BEVEL) {
550         FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
551         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
552         printf("passes: %d\n", f->passes);
553         printf("angle: %f distance: %f\n", f->angle, f->distance);
554         printf("strength: %f passes: %d\n", f->strength, f->passes);
555         printf("flags: %s%s%s%s\n", 
556                 f->ontop?"ontop":"",
557                 f->knockout?"knockout ":"",
558                 f->composite?"composite ":"",
559                 f->innershadow?"innershadow ":"");
560     } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
561         FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
562         swf_DumpGradient(stdout, f->gradient);
563         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
564         printf("angle: %f distance: %f\n", f->angle, f->distance);
565         printf("strength: %f passes: %d\n", f->strength, f->passes);
566         printf("flags: %s%s%s%s\n", 
567                 f->knockout?"knockout ":"",
568                 f->ontop?"ontop ":"",
569                 f->composite?"composite ":"",
570                 f->innershadow?"innershadow ":"");
571     }
572     rfx_free(filter);
573 }
574
575 void handlePlaceObject23(TAG*tag, char*prefix)
576 {
577     U8 flags,flags2=0;
578     MATRIX m;
579     CXFORM cx;
580     char pstr[3][256];
581     int ppos[3] = {0,0,0};
582     swf_SetTagPos(tag, 0);
583     flags = swf_GetU8(tag);
584     if(tag->id == ST_PLACEOBJECT3)
585         flags2 = swf_GetU8(tag);
586     swf_GetU16(tag); //depth
587
588     //flags&1: move
589     if(flags&2) swf_GetU16(tag); //id
590     if(flags&4) {
591         swf_GetMatrix(tag,&m);
592         if(placements) {
593             ppos[0] += sprintf(pstr[0], "| Matrix             ");
594             ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
595             ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
596         }
597     }
598     if(flags&8) {
599         swf_GetCXForm(tag, &cx, 1);
600         if(placements) {
601             ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm    r    g    b    a ");
602             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);
603             ppos[2] += sprintf(pstr[2]+ppos[2], "| add    %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
604         }
605     }
606     if(flags&16) {
607         U16 ratio = swf_GetU16(tag); //ratio
608         if(placements) {
609             ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
610             ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
611             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
612         }
613     }
614     if(flags&64) {
615         U16 clip = swf_GetU16(tag); //clip
616         if(placements) {
617             ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip  ");
618             ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
619             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
620         }
621     }
622     if(flags&32) { while(swf_GetU8(tag)); }
623
624     if(flags2&1) { // filter list
625         U8 num = swf_GetU8(tag);
626         if(placements)
627             printf("\n%d filters\n", num);
628         char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
629         int t;
630         for(t=0;t<num;t++) {
631             FILTER*filter = swf_GetFilter(tag);
632             if(!filter) {
633                 printf("\n"); 
634                 return;
635             }
636             if(placements) {
637                 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
638                 dumpFilter(filter);
639             }
640         }
641     }
642     if(flags2&2) { // blend mode
643         U8 blendmode = swf_GetU8(tag);
644         if(placements) {
645             int t;
646             char name[80];
647             sprintf(name, "%-5d", blendmode);
648             for(t=0;blendModeNames[t];t++) {
649                 if(blendmode==t) {
650                     sprintf(name, "%-5s", blendModeNames[t]);
651                     break;
652                 }
653             }
654             ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
655             ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
656             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
657         }
658     }
659
660     if(placements && ppos[0]) {
661         printf("\n");
662         printf("%s %s\n", prefix, pstr[0]);
663         printf("%s %s\n", prefix, pstr[1]);
664         printf("%s %s", prefix, pstr[2]);
665     }
666     if(flags&128) {
667       if (action) {
668         U16 reserved;
669         U32 globalflags;
670         U32 handlerflags;
671         char is32 = 0;
672         printf("\n");
673         reserved = swf_GetU16(tag); // must be 0
674         globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
675         if(reserved) {
676             printf("Unknown parameter field not zero: %04x\n", reserved);
677             return;
678         }
679         printf("global flags: %04x\n", globalflags);
680
681         handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
682         if(!handlerflags) {
683             handlerflags = swf_GetU32(tag);
684             is32 = 1;
685         }
686         while(handlerflags)  {
687             int length;
688             int t;
689             ActionTAG*a;
690
691             globalflags &= ~handlerflags;
692             printf("%s flags %08x ",prefix, handlerflags);
693             printhandlerflags(handlerflags);
694             length = swf_GetU32(tag);
695             printf(", %d bytes actioncode\n",length);
696             a = swf_ActionGet(tag);
697             swf_DumpActions(a,prefix);
698             swf_ActionFree(a);
699
700             handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
701         }
702         if(globalflags) // should go to sterr.
703             printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
704     } else {
705       printf(" has action code\n");
706     }
707     } else printf("\n");
708 }
709
710 void handlePlaceObject(TAG*tag, char*prefix)
711 {
712     TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
713     U16 id, depth;
714     MATRIX matrix; 
715     CXFORM cxform;
716
717     swf_SetTagPos(tag, 0);
718     id = swf_GetU16(tag);
719     depth = swf_GetU16(tag);
720     swf_GetMatrix(tag, &matrix);
721     swf_GetCXForm(tag, &cxform, 0);
722
723     swf_SetU8(tag2, 14 /* char, matrix, cxform */);
724     swf_SetU16(tag2, depth);
725     swf_SetU16(tag2, id);
726     swf_SetMatrix(tag2, &matrix);
727     swf_SetCXForm(tag2, &cxform, 1);
728
729     handlePlaceObject23(tag2, prefix);
730 }
731 char stylebuf[256];
732 char* fillstyle2str(FILLSTYLE*style)
733 {
734     switch(style->type) {
735         case 0x00:
736             sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
737             break;
738         case 0x10: case 0x11: case 0x12: case 0x13:
739             sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
740             break;
741         case 0x40: case 0x42:
742             /* TODO: display information about that bitmap */
743             sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
744             /* TODO: show matrix */
745             break;
746         case 0x41: case 0x43:
747             /* TODO: display information about that bitmap */
748             sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
749             /* TODO: show matrix */
750             break;
751         default:
752             sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
753     }
754     return stylebuf;
755 }
756 char* linestyle2str(LINESTYLE*style)
757 {
758     sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
759     return stylebuf;
760 }
761
762 void handleShape(TAG*tag, char*prefix)
763 {
764     SHAPE2 shape;
765     SHAPELINE*line;
766     int t,max;
767
768     tag->pos = 0;
769     tag->readBit = 0;
770     swf_ParseDefineShape(tag, &shape);
771
772     max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
773
774     if(max) printf("%s | fillstyles(%02d)        linestyles(%02d)\n", 
775             prefix,
776             shape.numfillstyles,
777             shape.numlinestyles
778             );
779     else    printf("%s | (Neither line nor fill styles)\n", prefix);
780
781     for(t=0;t<max;t++) {
782         printf("%s", prefix);
783         if(t < shape.numfillstyles) {
784             printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
785         } else {
786             printf("                         ");
787         }
788         if(t < shape.numlinestyles) {
789             printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
790         }
791         printf("\n");
792     }
793
794     printf("%s |\n", prefix);
795
796     line = shape.lines;
797     while(line) {
798         printf("%s | fill: %02d/%02d line:%02d - ",
799                 prefix, 
800                 line->fillstyle0,
801                 line->fillstyle1,
802                 line->linestyle);
803         if(line->type == moveTo) {
804             printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
805         } else if(line->type == lineTo) {
806             printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
807         } else if(line->type == splineTo) {
808             printf("splineTo (%.2f %.2f) %.2f %.2f\n", 
809                     line->sx/20.0, line->sy/20.0,
810                     line->x/20.0, line->y/20.0
811                     );
812         }
813         line = line->next;
814     }
815     printf("%s |\n", prefix);
816 }
817     
818 void fontcallback1(void*self, U16 id,U8 * name)
819 { fontnum++;
820 }
821
822 void fontcallback2(void*self, U16 id,U8 * name)
823
824   swf_FontExtract(&swf,id,&fonts[fontnum]);
825   fontnum++;
826 }
827
828 static U8 printable(U8 a)
829 {
830     if(a<32 || a==127) return '.';
831     else return a;
832 }
833 void hexdumpTag(TAG*tag, char* prefix)
834 {
835     int t;
836     char ascii[32];
837     printf("                %s-=> ",prefix);
838     for(t=0;t<tag->len;t++) {
839         printf("%02x ", tag->data[t]);
840         ascii[t&15] = printable(tag->data[t]);
841         if((t && ((t&15)==15)) || (t==tag->len-1))
842         {
843             int s,p=((t)&15)+1;
844             ascii[p] = 0;
845             for(s=p-1;s<16;s++) {
846                 printf("   ");
847             }
848             if(t==tag->len-1)
849                 printf(" %s\n", ascii);
850             else
851                 printf(" %s\n                %s-=> ",ascii,prefix);
852         }
853     }
854 }
855
856 void handleExportAssets(TAG*tag, char* prefix)
857 {
858     int num;
859     U16 id;
860     char* name;
861     int t;
862     num = swf_GetU16(tag);
863     for(t=0;t<num;t++)
864     {
865         id = swf_GetU16(tag);
866         name = swf_GetString(tag);
867         printf("%sexports %04d as \"%s\"\n", prefix, id, name);
868     }
869 }
870
871 void dumperror(const char* format, ...)
872 {
873     char buf[1024];
874     va_list arglist;
875
876     va_start(arglist, format);
877     vsprintf(buf, format, arglist);
878     va_end(arglist);
879
880     if(!html && !xy)
881         printf("==== Error: %s ====\n", buf);
882 }
883
884 static char strbuf[800];
885 static int bufpos=0;
886
887 char* timestring(double f)
888 {
889     int hours   = (int)(f/3600);
890     int minutes = (int)((f-hours*3600)/60);
891     int seconds = (int)((f-hours*3600-minutes*60));
892     int useconds = (int)((f-(int)f)*1000+0.5);
893     bufpos+=100;
894     bufpos%=800;
895     sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
896     return &strbuf[bufpos];
897 }
898
899 int main (int argc,char ** argv)
900
901     TAG*tag;
902 #ifdef HAVE_STAT
903     struct stat statbuf;
904 #endif
905     int f;
906     int xsize,ysize;
907     char issprite = 0; // are we inside a sprite definition?
908     int spriteframe = 0;
909     int mainframe=0;
910     char* spriteframelabel = 0;
911     char* framelabel = 0;
912     char prefix[128];
913     int filesize = 0;
914     int filepos = 0;
915     prefix[0] = 0;
916     memset(idtab,0,65536);
917
918     processargs(argc, argv);
919
920     if(!filename)
921     {
922         fprintf(stderr, "You must supply a filename.\n");
923         return 1;
924     }
925
926     f = open(filename,O_RDONLY|O_BINARY);
927
928     if (f<0)
929     { 
930         char buffer[256];
931         sprintf(buffer, "Couldn't open %s", filename);
932         perror(buffer);
933         exit(1);
934     }
935     if FAILED(swf_ReadSWF(f,&swf))
936     { 
937         fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
938         close(f);
939         exit(1);
940     }
941
942 #ifdef HAVE_STAT
943     fstat(f, &statbuf);
944     if(statbuf.st_size != swf.fileSize && !swf.compressed)
945         dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
946                 statbuf.st_size, swf.fileSize);
947     filesize = statbuf.st_size;
948 #endif
949
950     close(f);
951
952     xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
953     ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
954     if(xy)
955     {
956         if(xy&1)
957         printf("-X %d", xsize);
958
959         if((xy&1) && (xy&6))
960         printf(" ");
961
962         if(xy&2)
963         printf("-Y %d", ysize);
964         
965         if((xy&3) && (xy&4))
966         printf(" ");
967
968         if(xy&4)
969         printf("-r %.2f", swf.frameRate/256.0);
970         
971         if((xy&7) && (xy&8))
972         printf(" ");
973         
974         if(xy&8)
975         printf("-f %d", swf.frameCount);
976         
977         printf("\n");
978         return 0;
979     }
980     if(html)
981     {
982         char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
983                                "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
984         if(swf.fileVersion>9) {
985             fprintf(stderr, "Fileversion>9\n");
986             exit(1);
987         }
988
989         if(xhtml) {
990             printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
991                             "<param name=\"movie\" value=\"%s\"/>\n"
992                             "<param name=\"play\" value=\"true\"/>\n"
993                             "<param name=\"loop\" value=\"false\"/>\n"
994                             "<param name=\"quality\" value=\"high\"/>\n"
995                             "<param name=\"loop\" value=\"false\"/>\n"
996                             "</object>\n\n", filename, xsize, ysize, filename);
997         } else {
998             printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
999                    " WIDTH=\"%d\"\n"
1000                    //" BGCOLOR=#ffffffff\n"?
1001                    " HEIGHT=\"%d\"\n"
1002                    //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1003                    " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1004                    "  <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1005                    "  <PARAM NAME=\"PLAY\" VALUE=\"true\">\n" 
1006                    "  <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1007                    "  <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1008                    "  <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1009                    "   PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1010                    "   TYPE=\"application/x-shockwave-flash\"\n"
1011                    "   PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1012                    "  </EMBED>\n" 
1013                    "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion], 
1014                                   filename, filename, xsize, ysize);
1015         }
1016         return 0;
1017     } 
1018     printf("[HEADER]        File version: %d\n", swf.fileVersion);
1019     if(swf.compressed) {
1020         printf("[HEADER]        File is zlib compressed.");
1021         if(filesize && swf.fileSize)
1022             printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1023         else
1024             printf("\n");
1025     }
1026     printf("[HEADER]        File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1027     printf("[HEADER]        Frame rate: %f\n",swf.frameRate/256.0);
1028     printf("[HEADER]        Frame count: %d\n",swf.frameCount);
1029     printf("[HEADER]        Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1030     if(swf.movieSize.xmin)
1031         printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1032     else 
1033         printf("\n");
1034     printf("[HEADER]        Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1035     if(swf.movieSize.ymin)
1036         printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1037     else 
1038         printf("\n");
1039
1040     tag = swf.firstTag;
1041    
1042     if(showtext) {
1043         fontnum = 0;
1044         swf_FontEnumerate(&swf,&fontcallback1, 0);
1045         fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1046         fontnum = 0;
1047         swf_FontEnumerate(&swf,&fontcallback2, 0);
1048     }
1049
1050     while(tag) {
1051         char*name = swf_TagGetName(tag);
1052         char myprefix[128];
1053         if(!name) {
1054             dumperror("Unknown tag:0x%03x", tag->id);
1055             //tag = tag->next;
1056             //continue;
1057         }
1058         if(!name) {
1059             name = "UNKNOWN TAG";
1060         }
1061         if(cumulative) {
1062             filepos += tag->len;
1063             printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1064         } else {
1065             printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1066         }
1067         
1068         if(swf_isDefiningTag(tag)) {
1069             U16 id = swf_GetDefineID(tag);
1070             printf(" defines id %04d", id);
1071             if(idtab[id])
1072                 dumperror("Id %04d is defined more than once.", id);
1073             idtab[id] = 1;
1074         }
1075         else if(swf_isPseudoDefiningTag(tag)) {
1076             U16 id = swf_GetDefineID(tag);
1077             printf(" adds information to id %04d", id);
1078             if(!idtab[id])
1079                 dumperror("Id %04d is not yet defined.\n", id);
1080         }
1081         else if(tag->id == ST_PLACEOBJECT) {
1082             printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1083             if(swf_GetName(tag))
1084                 printf(" name \"%s\"",swf_GetName(tag));
1085         }
1086         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1087             if(tag->data[0]&1)
1088                 printf(" moves");
1089             else
1090                 printf(" places");
1091             
1092             if(tag->data[0]&2)
1093                 printf(" id %04d",swf_GetPlaceID(tag));
1094             else
1095                 printf(" object");
1096
1097             printf(" at depth %04d", swf_GetDepth(tag));
1098
1099             if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1100                 printf(" as bitmap");
1101            
1102             swf_SetTagPos(tag, 0);
1103             if(tag->data[0]&64) {
1104                 SWFPLACEOBJECT po;
1105                 swf_GetPlaceObject(tag, &po);
1106                 printf(" (clip to %04d)", po.clipdepth);
1107                 swf_PlaceObjectFree(&po);
1108             }
1109             if(swf_GetName(tag))
1110                 printf(" name \"%s\"",swf_GetName(tag));
1111
1112         }
1113         else if(tag->id == ST_REMOVEOBJECT) {
1114             printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1115         }
1116         else if(tag->id == ST_REMOVEOBJECT2) {
1117             printf(" removes object from depth %04d", swf_GetDepth(tag));
1118         }
1119         else if(tag->id == ST_FREECHARACTER) {
1120             printf(" frees object %04d", swf_GetPlaceID(tag));
1121         }
1122         else if(tag->id == ST_STARTSOUND) {
1123             U8 flags;
1124             U16 id;
1125             id = swf_GetU16(tag);
1126             flags = swf_GetU8(tag);
1127             if(flags & 32)
1128                 printf(" stops sound with id %04d", id);
1129             else
1130                 printf(" starts sound with id %04d", id);
1131             if(flags & 16)
1132                 printf(" (if not already playing)");
1133             if(flags & 1)
1134                 swf_GetU32(tag);
1135             if(flags & 2)
1136                 swf_GetU32(tag);
1137             if(flags & 4) {
1138                 printf(" looping %d times", swf_GetU16(tag));
1139             }
1140         }
1141         else if(tag->id == ST_FRAMELABEL) {
1142             int l = strlen(tag->data);
1143             printf(" \"%s\"", tag->data);
1144             if((l+1) < tag->len) {
1145                 printf(" has %d extra bytes", tag->len-1-l);
1146                 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1147                     printf(" (ANCHOR)");
1148             }
1149             if((framelabel && !issprite) ||
1150                (spriteframelabel && issprite)) {
1151                 dumperror("Frame %d has more than one label", 
1152                         issprite?spriteframe:mainframe);
1153             }
1154             if(issprite) spriteframelabel = tag->data;
1155             else framelabel = tag->data;
1156         }
1157         else if(tag->id == ST_SHOWFRAME) {
1158             char*label = issprite?spriteframelabel:framelabel;
1159             int frame = issprite?spriteframe:mainframe;
1160             int nframe = frame;
1161             if(!label) {
1162                 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1163                     tag = tag->next;
1164                     if(issprite) spriteframe++;
1165                     else mainframe++;
1166                     nframe++;
1167                 }
1168             }
1169             if(nframe == frame)
1170                 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1171             else
1172                 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1173                         timestring(frame*(256.0/(swf.frameRate+0.1))),
1174                         timestring(nframe*(256.0/(swf.frameRate+0.1)))
1175                         );
1176             if(label)
1177                 printf(" (label \"%s\")", label);
1178             if(issprite) {spriteframe++; spriteframelabel = 0;}
1179             if(!issprite) {mainframe++; framelabel = 0;}
1180         }
1181
1182         if(tag->id == ST_SETBACKGROUNDCOLOR) {
1183             U8 r = swf_GetU8(tag);
1184             U8 g = swf_GetU8(tag);
1185             U8 b = swf_GetU8(tag);
1186             printf(" (%02x/%02x/%02x)\n",r,g,b);
1187         }
1188         else if(tag->id == ST_PROTECT) {
1189             if(tag->len>0) {
1190                 printf(" %s\n", swf_GetString(tag));
1191             } else {
1192                 printf("\n");
1193             }
1194         }
1195         else if(tag->id == ST_CSMTEXTSETTINGS) {
1196             U16 id = swf_GetU16(tag);
1197             U8 flags = swf_GetU8(tag);
1198             printf(" (");
1199             if(flags&0x40) {
1200                 printf("flashtype,");
1201             }
1202             switch(((flags>>3)&7)) {
1203                 case 0:printf("no grid,");break;
1204                 case 1:printf("pixel grid,");break;
1205                 case 2:printf("subpixel grid,");break;
1206                 case 3:printf("unknown grid,");break;
1207             }
1208             if(flags&0x87) 
1209                 printf("unknown[%08x],", flags);
1210             float thickness = swf_GetFixed(tag);
1211             float sharpness = swf_GetFixed(tag);
1212             printf("s=%.2f,t=%.2f)\n", thickness, sharpness);
1213             swf_GetU8(tag);
1214         }
1215         else if(tag->id == ST_DEFINEBITSLOSSLESS ||
1216            tag->id == ST_DEFINEBITSLOSSLESS2) {
1217             handleDefineBits(tag);
1218             printf("\n");
1219         }
1220         else if(tag->id == ST_DEFINESOUND) {
1221             handleDefineSound(tag);
1222             printf("\n");
1223         }
1224         else if(tag->id == ST_VIDEOFRAME) {
1225             handleVideoFrame(tag, myprefix);
1226             printf("\n");
1227         }
1228         else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1229             handleVideoStream(tag, myprefix);
1230             printf("\n");
1231         }
1232         else if(tag->id == ST_DEFINEEDITTEXT) {
1233             handleEditText(tag);
1234             printf("\n");
1235         }
1236         else if(tag->id == ST_DEFINEMOVIE) {
1237             U16 id = swf_GetU16(tag);
1238             char*s = swf_GetString(tag);
1239             printf(" URL: %s\n", s);
1240         }
1241         else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1242             if(showtext)
1243                 handleText(tag);
1244             else
1245                 printf("\n");
1246         }
1247         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1248         }
1249         else if(tag->id == ST_NAMECHARACTER) {
1250             swf_GetU16(tag);
1251             printf(" \"%s\"\n", swf_GetString(tag));
1252         }
1253         else {
1254             printf("\n");
1255         }
1256
1257         if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1258             SRECT r = swf_GetDefineBBox(tag);
1259             printf("                %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1260                     r.xmin/20.0,
1261                     r.ymin/20.0,
1262                     r.xmax/20.0,
1263                     r.ymax/20.0);
1264         }
1265         
1266         sprintf(myprefix, "                %s", prefix);
1267
1268         if(tag->id == ST_DEFINESPRITE) {
1269             sprintf(prefix, "         ");
1270             if(issprite) {
1271                 dumperror("Sprite definition inside a sprite definition");
1272             }
1273             issprite = 1;
1274             spriteframe = 0;
1275             spriteframelabel = 0;
1276         }
1277         else if(tag->id == ST_END) {
1278             *prefix = 0;
1279             issprite = 0;
1280             spriteframelabel = 0;
1281             if(tag->len)
1282                 dumperror("End Tag not empty");
1283         }
1284         else if(tag->id == ST_EXPORTASSETS) {
1285             handleExportAssets(tag, myprefix);
1286         }
1287         else if(tag->id == ST_DOACTION && action) {
1288             ActionTAG*actions;
1289             actions = swf_ActionGet(tag);
1290             swf_DumpActions(actions, myprefix);
1291         }
1292         else if(tag->id == ST_DOINITACTION && action) {
1293             ActionTAG*actions;
1294             swf_GetU16(tag); // id
1295             actions = swf_ActionGet(tag);
1296             swf_DumpActions(actions, myprefix);
1297         }
1298         else if(tag->id == ST_DEFINEBUTTON && action) {
1299             dumpButtonActions(tag, myprefix);
1300         }
1301         else if(swf_isFontTag(tag) && showfonts) {
1302             dumpFont(tag, myprefix);
1303         }
1304         else if(tag->id == ST_DEFINEBUTTON2 && action) {
1305             dumpButton2Actions(tag, myprefix);
1306         }
1307         else if(tag->id == ST_PLACEOBJECT) {
1308             handlePlaceObject(tag, myprefix);
1309         }
1310         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1311             handlePlaceObject23(tag, myprefix);
1312         }
1313         else if(tag->id == ST_DEFINESHAPE ||
1314                 tag->id == ST_DEFINESHAPE2 ||
1315                 tag->id == ST_DEFINESHAPE3 ||
1316                 tag->id == ST_DEFINESHAPE4) {
1317             if(showshapes)
1318                 handleShape(tag, myprefix);
1319         }
1320
1321         if(tag->len && used) {
1322             int num = swf_GetNumUsedIDs(tag);
1323             int* used;
1324             int t;
1325             if(num) {
1326                 used = (int*)malloc(sizeof(int)*num);
1327                 swf_GetUsedIDs(tag, used);
1328                 printf("%s%suses IDs: ", indent, prefix);
1329                 for(t=0;t<num;t++) {
1330                     int id;
1331                     swf_SetTagPos(tag, used[t]);
1332                     id = swf_GetU16(tag);
1333                     printf("%d%s", id, t<num-1?", ":"");
1334                     if(!idtab[id]) {
1335                         dumperror("Id %04d is not yet defined.\n", id);
1336                     }
1337                 }
1338                 printf("\n");
1339             }
1340         }
1341         
1342         if(tag->id == ST_FREECHARACTER) {
1343             U16 id;
1344             swf_SetTagPos(tag, 0);
1345             id = swf_GetU16(tag);
1346             idtab[id] = 0;
1347         }
1348
1349         if(tag->len && hex) {
1350             hexdumpTag(tag, prefix);
1351         }
1352         tag = tag->next;
1353         fflush(stdout);
1354     }
1355
1356     swf_FreeTags(&swf);
1357     return 0;
1358 }
1359
1360