* removed the checks for X11 and pthread, as they aren't used at the moment.
[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 * NextTag(TAG * t) { return t->next; }
52 TAG * PrevTag(TAG * t) { return t->prev; }
53 int   GetFrameNo(TAG * t)  { return t->frame; }
54 U16   GetTagID(TAG * t)    { return t->id; }
55 U32   GetDataSize(TAG * t) { return t->len; }
56 U8*   GetDataSizePtr(TAG * t) { return &(t->data[t->len]); }
57 U32   GetTagPos(TAG * t)   { return t->pos; }
58
59 // Basic Data Access Functions
60
61 #define ResetBitmask(tag)   if (tag->bitmask)  { tag->pos++; tag->bitmask = 0; }
62 #define ResetBitcount(tag)  if (tag->bitcount) { tag->bitcount = 0; }
63
64 // for future purpose: avoid high level lib functions to change tagpos/bitcount
65
66 #define SaveTagPos(tag)
67 #define RestoreTagPos(tag)
68
69 void SetTagPos(TAG * t,U32 pos)
70 { ResetBitmask(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 GetU8(TAG * t)
78 { ResetBitmask(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 GetU16(TAG * t)
89 { U16 res;
90   ResetBitmask(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 GetU32(TAG * t)
103 { U32 res;
104   ResetBitmask(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 GetBlock(TAG * t,U8 * b,int l)
118 // returns number of bytes written (<=l)
119 // b = NULL -> skip data
120 { ResetBitmask(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 SetBlock(TAG * t,U8 * b,int l)
128 // Appends Block to the end of Tagdata, returns size
129 { U32 newlen = t->len + l;
130   ResetBitcount(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 SetU8(TAG * t,U8 v)
151 { ResetBitcount(t);
152   if ((t->len+1)>t->memsize) return (SetBlock(t,&v,1)==1)?0:-1;
153   t->data[t->len++] = v;
154   return 0;
155 }
156
157 int SetU16(TAG * t,U16 v)
158 { U8 a[2];
159   a[0] = v&0xff;
160   a[1] = v>>8;
161   
162   ResetBitcount(t);
163   if ((t->len+2)>t->memsize) return (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 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   ResetBitcount(t);
177   if ((t->len+4)>t->memsize) return (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 GetBits(TAG * t,int nbits)
186 { U32 res = 0;
187   if (!nbits) return 0;
188   if (!t->bitmask) t->bitmask = 0x80;
189   while (nbits)
190   { res<<=1;
191     if (t->data[t->pos]&t->bitmask) res|=1;
192     t->bitmask>>=1;
193     nbits--;
194     if (!t->bitmask)
195     { if (nbits) t->bitmask = 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 GetSBits(TAG * t,int nbits)
209 { U32 res = GetBits(t,nbits);
210   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
211   return (S32)res;
212 }
213
214 int SetBits(TAG * t,U32 v,int nbits)
215 { U32 bm = 1<<(nbits-1);
216
217   while (nbits)
218   { if (!t->bitcount)
219     { if (FAILED(SetU8(t,0))) return -1;
220       t->bitcount = 0x80;
221     }
222     if (v&bm) t->data[t->len-1] |= t->bitcount;
223     bm>>=1;
224     t->bitcount>>=1;
225     nbits--;
226   }
227   return 0;
228 }
229
230 // Advanced Data Access Functions
231
232 int SetRGB(TAG * t,RGBA * col)
233 { if (!t) return -1;
234   if (col)
235   { SetU8(t,col->r);
236     SetU8(t,col->g);
237     SetU8(t,col->b);
238   } else SetBlock(t,NULL,3);
239   return 0;
240 }
241
242 int SetRGBA(TAG * t,RGBA * col)
243 { if (!t) return -1;
244   if (col)
245   { SetU8(t,col->r);
246     SetU8(t,col->g);
247     SetU8(t,col->b);
248     SetU8(t,col->a);
249   } else SetBlock(t,NULL,4);
250   return 0;
251 }
252
253 int 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 GetRect(TAG * t,SRECT * r)
275 { int nbits;
276   SRECT dummy;
277   if (!r) r = &dummy;
278   nbits = (int) GetBits(t,5);
279   r->xmin = GetSBits(t,nbits);
280   r->xmax = GetSBits(t,nbits);
281   r->ymin = GetSBits(t,nbits);
282   r->ymax = GetSBits(t,nbits);
283   return 0;
284 }
285
286 int SetRect(TAG * t,SRECT * r)
287 { int nbits;
288     
289   nbits = CountBits(r->xmin,0);
290   nbits = CountBits(r->xmax,nbits);
291   nbits = CountBits(r->ymin,nbits);
292   nbits = CountBits(r->ymax,nbits);
293
294   SetBits(t,nbits,5);
295   SetBits(t,r->xmin,nbits);
296   SetBits(t,r->xmax,nbits);
297   SetBits(t,r->ymin,nbits);
298   SetBits(t,r->ymax,nbits);
299
300   return 0;
301 }
302
303 int 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   ResetBitmask(t);
317   
318   if (GetBits(t,1))
319   { nbits = GetBits(t,5);
320     m->sx = GetSBits(t,nbits);
321     m->sy = GetSBits(t,nbits);
322   }
323   else m->sx = m->sy = 0x10000;
324   
325   if (GetBits(t,1))
326   { nbits = GetBits(t,5);
327     m->r0 = GetSBits(t,nbits);
328     m->r1 = GetSBits(t,nbits);
329   }
330   else m->r0 = m->r1 = 0x0;
331
332   nbits = GetBits(t,5);
333   m->tx = GetSBits(t,nbits);
334   m->ty = GetSBits(t,nbits);
335   
336   return 0;
337 }
338
339 int 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   ResetBitcount(t);
351
352   if ((m->sx==0x10000)&&(m->sy==0x10000)) SetBits(t,0,1);
353   else
354   { SetBits(t,1,1);
355     nbits = CountBits(m->sx,0);
356     nbits = CountBits(m->sy,nbits);
357     SetBits(t,nbits,5);
358     SetBits(t,m->sx,nbits);
359     SetBits(t,m->sy,nbits);
360   }
361
362   if ((!m->r0)&&(!m->r1)) SetBits(t,0,1);
363   else
364   { SetBits(t,1,1);
365     nbits = CountBits(m->r0,0);
366     nbits = CountBits(m->r1,nbits);
367     SetBits(t,nbits,5);
368     SetBits(t,m->r0,nbits);
369     SetBits(t,m->r1,nbits);
370   }
371
372   nbits = CountBits(m->tx,0);
373   nbits = CountBits(m->ty,nbits);
374   SetBits(t,nbits,5);
375   SetBits(t,m->tx,nbits);
376   SetBits(t,m->ty,nbits);
377
378   return 0;
379 }
380
381 int 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   ResetBitmask(t);
395   hasadd = GetBits(t,1);
396   hasmul = GetBits(t,1);
397   nbits  = GetBits(t,4);
398
399   if (hasmul)
400   { cx->r0 = (S16)GetSBits(t,nbits);
401     cx->g0 = (S16)GetSBits(t,nbits);
402     cx->b0 = (S16)GetSBits(t,nbits);
403     if (alpha)
404       cx->a0 = (S16)GetSBits(t,nbits);
405   }
406
407   if (hasadd)
408   { cx->r1 = (S16)GetSBits(t,nbits);
409     cx->g1 = (S16)GetSBits(t,nbits);
410     cx->b1 = (S16)GetSBits(t,nbits);
411     if (alpha)
412       cx->a1 = (S16)GetSBits(t,nbits);
413   }
414   
415   return 0;
416 }
417
418 int 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 = CountBits((S32)cx->a0,nbits);
442     nbits = CountBits((S32)cx->r0,nbits);
443     nbits = CountBits((S32)cx->g0,nbits);
444     nbits = CountBits((S32)cx->b0,nbits);
445   }
446
447   if (hasadd)
448   { if (alpha) nbits = CountBits((S32)cx->a1,nbits);
449     nbits = CountBits((S32)cx->r1,nbits);
450     nbits = CountBits((S32)cx->g1,nbits);
451     nbits = CountBits((S32)cx->b1,nbits);
452   }
453   
454   ResetBitcount(t);
455   SetBits(t,hasadd?1:0,1);
456   SetBits(t,hasmul?1:0,1);
457   SetBits(t,nbits,4);
458
459   if (hasmul)
460   { SetBits(t,cx->r0,nbits);
461     SetBits(t,cx->g0,nbits);
462     SetBits(t,cx->b0,nbits);
463     if (alpha) SetBits(t,cx->a0,nbits);
464   }
465
466   if (hasadd)
467   { SetBits(t,cx->r1,nbits);
468     SetBits(t,cx->g1,nbits);
469     SetBits(t,cx->b1,nbits);
470     if (alpha) SetBits(t,cx->a1,nbits);
471   }
472   
473   return 0;
474 }
475
476 int GetPoint(TAG * t,SPOINT * p) { return 0; }
477 int 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 UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)
493
494 TAG * 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     t->bitcount = 0x80;
502     
503     if (after)
504     { t->frame = after->frame;
505       t->prev  = after;
506       t->next  = after->next;
507       after->next = t;
508       if (t->next) t->next->prev = t;
509       
510       if (id==ST_SHOWFRAME) UpdateFrame(t->next,+1);
511     }
512   }
513   return t;
514 }
515
516 int DeleteTag(TAG * t)
517 { if (!t) return -1;
518
519   if (t->id==ST_SHOWFRAME) UpdateFrame(t->next,-1);
520     
521   if (t->prev) t->prev->next = t->next;
522   if (t->next) t->next->prev = t->prev;
523
524   if (t->data) free(t->data);
525   free(t);
526   return 0;
527 }
528
529 TAG * RFXSWF_ReadTag(int handle,TAG * prev)
530 { TAG * t;
531   U16 raw;
532   U32 len;
533   int id;
534
535   if (read(handle,&raw,2)!=2) return NULL;
536
537   len = raw&0x3f;
538   id  = raw>>6;
539
540   if (len==0x3f)
541   { if (read(handle,&len,4)!=4) return NULL;
542   }
543
544   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
545   // Sprite handling fix: Flaten sprite tree
546
547   t = (TAG *)malloc(sizeof(TAG));
548   
549   if (!t)
550   {
551     #ifdef DEBUG_RFXSWF
552       fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
553     #endif
554     return NULL;
555   }
556
557   memset(t,0x00,sizeof(TAG));
558   
559   t->len = len;
560   t->id  = id;
561
562   if (t->len)
563   { t->data = (U8*)malloc(t->len);
564     if (!t->data)
565     {
566       #ifdef DEBUG_RFXSWF
567         fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
568       #endif
569       return NULL;
570     }
571     t->memsize = t->len;
572     if (read(handle,t->data,t->len)!=t->len) return NULL;
573   }
574
575   if (prev)
576   { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
577     t->prev  = prev;
578     prev->next = t;
579   }
580
581   return t;
582 }
583
584 int DefineSprite_GetRealSize(TAG * t);
585
586 int RFXSWF_WriteTag(int handle,TAG * t)
587 // returns tag length in bytes (incl. Header), -1 = Error
588 // handle = -1 -> no output
589 { U16 raw[3];
590   U32 len;
591   int short_tag;
592
593   if (!t) return -1;
594
595   len = (t->id==ST_DEFINESPRITE)?DefineSprite_GetRealSize(t):t->len;
596
597   short_tag = len<0x3f;
598
599   if (handle>=0)
600   { if (short_tag)
601     { raw[0] = len|((t->id&0x3ff)<<6);
602       if (write(handle,raw,2)!=2)
603       {
604         #ifdef DEBUG_RFXSWF
605           fprintf(stderr,"WriteTag() failed: Short Header.\n");
606         #endif
607         return -1;
608       }
609     }
610     else
611     { raw[0] = (t->id<<6)|0x3f;
612       raw[1] = (U16)(len&0xffff);
613       raw[2] = (U16)(len>>16);
614       if (write(handle,raw,6)!=6)
615       {
616         #ifdef DEBUG_RFXSWF
617           fprintf(stderr,"WriteTag() failed: Long Header.\n");
618         #endif
619         return -1;
620       }
621     }
622     
623     if (t->data)
624     { if (write(handle,t->data,t->len)!=t->len)
625       {
626         #ifdef DEBUG_RFXSWF
627           fprintf(stderr,"WriteTag() failed: Data.\n");
628         #endif
629         return -1;
630       }
631     }
632     #ifdef DEBUG_RFXSWF
633       else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
634     #endif
635   }
636
637   return t->len+(short_tag?2:6);
638 }
639
640 int DefineSprite_GetRealSize(TAG * t)
641 // Sprite Handling: Helper function to pack DefineSprite-Tag
642 { U32 len = t->len;
643   do
644   { t = NextTag(t);
645     if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
646     else t = NULL;
647   } while (t&&(t->id!=ST_END));
648   return len;
649 }
650
651 #define ReadTag(a,b)  RFXSWF_ReadTag(a,b)
652 #define WriteTag(a,b) RFXSWF_WriteTag(a,b)
653
654 // Movie Functions
655
656 int ReadSWF(int handle,SWF * swf)       // Reads SWF to memory (malloc'ed), returns length or <0 if fails
657 {     
658   if (!swf) return -1;
659   memset(swf,0x00,sizeof(SWF));
660
661   { char b[32];                         // read Header
662     TAG t1;
663     TAG * t;
664     
665     memset(&t1,0x00,sizeof(TAG));
666     
667     if ((t1.len=read(handle,b,32))<21) return -1;
668     t1.data = (U8*)b;
669
670     if (GetU8(&t1)!=(U8)'F') return -1;
671     if (GetU8(&t1)!=(U8)'W') return -1;
672     if (GetU8(&t1)!=(U8)'S') return -1;
673
674     swf->FileVersion = GetU8(&t1);
675     swf->FileSize    = GetU32(&t1);
676     GetRect(&t1,&swf->MovieSize);
677     swf->FrameRate   = GetU16(&t1);
678     swf->FrameCount  = GetU16(&t1);
679
680     GetU8(&t1);
681     lseek(handle,GetTagPos(&t1)-1,SEEK_SET);
682   
683                                         // reda tags and connect to list
684     t = &t1;
685     while (t) t = ReadTag(handle,t);
686     swf->FirstTag = t1.next;
687     t1.next->prev = NULL;
688   }
689   
690   return 0;
691 }
692 int  WriteSWF(int handle,SWF * swf)     // Writes SWF to file, returns length or <0 if fails
693 { U32 len;
694   TAG * t;
695     
696   if (!swf) return -1;
697
698   // Insert REFLEX Tag
699
700 #ifdef INSERT_RFX_TAG
701
702   if (NextTag(swf->FirstTag))
703     if (GetTagID(NextTag(swf->FirstTag))!=ST_REFLEX)
704       SetBlock(InsertTag(swf->FirstTag,ST_REFLEX),"rfx",3);
705
706 #endif // INSERT_RFX_TAG
707
708   // Count Frames + File Size
709
710   len = 0;
711   t = swf->FirstTag;
712   swf->FrameCount = 0;
713
714   while(t)
715   { len += WriteTag(-1,t);
716     if (t->id==ST_SHOWFRAME) swf->FrameCount++;
717     t = NextTag(t);
718   }
719   
720   { TAG t1;
721     char b[64];
722     U32 l;
723
724     memset(&t1,0x00,sizeof(TAG));
725     t1.data    = (U8*)b;
726     t1.memsize = 64;
727     
728     SetU8(&t1,'F');      
729     SetU8(&t1,'W');      
730     SetU8(&t1,'S');
731     SetU8(&t1,swf->FileVersion);
732     
733     SetU32(&t1,0);                      // Keep space for filesize
734     SetRect(&t1,&swf->MovieSize);
735     SetU16(&t1,swf->FrameRate);
736     SetU16(&t1,swf->FrameCount);
737
738     l = GetDataSize(&t1);
739     swf->FileSize = l+len;
740     t1.len = 4;                         // bad & ugly trick !
741     SetU32(&t1,swf->FileSize);
742
743     if (handle>=0)
744     { 
745       int ret = write(handle,b,l);
746       if (ret!=l)
747       {
748         #ifdef DEBUG_RFXSWF
749           printf("ret:%d (fd:%d)\n",ret, handle);
750           perror("write:");
751           fprintf(stderr,"WriteSWF() failed: Header.\n");
752         #endif
753         return -1;
754       }
755
756       t = swf->FirstTag;
757       while (t)
758       { if (WriteTag(handle,t)<0) return -1;
759         t = NextTag(t);
760       }
761     }
762   }
763   return (int)swf->FileSize;
764 }
765
766 int WriteCGI(SWF * swf)
767 { int len;
768   char s[1024];
769     
770   len = WriteSWF(-1,swf);
771
772   if (len<0) return -1;
773
774   sprintf(s,"Content-type: application/x-shockwave-flash\n"
775             "Accept-Ranges: bytes\n"
776             "Content-Length: %lu\n"
777             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
778             "\n",len);
779             
780   write(fileno(stdout),s,strlen(s));
781   return WriteSWF(fileno(stdout),swf);
782 }
783
784 void FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
785 { TAG * t = swf->FirstTag;
786
787   while (t)
788   { TAG * tnew = t->next;
789     if (t->data) free(t->data);
790     free(t);
791     t = tnew;
792   }
793 }
794
795 // include advanced functions
796
797 #ifdef __NT__
798
799 #include "modules\swfdump.c"
800 #include "modules\swfshape.c"
801 #include "modules\swftext.c"
802 #include "modules\swfobject.c"
803 #include "modules\swfbutton.c"
804 #include "modules\swftools.c"
805 #include "modules\swfcgi.c"
806 #include "modules\swfbits.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
819 #endif
820
821