fixed a mem leak
[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 static int showbuttons = 0;
64
65 static struct options_t options[] = {
66 {"h", "help"},
67 {"D", "full"},
68 {"V", "version"},
69 {"e", "html"},
70 {"E", "xhtml"},
71 {"a", "action"},
72 {"t", "text"},
73 {"s", "shapes"},
74 {"F", "fonts"},
75 {"p", "placements"},
76 {"b", "bbox"},
77 {"B", "buttons"},
78 {"X", "width"},
79 {"Y", "height"},
80 {"r", "rate"},
81 {"f", "frames"},
82 {"d", "hex"},
83 {"u", "used"},
84 {0,0}
85 };
86
87 int args_callback_option(char*name,char*val)
88 {
89     if(!strcmp(name, "V")) {
90         printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
91         exit(0);
92     } 
93     else if(name[0]=='a') {
94         action = 1;
95         return 0;
96     }
97     else if(name[0]=='p') {
98         placements = 1;
99         return 0;
100     }
101     else if(name[0]=='t') {
102         showtext = 1;
103         return 0;
104     }
105     else if(name[0]=='s') {
106         showshapes = 1;
107         return 0;
108     }
109     else if(name[0]=='e') {
110         html = 1;
111         return 0;
112     }
113     else if(name[0]=='c') {
114         cumulative = 1;
115         return 0;
116     }
117     else if(name[0]=='E') {
118         html = 1;
119         xhtml = 1;
120         return 0;
121     }
122     else if(name[0]=='X') {
123         xy |= 1;
124         return 0;
125     }
126     else if(name[0]=='Y') {
127         xy |= 2;
128         return 0;
129     }
130     else if(name[0]=='r') {
131         xy |= 4;
132         return 0;
133     }
134     else if(name[0]=='f') {
135         xy |= 8;
136         return 0;
137     }
138     else if(name[0]=='F') {
139         showfonts = 1;
140         return 0;
141     }
142     else if(name[0]=='d') {
143         hex = 1;
144         return 0;
145     }
146     else if(name[0]=='u') {
147         used = 1;
148         return 0;
149     }
150     else if(name[0]=='b') {
151         bbox = 1;
152         return 0;
153     }
154     else if(name[0]=='B') {
155         showbuttons = 1;
156         return 0;
157     }
158     else if(name[0]=='D') {
159         showbuttons = action = placements = showtext = showshapes = 1;
160         return 0;
161     }
162     else {
163         printf("Unknown option: -%s\n", name);
164         exit(1);
165     }
166
167     return 0;
168 }
169 int args_callback_longoption(char*name,char*val)
170 {
171     return args_long2shortoption(options, name, val);
172 }
173 void args_callback_usage(char *name)
174 {
175     printf("\n");
176     printf("Usage: %s [-atpdu] file.swf\n", name);
177     printf("\n");
178     printf("-h , --help                    Print short help message and exit\n");
179     printf("-D , --full                    Show everything. Same as -atp\n");
180     printf("-V , --version                 Print version info and exit\n");
181     printf("-e , --html                    Print out html code for embedding the file\n");
182     printf("-E , --xhtml                   Print out xhtml code for embedding the file\n");
183     printf("-a , --action                  Disassemble action tags\n");
184     printf("-t , --text                    Show text fields (like swfstrings).\n");
185     printf("-s , --shapes                  Show shape coordinates/styles\n");
186     printf("-F , --fonts                   Show font information\n");
187     printf("-p , --placements              Show placement information\n");
188     printf("-b , --bbox                    Print tag's bounding boxes\n");
189     printf("-X , --width                   Prints out a string of the form \"-X width\".\n");
190     printf("-Y , --height                  Prints out a string of the form \"-Y height\".\n");
191     printf("-r , --rate                    Prints out a string of the form \"-r rate\".\n");
192     printf("-f , --frames                  Prints out a string of the form \"-f framenum\".\n");
193     printf("-d , --hex                     Print hex output of tag data, too.\n");
194     printf("-u , --used                    Show referred IDs for each Tag.\n");
195     printf("\n");
196 }
197 int args_callback_command(char*name,char*val)
198 {
199     if(filename) {
200         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
201                  filename, name);
202     }
203     filename = name;
204     return 0;
205 }
206
207 char* what;
208 char* testfunc(char*str)
209 {
210     printf("%s: %s\n", what, str);
211     return 0;
212 }
213
214 void dumpButton2Actions(TAG*tag, char*prefix)
215 {
216     U32 oldTagPos;
217     U32 offsetpos;
218     U32 condition;
219
220     oldTagPos = swf_GetTagPos(tag);
221
222     // scan DefineButton2 Record
223     
224     swf_GetU16(tag);          // Character ID
225     swf_GetU8(tag);           // Flags;
226
227     offsetpos = swf_GetTagPos(tag);  // first offset
228     swf_GetU16(tag);
229
230     while (swf_GetU8(tag))      // state  -> parse ButtonRecord
231     { swf_GetU16(tag);          // id
232       swf_GetU16(tag);          // layer
233       swf_GetMatrix(tag,NULL);  // matrix
234       swf_GetCXForm(tag,NULL,1);  // cxform
235     }
236
237     while(offsetpos)
238     { U8 a;
239       ActionTAG*actions;
240
241       if(tag->pos >= tag->len)
242           break;
243         
244       offsetpos = swf_GetU16(tag);
245       condition = swf_GetU16(tag);                // condition
246       
247       actions = swf_ActionGet(tag);
248       printf("%s condition %04x\n", prefix, condition);
249       swf_DumpActions(actions, prefix);
250     }
251     
252     swf_SetTagPos(tag,oldTagPos);
253     return;
254 }
255
256 void dumpButtonActions(TAG*tag, char*prefix)
257 {
258     ActionTAG*actions;
259     swf_SetTagPos(tag, 0);
260     swf_GetU16(tag); // id
261     while (swf_GetU8(tag))      // state  -> parse ButtonRecord
262     { swf_GetU16(tag);          // id
263       swf_GetU16(tag);          // layer
264       swf_GetMatrix(tag,NULL);  // matrix
265     }
266     actions = swf_ActionGet(tag);
267     swf_DumpActions(actions, prefix);
268     swf_ActionFree(actions);
269 }
270
271 void dumpButton(TAG*tag, char*prefix)
272 {
273     swf_SetTagPos(tag, 0);
274     swf_GetU16(tag); // id
275     while (1) {
276         U8 flags = swf_GetU8(tag);
277         if(!flags)
278             break;
279         U16 id = swf_GetU16(tag);
280         U16 depth = swf_GetU16(tag);
281         char event[80];
282         sprintf(event, "%s%s%s%s", 
283                 (flags&BS_HIT)?"[hit]":"",
284                 (flags&BS_DOWN)?"[down]":"",
285                 (flags&BS_OVER)?"[over]":"",
286                 (flags&BS_UP)?"[up]":"");
287         if(flags&0xf0) {
288             printf("%s | Show %d at depth %d for %s flags=%02x\n", prefix, id, depth, event, flags);
289         } else {
290             printf("%s | Show %d at depth %d for %s\n", prefix, id, depth, event);
291         }
292         swf_GetMatrix(tag,NULL);  // matrix
293     }
294 }
295
296 void dumpFont(TAG*tag, char*prefix)
297 {
298     SWFFONT* font = malloc(sizeof(SWFFONT));
299     memset(font, 0, sizeof(SWFFONT));
300     if(tag->id == ST_DEFINEFONT2) {
301         swf_FontExtract_DefineFont2(0, font, tag);
302     } else if(tag->id == ST_DEFINEFONT) {
303         swf_FontExtract_DefineFont(0, font, tag);
304     } else {
305         printf("%sCan't parse %s yet\n", prefix,swf_TagGetName(tag));
306     }
307     printf("%sID: %d\n", prefix,font->id);
308     printf("%sVersion: %d\n", prefix,font->version);
309     printf("%sname: %s\n", prefix,font->name);
310     printf("%scharacters: %d\n", prefix,font->numchars);
311     printf("%shightest mapped unicode value: %d\n", prefix,font->maxascii);
312     if(font->layout)
313     {
314         printf("%sascent:%.2f\n", prefix,font->layout->ascent / 20.0);
315         printf("%sdescent:%.2f\n", prefix,font->layout->descent / 20.0);
316         printf("%sleading:%.2f\n", prefix,font->layout->leading / 20.0);
317         printf("%skerning records:%d\n", prefix,font->layout->kerningcount);
318     }
319     printf("%sstyle: %d\n", prefix,font->style);
320     printf("%sencoding: %02x\n", prefix,font->encoding);
321     printf("%slanguage: %02x\n", prefix,font->language);
322     int t;
323     for(t=0;t<font->numchars;t++) {
324         int u = font->glyph2ascii?font->glyph2ascii[t]:-1;
325         printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u);
326         SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape);
327         SHAPELINE*line = shape->lines;
328
329         while(line) {
330             if(line->type == moveTo) {
331                 printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
332             } else if(line->type == lineTo) {
333                 printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0);
334             } else if(line->type == splineTo) {
335                 printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix,
336                         line->sx/20.0, line->sy/20.0,
337                         line->x/20.0, line->y/20.0
338                         );
339             }
340             line = line->next;
341         }
342         swf_Shape2Free(shape);
343         free(shape);
344     }
345     swf_FontFree(font);
346 }
347
348 SWF swf;
349 int fontnum = 0;
350 SWFFONT**fonts;
351
352 void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color) 
353 {
354     int font=-1,t;
355     printf("                <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a);
356     for(t=0;t<fontnum;t++)
357     {
358         if(fonts[t]->id == fontid) {
359             font = t;
360             break;
361         }
362     }
363
364     for(t=0;t<nr;t++)
365     {
366         unsigned char a; 
367         if(font>=0) {
368             if(glyphs[t] >= fonts[font]->numchars  /*glyph is in range*/
369                     || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
370               ) a = glyphs[t];
371             else {
372                 if(fonts[font]->glyph2ascii[glyphs[t]])
373                     a = fonts[font]->glyph2ascii[glyphs[t]];
374                 else
375                     a = glyphs[t];
376             }
377         } else {
378             a = glyphs[t];
379         }
380         if(a>=32)
381             printf("%c", a);
382         else
383             printf("\\x%x", (int)a);
384     }
385     printf("\n");
386 }
387
388 void handleText(TAG*tag) 
389 {
390   printf("\n");
391   swf_ParseDefineText(tag,textcallback, 0);
392 }
393             
394 void handleDefineSound(TAG*tag)
395 {
396     U16 id = swf_GetU16(tag);
397     U8 flags = swf_GetU8(tag);
398     int compression = (flags>>4)&7;
399     int rate = (flags>>2)&3;
400     int bits = flags&2?16:8;
401     int stereo = flags&1;
402     printf(" (");
403     if(compression == 0) printf("Raw ");
404     else if(compression == 1) printf("ADPCM ");
405     else if(compression == 2) printf("MP3 ");
406     else if(compression == 3) printf("Raw little-endian ");
407     else if(compression == 6) printf("ASAO ");
408     else printf("? ");
409     if(rate == 0) printf("5.5Khz ");
410     if(rate == 1) printf("11Khz ");
411     if(rate == 2) printf("22Khz ");
412     if(rate == 3) printf("44Khz ");
413     printf("%dBit ", bits);
414     if(stereo) printf("stereo");
415     else printf("mono");
416     printf(")");
417 }
418
419 void handleDefineBits(TAG*tag)
420 {
421     U16 id;
422     U8 mode;
423     U16 width,height;
424     int bpp;
425     id = swf_GetU16(tag);
426     mode = swf_GetU8(tag);
427     width = swf_GetU16(tag);
428     height = swf_GetU16(tag);
429     printf(" image %dx%d",width,height);
430     if(mode == 3) printf(" (8 bpp)");
431     else if(mode == 4) printf(" (16 bpp)");
432     else if(mode == 5) printf(" (32 bpp)");
433     else printf(" (? bpp)");
434 }
435
436 void handleEditText(TAG*tag)
437 {
438     U16 id ;
439     U16 flags;
440     int t;
441     id = swf_GetU16(tag);
442     swf_GetRect(tag,0);
443     
444     //swf_ResetReadBits(tag);
445
446     if (tag->readBit)  
447     { tag->pos++; 
448       tag->readBit = 0; 
449     }
450     flags = swf_GetBits(tag,16);
451     if(flags & ET_HASFONT) {
452         swf_GetU16(tag); //font
453         swf_GetU16(tag); //fontheight
454     }
455     if(flags & ET_HASTEXTCOLOR) {
456         swf_GetU8(tag); //rgba
457         swf_GetU8(tag);
458         swf_GetU8(tag);
459         swf_GetU8(tag);
460     }
461     if(flags & ET_HASMAXLENGTH) {
462         swf_GetU16(tag); //maxlength
463     }
464     if(flags & ET_HASLAYOUT) {
465         swf_GetU8(tag); //align
466         swf_GetU16(tag); //left margin
467         swf_GetU16(tag); //right margin
468         swf_GetU16(tag); //indent
469         swf_GetU16(tag); //leading
470     }
471     printf(" variable \"%s\" ", &tag->data[tag->pos]);
472     if(flags & ET_HTML) printf("(html)");
473     if(flags & ET_NOSELECT) printf("(noselect)");
474     if(flags & ET_PASSWORD) printf("(password)");
475     if(flags & ET_READONLY) printf("(readonly)");
476
477     if(flags & (ET_X1 | ET_X3 ))
478     {
479         printf(" undefined flags: %08x (%08x)", (flags&(ET_X1|ET_X3)), flags);
480     }
481     
482     while(tag->data[tag->pos++]);
483     if(flags & ET_HASTEXT)
484    //  printf(" text \"%s\"\n", &tag->data[tag->pos]) //TODO
485         ;
486 }
487 void printhandlerflags(U32 handlerflags) 
488 {
489     if(handlerflags&1) printf("[on load]");
490     if(handlerflags&2) printf("[enter frame]");
491     if(handlerflags&4) printf("[unload]");
492     if(handlerflags&8) printf("[mouse move]");
493     if(handlerflags&16) printf("[mouse down]");
494     if(handlerflags&32) printf("[mouse up]");
495     if(handlerflags&64) printf("[key down]");
496     if(handlerflags&128) printf("[key up]");
497
498     if(handlerflags&256) printf("[data]");
499     if(handlerflags&512) printf("[initialize]");
500     if(handlerflags&1024) printf("[mouse press]");
501     if(handlerflags&2048) printf("[mouse release]");
502     if(handlerflags&4096) printf("[mouse release outside]");
503     if(handlerflags&8192) printf("[mouse rollover]");
504     if(handlerflags&16384) printf("[mouse rollout]");
505     if(handlerflags&32768) printf("[mouse drag over]");
506
507     if(handlerflags&0x10000) printf("[mouse drag out]");
508     if(handlerflags&0x20000) printf("[key press]");
509     if(handlerflags&0x40000) printf("[construct even]");
510     if(handlerflags&0xfff80000) printf("[???]");
511 }
512 void handleVideoStream(TAG*tag, char*prefix)
513 {
514     U16 id = swf_GetU16(tag);
515     U16 frames = swf_GetU16(tag);
516     U16 width = swf_GetU16(tag);
517     U16 height = swf_GetU16(tag);
518     U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
519     U8 codec = swf_GetU8(tag);
520     printf(" (%d frames, %dx%d", frames, width, height);
521     if(flags&1)
522         printf(" smoothed");
523     if(codec == 2)
524         printf(" sorenson h.263)");
525     else
526         printf(" codec 0x%02x)", codec);
527 }
528 void handleVideoFrame(TAG*tag, char*prefix)
529 {
530     U32 code, version, reference, sizeflags;
531     U32 width=0, height=0;
532     U8 type;
533     U16 id = swf_GetU16(tag);
534     U16 frame = swf_GetU16(tag);
535     U8 deblock,flags, tmp, bit;
536     U32 quantizer;
537     char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
538     printf(" (frame %d) ", frame);
539
540     /* video packet follows */
541     code = swf_GetBits(tag, 17);
542     version = swf_GetBits(tag, 5);
543     reference = swf_GetBits(tag, 8);
544
545     sizeflags = swf_GetBits(tag, 3);
546     switch(sizeflags)
547     {
548         case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
549         case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
550         case 2: width = 352; height = 288; break;
551         case 3: width = 176; height = 144; break;
552         case 4: width = 128; height = 96; break;
553         case 5: width = 320; height = 240; break;
554         case 6: width = 160; height = 120; break;
555         case 7: width = -1; height = -1;/*reserved*/ break;
556     }
557     printf("%dx%d ", width, height);
558     type = swf_GetBits(tag, 2);
559     printf("%s", types[type]);
560
561     deblock = swf_GetBits(tag, 1);
562     if(deblock)
563         printf(" deblock ", deblock);
564     quantizer = swf_GetBits(tag, 5);
565     printf(" quant: %d ", quantizer);
566 }
567
568 void dumpFilter(FILTER*filter)
569 {
570     if(filter->type == FILTERTYPE_BLUR) {
571         FILTER_BLUR*f = (FILTER_BLUR*)filter;
572         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
573         printf("passes: %d\n", f->passes);
574     } if(filter->type == FILTERTYPE_GLOW) {
575         FILTER_GLOW*f = (FILTER_GLOW*)filter;
576         printf("color %02x%02x%02x%02x\n", f->rgba.r,f->rgba.g,f->rgba.b,f->rgba.a);
577         printf("blurx: %f blury: %f strength: %f\n", f->blurx, f->blury, f->strength);
578         printf("passes: %d\n", f->passes);
579         printf("flags: %s%s%s\n", 
580                 f->knockout?"knockout ":"",
581                 f->composite?"composite ":"",
582                 f->innerglow?"innerglow":"");
583     } if(filter->type == FILTERTYPE_DROPSHADOW) {
584         FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)filter;
585         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
586         printf("passes: %d\n", f->passes);
587         printf("angle: %f distance: %f\n", f->angle, f->distance);
588         printf("strength: %f passes: %d\n", f->strength, f->passes);
589         printf("flags: %s%s%s\n", 
590                 f->knockout?"knockout ":"",
591                 f->composite?"composite ":"",
592                 f->innershadow?"innershadow ":"");
593     } if(filter->type == FILTERTYPE_BEVEL) {
594         FILTER_BEVEL*f = (FILTER_BEVEL*)filter;
595         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
596         printf("passes: %d\n", f->passes);
597         printf("angle: %f distance: %f\n", f->angle, f->distance);
598         printf("strength: %f passes: %d\n", f->strength, f->passes);
599         printf("flags: %s%s%s%s\n", 
600                 f->ontop?"ontop":"",
601                 f->knockout?"knockout ":"",
602                 f->composite?"composite ":"",
603                 f->innershadow?"innershadow ":"");
604     } if(filter->type == FILTERTYPE_GRADIENTGLOW) {
605         FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)filter;
606         swf_DumpGradient(stdout, f->gradient);
607         printf("blurx: %f blury: %f\n", f->blurx, f->blury);
608         printf("angle: %f distance: %f\n", f->angle, f->distance);
609         printf("strength: %f passes: %d\n", f->strength, f->passes);
610         printf("flags: %s%s%s%s\n", 
611                 f->knockout?"knockout ":"",
612                 f->ontop?"ontop ":"",
613                 f->composite?"composite ":"",
614                 f->innershadow?"innershadow ":"");
615     }
616     rfx_free(filter);
617 }
618
619 void handlePlaceObject23(TAG*tag, char*prefix)
620 {
621     U8 flags,flags2=0;
622     MATRIX m;
623     CXFORM cx;
624     char pstr[3][256];
625     int ppos[3] = {0,0,0};
626     swf_SetTagPos(tag, 0);
627     flags = swf_GetU8(tag);
628     if(tag->id == ST_PLACEOBJECT3)
629         flags2 = swf_GetU8(tag);
630     swf_GetU16(tag); //depth
631
632     //flags&1: move
633     if(flags&2) swf_GetU16(tag); //id
634     if(flags&4) {
635         swf_GetMatrix(tag,&m);
636         if(placements) {
637             ppos[0] += sprintf(pstr[0], "| Matrix             ");
638             ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
639             ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
640         }
641     }
642     if(flags&8) {
643         swf_GetCXForm(tag, &cx, 1);
644         if(placements) {
645             ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm    r    g    b    a ");
646             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);
647             ppos[2] += sprintf(pstr[2]+ppos[2], "| add    %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
648         }
649     }
650     if(flags&16) {
651         U16 ratio = swf_GetU16(tag); //ratio
652         if(placements) {
653             ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
654             ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
655             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
656         }
657     }
658     if(flags&64) {
659         U16 clip = swf_GetU16(tag); //clip
660         if(placements) {
661             ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip  ");
662             ppos[1] += sprintf(pstr[1]+ppos[1], "| %-4d ", clip);
663             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
664         }
665     }
666     if(flags&32) { while(swf_GetU8(tag)); }
667
668     if(flags2&1) { // filter list
669         U8 num = swf_GetU8(tag);
670         if(placements)
671             printf("\n%d filters\n", num);
672         char*filtername[] = {"dropshadow","blur","glow","bevel","gradientglow","convolution","colormatrix","gradientbevel"};
673         int t;
674         for(t=0;t<num;t++) {
675             FILTER*filter = swf_GetFilter(tag);
676             if(!filter) {
677                 printf("\n"); 
678                 return;
679             }
680             if(placements) {
681                 printf("filter %d: %02x (%s)\n", t, filter->type, (filter->type<sizeof(filtername)/sizeof(filtername[0]))?filtername[filter->type]:"?");
682                 dumpFilter(filter);
683             }
684         }
685     }
686     if(flags2&2) { // blend mode
687         U8 blendmode = swf_GetU8(tag);
688         if(placements) {
689             int t;
690             char name[80];
691             sprintf(name, "%-5d", blendmode);
692             for(t=0;blendModeNames[t];t++) {
693                 if(blendmode==t) {
694                     sprintf(name, "%-5s", blendModeNames[t]);
695                     break;
696                 }
697             }
698             ppos[0] += sprintf(pstr[0]+ppos[0], "| Blend ");
699             ppos[1] += sprintf(pstr[1]+ppos[1], "| %s ", name);
700             ppos[2] += sprintf(pstr[2]+ppos[2], "|       ");
701         }
702     }
703
704     if(placements && ppos[0]) {
705         printf("\n");
706         printf("%s %s\n", prefix, pstr[0]);
707         printf("%s %s\n", prefix, pstr[1]);
708         printf("%s %s", prefix, pstr[2]);
709     }
710     if(flags&128) {
711       if (action) {
712         U16 reserved;
713         U32 globalflags;
714         U32 handlerflags;
715         char is32 = 0;
716         printf("\n");
717         reserved = swf_GetU16(tag); // must be 0
718         globalflags = swf_GetU16(tag); //TODO: 32 if version>=6
719         if(reserved) {
720             printf("Unknown parameter field not zero: %04x\n", reserved);
721             return;
722         }
723         printf("global flags: %04x\n", globalflags);
724
725         handlerflags = swf_GetU16(tag); //TODO: 32 if version>=6
726         if(!handlerflags) {
727             handlerflags = swf_GetU32(tag);
728             is32 = 1;
729         }
730         while(handlerflags)  {
731             int length;
732             int t;
733             ActionTAG*a;
734
735             globalflags &= ~handlerflags;
736             printf("%s flags %08x ",prefix, handlerflags);
737             printhandlerflags(handlerflags);
738             length = swf_GetU32(tag);
739             printf(", %d bytes actioncode\n",length);
740             a = swf_ActionGet(tag);
741             swf_DumpActions(a,prefix);
742             swf_ActionFree(a);
743
744             handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag); //TODO: 32 if version>=6
745         }
746         if(globalflags) // should go to sterr.
747             printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
748     } else {
749       printf(" has action code\n");
750     }
751     } else printf("\n");
752 }
753
754 void handlePlaceObject(TAG*tag, char*prefix)
755 {
756     TAG*tag2 = swf_InsertTag(0, ST_PLACEOBJECT2);
757     U16 id, depth;
758     MATRIX matrix; 
759     CXFORM cxform;
760
761     swf_SetTagPos(tag, 0);
762     id = swf_GetU16(tag);
763     depth = swf_GetU16(tag);
764     swf_GetMatrix(tag, &matrix);
765     swf_GetCXForm(tag, &cxform, 0);
766
767     swf_SetU8(tag2, 14 /* char, matrix, cxform */);
768     swf_SetU16(tag2, depth);
769     swf_SetU16(tag2, id);
770     swf_SetMatrix(tag2, &matrix);
771     swf_SetCXForm(tag2, &cxform, 1);
772
773     handlePlaceObject23(tag2, prefix);
774 }
775 char stylebuf[256];
776 char* fillstyle2str(FILLSTYLE*style)
777 {
778     switch(style->type) {
779         case 0x00:
780             sprintf(stylebuf, "SOLID %02x%02x%02x%02x", style->color.r, style->color.g, style->color.b, style->color.a);
781             break;
782         case 0x10: case 0x11: case 0x12: case 0x13:
783             sprintf(stylebuf, "GRADIENT (%d steps)", style->gradient.num);
784             break;
785         case 0x40: case 0x42:
786             /* TODO: display information about that bitmap */
787             sprintf(stylebuf, "BITMAPt%s %d", (style->type&2)?"n":"", style->id_bitmap);
788             /* TODO: show matrix */
789             //swf_DumpMatrix(stdout, &style->m);
790             break;
791         case 0x41: case 0x43:
792             /* TODO: display information about that bitmap */
793             sprintf(stylebuf, "BITMAPc%s %d", (style->type&2)?"n":"", style->id_bitmap);
794             /* TODO: show matrix */
795             //swf_DumpMatrix(stdout, &style->m);
796             break;
797         default:
798             sprintf(stylebuf, "UNKNOWN[%02x]",style->type);
799     }
800     return stylebuf;
801 }
802 char* linestyle2str(LINESTYLE*style)
803 {
804     sprintf(stylebuf, "%.2f %02x%02x%02x%02x", style->width/20.0, style->color.r, style->color.g, style->color.b, style->color.a);
805     return stylebuf;
806 }
807
808 void handleShape(TAG*tag, char*prefix)
809 {
810     SHAPE2 shape;
811     SHAPELINE*line;
812     int t,max;
813
814     tag->pos = 0;
815     tag->readBit = 0;
816     swf_ParseDefineShape(tag, &shape);
817
818     max = shape.numlinestyles > shape.numfillstyles?shape.numlinestyles:shape.numfillstyles;
819
820     if(max) printf("%s | fillstyles(%02d)        linestyles(%02d)\n", 
821             prefix,
822             shape.numfillstyles,
823             shape.numlinestyles
824             );
825     else    printf("%s | (Neither line nor fill styles)\n", prefix);
826
827     for(t=0;t<max;t++) {
828         printf("%s", prefix);
829         if(t < shape.numfillstyles) {
830             printf(" | %-2d) %-18.18s", t+1, fillstyle2str(&shape.fillstyles[t]));
831         } else {
832             printf("                         ");
833         }
834         if(t < shape.numlinestyles) {
835             printf("%-2d) %s", t+1, linestyle2str(&shape.linestyles[t]));
836         }
837         printf("\n");
838         //if(shape.fillstyles[t].type&0x40) {
839         //    MATRIX m = shape.fillstyles[t].m;
840         //    swf_DumpMatrix(stdout, &m);
841         //}
842     }
843
844     printf("%s |\n", prefix);
845
846     line = shape.lines;
847     while(line) {
848         printf("%s | fill: %02d/%02d line:%02d - ",
849                 prefix, 
850                 line->fillstyle0,
851                 line->fillstyle1,
852                 line->linestyle);
853         if(line->type == moveTo) {
854             printf("moveTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
855         } else if(line->type == lineTo) {
856             printf("lineTo %.2f %.2f\n", line->x/20.0, line->y/20.0);
857         } else if(line->type == splineTo) {
858             printf("splineTo (%.2f %.2f) %.2f %.2f\n", 
859                     line->sx/20.0, line->sy/20.0,
860                     line->x/20.0, line->y/20.0
861                     );
862         }
863         line = line->next;
864     }
865     printf("%s |\n", prefix);
866 }
867     
868 void fontcallback1(void*self, U16 id,U8 * name)
869 { fontnum++;
870 }
871
872 void fontcallback2(void*self, U16 id,U8 * name)
873
874   swf_FontExtract(&swf,id,&fonts[fontnum]);
875   fontnum++;
876 }
877
878 static U8 printable(U8 a)
879 {
880     if(a<32 || a==127) return '.';
881     else return a;
882 }
883 void hexdumpTag(TAG*tag, char* prefix)
884 {
885     int t;
886     char ascii[32];
887     printf("                %s-=> ",prefix);
888     for(t=0;t<tag->len;t++) {
889         printf("%02x ", tag->data[t]);
890         ascii[t&15] = printable(tag->data[t]);
891         if((t && ((t&15)==15)) || (t==tag->len-1))
892         {
893             int s,p=((t)&15)+1;
894             ascii[p] = 0;
895             for(s=p-1;s<16;s++) {
896                 printf("   ");
897             }
898             if(t==tag->len-1)
899                 printf(" %s\n", ascii);
900             else
901                 printf(" %s\n                %s-=> ",ascii,prefix);
902         }
903     }
904 }
905
906 void handleExportAssets(TAG*tag, char* prefix)
907 {
908     int num;
909     U16 id;
910     char* name;
911     int t;
912     num = swf_GetU16(tag);
913     for(t=0;t<num;t++)
914     {
915         id = swf_GetU16(tag);
916         name = swf_GetString(tag);
917         printf("%sexports %04d as \"%s\"\n", prefix, id, name);
918     }
919 }
920
921 void dumperror(const char* format, ...)
922 {
923     char buf[1024];
924     va_list arglist;
925
926     va_start(arglist, format);
927     vsprintf(buf, format, arglist);
928     va_end(arglist);
929
930     if(!html && !xy)
931         printf("==== Error: %s ====\n", buf);
932 }
933
934 static char strbuf[800];
935 static int bufpos=0;
936
937 char* timestring(double f)
938 {
939     int hours   = (int)(f/3600);
940     int minutes = (int)((f-hours*3600)/60);
941     int seconds = (int)((f-hours*3600-minutes*60));
942     int useconds = (int)((f-(int)f)*1000+0.5);
943     bufpos+=100;
944     bufpos%=800;
945     sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
946     return &strbuf[bufpos];
947 }
948
949 int main (int argc,char ** argv)
950
951     TAG*tag;
952 #ifdef HAVE_STAT
953     struct stat statbuf;
954 #endif
955     int f;
956     int xsize,ysize;
957     char issprite = 0; // are we inside a sprite definition?
958     int spriteframe = 0;
959     int mainframe=0;
960     char* spriteframelabel = 0;
961     char* framelabel = 0;
962     char prefix[128];
963     int filesize = 0;
964     int filepos = 0;
965     prefix[0] = 0;
966     memset(idtab,0,65536);
967
968     processargs(argc, argv);
969
970     if(!filename)
971     {
972         fprintf(stderr, "You must supply a filename.\n");
973         return 1;
974     }
975
976     f = open(filename,O_RDONLY|O_BINARY);
977     if (f<0)
978     { 
979         char buffer[256];
980         sprintf(buffer, "Couldn't open %s", filename);
981         perror(buffer);
982         exit(1);
983     }
984     char header[3];
985     read(f, header, 3);
986     int compressed = (header[0]=='C');
987     close(f);
988     f = open(filename,O_RDONLY|O_BINARY);
989
990     if FAILED(swf_ReadSWF(f,&swf))
991     { 
992         fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
993         close(f);
994         exit(1);
995     }
996
997 #ifdef HAVE_STAT
998     fstat(f, &statbuf);
999     if(statbuf.st_size != swf.fileSize && !compressed)
1000         dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
1001                 statbuf.st_size, swf.fileSize);
1002     filesize = statbuf.st_size;
1003 #endif
1004
1005     close(f);
1006
1007     //if(action && swf.fileVersion>=9) {
1008     //    fprintf(stderr, "Actionscript parsing (-a) not yet supported for SWF versions>=9\n");
1009     //    action = 0;
1010     //}
1011
1012     xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
1013     ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
1014     if(xy)
1015     {
1016         if(xy&1)
1017         printf("-X %d", xsize);
1018
1019         if((xy&1) && (xy&6))
1020         printf(" ");
1021
1022         if(xy&2)
1023         printf("-Y %d", ysize);
1024         
1025         if((xy&3) && (xy&4))
1026         printf(" ");
1027
1028         if(xy&4)
1029         printf("-r %.2f", swf.frameRate/256.0);
1030         
1031         if((xy&7) && (xy&8))
1032         printf(" ");
1033         
1034         if(xy&8)
1035         printf("-f %d", swf.frameCount);
1036         
1037         printf("\n");
1038         return 0;
1039     }
1040     if(html)
1041     {
1042         char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
1043                                "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0","9,0,0,0"};
1044         if(swf.fileVersion>9) {
1045             fprintf(stderr, "Fileversion>9\n");
1046             exit(1);
1047         }
1048
1049         if(xhtml) {
1050             printf("<object type=\"application/x-shockwave-flash\" data=\"%s\" width=\"%d\" height=\"%d\">\n"
1051                             "<param name=\"movie\" value=\"%s\"/>\n"
1052                             "<param name=\"play\" value=\"true\"/>\n"
1053                             "<param name=\"loop\" value=\"false\"/>\n"
1054                             "<param name=\"quality\" value=\"high\"/>\n"
1055                             "<param name=\"loop\" value=\"false\"/>\n"
1056                             "</object>\n\n", filename, xsize, ysize, filename);
1057         } else {
1058             printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
1059                    " WIDTH=\"%d\"\n"
1060                    //" BGCOLOR=#ffffffff\n"?
1061                    " HEIGHT=\"%d\"\n"
1062                    //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
1063                    " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
1064                    "  <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
1065                    "  <PARAM NAME=\"PLAY\" VALUE=\"true\">\n" 
1066                    "  <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
1067                    "  <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
1068                    "  <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
1069                    "   PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
1070                    "   TYPE=\"application/x-shockwave-flash\"\n"
1071                    "   PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
1072                    "  </EMBED>\n" 
1073                    "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion], 
1074                                   filename, filename, xsize, ysize);
1075         }
1076         return 0;
1077     } 
1078     printf("[HEADER]        File version: %d\n", swf.fileVersion);
1079     if(compressed) {
1080         printf("[HEADER]        File is zlib compressed.");
1081         if(filesize && swf.fileSize)
1082             printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
1083         else
1084             printf("\n");
1085     }
1086     printf("[HEADER]        File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
1087     printf("[HEADER]        Frame rate: %f\n",swf.frameRate/256.0);
1088     printf("[HEADER]        Frame count: %d\n",swf.frameCount);
1089     printf("[HEADER]        Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
1090     if(swf.movieSize.xmin)
1091         printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
1092     else 
1093         printf("\n");
1094     printf("[HEADER]        Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
1095     if(swf.movieSize.ymin)
1096         printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
1097     else 
1098         printf("\n");
1099
1100     tag = swf.firstTag;
1101    
1102     if(showtext) {
1103         fontnum = 0;
1104         swf_FontEnumerate(&swf,&fontcallback1, 0);
1105         fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
1106         fontnum = 0;
1107         swf_FontEnumerate(&swf,&fontcallback2, 0);
1108     }
1109
1110     while(tag) {
1111         char*name = swf_TagGetName(tag);
1112         char myprefix[128];
1113         if(!name) {
1114             dumperror("Unknown tag:0x%03x", tag->id);
1115             //tag = tag->next;
1116             //continue;
1117         }
1118         if(!name) {
1119             name = "UNKNOWN TAG";
1120         }
1121         if(cumulative) {
1122             filepos += tag->len;
1123             printf("[%03x] %9ld %9ld %s%s", tag->id, tag->len, filepos, prefix, swf_TagGetName(tag));
1124         } else {
1125             printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
1126         }
1127         
1128         if(swf_isDefiningTag(tag)) {
1129             U16 id = swf_GetDefineID(tag);
1130             printf(" defines id %04d", id);
1131             if(idtab[id])
1132                 dumperror("Id %04d is defined more than once.", id);
1133             idtab[id] = 1;
1134         }
1135         else if(swf_isPseudoDefiningTag(tag)) {
1136             U16 id = swf_GetDefineID(tag);
1137             printf(" adds information to id %04d", id);
1138             if(!idtab[id])
1139                 dumperror("Id %04d is not yet defined.\n", id);
1140         }
1141         else if(tag->id == ST_PLACEOBJECT) {
1142             printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
1143             if(swf_GetName(tag))
1144                 printf(" name \"%s\"",swf_GetName(tag));
1145         }
1146         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1147             if(tag->data[0]&1)
1148                 printf(" moves");
1149             else
1150                 printf(" places");
1151             
1152             if(tag->data[0]&2)
1153                 printf(" id %04d",swf_GetPlaceID(tag));
1154             else
1155                 printf(" object");
1156
1157             printf(" at depth %04d", swf_GetDepth(tag));
1158
1159             if(tag->id == ST_PLACEOBJECT3 && tag->data[1]&4)
1160                 printf(" as bitmap");
1161            
1162             swf_SetTagPos(tag, 0);
1163             if(tag->data[0]&64) {
1164                 SWFPLACEOBJECT po;
1165                 swf_GetPlaceObject(tag, &po);
1166                 printf(" (clip to %04d)", po.clipdepth);
1167                 swf_PlaceObjectFree(&po);
1168             }
1169             if(swf_GetName(tag))
1170                 printf(" name \"%s\"",swf_GetName(tag));
1171
1172         }
1173         else if(tag->id == ST_REMOVEOBJECT) {
1174             printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
1175         }
1176         else if(tag->id == ST_REMOVEOBJECT2) {
1177             printf(" removes object from depth %04d", swf_GetDepth(tag));
1178         }
1179         else if(tag->id == ST_FREECHARACTER) {
1180             printf(" frees object %04d", swf_GetPlaceID(tag));
1181         }
1182         else if(tag->id == ST_DOABC) {
1183             swf_SetTagPos(tag, 0);
1184             U32 flags = swf_GetU32(tag);
1185             char*s = swf_GetString(tag);
1186             if(*s) {
1187                 printf(" \"%s\"", s);
1188             }
1189             if(flags&1) {
1190                 if(name)
1191                     printf(",");
1192                 printf(" lazy load");
1193             }
1194             swf_SetTagPos(tag, 0);
1195         }
1196         else if(tag->id == ST_STARTSOUND) {
1197             U8 flags;
1198             U16 id;
1199             id = swf_GetU16(tag);
1200             flags = swf_GetU8(tag);
1201             if(flags & 32)
1202                 printf(" stops sound with id %04d", id);
1203             else
1204                 printf(" starts sound with id %04d", id);
1205             if(flags & 16)
1206                 printf(" (if not already playing)");
1207             if(flags & 1)
1208                 swf_GetU32(tag);
1209             if(flags & 2)
1210                 swf_GetU32(tag);
1211             if(flags & 4) {
1212                 printf(" looping %d times", swf_GetU16(tag));
1213             }
1214         }
1215         else if(tag->id == ST_FRAMELABEL) {
1216             int l = strlen(tag->data);
1217             printf(" \"%s\"", tag->data);
1218             if((l+1) < tag->len) {
1219                 printf(" has %d extra bytes", tag->len-1-l);
1220                 if(tag ->len - (l+1) == 1 && tag->data[tag->len-1] == 1)
1221                     printf(" (ANCHOR)");
1222             }
1223             if((framelabel && !issprite) ||
1224                (spriteframelabel && issprite)) {
1225                 dumperror("Frame %d has more than one label", 
1226                         issprite?spriteframe:mainframe);
1227             }
1228             if(issprite) spriteframelabel = tag->data;
1229             else framelabel = tag->data;
1230         }
1231         else if(tag->id == ST_SHOWFRAME) {
1232             char*label = issprite?spriteframelabel:framelabel;
1233             int frame = issprite?spriteframe:mainframe;
1234             int nframe = frame;
1235             if(!label) {
1236                 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
1237                     tag = tag->next;
1238                     if(issprite) spriteframe++;
1239                     else mainframe++;
1240                     nframe++;
1241                 }
1242             }
1243             if(nframe == frame)
1244                 printf(" %d (%s)", frame+1, timestring(frame*(256.0/(swf.frameRate+0.1))));
1245             else
1246                 printf(" %d-%d (%s-%s)", frame+1, nframe+1,
1247                         timestring(frame*(256.0/(swf.frameRate+0.1))),
1248                         timestring(nframe*(256.0/(swf.frameRate+0.1)))
1249                         );
1250             if(label)
1251                 printf(" (label \"%s\")", label);
1252             if(issprite) {spriteframe++; spriteframelabel = 0;}
1253             if(!issprite) {mainframe++; framelabel = 0;}
1254         }
1255         else if(tag->id == ST_SETBACKGROUNDCOLOR) {
1256             U8 r = swf_GetU8(tag);
1257             U8 g = swf_GetU8(tag);
1258             U8 b = swf_GetU8(tag);
1259             printf(" (%02x/%02x/%02x)",r,g,b);
1260         }
1261         else if(tag->id == ST_PROTECT) {
1262             if(tag->len>0) {
1263                 printf(" %s", swf_GetString(tag));
1264             }
1265         }
1266         else if(tag->id == ST_CSMTEXTSETTINGS) {
1267             U16 id = swf_GetU16(tag);
1268             U8 flags = swf_GetU8(tag);
1269             printf(" (");
1270             if(flags&0x40) {
1271                 printf("flashtype,");
1272             }
1273             switch(((flags>>3)&7)) {
1274                 case 0:printf("no grid,");break;
1275                 case 1:printf("pixel grid,");break;
1276                 case 2:printf("subpixel grid,");break;
1277                 case 3:printf("unknown grid,");break;
1278             }
1279             if(flags&0x87) 
1280                 printf("unknown[%08x],", flags);
1281             float thickness = swf_GetFixed(tag);
1282             float sharpness = swf_GetFixed(tag);
1283             printf("s=%.2f,t=%.2f)", thickness, sharpness);
1284             swf_GetU8(tag);
1285         }
1286
1287         if(tag->id == ST_DEFINEBITSLOSSLESS ||
1288            tag->id == ST_DEFINEBITSLOSSLESS2) {
1289             handleDefineBits(tag);
1290             printf("\n");
1291         }
1292         else if(tag->id == ST_DEFINESOUND) {
1293             handleDefineSound(tag);
1294             printf("\n");
1295         }
1296         else if(tag->id == ST_VIDEOFRAME) {
1297             handleVideoFrame(tag, myprefix);
1298             printf("\n");
1299         }
1300         else if(tag->id == ST_DEFINEVIDEOSTREAM) {
1301             handleVideoStream(tag, myprefix);
1302             printf("\n");
1303         }
1304         else if(tag->id == ST_DEFINEEDITTEXT) {
1305             handleEditText(tag);
1306             printf("\n");
1307         }
1308         else if(tag->id == ST_DEFINEMOVIE) {
1309             U16 id = swf_GetU16(tag);
1310             char*s = swf_GetString(tag);
1311             printf(" URL: %s\n", s);
1312         }
1313         else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
1314             if(showtext)
1315                 handleText(tag);
1316             else
1317                 printf("\n");
1318         }
1319         else if(tag->id == ST_DEFINESCALINGGRID) {
1320             U16 id = swf_GetU16(tag);
1321             SRECT r;
1322             swf_GetRect(tag, &r);
1323             printf(" (%.2f,%.2f)-(%.2f,%.2f)\n", r.xmin/20.0, r.ymin/20.0, r.xmax/20.0, r.ymax/20.0);
1324         }
1325         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1326         }
1327         else if(tag->id == ST_NAMECHARACTER || tag->id==ST_DEFINEFONTNAME) {
1328             swf_GetU16(tag);
1329             printf(" \"%s\"\n", swf_GetString(tag));
1330         }
1331         else {
1332             printf("\n");
1333         }
1334
1335         if(bbox && swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
1336             SRECT r = swf_GetDefineBBox(tag);
1337             printf("                %s bbox [%.2f, %.2f, %.2f, %.2f]\n", prefix,
1338                     r.xmin/20.0,
1339                     r.ymin/20.0,
1340                     r.xmax/20.0,
1341                     r.ymax/20.0);
1342         }
1343         
1344         sprintf(myprefix, "                %s", prefix);
1345
1346         if(tag->id == ST_DEFINESPRITE) {
1347             sprintf(prefix, "         ");
1348             if(issprite) {
1349                 dumperror("Sprite definition inside a sprite definition");
1350             }
1351             issprite = 1;
1352             spriteframe = 0;
1353             spriteframelabel = 0;
1354         }
1355         else if(tag->id == ST_END) {
1356             *prefix = 0;
1357             issprite = 0;
1358             spriteframelabel = 0;
1359             if(tag->len)
1360                 dumperror("End Tag not empty");
1361         }
1362         else if(tag->id == ST_EXPORTASSETS || tag->id == ST_SYMBOLCLASS) {
1363             handleExportAssets(tag, myprefix);
1364         }
1365         else if(tag->id == ST_DOACTION && action) {
1366             ActionTAG*actions;
1367             actions = swf_ActionGet(tag);
1368             swf_DumpActions(actions, myprefix);
1369         }
1370         else if((tag->id == ST_DOABC || tag->id == ST_RAWABC) && action) {
1371             void*abccode = swf_ReadABC(tag);
1372             swf_DumpABC(stdout, abccode, "");
1373             swf_FreeABC(abccode);
1374         }
1375         else if(tag->id == ST_DOINITACTION && action) {
1376             ActionTAG*actions;
1377             swf_GetU16(tag); // id
1378             actions = swf_ActionGet(tag);
1379             swf_DumpActions(actions, myprefix);
1380         }
1381         else if(tag->id == ST_DEFINEBUTTON) {
1382             if(showbuttons) {
1383                 dumpButton(tag, myprefix);
1384             }
1385             if(action) {
1386                 dumpButtonActions(tag, myprefix);
1387             }
1388         }
1389         else if(swf_isFontTag(tag) && showfonts) {
1390             dumpFont(tag, myprefix);
1391         }
1392         else if(tag->id == ST_DEFINEBUTTON2) {
1393             if(action) {
1394                 dumpButton2Actions(tag, myprefix);
1395             }
1396         }
1397         else if(tag->id == ST_PLACEOBJECT) {
1398             handlePlaceObject(tag, myprefix);
1399         }
1400         else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
1401             handlePlaceObject23(tag, myprefix);
1402         }
1403         else if(tag->id == ST_DEFINEFONTNAME) {
1404             swf_SetTagPos(tag, 0);
1405             swf_GetU16(tag); //id
1406             swf_GetString(tag); //name
1407             char* copyright = swf_GetString(tag);
1408             printf("%s%s\n", myprefix, copyright);
1409         }
1410         else if(tag->id == ST_DEFINESHAPE ||
1411                 tag->id == ST_DEFINESHAPE2 ||
1412                 tag->id == ST_DEFINESHAPE3 ||
1413                 tag->id == ST_DEFINESHAPE4) {
1414             if(showshapes)
1415                 handleShape(tag, myprefix);
1416         }
1417
1418         if(tag->len && used) {
1419             int num = swf_GetNumUsedIDs(tag);
1420             int* used;
1421             int t;
1422             if(num) {
1423                 used = (int*)malloc(sizeof(int)*num);
1424                 swf_GetUsedIDs(tag, used);
1425                 printf("%s%suses IDs: ", indent, prefix);
1426                 for(t=0;t<num;t++) {
1427                     int id;
1428                     swf_SetTagPos(tag, used[t]);
1429                     id = swf_GetU16(tag);
1430                     printf("%d%s", id, t<num-1?", ":"");
1431                     if(!idtab[id]) {
1432                         dumperror("Id %04d is not yet defined.\n", id);
1433                     }
1434                 }
1435                 printf("\n");
1436             }
1437         }
1438         
1439         if(tag->id == ST_FREECHARACTER) {
1440             U16 id;
1441             swf_SetTagPos(tag, 0);
1442             id = swf_GetU16(tag);
1443             idtab[id] = 0;
1444         }
1445
1446         if(tag->len && hex) {
1447             hexdumpTag(tag, prefix);
1448         }
1449         tag = tag->next;
1450         fflush(stdout);
1451     }
1452
1453     swf_FreeTags(&swf);
1454     return 0;
1455 }
1456
1457