initial revision.
[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 int swf_CountBits(U32 v,int nbits)
302 { int n = 33;
303   U32 m = 0x80000000;
304   if (!v) n = 0; else
305   if (v&m)
306   { while (v&m)
307     { n--;
308       m>>=1;
309       if (!m) break;
310     } 
311   }
312   else
313   { while (!(v&m))
314     { n--;
315       m>>=1;
316       if (!m) break;
317     } 
318   }
319   return (n>nbits)?n:nbits;
320 }
321
322 int swf_GetRect(TAG * t,SRECT * r)
323 { int nbits;
324   SRECT dummy;
325   if(!t) {r->xmin=r->xmax=r->ymin=r->ymax;return 0;}
326   if (!r) r = &dummy;
327   nbits = (int) swf_GetBits(t,5);
328   r->xmin = swf_GetSBits(t,nbits);
329   r->xmax = swf_GetSBits(t,nbits);
330   r->ymin = swf_GetSBits(t,nbits);
331   r->ymax = swf_GetSBits(t,nbits);
332   return 0;
333 }
334
335 int reader_GetRect(struct reader_t*reader,SRECT * r)
336 { int nbits;
337   SRECT dummy;
338   if (!r) r = &dummy;
339   nbits = (int) reader_GetBits(reader,5);
340   r->xmin = reader_GetSBits(reader,nbits);
341   r->xmax = reader_GetSBits(reader,nbits);
342   r->ymin = reader_GetSBits(reader,nbits);
343   r->ymax = reader_GetSBits(reader,nbits);
344   return 0;
345 }
346
347 int swf_SetRect(TAG * t,SRECT * r)
348 { int nbits;
349     
350   nbits = swf_CountBits(r->xmin,0);
351   nbits = swf_CountBits(r->xmax,nbits);
352   nbits = swf_CountBits(r->ymin,nbits);
353   nbits = swf_CountBits(r->ymax,nbits);
354   if(nbits>=32) {
355     fprintf(stderr, "rfxswf: Warning: num_bits overflow in swf_SetRect\n");
356     nbits=31;
357   }
358
359   swf_SetBits(t,nbits,5);
360   swf_SetBits(t,r->xmin,nbits);
361   swf_SetBits(t,r->xmax,nbits);
362   swf_SetBits(t,r->ymin,nbits);
363   swf_SetBits(t,r->ymax,nbits);
364
365   return 0;
366 }
367
368 void swf_ExpandRect(SRECT*src, SPOINT add)
369 {
370     if(add.x < src->xmin)
371         src->xmin = add.x;
372     if(add.x > src->xmax)
373         src->xmax = add.x;
374     if(add.y < src->ymin)
375         src->ymin = add.y;
376     if(add.y > src->ymax)
377         src->ymax = add.y;
378 }
379 void swf_ExpandRect2(SRECT*src, SRECT*add)
380 {
381     if(add->xmin < src->xmin)
382         src->xmin = add->xmin;
383     if(add->ymin < src->ymin)
384         src->ymin = add->ymin;
385     if(add->xmax > src->xmax)
386         src->xmax = add->xmax;
387     if(add->ymax > src->ymax)
388         src->ymax = add->ymax;
389 }
390 SPOINT swf_TurnPoint(SPOINT p, MATRIX* m)
391 {
392     SPOINT r;
393     r.x = (int)(m->sx*(1/65536.0)*p.x + m->r0*(1/65536.0)*p.y + 0.5) + m->tx;
394     r.y = (int)(m->r1*(1/65536.0)*p.x + m->sy*(1/65536.0)*p.y + 0.5) + m->ty;
395     return r;
396 }
397 SRECT swf_TurnRect(SRECT r, MATRIX* m)
398 {
399     SRECT g;
400     SPOINT p1,p2,p3,p4,pp1,pp2,pp3,pp4;
401     p1.x = r.xmin;p1.y = r.ymin;
402     p2.x = r.xmax;p2.y = r.ymin;
403     p3.x = r.xmin;p3.y = r.ymax;
404     p4.x = r.xmax;p4.y = r.ymax;
405     pp1 = swf_TurnPoint(p1, m);
406     pp2 = swf_TurnPoint(p2, m);
407     pp3 = swf_TurnPoint(p3, m);
408     pp4 = swf_TurnPoint(p4, m);
409     g.xmin = g.xmax = pp1.x;
410     g.ymin = g.ymax = pp1.y;
411     swf_ExpandRect(&g, pp2);
412     swf_ExpandRect(&g, pp3);
413     swf_ExpandRect(&g, pp4);
414     return g;
415 }
416         
417
418 int swf_GetMatrix(TAG * t,MATRIX * m)
419 { MATRIX dummy;
420   int nbits;
421     
422   if (!m) m = &dummy;
423   
424   if (!t)
425   { m->sx = m->sy = 0x10000;
426     m->r0 = m->r1 = 0;
427     m->tx = m->ty = 0;
428     return -1;
429   }
430
431   swf_ResetReadBits(t);
432   
433   if (swf_GetBits(t,1))
434   { nbits = swf_GetBits(t,5);
435     m->sx = swf_GetSBits(t,nbits);
436     m->sy = swf_GetSBits(t,nbits);
437   }
438   else m->sx = m->sy = 0x10000;
439   
440   if (swf_GetBits(t,1))
441   { nbits = swf_GetBits(t,5);
442     m->r0 = swf_GetSBits(t,nbits);
443     m->r1 = swf_GetSBits(t,nbits);
444   }
445   else m->r0 = m->r1 = 0x0;
446
447   nbits = swf_GetBits(t,5);
448   m->tx = swf_GetSBits(t,nbits);
449   m->ty = swf_GetSBits(t,nbits);
450   
451   return 0;
452 }
453
454 int swf_SetMatrix(TAG * t,MATRIX * m)
455 { int nbits;
456   MATRIX ma;
457
458   if (!m)
459   { m = &ma;
460     ma.sx = ma.sy = 0x10000;
461     ma.r0 = ma.r1 = 0;
462     ma.tx = ma.ty = 0;
463   }
464
465   swf_ResetWriteBits(t);
466
467   if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
468   else
469   { swf_SetBits(t,1,1);
470     nbits = swf_CountBits(m->sx,0);
471     nbits = swf_CountBits(m->sy,nbits);
472     if(nbits>=32) {
473         fprintf(stderr,"rfxswf: Error: matrix values too large\n");
474         nbits = 31;
475     }
476     swf_SetBits(t,nbits,5);
477     swf_SetBits(t,m->sx,nbits);
478     swf_SetBits(t,m->sy,nbits);
479   }
480
481   if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
482   else
483   { swf_SetBits(t,1,1);
484     nbits = swf_CountBits(m->r0,0);
485     nbits = swf_CountBits(m->r1,nbits);
486     if(nbits>=32) {
487         fprintf(stderr,"rfxswf: Error: matrix values too large\n");
488         nbits = 31;
489     }
490     swf_SetBits(t,nbits,5);
491     swf_SetBits(t,m->r0,nbits);
492     swf_SetBits(t,m->r1,nbits);
493   }
494
495   nbits = swf_CountBits(m->tx,0);
496   nbits = swf_CountBits(m->ty,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->tx,nbits);
503   swf_SetBits(t,m->ty,nbits);
504
505   return 0;
506 }
507
508 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool
509 { CXFORM cxf;
510   int hasadd;
511   int hasmul;
512   int nbits;
513     
514   if (!cx) cx = &cxf;
515   
516   cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
517   cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
518
519   if (!t) return 0;
520   
521   swf_ResetReadBits(t);
522   hasadd = swf_GetBits(t,1);
523   hasmul = swf_GetBits(t,1);
524   nbits  = swf_GetBits(t,4);
525
526   if (hasmul)
527   { cx->r0 = (S16)swf_GetSBits(t,nbits);
528     cx->g0 = (S16)swf_GetSBits(t,nbits);
529     cx->b0 = (S16)swf_GetSBits(t,nbits);
530     if (alpha)
531       cx->a0 = (S16)swf_GetSBits(t,nbits);
532   }
533
534   if (hasadd)
535   { cx->r1 = (S16)swf_GetSBits(t,nbits);
536     cx->g1 = (S16)swf_GetSBits(t,nbits);
537     cx->b1 = (S16)swf_GetSBits(t,nbits);
538     if (alpha)
539       cx->a1 = (S16)swf_GetSBits(t,nbits);
540   }
541   
542   return 0;
543 }
544
545 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
546 { CXFORM cxf;
547   int hasadd;
548   int hasmul;
549   int nbits;
550     
551   if (!cx)
552   { cx = &cxf;
553     cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
554     cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
555   }
556
557   if (!alpha)
558   { cx->a0 = 256;
559     cx->a1 = 0;
560   }
561
562   nbits = 0;
563
564   hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
565   hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
566
567   if (hasmul)
568   { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits);
569     nbits = swf_CountBits((S32)cx->r0,nbits);
570     nbits = swf_CountBits((S32)cx->g0,nbits);
571     nbits = swf_CountBits((S32)cx->b0,nbits);
572   }
573
574   if (hasadd)
575   { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits);
576     nbits = swf_CountBits((S32)cx->r1,nbits);
577     nbits = swf_CountBits((S32)cx->g1,nbits);
578     nbits = swf_CountBits((S32)cx->b1,nbits);
579   }
580   
581   swf_ResetWriteBits(t);
582   swf_SetBits(t,hasadd?1:0,1);
583   swf_SetBits(t,hasmul?1:0,1);
584   swf_SetBits(t,nbits,4);
585
586   if (hasmul)
587   { swf_SetBits(t,cx->r0,nbits);
588     swf_SetBits(t,cx->g0,nbits);
589     swf_SetBits(t,cx->b0,nbits);
590     if (alpha) swf_SetBits(t,cx->a0,nbits);
591   }
592
593   if (hasadd)
594   { swf_SetBits(t,cx->r1,nbits);
595     swf_SetBits(t,cx->g1,nbits);
596     swf_SetBits(t,cx->b1,nbits);
597     if (alpha) swf_SetBits(t,cx->a1,nbits);
598   }
599   
600   return 0;
601 }
602
603 int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
604 int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
605
606 // Tag List Manipulating Functions
607
608 int swf_UpdateFrame(TAG * t,S8 delta)
609 // returns number of frames
610 { int res = -1;
611   while (t)
612   { t->frame+=delta;
613     res = t->frame;
614     t = t->next;
615   }
616   return res;
617 }
618
619 TAG * swf_InsertTag(TAG * after,U16 id)     // updates frames, if nescessary
620 { TAG * t;
621
622   t = (TAG *)malloc(sizeof(TAG));
623   if (t)
624   { memset(t,0x00,sizeof(TAG));
625     t->id = id;
626     
627     if (after)
628     { t->frame = after->frame;
629       t->prev  = after;
630       t->next  = after->next;
631       after->next = t;
632       if (t->next) t->next->prev = t;
633       
634       if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1);
635     }
636   }
637   return t;
638 }
639
640 int swf_DeleteTag(TAG * t)
641 { if (!t) return -1;
642
643   if (t->id==ST_SHOWFRAME) swf_UpdateFrame(t->next,-1);
644     
645   if (t->prev) t->prev->next = t->next;
646   if (t->next) t->next->prev = t->prev;
647
648   if (t->data) free(t->data);
649   free(t);
650   return 0;
651 }
652
653 TAG * swf_ReadTag(struct reader_t*reader, TAG * prev)
654 { TAG * t;
655   U16 raw;
656   U32 len;
657   int id;
658
659   if (reader->read(reader, &raw, 2) !=2 ) return NULL;
660   raw = SWAP16(raw);
661
662   len = raw&0x3f;
663   id  = raw>>6;
664
665   if (len==0x3f)
666   {
667       if (reader->read(reader, &len, 4) != 4) return NULL;
668       len = SWAP32(len);
669   }
670
671   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
672   // Sprite handling fix: Flaten sprite tree
673
674   t = (TAG *)malloc(sizeof(TAG));
675   
676   if (!t)
677   {
678     #ifdef DEBUG_RFXSWF
679       fprintf(stderr,"Fatal Error: malloc()/realloc() failed (2). (%d bytes)\n", sizeof(TAG));
680     #endif
681     return NULL;
682   }
683
684   memset(t,0x00,sizeof(TAG));
685   
686   t->len = len;
687   t->id  = id;
688
689   if (t->len)
690   { t->data = (U8*)malloc(t->len);
691     if (!t->data)
692     {
693       #ifdef DEBUG_RFXSWF
694         fprintf(stderr,"Fatal Error: malloc()/realloc() failed (3). (%d bytes)\n", t->len);
695       #endif
696       return NULL;
697     }
698     t->memsize = t->len;
699     if (reader->read(reader, t->data, t->len) != t->len) return NULL;
700   }
701
702   if (prev)
703   { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
704     t->prev  = prev;
705     prev->next = t;
706   }
707
708   return t;
709 }
710
711 int swf_DefineSprite_GetRealSize(TAG * t);
712
713 int swf_WriteTag2(struct writer_t*writer, TAG * t)
714 // returns tag length in bytes (incl. Header), -1 = Error
715 // writer = 0 -> no output
716 { U16 raw[3];
717   U32 len;
718   int short_tag;
719
720   if (!t) return -1;
721
722   len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len;
723
724   short_tag = len<0x3f;
725
726   if (writer)
727   { if (short_tag)
728     { raw[0] = SWAP16(len|((t->id&0x3ff)<<6));
729       if (writer->write(writer,raw,2)!=2)
730       {
731         #ifdef DEBUG_RFXSWF
732           fprintf(stderr,"WriteTag() failed: Short Header.\n");
733         #endif
734         return -1;
735       }
736     }
737     else
738     {
739       raw[0] = SWAP16((t->id<<6)|0x3f);
740       if (writer->write(writer,raw,2)!=2)
741       {
742 #ifdef DEBUG_RFXSWF
743           fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
744 #endif
745           return -1;
746       }
747       
748       len = SWAP32(len);
749       if (writer->write(writer,&len,4)!=4)
750       {
751         #ifdef DEBUG_RFXSWF
752           fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
753         #endif
754         return -1;
755       }
756     }
757     
758     if (t->data)
759     { if (writer->write(writer,t->data,t->len)!=t->len)
760       {
761         #ifdef DEBUG_RFXSWF
762           fprintf(stderr,"WriteTag() failed: Data.\n");
763         #endif
764         return -1;
765       }
766     }
767     #ifdef DEBUG_RFXSWF
768       else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
769     #endif
770   }
771
772   return t->len+(short_tag?2:6);
773 }
774
775 int swf_WriteTag(int handle, TAG * t)
776 {
777   struct writer_t writer;
778   if(handle<0)
779     return swf_WriteTag2(0, t);
780   writer_init_filewriter(&writer, handle);
781   return swf_WriteTag2(&writer, t);
782 }
783
784 int swf_DefineSprite_GetRealSize(TAG * t)
785 // Sprite Handling: Helper function to pack DefineSprite-Tag
786 { U32 len = t->len;
787   if(len>4) { // folded sprite
788       return t->len;
789   }
790   do
791   { t = swf_NextTag(t);
792     if (t && t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t);
793     else t = NULL;
794   } while (t&&(t->id!=ST_END));
795   return len;
796 }
797
798 void swf_UnFoldSprite(TAG * t)
799 {
800   U16 id,tmp;
801   U32 len;
802   TAG*next = t;
803   U16 spriteid,spriteframes;
804   int level;
805   if(t->id!=ST_DEFINESPRITE)
806     return;
807   if(t->len<=4) // not folded
808     return;
809
810   swf_SetTagPos(t,0);
811
812   spriteid = swf_GetU16(t); //id
813   spriteframes = swf_GetU16(t); //frames
814
815   level = 1;
816
817   while(1)
818   {
819     TAG*it = 0;
820     tmp = swf_GetU16(t);
821     len = tmp&0x3f;
822     id  = tmp>>6;
823     if(id == ST_END)
824         level--;
825     if(id == ST_DEFINESPRITE && len<=4)
826         level++;
827
828     if (len==0x3f)
829         len = swf_GetU32(t);
830     it = swf_InsertTag(next, id);
831     next = it;
832     it->len = len;
833     it->id  = id;
834     if (it->len)
835     { it->data = (U8*)malloc(it->len);
836       it->memsize = it->len;
837       swf_GetBlock(t, it->data, it->len);
838     }
839
840     if(!level)
841         break;
842   }
843   
844   free(t->data); t->data = 0;
845   t->memsize = t->len = t->pos = 0;
846
847   swf_SetU16(t, spriteid);
848   swf_SetU16(t, spriteframes);
849 }
850
851 void swf_FoldSprite(TAG * t)
852 {
853   TAG*sprtag=t,*tmp;
854   U16 id,frames,tmpid;
855   int level;
856   if(t->id!=ST_DEFINESPRITE)
857       return;
858   if(!t->len) {
859       fprintf(stderr, "Error: Sprite has no ID!");
860       return;
861   }
862   if(t->len>4) {
863     /* sprite is already folded */
864       return;
865   }
866
867   t->pos = 0;
868   id = swf_GetU16(t);
869   free(t->data);
870   t->len = t->pos = t->memsize = 0;
871   t->data = 0;
872
873   frames = 0;
874
875   t = swf_NextTag(sprtag);
876   level = 1;
877
878   do 
879   { 
880     if(t->id==ST_SHOWFRAME) frames++;
881     if(t->id == ST_DEFINESPRITE && t->len<=4)
882         level++;
883     if(t->id == ST_END)
884         level--;
885     t = swf_NextTag(t);
886   } while(t && level);
887   if(level)
888     fprintf(stderr, "rfxswf error: sprite doesn't end(1)\n");
889
890   swf_SetU16(sprtag, id);
891   swf_SetU16(sprtag, frames);
892
893   t = swf_NextTag(sprtag);
894   level = 1;
895
896   do
897   { 
898     if(t->len<0x3f) {
899         swf_SetU16(sprtag,t->len|(t->id<<6));
900     } else {
901         swf_SetU16(sprtag,0x3f|(t->id<<6));
902         swf_SetU32(sprtag,t->len);
903     }
904     if(t->len)
905         swf_SetBlock(sprtag,t->data, t->len);
906     tmp = t;
907     if(t->id == ST_DEFINESPRITE && t->len<=4)
908         level++;
909     if(t->id == ST_END)
910         level--;
911     t = swf_NextTag(t);
912     swf_DeleteTag(tmp);
913   } 
914   while (t && level);
915   if(level)
916     fprintf(stderr, "rfxswf error: sprite doesn't end(2)\n");
917
918 //  sprtag->next = t;
919 //  t->prev = sprtag;
920 }
921
922 void swf_FoldAll(SWF*swf)
923 {
924     TAG*tag = swf->firstTag;
925     while(tag) {
926         if(tag->id == ST_DEFINESPRITE)
927             swf_FoldSprite(tag);
928         tag = swf_NextTag(tag);
929     }
930 }
931
932 void swf_UnFoldAll(SWF*swf)
933 {
934     TAG*tag = swf->firstTag;
935     while(tag) {
936         if(tag->id == ST_DEFINESPRITE)
937             swf_UnFoldSprite(tag);
938         tag = tag->next;
939     }
940 }
941
942 void swf_OptimizeTagOrder(SWF*swf)
943 {
944   TAG*tag,*next;
945   TAG*level0;
946   int level;
947   int changes;
948   swf_UnFoldAll(swf);
949   /* at the moment, we don't actually do optimizing,
950      only fixing of non-spec-conformant things like
951      sprite tags */
952
953   do {
954     changes = 0;
955     level = 0;
956     level0 = 0;
957     tag = swf->firstTag;
958     while(tag) {
959       next = tag->next;
960       if(tag->id == ST_DEFINESPRITE) {
961         if(tag->len>4) {
962           /* ??? all sprites are supposed to be unfolded */
963           fprintf(stderr, "librfxswf error - internal error in OptimizeTagOrder/UnfoldAll\n");
964         }
965         level++;
966         if(level==1) {
967           level0 = tag;
968           tag = next;
969           continue;
970         }
971       }
972       if(level>=1) {
973         /* move non-sprite tags out of sprite */
974         if(!swf_isAllowedSpriteTag(tag) || level>=2) {
975           /* remove tag from current position */
976           tag->prev->next = tag->next;
977           if(tag->next)
978             tag->next->prev = tag->prev;
979
980           /* insert before tag level0 */
981           tag->next = level0;
982           tag->prev = level0->prev;
983           level0->prev = tag;
984           tag->prev->next = tag;
985           changes = 1;
986         }
987       }
988       if(tag->id == ST_END) {
989         level--;
990       }
991
992       tag = next;
993     }
994   } while(changes);
995 }
996
997 // Movie Functions
998
999 int swf_ReadSWF2(struct reader_t*reader, SWF * swf)   // Reads SWF to memory (malloc'ed), returns length or <0 if fails
1000 {     
1001   if (!swf) return -1;
1002   memset(swf,0x00,sizeof(SWF));
1003
1004   { char b[32];                         // read Header
1005     int len;
1006     TAG * t;
1007     TAG t1;
1008     struct reader_t zreader;
1009     
1010     if ((len = reader->read(reader ,b,8))<8) return -1;
1011
1012     if (b[0]!='F' && b[0]!='C') return -1;
1013     if (b[1]!='W') return -1;
1014     if (b[2]!='S') return -1;
1015     swf->fileVersion = b[3];
1016     swf->compressed  = (b[0]=='C')?1:0;
1017     swf->fileSize    = GET32(&b[4]);
1018     
1019     if(swf->compressed) {
1020         reader_init_zlibinflate(&zreader, reader);
1021         reader = &zreader;
1022     }
1023
1024     reader_GetRect(reader, &swf->movieSize);
1025     reader->read(reader, &swf->frameRate, 2);
1026     swf->frameRate = SWAP16(swf->frameRate);
1027     reader->read(reader, &swf->frameCount, 2);
1028     swf->frameCount = SWAP16(swf->frameCount);
1029
1030     /* read tags and connect to list */
1031     t = &t1;
1032     while (t) t = swf_ReadTag(reader,t);
1033     swf->firstTag = t1.next;
1034     t1.next->prev = NULL;
1035   }
1036   
1037   return reader->pos;
1038 }
1039
1040 int swf_ReadSWF(int handle, SWF * swf)
1041 {
1042   struct reader_t reader;
1043   reader_init_filereader(&reader, handle);
1044   return swf_ReadSWF2(&reader, swf);
1045 }
1046
1047 int  swf_WriteSWF2(struct writer_t*writer, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1048 { U32 len;
1049   TAG * t;
1050   int frameCount=0;
1051   struct writer_t zwriter;
1052   int fileSize = 0;
1053     
1054   if (!swf) return -1;
1055
1056   // Insert REFLEX Tag
1057
1058 #ifdef INSERT_RFX_TAG
1059
1060   if (swf->firstTag && swf_NextTag(swf->firstTag))
1061     if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
1062       swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
1063
1064 #endif // INSERT_RFX_TAG
1065
1066   // Count Frames + File Size
1067
1068   len = 0;
1069   t = swf->firstTag;
1070   frameCount = 0;
1071
1072   while(t)
1073   { len += swf_WriteTag(-1, t);
1074     if (t->id==ST_SHOWFRAME) frameCount++;
1075     t = swf_NextTag(t);
1076   }
1077   
1078   { TAG t1;
1079     char b[64],b4[4];
1080     U32 l;
1081
1082     memset(&t1,0x00,sizeof(TAG));
1083     t1.data    = (U8*)b;
1084     t1.memsize = 64;
1085     
1086     { // measure header file size
1087       TAG t2;
1088       char b2[64];
1089       memset(&t2,0x00,sizeof(TAG));
1090       t2.data    = (U8*)b2;
1091       t2.memsize = 64;
1092       swf_SetRect(&t2, &swf->movieSize);
1093       swf_SetU16(&t2, swf->frameRate);
1094       swf_SetU16(&t2, swf->frameCount);
1095       l = swf_GetTagLen(&t2)+8;
1096     }
1097
1098     fileSize = l+len;
1099     if(len) {// don't touch headers without tags
1100         swf->fileSize = fileSize;
1101         swf->frameCount = frameCount;
1102     }
1103    
1104     if(swf->compressed) {
1105       char*id = "CWS";
1106       writer->write(writer, id, 3);
1107     }
1108     else {
1109       char*id = "FWS";
1110       writer->write(writer, id, 3);
1111     }
1112
1113     writer->write(writer, &swf->fileVersion, 1);
1114     PUT32(b4, swf->fileSize);
1115     writer->write(writer, b4, 4);
1116
1117     if(swf->compressed) {
1118       writer_init_zlibdeflate(&zwriter, writer);
1119       writer = &zwriter;
1120     }
1121
1122     swf_SetRect(&t1,&swf->movieSize);
1123     swf_SetU16(&t1,swf->frameRate);
1124     swf_SetU16(&t1,swf->frameCount);
1125
1126     if (writer)
1127     { 
1128       int ret = writer->write(writer,b,swf_GetTagLen(&t1));
1129       if (ret!=swf_GetTagLen(&t1))
1130       {
1131         #ifdef DEBUG_RFXSWF
1132           fprintf(stderr, "ret:%d\n",ret);
1133           perror("write:");
1134           fprintf(stderr,"WriteSWF() failed: Header.\n");
1135         #endif
1136         return -1;
1137       }
1138
1139       t = swf->firstTag;
1140       while (t)
1141       { if (swf_WriteTag2(writer, t)<0) return -1;
1142         t = swf_NextTag(t);
1143       }
1144       writer->finish(writer); //e.g. flush zlib buffers
1145     }
1146   }
1147   return (int)fileSize;
1148 }
1149
1150 int  swf_WriteSWF(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1151 {
1152   struct writer_t writer;
1153   swf->compressed = 0;
1154   if(handle<0)
1155     return swf_WriteSWF2(&writer, swf);
1156   writer_init_filewriter(&writer, handle);
1157   return swf_WriteSWF2(&writer, swf);
1158 }
1159
1160 int  swf_WriteSWC(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1161 {
1162   struct writer_t writer;
1163   swf->compressed = 1;
1164   if(handle<0)
1165     return swf_WriteSWF2(&writer, swf);
1166   writer_init_filewriter(&writer, handle);
1167   return swf_WriteSWF2(&writer, swf);
1168 }
1169
1170 int swf_WriteHeader2(struct writer_t*writer,SWF * swf)
1171 {
1172   SWF myswf;
1173   memcpy(&myswf,swf,sizeof(SWF));
1174   myswf.firstTag = 0;
1175   return swf_WriteSWF2(writer, &myswf);
1176 }
1177
1178 int swf_WriteHeader(int handle,SWF * swf)
1179 {
1180   SWF myswf;
1181   memcpy(&myswf,swf,sizeof(SWF));
1182   myswf.firstTag = 0;
1183   return swf_WriteSWF(handle, &myswf);
1184 }
1185
1186 int swf_WriteCGI(SWF * swf)
1187 { int len;
1188   char s[1024];
1189     
1190   len = swf_WriteSWF(-1,swf);
1191
1192   if (len<0) return -1;
1193
1194   sprintf(s,"Content-type: application/x-shockwave-flash\n"
1195             "Accept-Ranges: bytes\n"
1196             "Content-Length: %lu\n"
1197             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
1198             "\n",len);
1199             
1200   write(fileno(stdout),s,strlen(s));
1201   return swf_WriteSWF(fileno(stdout),swf);
1202 }
1203
1204 void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
1205 { TAG * t = swf->firstTag;
1206
1207   while (t)
1208   { TAG * tnew = t->next;
1209     if (t->data) free(t->data);
1210     free(t);
1211     t = tnew;
1212   }
1213 }
1214
1215 // include advanced functions
1216
1217 #include "modules/swfdump.c"
1218 #include "modules/swfshape.c"
1219 #include "modules/swftext.c"
1220 #include "modules/swfobject.c"
1221 #include "modules/swfbutton.c"
1222 #include "modules/swftools.c"
1223 #include "modules/swfcgi.c"
1224 #include "modules/swfbits.c"
1225 #include "modules/swfaction.c"
1226 #include "modules/swfsound.c"
1227