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