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