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