4a7035cf3fbbf49e291a57e8989b3dfff12a1df7
[swftools.git] / lib / rfxswf.c
1 /* vi: set sts=2 sw=2 :*/
2
3 /* rfxswf.c 
4
5    Library for creating and reading SWF files or parts of it.
6    There's a module directory which provides some extended functionality.
7    Most modules are included at the bottom of this file.
8
9    Part of the swftools package.
10
11    Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
12  
13    This file is distributed under the GPL, see file COPYING for details 
14
15 */
16
17 #include "rfxswf.h"
18
19 #ifdef HAVE_LIBJPEG
20 #ifdef HAVE_JPEGLIB_H
21 #define HAVE_BOOLEAN
22 #include <jpeglib.h>
23 #define _JPEGLIB_INCLUDED_
24 #endif // HAVE_JPEGLIB_H
25 #endif // HAVE_LIBJPEG
26
27 #ifdef HAVE_LIBZ
28 #ifdef HAVE_ZLIB_H
29 #include <zlib.h>
30 #define _ZLIB_INCLUDED_
31 #endif // HAVE_ZLIB_H
32 #endif // HAVE_LIBZ
33
34 #define LAME
35 #include "lame/lame.h"
36
37 #include "./bitio.h"
38
39 // internal constants
40
41 #define MALLOC_SIZE     128
42 #define INSERT_RFX_TAG
43
44 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
45
46
47 // inline wrapper functions
48
49 TAG * swf_NextTag(TAG * t) { return t->next; }
50 TAG * swf_PrevTag(TAG * t) { return t->prev; }
51 int   swf_GetFrameNo(TAG * t)  { return t->frame; }
52 U16   swf_GetTagID(TAG * t)    { return t->id; }
53 U32   swf_GetTagLen(TAG * t) { return t->len; }
54 U8*   swf_GetTagLenPtr(TAG * t) { return &(t->data[t->len]); }
55 U32   swf_GetTagPos(TAG * t)   { return t->pos; }
56
57 // Basic Data Access Functions
58
59 #define swf_ResetReadBits(tag)   if (tag->readBit)  { tag->pos++; tag->readBit = 0; }
60 #define swf_ResetWriteBits(tag)  if (tag->writeBit) { tag->writeBit = 0; }
61
62 // for future purpose: avoid high level lib functions to change tagpos/bitpos
63
64 #define swf_SaveTagPos(tag)
65 #define swf_RestoreTagPos(tag)
66
67 void swf_SetTagPos(TAG * t,U32 pos)
68 { swf_ResetReadBits(t);
69   if (pos<=t->len) t->pos = pos;
70   #ifdef DEBUG_RFXSWF
71   else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
72   #endif
73 }
74
75 U8 swf_GetU8(TAG * t)
76 { swf_ResetReadBits(t);
77   #ifdef DEBUG_RFXSWF
78     if (t->pos>=t->len) 
79     { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
80       return 0;
81     }
82   #endif
83   return t->data[t->pos++];
84 }
85
86 U16 swf_GetU16(TAG * t)
87 { U16 res;
88   swf_ResetReadBits(t);
89   #ifdef DEBUG_RFXSWF
90     if (t->pos>(t->len-2)) 
91     { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
92       return 0;
93     }
94   #endif
95   res = t->data[t->pos] | (t->data[t->pos+1]<<8);
96   t->pos+=2;
97   return res;
98 }
99
100 U32 swf_GetU32(TAG * t)
101 { U32 res;
102   swf_ResetReadBits(t);
103   #ifdef DEBUG_RFXSWF
104     if (t->pos>(t->len-4)) 
105     { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
106       return 0;
107     }
108   #endif
109   res = t->data[t->pos]        | (t->data[t->pos+1]<<8) | 
110        (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);
111   t->pos+=4;
112   return res;
113 }
114
115 int swf_GetBlock(TAG * t,U8 * b,int l)
116 // returns number of bytes written (<=l)
117 // b = NULL -> skip data
118 { swf_ResetReadBits(t);
119   if ((t->len-t->pos)<l) l=t->len-t->pos;
120   if (b && l) memcpy(b,&t->data[t->pos],l);
121   t->pos+=l;
122   return l;
123 }
124
125 int swf_SetBlock(TAG * t,U8 * b,int l)
126 // Appends Block to the end of Tagdata, returns size
127 { U32 newlen = t->len + l;
128   swf_ResetWriteBits(t);
129   if (newlen>t->memsize)
130   { U32  newmem  = MEMSIZE(newlen);  
131     U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem));
132     if (!newdata)
133     {
134       #ifdef DEBUG_RFXSWF
135         fprintf(stderr,"Fatal Error: malloc()/realloc() failed (1). (%d bytes)\n", newmem);
136         *(int*)0=0;
137       #endif
138       return 0;
139     }
140     t->memsize = newmem;
141     t->data    = newdata;
142   }
143   if (b) memcpy(&t->data[t->len],b,l);
144   else memset(&t->data[t->len],0x00,l);
145   t->len+=l;
146   return l;
147 }
148
149 int swf_SetU8(TAG * t,U8 v)
150 { swf_ResetWriteBits(t);
151   if ((t->len+1)>t->memsize) return (swf_SetBlock(t,&v,1)==1)?0:-1;
152   t->data[t->len++] = v;
153   return 0;
154 }
155
156 int swf_SetU16(TAG * t,U16 v)
157 { U8 a[2];
158   a[0] = v&0xff;
159   a[1] = v>>8;
160   
161   swf_ResetWriteBits(t);
162   if ((t->len+2)>t->memsize) return (swf_SetBlock(t,a,2)==2)?0:-1;
163   t->data[t->len++] = a[0];
164   t->data[t->len++] = a[1];
165   return 0;
166 }
167
168 int swf_SetU32(TAG * t,U32 v)
169 { U8 a[4];
170   a[0] = v&0xff;        // to ensure correct handling of non-intel byteorder
171   a[1] = (v>>8)&0xff;
172   a[2] = (v>>16)&0xff;
173   a[3] = (v>>24)&0xff;
174   
175   swf_ResetWriteBits(t);
176   if ((t->len+4)>t->memsize) return (swf_SetBlock(t,a,4)==4)?0:-1;
177   t->data[t->len++] = a[0];
178   t->data[t->len++] = a[1];
179   t->data[t->len++] = a[2];
180   t->data[t->len++] = a[3];
181   return 0;
182 }
183
184 U32 swf_GetBits(TAG * t,int nbits)
185 { U32 res = 0;
186   if (!nbits) return 0;
187   if (!t->readBit) t->readBit = 0x80;
188   while (nbits)
189   { res<<=1;
190     if (t->data[t->pos]&t->readBit) res|=1;
191     t->readBit>>=1;
192     nbits--;
193     if (!t->readBit)
194     { if (nbits) t->readBit = 0x80;
195       #ifdef DEBUG_RFXSWF
196       if (t->pos>=t->len) 
197       { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
198         return res;
199       }
200       #endif
201       t->pos++;
202     }
203   }
204   return res;
205 }
206
207 S32 swf_GetSBits(TAG * t,int nbits)
208 { U32 res = swf_GetBits(t,nbits);
209   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
210   return (S32)res;
211 }
212
213 U32 reader_GetBits(struct reader_t*reader, int nbits)
214 { return reader_readbits(reader, nbits);
215 }
216 S32 reader_GetSBits(struct reader_t*reader, int nbits)
217 { U32 res = reader_readbits(reader, nbits);
218   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
219   return (S32)res;
220 }
221
222 int swf_SetBits(TAG * t,U32 v,int nbits)
223 { U32 bm = 1<<(nbits-1);
224
225   while (nbits)
226   { if (!t->writeBit)
227     { if (FAILED(swf_SetU8(t,0))) return -1;
228       t->writeBit = 0x80;
229     }
230     if (v&bm) t->data[t->len-1] |= t->writeBit;
231     bm>>=1;
232     t->writeBit>>=1;
233     nbits--;
234   }
235   return 0;
236 }
237
238 // Advanced Data Access Functions
239
240 int swf_SetRGB(TAG * t,RGBA * col)
241 { if (!t) return -1;
242   if (col)
243   { swf_SetU8(t,col->r);
244     swf_SetU8(t,col->g);
245     swf_SetU8(t,col->b);
246   } else swf_SetBlock(t,NULL,3);
247   return 0;
248 }
249 void swf_GetRGB(TAG * t, RGBA * col)
250 {
251     RGBA dummy;
252     if(!col);
253         col = &dummy;
254     col->r = swf_GetU8(t);
255     col->g = swf_GetU8(t);
256     col->b = swf_GetU8(t);
257     col->a = 255;
258 }
259
260 int swf_SetRGBA(TAG * t,RGBA * col)
261 { if (!t) return -1;
262   if (col)
263   { swf_SetU8(t,col->r);
264     swf_SetU8(t,col->g);
265     swf_SetU8(t,col->b);
266     swf_SetU8(t,col->a);
267   } else swf_SetBlock(t,NULL,4);
268   return 0;
269 }
270 void swf_GetRGBA(TAG * t, RGBA * col)
271 {
272     RGBA dummy;
273     if(!col);
274         col = &dummy;
275     col->r = swf_GetU8(t);
276     col->g = swf_GetU8(t);
277     col->b = swf_GetU8(t);
278     col->a = swf_GetU8(t);
279 }
280
281 void swf_GetGradient(TAG * tag, GRADIENT * gradient, char alpha)
282 {
283     GRADIENT dummy;
284     int t;
285     if(!gradient)
286         gradient = &dummy;
287     gradient->num = swf_GetU8(tag);
288     for(t=0;t<gradient->num;t++)
289     {
290         int s=t;
291         if(s>=8) //FIXME
292             s=7;
293         gradient->ratios[t] = swf_GetU8(tag);
294         if(!alpha)
295             swf_GetRGB(tag, &gradient->rgba[t]);
296         else
297             swf_GetRGBA(tag, &gradient->rgba[t]);
298     }
299 }
300
301 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
302 {
303     GRADIENT dummy1;
304     GRADIENT dummy2;
305     int t;
306     if(!gradient1)
307         gradient1 = &dummy1;
308     if(!gradient2)
309         gradient2 = &dummy2;
310     gradient1->num = 
311     gradient2->num = swf_GetU8(tag);
312     for(t=0;t<gradient1->num;t++)
313     {
314         int s=t;
315         if(s>=8) //FIXME
316             s=7;
317         gradient1->ratios[t] = swf_GetU8(tag);
318         swf_GetRGBA(tag, &gradient1->rgba[t]);
319         gradient2->ratios[t] = swf_GetU8(tag);
320         swf_GetRGBA(tag, &gradient2->rgba[t]);
321     }
322 }
323
324 int swf_CountBits(U32 v,int nbits)
325 { int n = 33;
326   U32 m = 0x80000000;
327   if (!v) n = 0; else
328   if (v&m)
329   { while (v&m)
330     { n--;
331       m>>=1;
332       if (!m) break;
333     } 
334   }
335   else
336   { while (!(v&m))
337     { n--;
338       m>>=1;
339       if (!m) break;
340     } 
341   }
342   return (n>nbits)?n:nbits;
343 }
344
345 int swf_GetRect(TAG * t,SRECT * r)
346 { int nbits;
347   SRECT dummy;
348   if (!r) r = &dummy;
349   nbits = (int) swf_GetBits(t,5);
350   r->xmin = swf_GetSBits(t,nbits);
351   r->xmax = swf_GetSBits(t,nbits);
352   r->ymin = swf_GetSBits(t,nbits);
353   r->ymax = swf_GetSBits(t,nbits);
354   return 0;
355 }
356
357 int reader_GetRect(struct reader_t*reader,SRECT * r)
358 { int nbits;
359   SRECT dummy;
360   if (!r) r = &dummy;
361   nbits = (int) reader_GetBits(reader,5);
362   r->xmin = reader_GetSBits(reader,nbits);
363   r->xmax = reader_GetSBits(reader,nbits);
364   r->ymin = reader_GetSBits(reader,nbits);
365   r->ymax = reader_GetSBits(reader,nbits);
366   return 0;
367 }
368
369 int swf_SetRect(TAG * t,SRECT * r)
370 { int nbits;
371     
372   nbits = swf_CountBits(r->xmin,0);
373   nbits = swf_CountBits(r->xmax,nbits);
374   nbits = swf_CountBits(r->ymin,nbits);
375   nbits = swf_CountBits(r->ymax,nbits);
376
377   swf_SetBits(t,nbits,5);
378   swf_SetBits(t,r->xmin,nbits);
379   swf_SetBits(t,r->xmax,nbits);
380   swf_SetBits(t,r->ymin,nbits);
381   swf_SetBits(t,r->ymax,nbits);
382
383   return 0;
384 }
385
386 int swf_GetMatrix(TAG * t,MATRIX * m)
387 { MATRIX dummy;
388   int nbits;
389     
390   if (!m) m = &dummy;
391   
392   if (!t)
393   { m->sx = m->sy = 0x10000;
394     m->r0 = m->r1 = 0;
395     m->tx = m->ty = 0;
396     return -1;
397   }
398
399   swf_ResetReadBits(t);
400   
401   if (swf_GetBits(t,1))
402   { nbits = swf_GetBits(t,5);
403     m->sx = swf_GetSBits(t,nbits);
404     m->sy = swf_GetSBits(t,nbits);
405   }
406   else m->sx = m->sy = 0x10000;
407   
408   if (swf_GetBits(t,1))
409   { nbits = swf_GetBits(t,5);
410     m->r0 = swf_GetSBits(t,nbits);
411     m->r1 = swf_GetSBits(t,nbits);
412   }
413   else m->r0 = m->r1 = 0x0;
414
415   nbits = swf_GetBits(t,5);
416   m->tx = swf_GetSBits(t,nbits);
417   m->ty = swf_GetSBits(t,nbits);
418   
419   return 0;
420 }
421
422 int swf_SetMatrix(TAG * t,MATRIX * m)
423 { int nbits;
424   MATRIX ma;
425
426   if (!m)
427   { m = &ma;
428     ma.sx = ma.sy = 0x10000;
429     ma.r0 = ma.r1 = 0;
430     ma.tx = ma.ty = 0;
431   }
432
433   swf_ResetWriteBits(t);
434
435   if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
436   else
437   { swf_SetBits(t,1,1);
438     nbits = swf_CountBits(m->sx,0);
439     nbits = swf_CountBits(m->sy,nbits);
440     if(nbits>=32) {
441         fprintf(stderr,"rfxswf: Error: matrix values too large\n");
442         nbits = 31;
443     }
444     swf_SetBits(t,nbits,5);
445     swf_SetBits(t,m->sx,nbits);
446     swf_SetBits(t,m->sy,nbits);
447   }
448
449   if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
450   else
451   { swf_SetBits(t,1,1);
452     nbits = swf_CountBits(m->r0,0);
453     nbits = swf_CountBits(m->r1,nbits);
454     if(nbits>=32) {
455         fprintf(stderr,"rfxswf: Error: matrix values too large\n");
456         nbits = 31;
457     }
458     swf_SetBits(t,nbits,5);
459     swf_SetBits(t,m->r0,nbits);
460     swf_SetBits(t,m->r1,nbits);
461   }
462
463   nbits = swf_CountBits(m->tx,0);
464   nbits = swf_CountBits(m->ty,nbits);
465   if(nbits>=32) {
466       fprintf(stderr,"rfxswf: Error: matrix values too large\n");
467       nbits = 31;
468   }
469   swf_SetBits(t,nbits,5);
470   swf_SetBits(t,m->tx,nbits);
471   swf_SetBits(t,m->ty,nbits);
472
473   return 0;
474 }
475
476 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool
477 { CXFORM cxf;
478   int hasadd;
479   int hasmul;
480   int nbits;
481     
482   if (!cx) cx = &cxf;
483   
484   cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
485   cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
486
487   if (!t) return 0;
488   
489   swf_ResetReadBits(t);
490   hasadd = swf_GetBits(t,1);
491   hasmul = swf_GetBits(t,1);
492   nbits  = swf_GetBits(t,4);
493
494   if (hasmul)
495   { cx->r0 = (S16)swf_GetSBits(t,nbits);
496     cx->g0 = (S16)swf_GetSBits(t,nbits);
497     cx->b0 = (S16)swf_GetSBits(t,nbits);
498     if (alpha)
499       cx->a0 = (S16)swf_GetSBits(t,nbits);
500   }
501
502   if (hasadd)
503   { cx->r1 = (S16)swf_GetSBits(t,nbits);
504     cx->g1 = (S16)swf_GetSBits(t,nbits);
505     cx->b1 = (S16)swf_GetSBits(t,nbits);
506     if (alpha)
507       cx->a1 = (S16)swf_GetSBits(t,nbits);
508   }
509   
510   return 0;
511 }
512
513 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
514 { CXFORM cxf;
515   int hasadd;
516   int hasmul;
517   int nbits;
518     
519   if (!cx)
520   { cx = &cxf;
521     cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
522     cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
523   }
524
525   if (!alpha)
526   { cx->a0 = 256;
527     cx->a1 = 0;
528   }
529
530   nbits = 0;
531
532   hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
533   hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
534
535   if (hasmul)
536   { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits);
537     nbits = swf_CountBits((S32)cx->r0,nbits);
538     nbits = swf_CountBits((S32)cx->g0,nbits);
539     nbits = swf_CountBits((S32)cx->b0,nbits);
540   }
541
542   if (hasadd)
543   { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits);
544     nbits = swf_CountBits((S32)cx->r1,nbits);
545     nbits = swf_CountBits((S32)cx->g1,nbits);
546     nbits = swf_CountBits((S32)cx->b1,nbits);
547   }
548   
549   swf_ResetWriteBits(t);
550   swf_SetBits(t,hasadd?1:0,1);
551   swf_SetBits(t,hasmul?1:0,1);
552   swf_SetBits(t,nbits,4);
553
554   if (hasmul)
555   { swf_SetBits(t,cx->r0,nbits);
556     swf_SetBits(t,cx->g0,nbits);
557     swf_SetBits(t,cx->b0,nbits);
558     if (alpha) swf_SetBits(t,cx->a0,nbits);
559   }
560
561   if (hasadd)
562   { swf_SetBits(t,cx->r1,nbits);
563     swf_SetBits(t,cx->g1,nbits);
564     swf_SetBits(t,cx->b1,nbits);
565     if (alpha) swf_SetBits(t,cx->a1,nbits);
566   }
567   
568   return 0;
569 }
570
571 int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
572 int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
573
574 // Tag List Manipulating Functions
575
576 int swf_UpdateFrame(TAG * t,S8 delta)
577 // returns number of frames
578 { int res = -1;
579   while (t)
580   { t->frame+=delta;
581     res = t->frame;
582     t = t->next;
583   }
584   return res;
585 }
586
587 TAG * swf_InsertTag(TAG * after,U16 id)     // updates frames, if nescessary
588 { TAG * t;
589
590   t = (TAG *)malloc(sizeof(TAG));
591   if (t)
592   { memset(t,0x00,sizeof(TAG));
593     t->id = id;
594     
595     if (after)
596     { t->frame = after->frame;
597       t->prev  = after;
598       t->next  = after->next;
599       after->next = t;
600       if (t->next) t->next->prev = t;
601       
602       if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1);
603     }
604   }
605   return t;
606 }
607
608 int swf_DeleteTag(TAG * t)
609 { if (!t) return -1;
610
611   if (t->id==ST_SHOWFRAME) swf_UpdateFrame(t->next,-1);
612     
613   if (t->prev) t->prev->next = t->next;
614   if (t->next) t->next->prev = t->prev;
615
616   if (t->data) free(t->data);
617   free(t);
618   return 0;
619 }
620
621 TAG * swf_ReadTag(struct reader_t*reader, TAG * prev)
622 { TAG * t;
623   U16 raw;
624   U32 len;
625   int id;
626
627   if (reader->read(reader, &raw, 2) !=2 ) return NULL;
628   raw = SWAP16(raw);
629
630   len = raw&0x3f;
631   id  = raw>>6;
632
633   if (len==0x3f)
634   {
635       if (reader->read(reader, &len, 4) != 4) return NULL;
636       len = SWAP32(len);
637   }
638
639   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
640   // Sprite handling fix: Flaten sprite tree
641
642   t = (TAG *)malloc(sizeof(TAG));
643   
644   if (!t)
645   {
646     #ifdef DEBUG_RFXSWF
647       fprintf(stderr,"Fatal Error: malloc()/realloc() failed (2). (%d bytes)\n", sizeof(TAG));
648     #endif
649     return NULL;
650   }
651
652   memset(t,0x00,sizeof(TAG));
653   
654   t->len = len;
655   t->id  = id;
656
657   if (t->len)
658   { t->data = (U8*)malloc(t->len);
659     if (!t->data)
660     {
661       #ifdef DEBUG_RFXSWF
662         fprintf(stderr,"Fatal Error: malloc()/realloc() failed (3). (%d bytes)\n", t->len);
663       #endif
664       return NULL;
665     }
666     t->memsize = t->len;
667     if (reader->read(reader, t->data, t->len) != t->len) return NULL;
668   }
669
670   if (prev)
671   { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
672     t->prev  = prev;
673     prev->next = t;
674   }
675
676   return t;
677 }
678
679 int swf_DefineSprite_GetRealSize(TAG * t);
680
681 int swf_WriteTag2(struct writer_t*writer, TAG * t)
682 // returns tag length in bytes (incl. Header), -1 = Error
683 // writer = 0 -> no output
684 { U16 raw[3];
685   U32 len;
686   int short_tag;
687
688   if (!t) return -1;
689
690   len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len;
691
692   short_tag = len<0x3f;
693
694   if (writer)
695   { if (short_tag)
696     { raw[0] = SWAP16(len|((t->id&0x3ff)<<6));
697       if (writer->write(writer,raw,2)!=2)
698       {
699         #ifdef DEBUG_RFXSWF
700           fprintf(stderr,"WriteTag() failed: Short Header.\n");
701         #endif
702         return -1;
703       }
704     }
705     else
706     {
707       raw[0] = SWAP16((t->id<<6)|0x3f);
708       if (writer->write(writer,raw,2)!=2)
709       {
710 #ifdef DEBUG_RFXSWF
711           fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
712 #endif
713           return -1;
714       }
715       
716       len = SWAP32(len);
717       if (writer->write(writer,&len,4)!=4)
718       {
719         #ifdef DEBUG_RFXSWF
720           fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
721         #endif
722         return -1;
723       }
724     }
725     
726     if (t->data)
727     { if (writer->write(writer,t->data,t->len)!=t->len)
728       {
729         #ifdef DEBUG_RFXSWF
730           fprintf(stderr,"WriteTag() failed: Data.\n");
731         #endif
732         return -1;
733       }
734     }
735     #ifdef DEBUG_RFXSWF
736       else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
737     #endif
738   }
739
740   return t->len+(short_tag?2:6);
741 }
742
743 int swf_WriteTag(int handle, TAG * t)
744 {
745   struct writer_t writer;
746   if(handle<0)
747     return swf_WriteTag2(0, t);
748   writer_init_filewriter(&writer, handle);
749   return swf_WriteTag2(&writer, t);
750 }
751
752 int swf_DefineSprite_GetRealSize(TAG * t)
753 // Sprite Handling: Helper function to pack DefineSprite-Tag
754 { U32 len = t->len;
755   if(len>4) { // folded sprite
756       return t->len;
757   }
758   do
759   { t = swf_NextTag(t);
760     if (t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t);
761     else t = NULL;
762   } while (t&&(t->id!=ST_END));
763   return len;
764 }
765
766 void swf_FoldSprite(TAG * t)
767 {
768   TAG*sprtag=t,*tmp;
769   U16 id,frames,tmpid;
770   if(t->id!=ST_DEFINESPRITE)
771       return;
772   if(!t->len) {
773       fprintf(stderr, "Error: Sprite has no ID!");
774       return;
775   }
776   if(t->len>4) {
777     /* sprite is already folded */
778       return;
779   }
780
781   t->pos = 0;
782   id = swf_GetU16(t);
783   //frames = swf_GetU16(t);
784   free(t->data);
785   t->len = t->pos = t->memsize = 0;
786   t->data = 0;
787
788   frames = 0;
789
790   do 
791   { 
792     if(t->id==ST_SHOWFRAME) frames++;
793     t = swf_NextTag(t);
794   } while(t&&t!=ST_END);
795
796   t = swf_NextTag(sprtag);
797   swf_SetU16(sprtag, id);
798   swf_SetU16(sprtag, frames);
799
800   do
801   { 
802     tmpid= t->id;
803     if(t->len<0x3f) {
804         swf_SetU16(sprtag,t->len|(t->id<<6));
805     } else {
806         swf_SetU16(sprtag,0x3f|(t->id<<6));
807         swf_SetU32(sprtag,t->len);
808     }
809     if(t->len)
810         swf_SetBlock(sprtag,t->data, t->len);
811     tmp = t;
812     t = swf_NextTag(t);
813     swf_DeleteTag(tmp);
814   } 
815   while (t&&(tmpid!=ST_END));
816
817 //  sprtag->next = t;
818 //  t->prev = sprtag;
819 }
820
821 void swf_FoldAll(SWF*swf)
822 {
823     TAG*tag = swf->firstTag;
824     while(tag) {
825         if(tag->id == ST_DEFINESPRITE)
826             swf_FoldSprite(tag);
827         tag = swf_NextTag(tag);
828     }
829 }
830
831 // Movie Functions
832
833 int swf_ReadSWF2(struct reader_t*reader, SWF * swf)   // Reads SWF to memory (malloc'ed), returns length or <0 if fails
834 {     
835   if (!swf) return -1;
836   memset(swf,0x00,sizeof(SWF));
837
838   { char b[32];                         // read Header
839     int len;
840     TAG * t;
841     TAG t1;
842     struct reader_t zreader;
843     
844     if ((len = reader->read(reader ,b,8))<8) return -1;
845
846     if (b[0]!='F' && b[0]!='C') return -1;
847     if (b[1]!='W') return -1;
848     if (b[2]!='S') return -1;
849     swf->fileVersion = b[3];
850     swf->compressed  = (b[0]=='C')?1:0;
851     swf->fileSize    = GET32(&b[4]);
852     
853     if(swf->compressed) {
854         reader_init_zlibinflate(&zreader, reader);
855         reader = &zreader;
856     }
857
858     reader_GetRect(reader, &swf->movieSize);
859     reader->read(reader, &swf->frameRate, 2);
860     swf->frameRate = SWAP16(swf->frameRate);
861     reader->read(reader, &swf->frameCount, 2);
862     swf->frameCount = SWAP16(swf->frameCount);
863
864     /* read tags and connect to list */
865     t = &t1;
866     while (t) t = swf_ReadTag(reader,t);
867     swf->firstTag = t1.next;
868     t1.next->prev = NULL;
869   }
870   
871   return reader->pos;
872 }
873
874 int swf_ReadSWF(int handle, SWF * swf)
875 {
876   struct reader_t reader;
877   reader_init_filereader(&reader, handle);
878   return swf_ReadSWF2(&reader, swf);
879 }
880
881 int  swf_WriteSWF2(struct writer_t*writer, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
882 { U32 len;
883   TAG * t;
884   int frameCount=0;
885   struct writer_t zwriter;
886     
887   if (!swf) return -1;
888
889   // Insert REFLEX Tag
890
891 #ifdef INSERT_RFX_TAG
892
893   if (swf->firstTag && swf_NextTag(swf->firstTag))
894     if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
895       swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
896
897 #endif // INSERT_RFX_TAG
898
899   // Count Frames + File Size
900
901   len = 0;
902   t = swf->firstTag;
903   frameCount = 0;
904
905   while(t)
906   { len += swf_WriteTag(-1, t);
907     if (t->id==ST_SHOWFRAME) frameCount++;
908     t = swf_NextTag(t);
909   }
910   
911   { TAG t1;
912     char b[64],b4[4];
913     U32 l;
914
915     memset(&t1,0x00,sizeof(TAG));
916     t1.data    = (U8*)b;
917     t1.memsize = 64;
918     
919     { // measure header file size
920       TAG t2;
921       char b2[64];
922       memset(&t2,0x00,sizeof(TAG));
923       t2.data    = (U8*)b2;
924       t2.memsize = 64;
925       swf_SetRect(&t2, &swf->movieSize);
926       swf_SetU16(&t2, swf->frameRate);
927       swf_SetU16(&t2, swf->frameCount);
928       l = swf_GetTagLen(&t2)+8;
929     }
930
931     if(len) {// don't touch headers without tags
932         swf->fileSize = l+len;
933         swf->frameCount = frameCount;
934     }
935    
936     if(swf->compressed) {
937       char*id = "CWS";
938       writer->write(writer, id, 3);
939     }
940     else {
941       char*id = "FWS";
942       writer->write(writer, id, 3);
943     }
944
945     writer->write(writer, &swf->fileVersion, 1);
946     PUT32(b4, swf->fileSize);
947     writer->write(writer, b4, 4);
948
949     if(swf->compressed) {
950       writer_init_zlibdeflate(&zwriter, writer);
951       writer = &zwriter;
952     }
953
954     swf_SetRect(&t1,&swf->movieSize);
955     swf_SetU16(&t1,swf->frameRate);
956     swf_SetU16(&t1,swf->frameCount);
957
958     if (writer)
959     { 
960       int ret = writer->write(writer,b,swf_GetTagLen(&t1));
961       if (ret!=swf_GetTagLen(&t1))
962       {
963         #ifdef DEBUG_RFXSWF
964           printf("ret:%d\n",ret);
965           perror("write:");
966           fprintf(stderr,"WriteSWF() failed: Header.\n");
967         #endif
968         return -1;
969       }
970
971       t = swf->firstTag;
972       while (t)
973       { if (swf_WriteTag2(writer, t)<0) return -1;
974         t = swf_NextTag(t);
975       }
976       writer->finish(writer); //e.g. flush zlib buffers
977     }
978   }
979   return (int)swf->fileSize;
980 }
981
982 int  swf_WriteSWF(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
983 {
984   struct writer_t writer;
985   swf->compressed = 0;
986   if(handle<0)
987     return swf_WriteSWF2(&writer, swf);
988   writer_init_filewriter(&writer, handle);
989   return swf_WriteSWF2(&writer, swf);
990 }
991
992 int  swf_WriteSWC(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
993 {
994   struct writer_t writer;
995   swf->compressed = 1;
996   if(handle<0)
997     return swf_WriteSWF2(&writer, swf);
998   writer_init_filewriter(&writer, handle);
999   return swf_WriteSWF2(&writer, swf);
1000 }
1001
1002 int swf_WriteHeader2(struct writer_t*writer,SWF * swf)
1003 {
1004   SWF myswf;
1005   memcpy(&myswf,swf,sizeof(SWF));
1006   myswf.firstTag = 0;
1007   return swf_WriteSWF2(writer, &myswf);
1008 }
1009
1010 int swf_WriteHeader(int handle,SWF * swf)
1011 {
1012   SWF myswf;
1013   memcpy(&myswf,swf,sizeof(SWF));
1014   myswf.firstTag = 0;
1015   return swf_WriteSWF(handle, &myswf);
1016 }
1017
1018 int swf_WriteCGI(SWF * swf)
1019 { int len;
1020   char s[1024];
1021     
1022   len = swf_WriteSWF(-1,swf);
1023
1024   if (len<0) return -1;
1025
1026   sprintf(s,"Content-type: application/x-shockwave-flash\n"
1027             "Accept-Ranges: bytes\n"
1028             "Content-Length: %lu\n"
1029             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
1030             "\n",len);
1031             
1032   write(fileno(stdout),s,strlen(s));
1033   return swf_WriteSWF(fileno(stdout),swf);
1034 }
1035
1036 void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
1037 { TAG * t = swf->firstTag;
1038
1039   while (t)
1040   { TAG * tnew = t->next;
1041     if (t->data) free(t->data);
1042     free(t);
1043     t = tnew;
1044   }
1045 }
1046
1047 // include advanced functions
1048
1049 #include "modules/swfdump.c"
1050 #include "modules/swfshape.c"
1051 #include "modules/swftext.c"
1052 #include "modules/swfobject.c"
1053 #include "modules/swfbutton.c"
1054 #include "modules/swftools.c"
1055 #include "modules/swfcgi.c"
1056 #include "modules/swfbits.c"
1057 #include "modules/swfaction.c"
1058 #include "modules/swfsound.c"
1059