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