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