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