new function isFolded().
[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 int swf_IsFolded(TAG * t)
923 {
924     return (t->id == ST_DEFINESPRITE && t->len>4);
925 }
926
927 void swf_FoldAll(SWF*swf)
928 {
929     TAG*tag = swf->firstTag;
930     while(tag) {
931         if(tag->id == ST_DEFINESPRITE)
932             swf_FoldSprite(tag);
933         tag = swf_NextTag(tag);
934     }
935 }
936
937 void swf_UnFoldAll(SWF*swf)
938 {
939     TAG*tag = swf->firstTag;
940     while(tag) {
941         if(tag->id == ST_DEFINESPRITE)
942             swf_UnFoldSprite(tag);
943         tag = tag->next;
944     }
945 }
946
947 void swf_OptimizeTagOrder(SWF*swf)
948 {
949   TAG*tag,*next;
950   TAG*level0;
951   int level;
952   int changes;
953   swf_UnFoldAll(swf);
954   /* at the moment, we don't actually do optimizing,
955      only fixing of non-spec-conformant things like
956      sprite tags */
957
958   do {
959     changes = 0;
960     level = 0;
961     level0 = 0;
962     tag = swf->firstTag;
963     while(tag) {
964       next = tag->next;
965       if(tag->id == ST_DEFINESPRITE) {
966         if(tag->len>4) {
967           /* ??? all sprites are supposed to be unfolded */
968           fprintf(stderr, "librfxswf error - internal error in OptimizeTagOrder/UnfoldAll\n");
969         }
970         level++;
971         if(level==1) {
972           level0 = tag;
973           tag = next;
974           continue;
975         }
976       }
977       if(level>=1) {
978         /* move non-sprite tags out of sprite */
979         if(!swf_isAllowedSpriteTag(tag) || level>=2) {
980           /* remove tag from current position */
981           tag->prev->next = tag->next;
982           if(tag->next)
983             tag->next->prev = tag->prev;
984
985           /* insert before tag level0 */
986           tag->next = level0;
987           tag->prev = level0->prev;
988           level0->prev = tag;
989           tag->prev->next = tag;
990           changes = 1;
991         }
992       }
993       if(tag->id == ST_END) {
994         level--;
995       }
996
997       tag = next;
998     }
999   } while(changes);
1000 }
1001
1002 // Movie Functions
1003
1004 int swf_ReadSWF2(struct reader_t*reader, SWF * swf)   // Reads SWF to memory (malloc'ed), returns length or <0 if fails
1005 {     
1006   if (!swf) return -1;
1007   memset(swf,0x00,sizeof(SWF));
1008
1009   { char b[32];                         // read Header
1010     int len;
1011     TAG * t;
1012     TAG t1;
1013     struct reader_t zreader;
1014     
1015     if ((len = reader->read(reader ,b,8))<8) return -1;
1016
1017     if (b[0]!='F' && b[0]!='C') return -1;
1018     if (b[1]!='W') return -1;
1019     if (b[2]!='S') return -1;
1020     swf->fileVersion = b[3];
1021     swf->compressed  = (b[0]=='C')?1:0;
1022     swf->fileSize    = GET32(&b[4]);
1023     
1024     if(swf->compressed) {
1025         reader_init_zlibinflate(&zreader, reader);
1026         reader = &zreader;
1027     }
1028
1029     reader_GetRect(reader, &swf->movieSize);
1030     reader->read(reader, &swf->frameRate, 2);
1031     swf->frameRate = SWAP16(swf->frameRate);
1032     reader->read(reader, &swf->frameCount, 2);
1033     swf->frameCount = SWAP16(swf->frameCount);
1034
1035     /* read tags and connect to list */
1036     t = &t1;
1037     while (t) t = swf_ReadTag(reader,t);
1038     swf->firstTag = t1.next;
1039     t1.next->prev = NULL;
1040   }
1041   
1042   return reader->pos;
1043 }
1044
1045 int swf_ReadSWF(int handle, SWF * swf)
1046 {
1047   struct reader_t reader;
1048   reader_init_filereader(&reader, handle);
1049   return swf_ReadSWF2(&reader, swf);
1050 }
1051
1052 int  swf_WriteSWF2(struct writer_t*writer, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1053 { U32 len;
1054   TAG * t;
1055   int frameCount=0;
1056   struct writer_t zwriter;
1057   int fileSize = 0;
1058     
1059   if (!swf) return -1;
1060
1061   // Insert REFLEX Tag
1062
1063 #ifdef INSERT_RFX_TAG
1064
1065   if (swf->firstTag && swf_NextTag(swf->firstTag))
1066     if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
1067       swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
1068
1069 #endif // INSERT_RFX_TAG
1070
1071   // Count Frames + File Size
1072
1073   len = 0;
1074   t = swf->firstTag;
1075   frameCount = 0;
1076
1077   while(t)
1078   { len += swf_WriteTag(-1, t);
1079     if (t->id==ST_SHOWFRAME) frameCount++;
1080     t = swf_NextTag(t);
1081   }
1082   
1083   { TAG t1;
1084     char b[64],b4[4];
1085     U32 l;
1086
1087     memset(&t1,0x00,sizeof(TAG));
1088     t1.data    = (U8*)b;
1089     t1.memsize = 64;
1090     
1091     { // measure header file size
1092       TAG t2;
1093       char b2[64];
1094       memset(&t2,0x00,sizeof(TAG));
1095       t2.data    = (U8*)b2;
1096       t2.memsize = 64;
1097       swf_SetRect(&t2, &swf->movieSize);
1098       swf_SetU16(&t2, swf->frameRate);
1099       swf_SetU16(&t2, swf->frameCount);
1100       l = swf_GetTagLen(&t2)+8;
1101     }
1102
1103     fileSize = l+len;
1104     if(len) {// don't touch headers without tags
1105         swf->fileSize = fileSize;
1106         swf->frameCount = frameCount;
1107     }
1108    
1109     if(swf->compressed) {
1110       char*id = "CWS";
1111       writer->write(writer, id, 3);
1112     }
1113     else {
1114       char*id = "FWS";
1115       writer->write(writer, id, 3);
1116     }
1117
1118     writer->write(writer, &swf->fileVersion, 1);
1119     PUT32(b4, swf->fileSize);
1120     writer->write(writer, b4, 4);
1121
1122     if(swf->compressed) {
1123       writer_init_zlibdeflate(&zwriter, writer);
1124       writer = &zwriter;
1125     }
1126
1127     swf_SetRect(&t1,&swf->movieSize);
1128     swf_SetU16(&t1,swf->frameRate);
1129     swf_SetU16(&t1,swf->frameCount);
1130
1131     if (writer)
1132     { 
1133       int ret = writer->write(writer,b,swf_GetTagLen(&t1));
1134       if (ret!=swf_GetTagLen(&t1))
1135       {
1136         #ifdef DEBUG_RFXSWF
1137           fprintf(stderr, "ret:%d\n",ret);
1138           perror("write:");
1139           fprintf(stderr,"WriteSWF() failed: Header.\n");
1140         #endif
1141         return -1;
1142       }
1143
1144       t = swf->firstTag;
1145       while (t)
1146       { if (swf_WriteTag2(writer, t)<0) return -1;
1147         t = swf_NextTag(t);
1148       }
1149       writer->finish(writer); //e.g. flush zlib buffers
1150     }
1151   }
1152   return (int)fileSize;
1153 }
1154
1155 int  swf_WriteSWF(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1156 {
1157   struct writer_t writer;
1158   swf->compressed = 0;
1159   if(handle<0)
1160     return swf_WriteSWF2(&writer, swf);
1161   writer_init_filewriter(&writer, handle);
1162   return swf_WriteSWF2(&writer, swf);
1163 }
1164
1165 int  swf_WriteSWC(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
1166 {
1167   struct writer_t writer;
1168   swf->compressed = 1;
1169   if(handle<0)
1170     return swf_WriteSWF2(&writer, swf);
1171   writer_init_filewriter(&writer, handle);
1172   return swf_WriteSWF2(&writer, swf);
1173 }
1174
1175 int swf_WriteHeader2(struct writer_t*writer,SWF * swf)
1176 {
1177   SWF myswf;
1178   memcpy(&myswf,swf,sizeof(SWF));
1179   myswf.firstTag = 0;
1180   return swf_WriteSWF2(writer, &myswf);
1181 }
1182
1183 int swf_WriteHeader(int handle,SWF * swf)
1184 {
1185   SWF myswf;
1186   memcpy(&myswf,swf,sizeof(SWF));
1187   myswf.firstTag = 0;
1188   return swf_WriteSWF(handle, &myswf);
1189 }
1190
1191 int swf_WriteCGI(SWF * swf)
1192 { int len;
1193   char s[1024];
1194     
1195   len = swf_WriteSWF(-1,swf);
1196
1197   if (len<0) return -1;
1198
1199   sprintf(s,"Content-type: application/x-shockwave-flash\n"
1200             "Accept-Ranges: bytes\n"
1201             "Content-Length: %lu\n"
1202             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
1203             "\n",len);
1204             
1205   write(fileno(stdout),s,strlen(s));
1206   return swf_WriteSWF(fileno(stdout),swf);
1207 }
1208
1209 void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
1210 { TAG * t = swf->firstTag;
1211
1212   while (t)
1213   { TAG * tnew = t->next;
1214     if (t->data) free(t->data);
1215     free(t);
1216     t = tnew;
1217   }
1218 }
1219
1220 // include advanced functions
1221
1222 #include "modules/swfdump.c"
1223 #include "modules/swfshape.c"
1224 #include "modules/swftext.c"
1225 #include "modules/swfobject.c"
1226 #include "modules/swfbutton.c"
1227 #include "modules/swftools.c"
1228 #include "modules/swfcgi.c"
1229 #include "modules/swfbits.c"
1230 #include "modules/swfaction.c"
1231 #include "modules/swfsound.c"
1232