added functions GET16, GET32, PUT16, PUT32
[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   raw = SWAP16(raw);
549
550   len = raw&0x3f;
551   id  = raw>>6;
552
553   if (len==0x3f)
554   {
555       if (read(handle,&len,4)!=4) return NULL;
556       len = SWAP32(len);
557   }
558
559   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
560   // Sprite handling fix: Flaten sprite tree
561
562   t = (TAG *)malloc(sizeof(TAG));
563   
564   if (!t)
565   {
566     #ifdef DEBUG_RFXSWF
567       fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
568     #endif
569     return NULL;
570   }
571
572   memset(t,0x00,sizeof(TAG));
573   
574   t->len = len;
575   t->id  = id;
576
577   if (t->len)
578   { t->data = (U8*)malloc(t->len);
579     if (!t->data)
580     {
581       #ifdef DEBUG_RFXSWF
582         fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
583       #endif
584       return NULL;
585     }
586     t->memsize = t->len;
587     if (read(handle,t->data,t->len)!=t->len) return NULL;
588   }
589
590   if (prev)
591   { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
592     t->prev  = prev;
593     prev->next = t;
594   }
595
596   return t;
597 }
598
599 int RFXSWF_DefineSprite_GetRealSize(TAG * t);
600
601 int RFXSWF_WriteTag(int handle,TAG * t)
602 // returns tag length in bytes (incl. Header), -1 = Error
603 // handle = -1 -> no output
604 { U16 raw[3];
605   U32 len;
606   int short_tag;
607
608   if (!t) return -1;
609
610   len = (t->id==ST_DEFINESPRITE)?RFXSWF_DefineSprite_GetRealSize(t):t->len;
611
612   short_tag = len<0x3f;
613
614   if (handle>=0)
615   { if (short_tag)
616     { raw[0] = SWAP16(len|((t->id&0x3ff)<<6));
617       if (write(handle,raw,2)!=2)
618       {
619         #ifdef DEBUG_RFXSWF
620           fprintf(stderr,"WriteTag() failed: Short Header.\n");
621         #endif
622         return -1;
623       }
624     }
625     else
626     {
627       raw[0] = SWAP16((t->id<<6)|0x3f);
628       if (write(handle,raw,2)!=2)
629       {
630 #ifdef DEBUG_RFXSWF
631           fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
632 #endif
633           return -1;
634       }
635       
636       len = SWAP32(len);
637       if (write(handle,&len,4)!=4)
638       {
639         #ifdef DEBUG_RFXSWF
640           fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
641         #endif
642         return -1;
643       }
644     }
645     
646     if (t->data)
647     { if (write(handle,t->data,t->len)!=t->len)
648       {
649         #ifdef DEBUG_RFXSWF
650           fprintf(stderr,"WriteTag() failed: Data.\n");
651         #endif
652         return -1;
653       }
654     }
655     #ifdef DEBUG_RFXSWF
656       else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
657     #endif
658   }
659
660   return t->len+(short_tag?2:6);
661 }
662
663 int swf_WriteTag(int handle,TAG * t)
664 {
665     return RFXSWF_WriteTag(handle, t);
666 }
667
668 int RFXSWF_DefineSprite_GetRealSize(TAG * t)
669 // Sprite Handling: Helper function to pack DefineSprite-Tag
670 { U32 len = t->len;
671   do
672   { t = swf_NextTag(t);
673     if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
674     else t = NULL;
675   } while (t&&(t->id!=ST_END));
676   return len;
677 }
678
679 #define swf_ReadTag(a,b)  RFXSWF_ReadTag(a,b)
680 #define swf_WriteTag(a,b)  RFXSWF_WriteTag(a,b)
681
682 // Movie Functions
683
684 int swf_InitSWF(void*data, int length, SWF * swf) /* copy a swf in memory into SWF struct */
685 {
686   TAG reader;
687     /* 
688         unfinished!
689      */
690   *(int*)0=0xDEAD;
691   if (!swf) return -1;
692   memset(swf,0x00,sizeof(SWF));
693   memset(&reader,0x00,sizeof(TAG));
694   reader.data = data;
695   reader.len = reader.memsize = length;
696
697   { char b[32];                         // read Header
698     TAG * t;
699     
700     if (swf_GetU8(&reader)!=(U8)'F') return -1;
701     if (swf_GetU8(&reader)!=(U8)'W') return -1;
702     if (swf_GetU8(&reader)!=(U8)'S') return -1;
703
704     swf->fileVersion = swf_GetU8(&reader);
705     swf->fileSize    = swf_GetU32(&reader);
706     swf_GetRect(&reader,&swf->movieSize);
707     swf->frameRate   = swf_GetU16(&reader);
708     swf->frameCount  = swf_GetU16(&reader);
709
710     /*t = &t1;
711     while (t) t = swf_ReadTag(handle,t);
712     swf->firstTag = t1.next;
713     t1.next->prev = NULL;*/
714   }
715 }
716
717 int swf_ReadSWF(int handle,SWF * swf)   // Reads SWF to memory (malloc'ed), returns length or <0 if fails
718 {     
719   if (!swf) return -1;
720   memset(swf,0x00,sizeof(SWF));
721
722   { char b[32];                         // read Header
723     TAG t1;
724     TAG * t;
725     
726     memset(&t1,0x00,sizeof(TAG));
727     
728     if ((t1.len=read(handle,b,32))<21) return -1;
729     t1.data = (U8*)b;
730
731     if (swf_GetU8(&t1)!=(U8)'F') return -1;
732     if (swf_GetU8(&t1)!=(U8)'W') return -1;
733     if (swf_GetU8(&t1)!=(U8)'S') return -1;
734
735     swf->fileVersion = swf_GetU8(&t1);
736     swf->fileSize    = swf_GetU32(&t1);
737     swf_GetRect(&t1,&swf->movieSize);
738     swf->frameRate   = swf_GetU16(&t1);
739     swf->frameCount  = swf_GetU16(&t1);
740
741     swf_GetU8(&t1);
742     lseek(handle,swf_GetTagPos(&t1)-1,SEEK_SET);
743   
744                                         // reda tags and connect to list
745     t = &t1;
746     while (t) t = swf_ReadTag(handle,t);
747     swf->firstTag = t1.next;
748     t1.next->prev = NULL;
749   }
750   
751   return 0;
752 }
753
754 int  swf_WriteSWF(int handle,SWF * swf)     // Writes SWF to file, returns length or <0 if fails
755 { U32 len;
756   TAG * t;
757     
758   if (!swf) return -1;
759
760   // Insert REFLEX Tag
761
762 #ifdef INSERT_RFX_TAG
763
764   if (swf->firstTag && swf_NextTag(swf->firstTag))
765     if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
766       swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
767
768 #endif // INSERT_RFX_TAG
769
770   // Count Frames + File Size
771
772   len = 0;
773   t = swf->firstTag;
774   swf->frameCount = 0;
775
776   while(t)
777   { len += swf_WriteTag(-1,t);
778     if (t->id==ST_SHOWFRAME) swf->frameCount++;
779     t = swf_NextTag(t);
780   }
781   
782   { TAG t1;
783     char b[64];
784     U32 l;
785
786     memset(&t1,0x00,sizeof(TAG));
787     t1.data    = (U8*)b;
788     t1.memsize = 64;
789     
790     swf_SetU8(&t1,'F');      
791     swf_SetU8(&t1,'W');      
792     swf_SetU8(&t1,'S');
793     swf_SetU8(&t1,swf->fileVersion);
794     
795     swf_SetU32(&t1,swf->fileSize);         // Keep space for filesize
796     swf_SetRect(&t1,&swf->movieSize);
797     swf_SetU16(&t1,swf->frameRate);
798     swf_SetU16(&t1,swf->frameCount);
799
800     l = swf_GetTagLen(&t1);
801     swf->fileSize = l+len;
802     if(swf->firstTag) {
803         t1.len = 4;                         // bad & ugly trick !
804         swf_SetU32(&t1,swf->fileSize);
805     }
806
807     if (handle>=0)
808     { 
809       int ret = write(handle,b,l);
810       if (ret!=l)
811       {
812         #ifdef DEBUG_RFXSWF
813           printf("ret:%d (fd:%d)\n",ret, handle);
814           perror("write:");
815           fprintf(stderr,"WriteSWF() failed: Header.\n");
816         #endif
817         return -1;
818       }
819
820       t = swf->firstTag;
821       while (t)
822       { if (swf_WriteTag(handle,t)<0) return -1;
823         t = swf_NextTag(t);
824       }
825     }
826   }
827   return (int)swf->fileSize;
828 }
829
830 int swf_WriteHeader(int handle,SWF * swf)
831 {
832     SWF myswf;
833     memcpy(&myswf,swf,sizeof(SWF));
834     myswf.firstTag = 0;
835     swf_WriteSWF(handle, &myswf);
836 }
837
838 int swf_WriteCGI(SWF * swf)
839 { int len;
840   char s[1024];
841     
842   len = swf_WriteSWF(-1,swf);
843
844   if (len<0) return -1;
845
846   sprintf(s,"Content-type: application/x-shockwave-flash\n"
847             "Accept-Ranges: bytes\n"
848             "Content-Length: %lu\n"
849             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
850             "\n",len);
851             
852   write(fileno(stdout),s,strlen(s));
853   return swf_WriteSWF(fileno(stdout),swf);
854 }
855
856 void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
857 { TAG * t = swf->firstTag;
858
859   while (t)
860   { TAG * tnew = t->next;
861     if (t->data) free(t->data);
862     free(t);
863     t = tnew;
864   }
865 }
866
867 // include advanced functions
868
869 #ifdef __NT__
870
871 #include "modules\swfdump.c"
872 #include "modules\swfshape.c"
873 #include "modules\swftext.c"
874 #include "modules\swfobject.c"
875 #include "modules\swfbutton.c"
876 #include "modules\swftools.c"
877 #include "modules\swfcgi.c"
878 #include "modules\swfbits.c"
879 #include "modules\swfaction.c"
880
881 #else
882
883 #include "modules/swfdump.c"
884 #include "modules/swfshape.c"
885 #include "modules/swftext.c"
886 #include "modules/swfobject.c"
887 #include "modules/swfbutton.c"
888 #include "modules/swftools.c"
889 #include "modules/swfcgi.c"
890 #include "modules/swfbits.c"
891 #include "modules/swfaction.c"
892
893 #endif
894
895