minor fixes: swf_SetBits(), cleanup shape struct, fixed dumpfont
[swftools.git] / lib / rfxswf.c
1 /* rfxswf.c
2
3    Library for creating and reading SWF files or parts of it.
4    There's a module directory which provides some extended functionality.
5    Most modules are included at the bottom of this file.
6
7    Part of the swftools package.
8
9    Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
10  
11    This file is distributed under the GPL, see file COPYING for details 
12
13 */
14
15 #include "rfxswf.h"
16
17 #ifdef HAVE_LIBJPEG
18 #ifdef HAVE_JPEGLIB_H
19 #include <jpeglib.h>
20 #define _JPEGLIB_INCLUDED_
21 #endif // HAVE_JPEGLIB_H
22 #endif // HAVE_LIBJPEG
23
24 #ifdef HAVE_LIBZ
25 #ifdef HAVE_ZLIB_H
26 #include <zlib.h>
27 #define _ZLIB_INCLUDED_
28 #endif // HAVE_ZLIB_H
29 #endif // HAVE_LIBZ
30
31 // Win32 support may be broken since it was only tested in an older version for Watcom C
32 #ifdef __NT__
33 #  include <io.h>
34 #  include <malloc.h>
35 #  include <string.h>
36 #  ifdef DEBUG_RFXSWF
37 #    include <stdio.h>
38 #  endif
39 #else
40 #endif
41
42 // internal constants
43
44 #define MALLOC_SIZE     128
45 #define INSERT_RFX_TAG
46
47 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
48
49 // inline wrapper functions
50
51 TAG * swf_NextTag(TAG * t) { return t->next; }
52 TAG * swf_PrevTag(TAG * t) { return t->prev; }
53 int   swf_GetFrameNo(TAG * t)  { return t->frame; }
54 U16   swf_GetTagID(TAG * t)    { return t->id; }
55 U32   swf_GetDataSize(TAG * t) { return t->len; }
56 U8*   swf_GetDataSizePtr(TAG * t) { return &(t->data[t->len]); }
57 U32   swf_GetTagPos(TAG * t)   { return t->pos; }
58
59 // Basic Data Access Functions
60
61 #define swf_ResetReadBits(tag)   if (tag->readBit)  { tag->pos++; tag->readBit = 0; }
62 #define swf_ResetWriteBits(tag)  if (tag->writeBit) { tag->writeBit = 0; }
63
64 // for future purpose: avoid high level lib functions to change tagpos/bitpos
65
66 #define swf_SaveTagPos(tag)
67 #define swf_RestoreTagPos(tag)
68
69 void swf_SetTagPos(TAG * t,U32 pos)
70 { swf_ResetReadBits(t);
71   if (pos<=t->len) t->pos = pos;
72   #ifdef DEBUG_RFXSWF
73   else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
74   #endif
75 }
76
77 U8 swf_GetU8(TAG * t)
78 { swf_ResetReadBits(t);
79   #ifdef DEBUG_RFXSWF
80     if (t->pos>=t->len) 
81     { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
82       return 0;
83     }
84   #endif
85   return t->data[t->pos++];
86 }
87
88 U16 swf_GetU16(TAG * t)
89 { U16 res;
90   swf_ResetReadBits(t);
91   #ifdef DEBUG_RFXSWF
92     if (t->pos>(t->len-2)) 
93     { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
94       return 0;
95     }
96   #endif
97   res = t->data[t->pos] | (t->data[t->pos+1]<<8);
98   t->pos+=2;
99   return res;
100 }
101
102 U32 swf_GetU32(TAG * t)
103 { U32 res;
104   swf_ResetReadBits(t);
105   #ifdef DEBUG_RFXSWF
106     if (t->pos>(t->len-4)) 
107     { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
108       return 0;
109     }
110   #endif
111   res = t->data[t->pos]        | (t->data[t->pos+1]<<8) | 
112        (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);
113   t->pos+=4;
114   return res;
115 }
116
117 int swf_GetBlock(TAG * t,U8 * b,int l)
118 // returns number of bytes written (<=l)
119 // b = NULL -> skip data
120 { swf_ResetReadBits(t);
121   if ((t->len-t->pos)<l) l=t->len-t->pos;
122   if (b && l) memcpy(b,&t->data[t->pos],l);
123   t->pos+=l;
124   return l;
125 }
126
127 int swf_SetBlock(TAG * t,U8 * b,int l)
128 // Appends Block to the end of Tagdata, returns size
129 { U32 newlen = t->len + l;
130   swf_ResetWriteBits(t);
131   if (newlen>t->memsize)
132   { U32  newmem  = MEMSIZE(newlen);  
133     U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem));
134     if (!newdata)
135     {
136       #ifdef DEBUG_RFXSWF
137         fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
138       #endif
139       return 0;
140     }
141     t->memsize = newmem;
142     t->data    = newdata;
143   }
144   if (b) memcpy(&t->data[t->len],b,l);
145   else memset(&t->data[t->len],0x00,l);
146   t->len+=l;
147   return l;
148 }
149
150 int swf_SetU8(TAG * t,U8 v)
151 { swf_ResetWriteBits(t);
152   if ((t->len+1)>t->memsize) return (swf_SetBlock(t,&v,1)==1)?0:-1;
153   t->data[t->len++] = v;
154   return 0;
155 }
156
157 int swf_SetU16(TAG * t,U16 v)
158 { U8 a[2];
159   a[0] = v&0xff;
160   a[1] = v>>8;
161   
162   swf_ResetWriteBits(t);
163   if ((t->len+2)>t->memsize) return (swf_SetBlock(t,a,2)==2)?0:-1;
164   t->data[t->len++] = a[0];
165   t->data[t->len++] = a[1];
166   return 0;
167 }
168
169 int swf_SetU32(TAG * t,U32 v)
170 { U8 a[4];
171   a[0] = v&0xff;        // to ensure correct handling of non-intel byteorder
172   a[1] = (v>>8)&0xff;
173   a[2] = (v>>16)&0xff;
174   a[3] = (v>>24)&0xff;
175   
176   swf_ResetWriteBits(t);
177   if ((t->len+4)>t->memsize) return (swf_SetBlock(t,a,4)==4)?0:-1;
178   t->data[t->len++] = a[0];
179   t->data[t->len++] = a[1];
180   t->data[t->len++] = a[2];
181   t->data[t->len++] = a[3];
182   return 0;
183 }
184
185 U32 swf_GetBits(TAG * t,int nbits)
186 { U32 res = 0;
187   if (!nbits) return 0;
188   if (!t->readBit) t->readBit = 0x80;
189   while (nbits)
190   { res<<=1;
191     if (t->data[t->pos]&t->readBit) res|=1;
192     t->readBit>>=1;
193     nbits--;
194     if (!t->readBit)
195     { if (nbits) t->readBit = 0x80;
196       #ifdef DEBUG_RFXSWF
197       if (t->pos>=t->len) 
198       { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
199         return res;
200       }
201       #endif
202       t->pos++;
203     }
204   }
205   return res;
206 }
207
208 S32 swf_GetSBits(TAG * t,int nbits)
209 { U32 res = swf_GetBits(t,nbits);
210   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
211   return (S32)res;
212 }
213
214 int swf_SetBits(TAG * t,U32 v,int nbits)
215 { U32 bm = 1<<(nbits-1);
216
217   while (nbits)
218   { if (!t->writeBit)
219     { if (FAILED(swf_SetU8(t,0))) return -1;
220       t->writeBit = 0x80;
221     }
222     if (v&bm) t->data[t->len-1] |= t->writeBit;
223     bm>>=1;
224     t->writeBit>>=1;
225     nbits--;
226   }
227   return 0;
228 }
229
230 // Advanced Data Access Functions
231
232 int swf_SetRGB(TAG * t,RGBA * col)
233 { if (!t) return -1;
234   if (col)
235   { swf_SetU8(t,col->r);
236     swf_SetU8(t,col->g);
237     swf_SetU8(t,col->b);
238   } else swf_SetBlock(t,NULL,3);
239   return 0;
240 }
241
242 int swf_SetRGBA(TAG * t,RGBA * col)
243 { if (!t) return -1;
244   if (col)
245   { swf_SetU8(t,col->r);
246     swf_SetU8(t,col->g);
247     swf_SetU8(t,col->b);
248     swf_SetU8(t,col->a);
249   } else swf_SetBlock(t,NULL,4);
250   return 0;
251 }
252
253 int swf_CountBits(U32 v,int nbits)
254 { int n = 33;
255   U32 m = 0x80000000;
256   if (!v) n = 0; else
257   if (v&m)
258   { while (v&m)
259     { n--;
260       m>>=1;
261       if (!m) break;
262     } 
263   }
264   else
265   { while (!(v&m))
266     { n--;
267       m>>=1;
268       if (!m) break;
269     } 
270   }
271   return (n>nbits)?n:nbits;
272 }
273
274 int swf_GetRect(TAG * t,SRECT * r)
275 { int nbits;
276   SRECT dummy;
277   if (!r) r = &dummy;
278   nbits = (int) swf_GetBits(t,5);
279   r->xmin = swf_GetSBits(t,nbits);
280   r->xmax = swf_GetSBits(t,nbits);
281   r->ymin = swf_GetSBits(t,nbits);
282   r->ymax = swf_GetSBits(t,nbits);
283   return 0;
284 }
285
286 int swf_SetRect(TAG * t,SRECT * r)
287 { int nbits;
288     
289   nbits = swf_CountBits(r->xmin,0);
290   nbits = swf_CountBits(r->xmax,nbits);
291   nbits = swf_CountBits(r->ymin,nbits);
292   nbits = swf_CountBits(r->ymax,nbits);
293
294   swf_SetBits(t,nbits,5);
295   swf_SetBits(t,r->xmin,nbits);
296   swf_SetBits(t,r->xmax,nbits);
297   swf_SetBits(t,r->ymin,nbits);
298   swf_SetBits(t,r->ymax,nbits);
299
300   return 0;
301 }
302
303 int swf_GetMatrix(TAG * t,MATRIX * m)
304 { MATRIX dummy;
305   int nbits;
306     
307   if (!m) m = &dummy;
308   
309   if (!t)
310   { m->sx = m->sy = 0x10000;
311     m->r0 = m->r1 = 0;
312     m->tx = m->ty = 0;
313     return -1;
314   }
315
316   swf_ResetReadBits(t);
317   
318   if (swf_GetBits(t,1))
319   { nbits = swf_GetBits(t,5);
320     m->sx = swf_GetSBits(t,nbits);
321     m->sy = swf_GetSBits(t,nbits);
322   }
323   else m->sx = m->sy = 0x10000;
324   
325   if (swf_GetBits(t,1))
326   { nbits = swf_GetBits(t,5);
327     m->r0 = swf_GetSBits(t,nbits);
328     m->r1 = swf_GetSBits(t,nbits);
329   }
330   else m->r0 = m->r1 = 0x0;
331
332   nbits = swf_GetBits(t,5);
333   m->tx = swf_GetSBits(t,nbits);
334   m->ty = swf_GetSBits(t,nbits);
335   
336   return 0;
337 }
338
339 int swf_SetMatrix(TAG * t,MATRIX * m)
340 { int nbits;
341   MATRIX ma;
342
343   if (!m)
344   { m = &ma;
345     ma.sx = ma.sy = 0x10000;
346     ma.r0 = ma.r1 = 0;
347     ma.tx = ma.ty = 0;
348   }
349
350   swf_ResetWriteBits(t);
351
352   if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
353   else
354   { swf_SetBits(t,1,1);
355     nbits = swf_CountBits(m->sx,0);
356     nbits = swf_CountBits(m->sy,nbits);
357     swf_SetBits(t,nbits,5);
358     swf_SetBits(t,m->sx,nbits);
359     swf_SetBits(t,m->sy,nbits);
360   }
361
362   if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
363   else
364   { swf_SetBits(t,1,1);
365     nbits = swf_CountBits(m->r0,0);
366     nbits = swf_CountBits(m->r1,nbits);
367     swf_SetBits(t,nbits,5);
368     swf_SetBits(t,m->r0,nbits);
369     swf_SetBits(t,m->r1,nbits);
370   }
371
372   nbits = swf_CountBits(m->tx,0);
373   nbits = swf_CountBits(m->ty,nbits);
374   swf_SetBits(t,nbits,5);
375   swf_SetBits(t,m->tx,nbits);
376   swf_SetBits(t,m->ty,nbits);
377
378   return 0;
379 }
380
381 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool
382 { CXFORM cxf;
383   int hasadd;
384   int hasmul;
385   int nbits;
386     
387   if (!cx) cx = &cxf;
388   
389   cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
390   cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
391
392   if (!t) return 0;
393   
394   swf_ResetReadBits(t);
395   hasadd = swf_GetBits(t,1);
396   hasmul = swf_GetBits(t,1);
397   nbits  = swf_GetBits(t,4);
398
399   if (hasmul)
400   { cx->r0 = (S16)swf_GetSBits(t,nbits);
401     cx->g0 = (S16)swf_GetSBits(t,nbits);
402     cx->b0 = (S16)swf_GetSBits(t,nbits);
403     if (alpha)
404       cx->a0 = (S16)swf_GetSBits(t,nbits);
405   }
406
407   if (hasadd)
408   { cx->r1 = (S16)swf_GetSBits(t,nbits);
409     cx->g1 = (S16)swf_GetSBits(t,nbits);
410     cx->b1 = (S16)swf_GetSBits(t,nbits);
411     if (alpha)
412       cx->a1 = (S16)swf_GetSBits(t,nbits);
413   }
414   
415   return 0;
416 }
417
418 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
419 { CXFORM cxf;
420   int hasadd;
421   int hasmul;
422   int nbits;
423     
424   if (!cx)
425   { cx = &cxf;
426     cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
427     cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
428   }
429
430   if (!alpha)
431   { cx->a0 = 256;
432     cx->a1 = 0;
433   }
434
435   nbits = 0;
436
437   hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
438   hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
439
440   if (hasmul)
441   { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits);
442     nbits = swf_CountBits((S32)cx->r0,nbits);
443     nbits = swf_CountBits((S32)cx->g0,nbits);
444     nbits = swf_CountBits((S32)cx->b0,nbits);
445   }
446
447   if (hasadd)
448   { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits);
449     nbits = swf_CountBits((S32)cx->r1,nbits);
450     nbits = swf_CountBits((S32)cx->g1,nbits);
451     nbits = swf_CountBits((S32)cx->b1,nbits);
452   }
453   
454   swf_ResetWriteBits(t);
455   swf_SetBits(t,hasadd?1:0,1);
456   swf_SetBits(t,hasmul?1:0,1);
457   swf_SetBits(t,nbits,4);
458
459   if (hasmul)
460   { swf_SetBits(t,cx->r0,nbits);
461     swf_SetBits(t,cx->g0,nbits);
462     swf_SetBits(t,cx->b0,nbits);
463     if (alpha) swf_SetBits(t,cx->a0,nbits);
464   }
465
466   if (hasadd)
467   { swf_SetBits(t,cx->r1,nbits);
468     swf_SetBits(t,cx->g1,nbits);
469     swf_SetBits(t,cx->b1,nbits);
470     if (alpha) swf_SetBits(t,cx->a1,nbits);
471   }
472   
473   return 0;
474 }
475
476 int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
477 int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
478
479 // Tag List Manipulating Functions
480
481 int RFXSWF_UpdateFrame(TAG * t,S8 delta)
482 // returns number of frames
483 { int res = -1;
484   while (t)
485   { t->frame+=delta;
486     res = t->frame;
487     t = t->next;
488   }
489   return res;
490 }
491
492 #define swf_UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)
493
494 TAG * swf_InsertTag(TAG * after,U16 id)     // updates frames, if nescessary
495 { TAG * t;
496
497   t = (TAG *)malloc(sizeof(TAG));
498   if (t)
499   { memset(t,0x00,sizeof(TAG));
500     t->id = id;
501     
502     if (after)
503     { t->frame = after->frame;
504       t->prev  = after;
505       t->next  = after->next;
506       after->next = t;
507       if (t->next) t->next->prev = t;
508       
509       if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1);
510     }
511   }
512   return t;
513 }
514
515 int swf_DeleteTag(TAG * t)
516 { if (!t) return -1;
517
518   if (t->id==ST_SHOWFRAME) swf_UpdateFrame(t->next,-1);
519     
520   if (t->prev) t->prev->next = t->next;
521   if (t->next) t->next->prev = t->prev;
522
523   if (t->data) free(t->data);
524   free(t);
525   return 0;
526 }
527
528 TAG * RFXSWF_ReadTag(int handle,TAG * prev)
529 { TAG * t;
530   U16 raw;
531   U32 len;
532   int id;
533
534   if (read(handle,&raw,2)!=2) return NULL;
535
536   len = raw&0x3f;
537   id  = raw>>6;
538
539   if (len==0x3f)
540   { if (read(handle,&len,4)!=4) return NULL;
541   }
542
543   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
544   // Sprite handling fix: Flaten sprite tree
545
546   t = (TAG *)malloc(sizeof(TAG));
547   
548   if (!t)
549   {
550     #ifdef DEBUG_RFXSWF
551       fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
552     #endif
553     return NULL;
554   }
555
556   memset(t,0x00,sizeof(TAG));
557   
558   t->len = len;
559   t->id  = id;
560
561   if (t->len)
562   { t->data = (U8*)malloc(t->len);
563     if (!t->data)
564     {
565       #ifdef DEBUG_RFXSWF
566         fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
567       #endif
568       return NULL;
569     }
570     t->memsize = t->len;
571     if (read(handle,t->data,t->len)!=t->len) return NULL;
572   }
573
574   if (prev)
575   { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
576     t->prev  = prev;
577     prev->next = t;
578   }
579
580   return t;
581 }
582
583 int RFXSWF_DefineSprite_GetRealSize(TAG * t);
584
585 int RFXSWF_WriteTag(int handle,TAG * t)
586 // returns tag length in bytes (incl. Header), -1 = Error
587 // handle = -1 -> no output
588 { U16 raw[3];
589   U32 len;
590   int short_tag;
591
592   if (!t) return -1;
593
594   len = (t->id==ST_DEFINESPRITE)?RFXSWF_DefineSprite_GetRealSize(t):t->len;
595
596   short_tag = len<0x3f;
597
598   if (handle>=0)
599   { if (short_tag)
600     { raw[0] = len|((t->id&0x3ff)<<6);
601       if (write(handle,raw,2)!=2)
602       {
603         #ifdef DEBUG_RFXSWF
604           fprintf(stderr,"WriteTag() failed: Short Header.\n");
605         #endif
606         return -1;
607       }
608     }
609     else
610     { raw[0] = (t->id<<6)|0x3f;
611       raw[1] = (U16)(len&0xffff);
612       raw[2] = (U16)(len>>16);
613       if (write(handle,raw,6)!=6)
614       {
615         #ifdef DEBUG_RFXSWF
616           fprintf(stderr,"WriteTag() failed: Long Header.\n");
617         #endif
618         return -1;
619       }
620     }
621     
622     if (t->data)
623     { if (write(handle,t->data,t->len)!=t->len)
624       {
625         #ifdef DEBUG_RFXSWF
626           fprintf(stderr,"WriteTag() failed: Data.\n");
627         #endif
628         return -1;
629       }
630     }
631     #ifdef DEBUG_RFXSWF
632       else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
633     #endif
634   }
635
636   return t->len+(short_tag?2:6);
637 }
638
639 int RFXSWF_DefineSprite_GetRealSize(TAG * t)
640 // Sprite Handling: Helper function to pack DefineSprite-Tag
641 { U32 len = t->len;
642   do
643   { t = swf_NextTag(t);
644     if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
645     else t = NULL;
646   } while (t&&(t->id!=ST_END));
647   return len;
648 }
649
650 #define swf_ReadTag(a,b)  RFXSWF_ReadTag(a,b)
651 #define swf_WriteTag(a,b) RFXSWF_WriteTag(a,b)
652
653 // Movie Functions
654
655 int swf_ReadSWF(int handle,SWF * swf)   // Reads SWF to memory (malloc'ed), returns length or <0 if fails
656 {     
657   if (!swf) return -1;
658   memset(swf,0x00,sizeof(SWF));
659
660   { char b[32];                         // read Header
661     TAG t1;
662     TAG * t;
663     
664     memset(&t1,0x00,sizeof(TAG));
665     
666     if ((t1.len=read(handle,b,32))<21) return -1;
667     t1.data = (U8*)b;
668
669     if (swf_GetU8(&t1)!=(U8)'F') return -1;
670     if (swf_GetU8(&t1)!=(U8)'W') return -1;
671     if (swf_GetU8(&t1)!=(U8)'S') return -1;
672
673     swf->fileVersion = swf_GetU8(&t1);
674     swf->fileSize    = swf_GetU32(&t1);
675     swf_GetRect(&t1,&swf->movieSize);
676     swf->frameRate   = swf_GetU16(&t1);
677     swf->frameCount  = swf_GetU16(&t1);
678
679     swf_GetU8(&t1);
680     lseek(handle,swf_GetTagPos(&t1)-1,SEEK_SET);
681   
682                                         // reda tags and connect to list
683     t = &t1;
684     while (t) t = swf_ReadTag(handle,t);
685     swf->firstTag = t1.next;
686     t1.next->prev = NULL;
687   }
688   
689   return 0;
690 }
691 int  swf_WriteSWF(int handle,SWF * swf)     // Writes SWF to file, returns length or <0 if fails
692 { U32 len;
693   TAG * t;
694     
695   if (!swf) return -1;
696
697   // Insert REFLEX Tag
698
699 #ifdef INSERT_RFX_TAG
700
701   if (swf_NextTag(swf->firstTag))
702     if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
703       swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
704
705 #endif // INSERT_RFX_TAG
706
707   // Count Frames + File Size
708
709   len = 0;
710   t = swf->firstTag;
711   swf->frameCount = 0;
712
713   while(t)
714   { len += swf_WriteTag(-1,t);
715     if (t->id==ST_SHOWFRAME) swf->frameCount++;
716     t = swf_NextTag(t);
717   }
718   
719   { TAG t1;
720     char b[64];
721     U32 l;
722
723     memset(&t1,0x00,sizeof(TAG));
724     t1.data    = (U8*)b;
725     t1.memsize = 64;
726     
727     swf_SetU8(&t1,'F');      
728     swf_SetU8(&t1,'W');      
729     swf_SetU8(&t1,'S');
730     swf_SetU8(&t1,swf->fileVersion);
731     
732     swf_SetU32(&t1,0);                      // Keep space for filesize
733     swf_SetRect(&t1,&swf->movieSize);
734     swf_SetU16(&t1,swf->frameRate);
735     swf_SetU16(&t1,swf->frameCount);
736
737     l = swf_GetDataSize(&t1);
738     swf->fileSize = l+len;
739     t1.len = 4;                         // bad & ugly trick !
740     swf_SetU32(&t1,swf->fileSize);
741
742     if (handle>=0)
743     { 
744       int ret = write(handle,b,l);
745       if (ret!=l)
746       {
747         #ifdef DEBUG_RFXSWF
748           printf("ret:%d (fd:%d)\n",ret, handle);
749           perror("write:");
750           fprintf(stderr,"WriteSWF() failed: Header.\n");
751         #endif
752         return -1;
753       }
754
755       t = swf->firstTag;
756       while (t)
757       { if (swf_WriteTag(handle,t)<0) return -1;
758         t = swf_NextTag(t);
759       }
760     }
761   }
762   return (int)swf->fileSize;
763 }
764
765 int swf_WriteCGI(SWF * swf)
766 { int len;
767   char s[1024];
768     
769   len = swf_WriteSWF(-1,swf);
770
771   if (len<0) return -1;
772
773   sprintf(s,"Content-type: application/x-shockwave-flash\n"
774             "Accept-Ranges: bytes\n"
775             "Content-Length: %lu\n"
776             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
777             "\n",len);
778             
779   write(fileno(stdout),s,strlen(s));
780   return swf_WriteSWF(fileno(stdout),swf);
781 }
782
783 void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
784 { TAG * t = swf->firstTag;
785
786   while (t)
787   { TAG * tnew = t->next;
788     if (t->data) free(t->data);
789     free(t);
790     t = tnew;
791   }
792 }
793
794 // include advanced functions
795
796 #ifdef __NT__
797
798 #include "modules\swfdump.c"
799 #include "modules\swfshape.c"
800 #include "modules\swftext.c"
801 #include "modules\swfobject.c"
802 #include "modules\swfbutton.c"
803 #include "modules\swftools.c"
804 #include "modules\swfcgi.c"
805 #include "modules\swfbits.c"
806 #include "modules\swfaction.c"
807
808 #else
809
810 #include "modules/swfdump.c"
811 #include "modules/swfshape.c"
812 #include "modules/swftext.c"
813 #include "modules/swfobject.c"
814 #include "modules/swfbutton.c"
815 #include "modules/swftools.c"
816 #include "modules/swfcgi.c"
817 #include "modules/swfbits.c"
818 #include "modules/swfaction.c"
819
820 #endif
821
822