made bitio visible from outside.
[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 #include "./bitio.h"
35
36 // internal constants
37
38 #define MALLOC_SIZE     128
39 #define INSERT_RFX_TAG
40
41 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
42
43
44 // inline wrapper functions
45
46 TAG * swf_NextTag(TAG * t) { return t->next; }
47 TAG * swf_PrevTag(TAG * t) { return t->prev; }
48 int   swf_GetFrameNo(TAG * t)  { return t->frame; }
49 U16   swf_GetTagID(TAG * t)    { return t->id; }
50 U32   swf_GetTagLen(TAG * t) { return t->len; }
51 U8*   swf_GetTagLenPtr(TAG * t) { return &(t->data[t->len]); }
52 U32   swf_GetTagPos(TAG * t)   { return t->pos; }
53
54 // Basic Data Access Functions
55
56 #define swf_ResetReadBits(tag)   if (tag->readBit)  { tag->pos++; tag->readBit = 0; }
57 #define swf_ResetWriteBits(tag)  if (tag->writeBit) { tag->writeBit = 0; }
58
59 // for future purpose: avoid high level lib functions to change tagpos/bitpos
60
61 #define swf_SaveTagPos(tag)
62 #define swf_RestoreTagPos(tag)
63
64 void swf_SetTagPos(TAG * t,U32 pos)
65 { swf_ResetReadBits(t);
66   if (pos<=t->len) t->pos = pos;
67   #ifdef DEBUG_RFXSWF
68   else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
69   #endif
70 }
71
72 U8 swf_GetU8(TAG * t)
73 { swf_ResetReadBits(t);
74   #ifdef DEBUG_RFXSWF
75     if (t->pos>=t->len) 
76     { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
77       return 0;
78     }
79   #endif
80   return t->data[t->pos++];
81 }
82
83 U16 swf_GetU16(TAG * t)
84 { U16 res;
85   swf_ResetReadBits(t);
86   #ifdef DEBUG_RFXSWF
87     if (t->pos>(t->len-2)) 
88     { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
89       return 0;
90     }
91   #endif
92   res = t->data[t->pos] | (t->data[t->pos+1]<<8);
93   t->pos+=2;
94   return res;
95 }
96
97 U32 swf_GetU32(TAG * t)
98 { U32 res;
99   swf_ResetReadBits(t);
100   #ifdef DEBUG_RFXSWF
101     if (t->pos>(t->len-4)) 
102     { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
103       return 0;
104     }
105   #endif
106   res = t->data[t->pos]        | (t->data[t->pos+1]<<8) | 
107        (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);
108   t->pos+=4;
109   return res;
110 }
111
112 int swf_GetBlock(TAG * t,U8 * b,int l)
113 // returns number of bytes written (<=l)
114 // b = NULL -> skip data
115 { swf_ResetReadBits(t);
116   if ((t->len-t->pos)<l) l=t->len-t->pos;
117   if (b && l) memcpy(b,&t->data[t->pos],l);
118   t->pos+=l;
119   return l;
120 }
121
122 int swf_SetBlock(TAG * t,U8 * b,int l)
123 // Appends Block to the end of Tagdata, returns size
124 { U32 newlen = t->len + l;
125   swf_ResetWriteBits(t);
126   if (newlen>t->memsize)
127   { U32  newmem  = MEMSIZE(newlen);  
128     U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem));
129     if (!newdata)
130     {
131       #ifdef DEBUG_RFXSWF
132         fprintf(stderr,"Fatal Error: malloc()/realloc() failed (1). (%d bytes)\n", newmem);
133         *(int*)0=0;
134       #endif
135       return 0;
136     }
137     t->memsize = newmem;
138     t->data    = newdata;
139   }
140   if (b) memcpy(&t->data[t->len],b,l);
141   else memset(&t->data[t->len],0x00,l);
142   t->len+=l;
143   return l;
144 }
145
146 int swf_SetU8(TAG * t,U8 v)
147 { swf_ResetWriteBits(t);
148   if ((t->len+1)>t->memsize) return (swf_SetBlock(t,&v,1)==1)?0:-1;
149   t->data[t->len++] = v;
150   return 0;
151 }
152
153 int swf_SetU16(TAG * t,U16 v)
154 { U8 a[2];
155   a[0] = v&0xff;
156   a[1] = v>>8;
157   
158   swf_ResetWriteBits(t);
159   if ((t->len+2)>t->memsize) return (swf_SetBlock(t,a,2)==2)?0:-1;
160   t->data[t->len++] = a[0];
161   t->data[t->len++] = a[1];
162   return 0;
163 }
164
165 int swf_SetU32(TAG * t,U32 v)
166 { U8 a[4];
167   a[0] = v&0xff;        // to ensure correct handling of non-intel byteorder
168   a[1] = (v>>8)&0xff;
169   a[2] = (v>>16)&0xff;
170   a[3] = (v>>24)&0xff;
171   
172   swf_ResetWriteBits(t);
173   if ((t->len+4)>t->memsize) return (swf_SetBlock(t,a,4)==4)?0:-1;
174   t->data[t->len++] = a[0];
175   t->data[t->len++] = a[1];
176   t->data[t->len++] = a[2];
177   t->data[t->len++] = a[3];
178   return 0;
179 }
180
181 U32 swf_GetBits(TAG * t,int nbits)
182 { U32 res = 0;
183   if (!nbits) return 0;
184   if (!t->readBit) t->readBit = 0x80;
185   while (nbits)
186   { res<<=1;
187     if (t->data[t->pos]&t->readBit) res|=1;
188     t->readBit>>=1;
189     nbits--;
190     if (!t->readBit)
191     { if (nbits) t->readBit = 0x80;
192       #ifdef DEBUG_RFXSWF
193       if (t->pos>=t->len) 
194       { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
195         return res;
196       }
197       #endif
198       t->pos++;
199     }
200   }
201   return res;
202 }
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)     // Writes SWF to file, returns length or <0 if fails
852 { U32 len;
853   TAG * t;
854   int frameCount=0;
855   struct writer_t zwriter;
856     
857   if (!swf) return -1;
858
859   // Insert REFLEX Tag
860
861 #ifdef INSERT_RFX_TAG
862
863   if (swf->firstTag && swf_NextTag(swf->firstTag))
864     if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
865       swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
866
867 #endif // INSERT_RFX_TAG
868
869   // Count Frames + File Size
870
871   len = 0;
872   t = swf->firstTag;
873   frameCount = 0;
874
875   while(t)
876   { len += swf_WriteTag(-1, t);
877     if (t->id==ST_SHOWFRAME) frameCount++;
878     t = swf_NextTag(t);
879   }
880   
881   { TAG t1;
882     char b[64],b4[4];
883     U32 l;
884
885     memset(&t1,0x00,sizeof(TAG));
886     t1.data    = (U8*)b;
887     t1.memsize = 64;
888     
889     { // measure header file size
890       TAG t2;
891       char b2[64];
892       memset(&t2,0x00,sizeof(TAG));
893       t2.data    = (U8*)b2;
894       t2.memsize = 64;
895       swf_SetRect(&t2, &swf->movieSize);
896       swf_SetU16(&t2, swf->frameRate);
897       swf_SetU16(&t2, swf->frameCount);
898       l = swf_GetTagLen(&t2)+8;
899     }
900
901     if(len) {// don't touch headers without tags
902         swf->fileSize = l+len;
903         swf->frameCount = frameCount;
904     }
905    
906     if(swf->compressed) {
907       char*id = "CWS";
908       writer->write(writer, id, 3);
909     }
910     else {
911       char*id = "FWS";
912       writer->write(writer, id, 3);
913     }
914
915     writer->write(writer, &swf->fileVersion, 1);
916     PUT32(b4, swf->fileSize);
917     writer->write(writer, b4, 4);
918
919     if(swf->compressed) {
920       writer_init_zlibdeflate(&zwriter, writer);
921       writer = &zwriter;
922     }
923
924     swf_SetRect(&t1,&swf->movieSize);
925     swf_SetU16(&t1,swf->frameRate);
926     swf_SetU16(&t1,swf->frameCount);
927
928     if (writer)
929     { 
930       int ret = writer->write(writer,b,swf_GetTagLen(&t1));
931       if (ret!=swf_GetTagLen(&t1))
932       {
933         #ifdef DEBUG_RFXSWF
934           printf("ret:%d\n",ret);
935           perror("write:");
936           fprintf(stderr,"WriteSWF() failed: Header.\n");
937         #endif
938         return -1;
939       }
940
941       t = swf->firstTag;
942       while (t)
943       { if (swf_WriteTag2(writer, t)<0) return -1;
944         t = swf_NextTag(t);
945       }
946       writer->finish(writer); //e.g. flush zlib buffers
947     }
948   }
949   return (int)swf->fileSize;
950 }
951
952 int  swf_WriteSWF(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
953 {
954   struct writer_t writer;
955   swf->compressed = 0;
956   if(handle<0)
957     return swf_WriteSWF2(&writer, swf);
958   writer_init_filewriter(&writer, handle);
959   return swf_WriteSWF2(&writer, swf);
960 }
961
962 int  swf_WriteSWC(int handle, SWF * swf)     // Writes SWF to file, returns length or <0 if fails
963 {
964   struct writer_t writer;
965   swf->compressed = 1;
966   if(handle<0)
967     return swf_WriteSWF2(&writer, swf);
968   writer_init_filewriter(&writer, handle);
969   return swf_WriteSWF2(&writer, swf);
970 }
971
972 int swf_WriteHeader2(struct writer_t*writer,SWF * swf)
973 {
974   SWF myswf;
975   memcpy(&myswf,swf,sizeof(SWF));
976   myswf.firstTag = 0;
977   return swf_WriteSWF2(writer, &myswf);
978 }
979
980 int swf_WriteHeader(int handle,SWF * swf)
981 {
982   SWF myswf;
983   memcpy(&myswf,swf,sizeof(SWF));
984   myswf.firstTag = 0;
985   return swf_WriteSWF(handle, &myswf);
986 }
987
988 int swf_WriteCGI(SWF * swf)
989 { int len;
990   char s[1024];
991     
992   len = swf_WriteSWF(-1,swf);
993
994   if (len<0) return -1;
995
996   sprintf(s,"Content-type: application/x-shockwave-flash\n"
997             "Accept-Ranges: bytes\n"
998             "Content-Length: %lu\n"
999             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
1000             "\n",len);
1001             
1002   write(fileno(stdout),s,strlen(s));
1003   return swf_WriteSWF(fileno(stdout),swf);
1004 }
1005
1006 void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for tags
1007 { TAG * t = swf->firstTag;
1008
1009   while (t)
1010   { TAG * tnew = t->next;
1011     if (t->data) free(t->data);
1012     free(t);
1013     t = tnew;
1014   }
1015 }
1016
1017 // include advanced functions
1018
1019 #include "modules/swfdump.c"
1020 #include "modules/swfshape.c"
1021 #include "modules/swftext.c"
1022 #include "modules/swfobject.c"
1023 #include "modules/swfbutton.c"
1024 #include "modules/swftools.c"
1025 #include "modules/swfcgi.c"
1026 #include "modules/swfbits.c"
1027 #include "modules/swfaction.c"
1028 #include "modules/swfsound.c"
1029