added gradient fill.
[swftools.git] / lib / rfxswf.c
1 /* vi: set sts=2 sw=2 :*/
2 /* rfxswf.c 
3
4    Library for creating and reading SWF files or parts of it.
5    There's a module directory which provides some extended functionality.
6    Most modules are included at the bottom of this file.
7
8    Part of the swftools package.
9
10    Copyright (c) 2000-2003 Rainer Böhme <rfxswf@reflex-studio.de>
11    Copyright (c) 2003 Matthias Kramm <kramm@quiss.org> 
12
13    This program is free software; you can redistribute it and/or modify
14    it under the terms of the GNU General Public License as published by
15    the Free Software Foundation; either version 2 of the License, or
16    (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
26
27 #include "rfxswf.h"
28
29 #ifdef HAVE_JPEGLIB
30 #define HAVE_BOOLEAN
31 #include <jpeglib.h>
32 #endif // HAVE_JPEGLIB
33
34 #ifdef HAVE_ZLIB
35 #include <zlib.h>
36 #endif // HAVE_ZLIB
37
38 #define LAME
39 #include "lame/lame.h"
40
41 #include "./bitio.h"
42 #include "./MD5.h"
43
44 // internal constants
45
46 #define MALLOC_SIZE     128
47 #define INSERT_RFX_TAG
48
49 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
50
51
52 // inline wrapper functions
53
54 TAG * swf_NextTag(TAG * t) { return t->next; }
55 TAG * swf_PrevTag(TAG * t) { return t->prev; }
56 U16   swf_GetTagID(TAG * t)    { return t->id; }
57 U32   swf_GetTagLen(TAG * t) { return t->len; }
58 U8*   swf_GetTagLenPtr(TAG * t) { return &(t->data[t->len]); }
59 U32   swf_GetTagPos(TAG * t)   { return t->pos; }
60
61 // Basic Data Access Functions
62
63 #define swf_ResetReadBits(tag)   if (tag->readBit)  { tag->pos++; tag->readBit = 0; }
64 #define swf_ResetWriteBits(tag)  if (tag->writeBit) { tag->writeBit = 0; }
65
66 // for future purpose: avoid high level lib functions to change tagpos/bitpos
67
68 #define swf_SaveTagPos(tag)
69 #define swf_RestoreTagPos(tag)
70
71 void swf_SetTagPos(TAG * t,U32 pos)
72 { swf_ResetReadBits(t);
73   if (pos<=t->len) t->pos = pos;
74   #ifdef DEBUG_RFXSWF
75   else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
76   #endif
77 }
78
79 char* swf_GetString(TAG*t)
80 {
81     char* str = ((char*)(&(t)->data[(t)->pos]));
82     while(swf_GetU8(t));
83     return str;
84 }
85
86 U8 swf_GetU8(TAG * t)
87 { swf_ResetReadBits(t);
88   #ifdef DEBUG_RFXSWF
89     if (t->pos>=t->len) 
90     { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
91       return 0;
92     }
93   #endif
94   return t->data[t->pos++];
95 }
96
97 U16 swf_GetU16(TAG * t)
98 { U16 res;
99   swf_ResetReadBits(t);
100   #ifdef DEBUG_RFXSWF
101     if (t->pos>(t->len-2)) 
102     { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
103       return 0;
104     }
105   #endif
106   res = t->data[t->pos] | (t->data[t->pos+1]<<8);
107   t->pos+=2;
108   return res;
109 }
110
111 U32 swf_GetU32(TAG * t)
112 { U32 res;
113   swf_ResetReadBits(t);
114   #ifdef DEBUG_RFXSWF
115     if (t->pos>(t->len-4)) 
116     { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
117       return 0;
118     }
119   #endif
120   res = t->data[t->pos]        | (t->data[t->pos+1]<<8) | 
121        (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);
122   t->pos+=4;
123   return res;
124 }
125
126 int swf_GetBlock(TAG * t,U8 * b,int l)
127 // returns number of bytes written (<=l)
128 // b = NULL -> skip data
129 { swf_ResetReadBits(t);
130   if ((t->len-t->pos)<l) l=t->len-t->pos;
131   if (b && l) memcpy(b,&t->data[t->pos],l);
132   t->pos+=l;
133   return l;
134 }
135
136 int swf_SetBlock(TAG * t,U8 * b,int l)
137 // Appends Block to the end of Tagdata, returns size
138 { U32 newlen = t->len + l;
139   swf_ResetWriteBits(t);
140   if (newlen>t->memsize)
141   { U32  newmem  = MEMSIZE(newlen);  
142     U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem));
143     if (!newdata)
144     {
145       #ifdef DEBUG_RFXSWF
146         fprintf(stderr,"Fatal Error: malloc()/realloc() failed (1). (%d bytes)\n", newmem);
147         *(int*)0=0;
148       #endif
149       return 0;
150     }
151     t->memsize = newmem;
152     t->data    = newdata;
153   }
154   if (b) memcpy(&t->data[t->len],b,l);
155   else memset(&t->data[t->len],0x00,l);
156   t->len+=l;
157   return l;
158 }
159
160 int swf_SetU8(TAG * t,U8 v)
161 { swf_ResetWriteBits(t);
162   if ((t->len+1)>t->memsize) return (swf_SetBlock(t,&v,1)==1)?0:-1;
163   t->data[t->len++] = v;
164   return 0;
165 }
166
167 int swf_SetU16(TAG * t,U16 v)
168 { U8 a[2];
169   a[0] = v&0xff;
170   a[1] = v>>8;
171   
172   swf_ResetWriteBits(t);
173   if ((t->len+2)>t->memsize) return (swf_SetBlock(t,a,2)==2)?0:-1;
174   t->data[t->len++] = a[0];
175   t->data[t->len++] = a[1];
176   return 0;
177 }
178
179 int swf_SetU32(TAG * t,U32 v)
180 { U8 a[4];
181   a[0] = v&0xff;        // to ensure correct handling of non-intel byteorder
182   a[1] = (v>>8)&0xff;
183   a[2] = (v>>16)&0xff;
184   a[3] = (v>>24)&0xff;
185   
186   swf_ResetWriteBits(t);
187   if ((t->len+4)>t->memsize) return (swf_SetBlock(t,a,4)==4)?0:-1;
188   t->data[t->len++] = a[0];
189   t->data[t->len++] = a[1];
190   t->data[t->len++] = a[2];
191   t->data[t->len++] = a[3];
192   return 0;
193 }
194
195 U32 swf_GetBits(TAG * t,int nbits)
196 { U32 res = 0;
197   if (!nbits) return 0;
198   if (!t->readBit) t->readBit = 0x80;
199   while (nbits)
200   { res<<=1;
201     if (t->data[t->pos]&t->readBit) res|=1;
202     t->readBit>>=1;
203     nbits--;
204     if (!t->readBit)
205     { if (nbits) t->readBit = 0x80;
206       #ifdef DEBUG_RFXSWF
207       if (t->pos>=t->len) 
208       { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
209         return res;
210       }
211       #endif
212       t->pos++;
213     }
214   }
215   return res;
216 }
217
218 S32 swf_GetSBits(TAG * t,int nbits)
219 { U32 res = swf_GetBits(t,nbits);
220   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
221   return (S32)res;
222 }
223
224 U32 reader_GetBits(struct reader_t*reader, int nbits)
225 { return reader_readbits(reader, nbits);
226 }
227 S32 reader_GetSBits(struct reader_t*reader, int nbits)
228 { U32 res = reader_readbits(reader, nbits);
229   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
230   return (S32)res;
231 }
232
233 int swf_SetBits(TAG * t,U32 v,int nbits)
234 { U32 bm = 1<<(nbits-1);
235
236   while (nbits)
237   { if (!t->writeBit)
238     { if (FAILED(swf_SetU8(t,0))) return -1;
239       t->writeBit = 0x80;
240     }
241     if (v&bm) t->data[t->len-1] |= t->writeBit;
242     bm>>=1;
243     t->writeBit>>=1;
244     nbits--;
245   }
246   return 0;
247 }
248
249 // Advanced Data Access Functions
250
251 int swf_SetRGB(TAG * t,RGBA * col)
252 { if (!t) return -1;
253   if (col)
254   { swf_SetU8(t,col->r);
255     swf_SetU8(t,col->g);
256     swf_SetU8(t,col->b);
257   } else swf_SetBlock(t,NULL,3);
258   return 0;
259 }
260 void swf_GetRGB(TAG * t, RGBA * col)
261 {
262     RGBA dummy;
263     if(!col)
264         col = &dummy;
265     col->r = swf_GetU8(t);
266     col->g = swf_GetU8(t);
267     col->b = swf_GetU8(t);
268     col->a = 255;
269 }
270
271 int swf_SetRGBA(TAG * t,RGBA * col)
272 { if (!t) return -1;
273   if (col)
274   { swf_SetU8(t,col->r);
275     swf_SetU8(t,col->g);
276     swf_SetU8(t,col->b);
277     swf_SetU8(t,col->a);
278   } else swf_SetBlock(t,NULL,4);
279   return 0;
280 }
281 void swf_GetRGBA(TAG * t, RGBA * col)
282 {
283     RGBA dummy;
284     if(!col);
285         col = &dummy;
286     col->r = swf_GetU8(t);
287     col->g = swf_GetU8(t);
288     col->b = swf_GetU8(t);
289     col->a = swf_GetU8(t);
290 }
291
292 void swf_GetGradient(TAG * tag, GRADIENT * gradient, char alpha)
293 {
294     GRADIENT dummy;
295     int t;
296     if(!tag) {
297       memset(gradient, 0, sizeof(GRADIENT));
298       return;
299     }
300     if(!gradient)
301         gradient = &dummy;
302     gradient->num = swf_GetU8(tag);
303     for(t=0;t<gradient->num;t++)
304     {
305         int s=t;
306         if(s>=8) //FIXME
307             s=7;
308         gradient->ratios[t] = swf_GetU8(tag);
309         if(!alpha)
310             swf_GetRGB(tag, &gradient->rgba[t]);
311         else
312             swf_GetRGBA(tag, &gradient->rgba[t]);
313     }
314 }
315
316 void swf_SetGradient(TAG * tag, GRADIENT * gradient, char alpha)
317 {
318     int t;
319     if(!tag) {
320       memset(gradient, 0, sizeof(GRADIENT));
321       return;
322     }
323     swf_SetU8(tag, gradient->num);
324     for(t=0; t<8 && t<gradient->num; t++)
325     {
326         swf_SetU8(tag, gradient->ratios[t]);
327         if(!alpha)
328             swf_SetRGB(tag, &gradient->rgba[t]);
329         else
330             swf_SetRGBA(tag, &gradient->rgba[t]);
331     }
332 }
333
334 int swf_CountUBits(U32 v,int nbits)
335 { int n = 32;
336   U32 m = 0x80000000;
337   if(v == 0x00000000) n = 0; 
338   else
339     while (!(v&m))
340     { n--;
341       m>>=1;
342     } 
343   return (n>nbits)?n:nbits;
344 }
345
346 int swf_CountBits(U32 v,int nbits)
347 { int n = 33;
348   U32 m = 0x80000000;
349   if (v&m)
350   { if(v == 0xffffffff) n = 1;
351     else 
352     while (v&m)
353     { n--;
354       m>>=1;
355     } 
356   }
357   else
358   { if(v == 0x00000000) n = 0; 
359     else
360     while (!(v&m))
361     { n--;
362       m>>=1;
363     } 
364   }
365   return (n>nbits)?n:nbits;
366 }
367
368 int swf_GetRect(TAG * t,SRECT * r)
369 { int nbits;
370   SRECT dummy;
371   if(!t) {r->xmin=r->xmax=r->ymin=r->ymax=0;return 0;}
372   if (!r) r = &dummy;
373   nbits = (int) swf_GetBits(t,5);
374   r->xmin = swf_GetSBits(t,nbits);
375   r->xmax = swf_GetSBits(t,nbits);
376   r->ymin = swf_GetSBits(t,nbits);
377   r->ymax = swf_GetSBits(t,nbits);
378   return 0;
379 }
380
381 int reader_GetRect(struct reader_t*reader,SRECT * r)
382 { int nbits;
383   SRECT dummy;
384   if (!r) r = &dummy;
385   nbits = (int) reader_GetBits(reader,5);
386   r->xmin = reader_GetSBits(reader,nbits);
387   r->xmax = reader_GetSBits(reader,nbits);
388   r->ymin = reader_GetSBits(reader,nbits);
389   r->ymax = reader_GetSBits(reader,nbits);
390   return 0;
391 }
392
393 int swf_SetRect(TAG * t,SRECT * r)
394 { int nbits;
395     
396   nbits = swf_CountBits(r->xmin,0);
397   nbits = swf_CountBits(r->xmax,nbits);
398   nbits = swf_CountBits(r->ymin,nbits);
399   nbits = swf_CountBits(r->ymax,nbits);
400   if(nbits>=32) {
401     fprintf(stderr, "rfxswf: Warning: num_bits overflow in swf_SetRect\n");
402     nbits=31;
403   }
404
405   swf_SetBits(t,nbits,5);
406   swf_SetBits(t,r->xmin,nbits);
407   swf_SetBits(t,r->xmax,nbits);
408   swf_SetBits(t,r->ymin,nbits);
409   swf_SetBits(t,r->ymax,nbits);
410
411   return 0;
412 }
413
414 void swf_ExpandRect(SRECT*src, SPOINT add)
415 {
416     if(add.x < src->xmin)
417         src->xmin = add.x;
418     if(add.x > src->xmax)
419         src->xmax = add.x;
420     if(add.y < src->ymin)
421         src->ymin = add.y;
422     if(add.y > src->ymax)
423         src->ymax = add.y;
424 }
425 void swf_ExpandRect2(SRECT*src, SRECT*add)
426 {
427     if((add->xmin | add->ymin | add->xmax | add->ymax)==0)
428         return;
429     if(add->xmin < src->xmin)
430         src->xmin = add->xmin;
431     if(add->ymin < src->ymin)
432         src->ymin = add->ymin;
433     if(add->xmax > src->xmax)
434         src->xmax = add->xmax;
435     if(add->ymax > src->ymax)
436         src->ymax = add->ymax;
437 }
438 SPOINT swf_TurnPoint(SPOINT p, MATRIX* m)
439 {
440     SPOINT r;
441     r.x = (int)(m->sx*(1/65536.0)*p.x + m->r1*(1/65536.0)*p.y + 0.5) + m->tx;
442     r.y = (int)(m->r0*(1/65536.0)*p.x + m->sy*(1/65536.0)*p.y + 0.5) + m->ty;
443     return r;
444 }
445 SRECT swf_TurnRect(SRECT r, MATRIX* m)
446 {
447     SRECT g;
448     SPOINT p1,p2,p3,p4,pp1,pp2,pp3,pp4;
449     p1.x = r.xmin;p1.y = r.ymin;
450     p2.x = r.xmax;p2.y = r.ymin;
451     p3.x = r.xmin;p3.y = r.ymax;
452     p4.x = r.xmax;p4.y = r.ymax;
453     pp1 = swf_TurnPoint(p1, m);
454     pp2 = swf_TurnPoint(p2, m);
455     pp3 = swf_TurnPoint(p3, m);
456     pp4 = swf_TurnPoint(p4, m);
457     g.xmin = g.xmax = pp1.x;
458     g.ymin = g.ymax = pp1.y;
459     swf_ExpandRect(&g, pp2);
460     swf_ExpandRect(&g, pp3);
461     swf_ExpandRect(&g, pp4);
462     return g;
463 }
464         
465
466 int swf_GetMatrix(TAG * t,MATRIX * m)
467 { MATRIX dummy;
468   int nbits;
469     
470   if (!m) m = &dummy;
471   
472   if (!t)
473   { m->sx = m->sy = 0x10000;
474     m->r0 = m->r1 = 0;
475     m->tx = m->ty = 0;
476     return -1;
477   }
478
479   swf_ResetReadBits(t);
480   
481   if (swf_GetBits(t,1))
482   { nbits = swf_GetBits(t,5);
483     m->sx = swf_GetSBits(t,nbits);
484     m->sy = swf_GetSBits(t,nbits);
485   }
486   else m->sx = m->sy = 0x10000;
487   
488   if (swf_GetBits(t,1))
489   { nbits = swf_GetBits(t,5);
490     m->r0 = swf_GetSBits(t,nbits);
491     m->r1 = swf_GetSBits(t,nbits);
492   }
493   else m->r0 = m->r1 = 0x0;
494
495   nbits = swf_GetBits(t,5);
496   m->tx = swf_GetSBits(t,nbits);
497   m->ty = swf_GetSBits(t,nbits);
498   
499   return 0;
500 }
501
502 int swf_SetMatrix(TAG * t,MATRIX * m)
503 { int nbits;
504   MATRIX ma;
505
506   if (!m)
507   { m = &ma;
508     ma.sx = ma.sy = 0x10000;
509     ma.r0 = ma.r1 = 0;
510     ma.tx = ma.ty = 0;
511   }
512
513   swf_ResetWriteBits(t);
514
515   if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
516   else
517   { swf_SetBits(t,1,1);
518     nbits = swf_CountBits(m->sx,0);
519     nbits = swf_CountBits(m->sy,nbits);
520     if(nbits>=32) {
521         fprintf(stderr,"rfxswf: Error: matrix values too large\n");
522         nbits = 31;
523     }
524     swf_SetBits(t,nbits,5);
525     swf_SetBits(t,m->sx,nbits);
526     swf_SetBits(t,m->sy,nbits);
527   }
528
529   if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
530   else
531   { swf_SetBits(t,1,1);
532     nbits = swf_CountBits(m->r0,0);
533     nbits = swf_CountBits(m->r1,nbits);
534     if(nbits>=32) {
535         fprintf(stderr,"rfxswf: Error: matrix values too large\n");
536         nbits = 31;
537     }
538     swf_SetBits(t,nbits,5);
539     swf_SetBits(t,m->r0,nbits);
540     swf_SetBits(t,m->r1,nbits);
541   }
542
543   nbits = swf_CountBits(m->tx,0);
544   nbits = swf_CountBits(m->ty,nbits);
545   if(nbits>=32) {
546       fprintf(stderr,"rfxswf: Error: matrix values too large\n");
547       nbits = 31;
548   }
549   swf_SetBits(t,nbits,5);
550   swf_SetBits(t,m->tx,nbits);
551   swf_SetBits(t,m->ty,nbits);
552
553   return 0;
554 }
555
556 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool
557 { CXFORM cxf;
558   int hasadd;
559   int hasmul;
560   int nbits;
561     
562   if (!cx) cx = &cxf;
563   
564   cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
565   cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
566
567   if (!t) return 0;
568   
569   swf_ResetReadBits(t);
570   hasadd = swf_GetBits(t,1);
571   hasmul = swf_GetBits(t,1);
572   nbits  = swf_GetBits(t,4);
573
574   if (hasmul)
575   { cx->r0 = (S16)swf_GetSBits(t,nbits);
576     cx->g0 = (S16)swf_GetSBits(t,nbits);
577     cx->b0 = (S16)swf_GetSBits(t,nbits);
578     if (alpha)
579       cx->a0 = (S16)swf_GetSBits(t,nbits);
580   }
581
582   if (hasadd)
583   { cx->r1 = (S16)swf_GetSBits(t,nbits);
584     cx->g1 = (S16)swf_GetSBits(t,nbits);
585     cx->b1 = (S16)swf_GetSBits(t,nbits);
586     if (alpha)
587       cx->a1 = (S16)swf_GetSBits(t,nbits);
588   }
589   
590   return 0;
591 }
592
593 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
594 { CXFORM cxf;
595   int hasadd;
596   int hasmul;
597   int nbits;
598     
599   if (!cx)
600   { cx = &cxf;
601     cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
602     cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
603   }
604
605   if (!alpha)
606   { cx->a0 = 256;
607     cx->a1 = 0;
608   }
609
610   nbits = 0;
611
612   hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
613   hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
614
615   if (hasmul)
616   { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits);
617     nbits = swf_CountBits((S32)cx->r0,nbits);
618     nbits = swf_CountBits((S32)cx->g0,nbits);
619     nbits = swf_CountBits((S32)cx->b0,nbits);
620   }
621
622   if (hasadd)
623   { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits);
624     nbits = swf_CountBits((S32)cx->r1,nbits);
625     nbits = swf_CountBits((S32)cx->g1,nbits);
626     nbits = swf_CountBits((S32)cx->b1,nbits);
627   }
628   
629   swf_ResetWriteBits(t);
630   swf_SetBits(t,hasadd?1:0,1);
631   swf_SetBits(t,hasmul?1:0,1);
632   swf_SetBits(t,nbits,4);
633
634   if (hasmul)
635   { swf_SetBits(t,cx->r0,nbits);
636     swf_SetBits(t,cx->g0,nbits);
637     swf_SetBits(t,cx->b0,nbits);
638     if (alpha) swf_SetBits(t,cx->a0,nbits);
639   }
640
641   if (hasadd)
642   { swf_SetBits(t,cx->r1,nbits);
643     swf_SetBits(t,cx->g1,nbits);
644     swf_SetBits(t,cx->b1,nbits);
645     if (alpha) swf_SetBits(t,cx->a1,nbits);
646   }
647   
648   return 0;
649 }
650
651 //int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
652 //int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
653
654 void  swf_SetPassword(TAG * t, const char * password)
655 {
656     /* WARNING: crypt_md5 is not reentrant */
657     char* md5string = crypt_md5(password, "salt"); /* FIXME- get random salt */
658     swf_SetString(t, md5string);
659 }
660
661 int swf_VerifyPassword(TAG * t, const char * password)
662 {
663     char*md5string1, *md5string2;
664     char*x;
665     char*md5, *salt;
666     int n;
667
668     md5string1 = swf_GetString(t);
669
670     if(!strncmp(md5string1, "$1$",3 )) {
671         return 0;
672     }
673     x = strchr(md5string1+3, '$');
674     if(!x)
675         return 0;
676     n = x-(md5string1+3);
677     salt = (char*)malloc(n+1);
678     memcpy(salt, md5string1+3, n);
679     salt[n] = 0;
680
681     md5string2 = crypt_md5(password, salt);
682     free(salt);
683     if(strcmp(md5string1, md5string2) != 0)
684         return 0;
685     return 1;
686 }
687
688 // Tag List Manipulating Functions
689
690 TAG * swf_InsertTag(TAG * after,U16 id)
691 { TAG * t;
692
693   t = (TAG *)malloc(sizeof(TAG));
694   if (t)
695   { memset(t,0x00,sizeof(TAG));
696     t->id = id;
697     
698     if (after)
699     {
700       t->prev  = after;
701       t->next  = after->next;
702       after->next = t;
703       if (t->next) t->next->prev = t;
704     }
705   }
706   return t;
707 }
708
709 TAG * swf_InsertTagBefore(SWF* swf, TAG * before,U16 id)
710 { TAG * t;
711
712   t = (TAG *)malloc(sizeof(TAG));
713   if (t)
714   { memset(t,0x00,sizeof(TAG));
715     t->id = id;
716     
717     if (before)
718     {
719       t->next  = before;
720       t->prev  = before->prev;
721       before->prev = t;
722       if (t->prev) t->prev->next = t;
723     }
724   }
725   if(swf && swf->firstTag == before) {
726     swf->firstTag = t;
727   }
728   return t;
729 }
730
731 void swf_ClearTag(TAG * t)
732 {
733   if (t->data) free(t->data);
734   t->data = 0;
735   t->pos = 0;
736   t->len = 0;
737   t->readBit = 0;
738   t->writeBit = 0;
739   t->memsize = 0;
740 }
741
742 void swf_ResetTag(TAG*tag, U16 id)
743 {
744     tag->len = tag->pos = tag->readBit = tag->writeBit = 0;
745     tag->id = id;
746 }
747
748 int swf_DeleteTag(TAG * t)
749 { if (!t) return -1;
750
751   if (t->prev) t->prev->next = t->next;
752   if (t->next) t->next->prev = t->prev;
753
754   if (t->data) free(t->data);
755   free(t);
756   return 0;
757 }
758
759 TAG * swf_ReadTag(struct reader_t*reader, TAG * prev)
760 { TAG * t;
761   U16 raw;
762   U32 len;
763   int id;
764
765   if (reader->read(reader, &raw, 2) !=2 ) return NULL;
766   raw = SWAP16(raw);
767
768   len = raw&0x3f;
769   id  = raw>>6;
770
771   if (len==0x3f)
772   {
773       if (reader->read(reader, &len, 4) != 4) return NULL;
774       len = SWAP32(len);
775   }
776
777   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
778   // Sprite handling fix: Flatten sprite tree
779
780   t = (TAG *)malloc(sizeof(TAG));
781   
782   if (!t)
783   {
784     #ifdef DEBUG_RFXSWF
785       fprintf(stderr,"Fatal Error: malloc()/realloc() failed (2). (%d bytes)\n", sizeof(TAG));
786     #endif
787     return NULL;
788   }
789
790   memset(t,0x00,sizeof(TAG));
791   
792   t->len = len;
793   t->id  = id;
794
795   if (t->len)
796   { t->data = (U8*)malloc(t->len);
797     if (!t->data)
798     {
799       #ifdef DEBUG_RFXSWF
800         fprintf(stderr,"Fatal Error: malloc()/realloc() failed (3). (%d bytes)\n", t->len);
801       #endif
802       return NULL;
803     }
804     t->memsize = t->len;
805     if (reader->read(reader, t->data, t->len) != t->len) return NULL;
806   }
807
808   if (prev)
809   {
810     t->prev  = prev;
811     prev->next = t;
812   }
813
814   return t;
815 }
816
817 int swf_DefineSprite_GetRealSize(TAG * t);
818
819 int swf_WriteTag2(struct writer_t*writer, TAG * t)
820 // returns tag length in bytes (incl. Header), -1 = Error
821 // writer = 0 -> no output
822 { U16 raw[3];
823   U32 len;
824   int short_tag;
825
826   if (!t) return -1;
827
828   len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len;
829
830   short_tag = len<0x3f;
831
832   if (writer)
833   { if (short_tag)
834     { raw[0] = SWAP16(len|((t->id&0x3ff)<<6));
835       if (writer->write(writer,raw,2)!=2)
836       {
837         #ifdef DEBUG_RFXSWF
838           fprintf(stderr,"WriteTag() failed: Short Header.\n");
839         #endif
840         return -1;
841       }
842     }
843     else
844     {
845       raw[0] = SWAP16((t->id<<6)|0x3f);
846       if (writer->write(writer,raw,2)!=2)
847       {
848 #ifdef DEBUG_RFXSWF
849           fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
850 #endif
851           return -1;
852       }
853       
854       len = SWAP32(len);
855       if (writer->write(writer,&len,4)!=4)
856       {
857         #ifdef DEBUG_RFXSWF
858           fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
859         #endif
860         return -1;
861       }
862     }
863     
864     if (t->data)
865     { if (writer->write(writer,t->data,t->len)!=t->len)
866       {
867         #ifdef DEBUG_RFXSWF
868           fprintf(stderr,"WriteTag() failed: Data.\n");
869         #endif
870         return -1;
871       }
872     }
873     #ifdef DEBUG_RFXSWF
874       else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
875     #endif
876   }
877
878   return t->len+(short_tag?2:6);
879 }
880
881 int swf_WriteTag(int handle, TAG * t)
882 {
883   struct writer_t writer;
884   if(handle<0)
885     return swf_WriteTag2(0, t);
886   writer_init_filewriter(&writer, handle);
887   return swf_WriteTag2(&writer, t);
888 }
889
890 int swf_DefineSprite_GetRealSize(TAG * t)
891 // Sprite Handling: Helper function to pack DefineSprite-Tag
892 { U32 len = t->len;
893   if(len>4) { // folded sprite
894       return t->len;
895   }
896   do
897   { t = swf_NextTag(t);
898     if (t && t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t);
899     else t = NULL;
900   } while (t&&(t->id!=ST_END));
901   return len;
902 }
903
904 void swf_UnFoldSprite(TAG * t)
905 {
906   U16 id,tmp;
907   U32 len;
908   TAG*next = t;
909   U16 spriteid,spriteframes;
910   int level;
911   if(t->id!=ST_DEFINESPRITE)
912     return;
913   if(t->len<=4) // not folded
914     return;
915
916   swf_SetTagPos(t,0);
917
918   spriteid = swf_GetU16(t); //id
919   spriteframes = swf_GetU16(t); //frames
920
921   level = 1;
922
923   while(1)
924   {
925     TAG*it = 0;
926     tmp = swf_GetU16(t);
927     len = tmp&0x3f;
928     id  = tmp>>6;
929     if(id == ST_END)
930         level--;
931     if(id == ST_DEFINESPRITE && len<=4)
932         level++;
933
934     if (len==0x3f)
935         len = swf_GetU32(t);
936     it = swf_InsertTag(next, id);
937     next = it;
938     it->len = len;
939     it->id  = id;
940     if (it->len)
941     { it->data = (U8*)malloc(it->len);
942       it->memsize = it->len;
943       swf_GetBlock(t, it->data, it->len);
944     }
945
946     if(!level)
947         break;
948   }
949   
950   free(t->data); t->data = 0;
951   t->memsize = t->len = t->pos = 0;
952
953   swf_SetU16(t, spriteid);
954   swf_SetU16(t, spriteframes);
955 }
956
957 void swf_FoldSprite(TAG * t)
958 {
959   TAG*sprtag=t,*tmp;
960   U16 id,frames,tmpid;
961   int level;
962   if(t->id!=ST_DEFINESPRITE)
963       return;
964   if(!t->len) {
965       fprintf(stderr, "Error: Sprite has no ID!");
966       return;
967   }
968   if(t->len>4) {
969     /* sprite is already folded */
970       return;
971   }
972
973   t->pos = 0;
974   id = swf_GetU16(t);
975   free(t->data);
976   t->len = t->pos = t->memsize = 0;
977   t->data = 0;
978
979   frames = 0;
980
981   t = swf_NextTag(sprtag);
982   level = 1;
983
984   do 
985   { 
986     if(t->id==ST_SHOWFRAME) frames++;
987     if(t->id == ST_DEFINESPRITE && t->len<=4)
988         level++;
989     if(t->id == ST_END)
990         level--;
991     t = swf_NextTag(t);
992   } while(t && level);
993   if(level)
994     fprintf(stderr, "rfxswf error: sprite doesn't end(1)\n");
995
996   swf_SetU16(sprtag, id);
997   swf_SetU16(sprtag, frames);
998
999   t = swf_NextTag(sprtag);
1000   level = 1;
1001
1002   do
1003   { 
1004     if(t->len<0x3f) {
1005         swf_SetU16(sprtag,t->len|(t->id<<6));
1006     } else {
1007         swf_SetU16(sprtag,0x3f|(t->id<<6));
1008         swf_SetU32(sprtag,t->len);
1009     }
1010     if(t->len)
1011         swf_SetBlock(sprtag,t->data, t->len);
1012     tmp = t;
1013     if(t->id == ST_DEFINESPRITE && t->len<=4)
1014         level++;
1015     if(t->id == ST_END)
1016         level--;
1017     t = swf_NextTag(t);
1018     swf_DeleteTag(tmp);
1019   } 
1020   while (t && level);
1021   if(level)
1022     fprintf(stderr, "rfxswf error: sprite doesn't end(2)\n");
1023
1024 //  sprtag->next = t;
1025 //  t->prev = sprtag;
1026 }
1027
1028 int swf_IsFolded(TAG * t)
1029 {
1030     return (t->id == ST_DEFINESPRITE && t->len>4);
1031 }
1032
1033 void swf_FoldAll(SWF*swf)
1034 {
1035     TAG*tag = swf->firstTag;
1036     //swf_DumpSWF(stdout, swf);
1037     while(tag) {
1038         if(tag->id == ST_DEFINESPRITE) {
1039             swf_FoldSprite(tag);
1040             //swf_DumpSWF(stdout, swf);
1041         }
1042         tag = swf_NextTag(tag);
1043     }
1044 }
1045
1046 void swf_UnFoldAll(SWF*swf)
1047 {
1048     TAG*tag = swf->firstTag;
1049     while(tag) {
1050         if(tag->id == ST_DEFINESPRITE)
1051             swf_UnFoldSprite(tag);
1052         tag = tag->next;
1053     }
1054 }
1055
1056 void swf_OptimizeTagOrder(SWF*swf)
1057 {
1058   TAG*tag,*next;
1059   TAG*level0;
1060   int level;
1061   int changes;
1062   swf_UnFoldAll(swf);
1063   /* at the moment, we don't actually do optimizing,
1064      only fixing of non-spec-conformant things like
1065      sprite tags */
1066
1067   do {
1068     changes = 0;
1069     level = 0;
1070     level0 = 0;
1071     tag = swf->firstTag;
1072     while(tag) {
1073       next = tag->next;
1074       if(tag->id == ST_DEFINESPRITE) {
1075         if(tag->len>4) {
1076           /* ??? all sprites are supposed to be unfolded */
1077           fprintf(stderr, "librfxswf error - internal error in OptimizeTagOrder/UnfoldAll\n");
1078         }
1079         level++;
1080         if(level==1) {
1081           level0 = tag;
1082           tag = next;
1083           continue;
1084         }
1085       }
1086       if(level>=1) {
1087         /* move non-sprite tags out of sprite */
1088         if(!swf_isAllowedSpriteTag(tag) || level>=2) {
1089           /* remove tag from current position */
1090           tag->prev->next = tag->next;
1091           if(tag->next)
1092             tag->next->prev = tag->prev;
1093
1094           /* insert before tag level0 */
1095           tag->next = level0;
1096           tag->prev = level0->prev;
1097           level0->prev = tag;
1098           tag->prev->next = tag;
1099           changes = 1;
1100         }
1101       }
1102       if(tag->id == ST_END) {
1103         level--;
1104       }
1105
1106       tag = next;
1107     }
1108   } while(changes);
1109 }
1110
1111 // Movie Functions
1112
1113 int swf_ReadSWF2(struct reader_t*reader, SWF * swf)   // Reads SWF to memory (malloc'ed), returns length or <0 if fails
1114 {     
1115   if (!swf) return -1;
1116   memset(swf,0x00,sizeof(SWF));
1117
1118   { char b[32];                         // read Header
1119     int len;
1120     TAG * t;
1121     TAG t1;
1122     struct reader_t zreader;
1123     
1124     if ((len = reader->read(reader ,b,8))<8) return -1;
1125
1126     if (b[0]!='F' && b[0]!='C') return -1;
1127     if (b[1]!='W') return -1;
1128     if (b[2]!='S') return -1;
1129     swf->fileVersion = b[3];
1130     swf->compressed  = (b[0]=='C')?1:0;
1131     swf->fileSize    = GET32(&b[4]);
1132     
1133     if(swf->compressed) {
1134         reader_init_zlibinflate(&zreader, reader);
1135         reader = &zreader;
1136     }
1137
1138     reader_GetRect(reader, &swf->movieSize);
1139     reader->read(reader, &swf->frameRate, 2);
1140     swf->frameRate = SWAP16(swf->frameRate);
1141     reader->read(reader, &swf->frameCount, 2);
1142     swf->frameCount = SWAP16(swf->frameCount);
1143
1144     /* read tags and connect to list */
1145     t = &t1;
1146     while (t) t = swf_ReadTag(reader,t);
1147     swf->firstTag = t1.next;
1148     t1.next->prev = NULL;
1149   }
1150   
1151   return reader->pos;
1152 }
1153
1154 int swf_ReadSWF(int handle, SWF * swf)
1155 {
1156   struct reader_t reader;
1157   reader_init_filereader(&reader, handle);
1158   return swf_ReadSWF2(&reader, swf);
1159 }
1160
1161 int  swf_WriteSWF2(struct writer_t*writer, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1162 { U32 len;
1163   TAG * t;
1164   int frameCount=0;
1165   struct writer_t zwriter;
1166   int fileSize = 0;
1167     
1168   if (!swf) return -1;
1169
1170   // Insert REFLEX Tag
1171
1172 #ifdef INSERT_RFX_TAG
1173
1174   if (swf->firstTag && swf_NextTag(swf->firstTag))
1175     if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
1176       swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
1177
1178 #endif // INSERT_RFX_TAG
1179
1180   // Count Frames + File Size
1181
1182   len = 0;
1183   t = swf->firstTag;
1184   frameCount = 0;
1185
1186   while(t)
1187   { len += swf_WriteTag(-1, t);
1188     if (t->id==ST_SHOWFRAME) frameCount++;
1189     t = swf_NextTag(t);
1190   }
1191   
1192   { TAG t1;
1193     char b[64],b4[4];
1194     U32 l;
1195
1196     memset(&t1,0x00,sizeof(TAG));
1197     t1.data    = (U8*)b;
1198     t1.memsize = 64;
1199     
1200     { // measure header file size
1201       TAG t2;
1202       char b2[64];
1203       memset(&t2,0x00,sizeof(TAG));
1204       t2.data    = (U8*)b2;
1205       t2.memsize = 64;
1206       swf_SetRect(&t2, &swf->movieSize);
1207       swf_SetU16(&t2, swf->frameRate);
1208       swf_SetU16(&t2, swf->frameCount);
1209       l = swf_GetTagLen(&t2)+8;
1210     }
1211     if(swf->compressed == 8) {
1212       l -= 8;
1213     }
1214
1215     fileSize = l+len;
1216     if(len) {// don't touch headers without tags
1217         swf->fileSize = fileSize;
1218         swf->frameCount = frameCount;
1219     }
1220
1221     if(swf->compressed != 8) {
1222     /* compressed flag set to 8 means "skip first 8 
1223        header bytes". This is necessary if the caller wants to
1224        create compressed SWFs himself */
1225       if(swf->compressed) {
1226         char*id = "CWS";
1227         writer->write(writer, id, 3);
1228       }
1229       else {
1230         char*id = "FWS";
1231         writer->write(writer, id, 3);
1232       }
1233
1234       writer->write(writer, &swf->fileVersion, 1);
1235       PUT32(b4, swf->fileSize);
1236       writer->write(writer, b4, 4);
1237       
1238       if(swf->compressed) {
1239         writer_init_zlibdeflate(&zwriter, writer);
1240         writer = &zwriter;
1241       }
1242     }
1243
1244     swf_SetRect(&t1,&swf->movieSize);
1245     swf_SetU16(&t1,swf->frameRate);
1246     swf_SetU16(&t1,swf->frameCount);
1247
1248     if (writer)
1249     { 
1250       int ret = writer->write(writer,b,swf_GetTagLen(&t1));
1251       if (ret!=swf_GetTagLen(&t1))
1252       {
1253         #ifdef DEBUG_RFXSWF
1254           fprintf(stderr, "ret:%d\n",ret);
1255           perror("write:");
1256           fprintf(stderr,"WriteSWF() failed: Header.\n");
1257         #endif
1258         return -1;
1259       }
1260
1261       t = swf->firstTag;
1262       while (t)
1263       { if (swf_WriteTag2(writer, t)<0) return -1;
1264         t = swf_NextTag(t);
1265       }
1266       if(swf->compressed != 8)
1267         writer->finish(writer); // flush zlib buffers - only if _we_ initialized that writer.
1268     }
1269   }
1270   return (int)fileSize;
1271 }
1272
1273 int  swf_WriteSWF(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1274 {
1275   struct writer_t writer;
1276   swf->compressed = 0;
1277   if(handle<0) {
1278     writer_init_nullwriter(&writer);
1279     return swf_WriteSWF2(&writer, swf);
1280   }
1281   writer_init_filewriter(&writer, handle);
1282   return swf_WriteSWF2(&writer, swf);
1283 }
1284
1285 int  swf_WriteSWC(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1286 {
1287   struct writer_t writer;
1288   swf->compressed = 1;
1289   if(handle<0) {
1290     writer_init_nullwriter(&writer);
1291     return swf_WriteSWF2(&writer, swf);
1292   }
1293   writer_init_filewriter(&writer, handle);
1294   return swf_WriteSWF2(&writer, swf);
1295 }
1296
1297 int swf_WriteHeader2(struct writer_t*writer,SWF * swf)
1298 {
1299   SWF myswf;
1300   memcpy(&myswf,swf,sizeof(SWF));
1301   myswf.firstTag = 0;
1302   return swf_WriteSWF2(writer, &myswf);
1303 }
1304
1305 int swf_WriteHeader(int handle,SWF * swf)
1306 {
1307   SWF myswf;
1308   memcpy(&myswf,swf,sizeof(SWF));
1309   myswf.firstTag = 0;
1310   return swf_WriteSWF(handle, &myswf);
1311 }
1312
1313 int swf_WriteCGI(SWF * swf)
1314 { int len;
1315   char s[1024];
1316     
1317   len = swf_WriteSWF(-1,swf);
1318
1319   if (len<0) return -1;
1320
1321   sprintf(s,"Content-type: application/x-shockwave-flash\n"
1322             "Accept-Ranges: bytes\n"
1323             "Content-Length: %lu\n"
1324             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
1325             "\n",len);
1326             
1327   write(fileno(stdout),s,strlen(s));
1328   return swf_WriteSWF(fileno(stdout),swf);
1329 }
1330
1331 void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
1332 { TAG * t = swf->firstTag;
1333
1334   while (t)
1335   { TAG * tnew = t->next;
1336     if (t->data) free(t->data);
1337     free(t);
1338     t = tnew;
1339   }
1340 }
1341
1342 // include advanced functions
1343
1344 #include "modules/swfdump.c"
1345 #include "modules/swfshape.c"
1346 #include "modules/swftext.c"
1347 #include "modules/swfobject.c"
1348 #include "modules/swfbutton.c"
1349 #include "modules/swftools.c"
1350 #include "modules/swfcgi.c"
1351 #include "modules/swfbits.c"
1352 #include "modules/swfaction.c"
1353 #include "modules/swfsound.c"
1354 #include "modules/swfdraw.c"