* InsertTag now sets an initial bitcount
[swftools.git] / lib / rfxswf.c
1 /* rfxswf.c\r
2 \r
3    Library for creating and reading SWF files or parts of it.\r
4    There's a module directory which provides some extended functionality.\r
5    Most modules are included at the bottom of this file.\r
6 \r
7    Part of the swftools package.\r
8 \r
9    Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>\r
10  \r
11    This file is distributed under the GPL, see file COPYING for details \r
12 \r
13 */\r
14 \r
15 #include "rfxswf.h"\r
16 \r
17 #include <jpeglib.h>\r
18 #define _JPEGLIB_INCLUDED_\r
19 \r
20 // Win32 support may be broken since it was only tested in an older version for Watcom C\r
21 #ifdef __NT__\r
22 #  include <io.h>\r
23 #  include <malloc.h>\r
24 #  include <string.h>\r
25 #  ifdef DEBUG_RFXSWF\r
26 #    include <stdio.h>\r
27 #  endif\r
28 #else\r
29 #endif\r
30 \r
31 // internal constants\r
32 \r
33 #define MALLOC_SIZE     128\r
34 #define INSERT_RFX_TAG\r
35 \r
36 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)\r
37 \r
38 // inline wrapper functions\r
39 \r
40 LPTAG NextTag(LPTAG t) { return t->next; }\r
41 LPTAG PrevTag(LPTAG t) { return t->prev; }\r
42 int   GetFrameNo(LPTAG t)  { return t->frame; }\r
43 U16   GetTagID(LPTAG t)    { return t->id; }\r
44 U32   GetDataSize(LPTAG t) { return t->len; }\r
45 U8*   GetDataSizePtr(LPTAG t) { return &(t->data[t->len]); }\r
46 U32   GetTagPos(LPTAG t)   { return t->pos; }\r
47 \r
48 // Basic Data Access Functions\r
49 \r
50 #define ResetBitmask(tag)   if (tag->bitmask)  { tag->pos++; tag->bitmask = 0; }\r
51 #define ResetBitcount(tag)  if (tag->bitcount) { tag->bitcount = 0; }\r
52 \r
53 // for future purpose: avoid high level lib functions to change tagpos/bitcount\r
54 \r
55 #define SaveTagPos(tag)\r
56 #define RestoreTagPos(tag)\r
57 \r
58 void SetTagPos(LPTAG t,U32 pos)\r
59 { ResetBitmask(t);\r
60   if (pos<=t->len) t->pos = pos;\r
61   #ifdef DEBUG_RFXSWF\r
62   else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);\r
63   #endif\r
64 }\r
65 \r
66 U8 GetU8(LPTAG t)\r
67 { ResetBitmask(t);\r
68   #ifdef DEBUG_RFXSWF\r
69     if (t->pos>=t->len) \r
70     { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);\r
71       return 0;\r
72     }\r
73   #endif\r
74   return t->data[t->pos++];\r
75 }\r
76 \r
77 U16 GetU16(LPTAG t)\r
78 { U16 res;\r
79   ResetBitmask(t);\r
80   #ifdef DEBUG_RFXSWF\r
81     if (t->pos>(t->len-2)) \r
82     { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);\r
83       return 0;\r
84     }\r
85   #endif\r
86   res = t->data[t->pos] | (t->data[t->pos+1]<<8);\r
87   t->pos+=2;\r
88   return res;\r
89 }\r
90 \r
91 U32 GetU32(LPTAG t)\r
92 { U32 res;\r
93   ResetBitmask(t);\r
94   #ifdef DEBUG_RFXSWF\r
95     if (t->pos>(t->len-4)) \r
96     { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);\r
97       return 0;\r
98     }\r
99   #endif\r
100   res = t->data[t->pos]        | (t->data[t->pos+1]<<8) | \r
101        (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);\r
102   t->pos+=4;\r
103   return res;\r
104 }\r
105 \r
106 int GetBlock(LPTAG t,U8 * b,int l)\r
107 // returns number of bytes written (<=l)\r
108 // b = NULL -> skip data\r
109 { ResetBitmask(t);\r
110   if ((t->len-t->pos)<l) l=t->len-t->pos;\r
111   if (b && l) memcpy(b,&t->data[t->pos],l);\r
112   t->pos+=l;\r
113   return l;\r
114 }\r
115 \r
116 int SetBlock(LPTAG t,U8 * b,int l)\r
117 // Appends Block to the end of Tagdata, returns size\r
118 { U32 newlen = t->len + l;\r
119   ResetBitcount(t);\r
120   if (newlen>t->memsize)\r
121   { U32  newmem  = MEMSIZE(newlen);  \r
122     U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem));\r
123     if (!newdata)\r
124     {\r
125       #ifdef DEBUG_RFXSWF\r
126         fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");\r
127       #endif\r
128       return 0;\r
129     }\r
130     t->memsize = newmem;\r
131     t->data    = newdata;\r
132   }\r
133   if (b) memcpy(&t->data[t->len],b,l);\r
134   else memset(&t->data[t->len],0x00,l);\r
135   t->len+=l;\r
136   return l;\r
137 }\r
138 \r
139 int SetU8(LPTAG t,U8 v)\r
140 { ResetBitcount(t);\r
141   if ((t->len+1)>t->memsize) return (SetBlock(t,&v,1)==1)?0:-1;\r
142   t->data[t->len++] = v;\r
143   return 0;\r
144 }\r
145 \r
146 int SetU16(LPTAG t,U16 v)\r
147 { U8 a[2];\r
148   a[0] = v&0xff;\r
149   a[1] = v>>8;\r
150   \r
151   ResetBitcount(t);\r
152   if ((t->len+2)>t->memsize) return (SetBlock(t,a,2)==2)?0:-1;\r
153   t->data[t->len++] = a[0];\r
154   t->data[t->len++] = a[1];\r
155   return 0;\r
156 }\r
157 \r
158 int SetU32(LPTAG t,U32 v)\r
159 { U8 a[4];\r
160   a[0] = v&0xff;        // to ensure correct handling of non-intel byteorder\r
161   a[1] = (v>>8)&0xff;\r
162   a[2] = (v>>16)&0xff;\r
163   a[3] = (v>>24)&0xff;\r
164   \r
165   ResetBitcount(t);\r
166   if ((t->len+4)>t->memsize) return (SetBlock(t,a,4)==4)?0:-1;\r
167   t->data[t->len++] = a[0];\r
168   t->data[t->len++] = a[1];\r
169   t->data[t->len++] = a[2];\r
170   t->data[t->len++] = a[3];\r
171   return 0;\r
172 }\r
173 \r
174 U32 GetBits(LPTAG t,int nbits)\r
175 { U32 res = 0;\r
176   if (!nbits) return 0;\r
177   if (!t->bitmask) t->bitmask = 0x80;\r
178   while (nbits)\r
179   { res<<=1;\r
180     if (t->data[t->pos]&t->bitmask) res|=1;\r
181     t->bitmask>>=1;\r
182     nbits--;\r
183     if (!t->bitmask)\r
184     { if (nbits) t->bitmask = 0x80;\r
185       #ifdef DEBUG_RFXSWF\r
186       if (t->pos>=t->len) \r
187       { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);\r
188         return res;\r
189       }\r
190       #endif\r
191       t->pos++;\r
192     }\r
193   }\r
194   return res;\r
195 }\r
196 \r
197 S32 GetSBits(LPTAG t,int nbits)\r
198 { U32 res = GetBits(t,nbits);\r
199   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  \r
200   return (S32)res;\r
201 }\r
202 \r
203 int SetBits(LPTAG t,U32 v,int nbits)\r
204 { U32 bm = 1<<(nbits-1);\r
205 \r
206   while (nbits)\r
207   { if (!t->bitcount)\r
208     { if (FAILED(SetU8(t,0))) return -1;\r
209       t->bitcount = 0x80;\r
210     }\r
211     if (v&bm) t->data[t->len-1] |= t->bitcount;\r
212     bm>>=1;\r
213     t->bitcount>>=1;\r
214     nbits--;\r
215   }\r
216   return 0;\r
217 }\r
218 \r
219 // Advanced Data Access Functions\r
220 \r
221 int SetRGB(LPTAG t,LPRGBA col)\r
222 { if (!t) return -1;\r
223   if (col)\r
224   { SetU8(t,col->r);\r
225     SetU8(t,col->g);\r
226     SetU8(t,col->b);\r
227   } else SetBlock(t,NULL,3);\r
228   return 0;\r
229 }\r
230 \r
231 int SetRGBA(LPTAG t,LPRGBA col)\r
232 { if (!t) return -1;\r
233   if (col)\r
234   { SetU8(t,col->r);\r
235     SetU8(t,col->g);\r
236     SetU8(t,col->b);\r
237     SetU8(t,col->a);\r
238   } else SetBlock(t,NULL,4);\r
239   return 0;\r
240 }\r
241 \r
242 int CountBits(U32 v,int nbits)\r
243 { int n = 33;\r
244   U32 m = 0x80000000;\r
245   if (!v) n = 0; else\r
246   if (v&m)\r
247   { while (v&m)\r
248     { n--;\r
249       m>>=1;\r
250       if (!m) break;\r
251     } \r
252   }\r
253   else\r
254   { while (!(v&m))\r
255     { n--;\r
256       m>>=1;\r
257       if (!m) break;\r
258     } \r
259   }\r
260   return (n>nbits)?n:nbits;\r
261 }\r
262 \r
263 int GetRect(LPTAG t,LPSRECT r)\r
264 { int nbits;\r
265   SRECT dummy;\r
266   if (!r) r = &dummy;\r
267   nbits = (int) GetBits(t,5);\r
268   r->xmin = GetSBits(t,nbits);\r
269   r->xmax = GetSBits(t,nbits);\r
270   r->ymin = GetSBits(t,nbits);\r
271   r->ymax = GetSBits(t,nbits);\r
272   return 0;\r
273 }\r
274 \r
275 int SetRect(LPTAG t,LPSRECT r)\r
276 { int nbits;\r
277     \r
278   nbits = CountBits(r->xmin,0);\r
279   nbits = CountBits(r->xmax,nbits);\r
280   nbits = CountBits(r->ymin,nbits);\r
281   nbits = CountBits(r->ymax,nbits);\r
282 \r
283   SetBits(t,nbits,5);\r
284   SetBits(t,r->xmin,nbits);\r
285   SetBits(t,r->xmax,nbits);\r
286   SetBits(t,r->ymin,nbits);\r
287   SetBits(t,r->ymax,nbits);\r
288 \r
289   return 0;\r
290 }\r
291 \r
292 int GetMatrix(LPTAG t,LPMATRIX m)\r
293 { MATRIX dummy;\r
294   int nbits;\r
295     \r
296   if (!m) m = &dummy;\r
297   \r
298   if (!t)\r
299   { m->sx = m->sy = 0x10000;\r
300     m->r0 = m->r1 = 0;\r
301     m->tx = m->ty = 0;\r
302     return -1;\r
303   }\r
304 \r
305   ResetBitmask(t);\r
306   \r
307   if (GetBits(t,1))\r
308   { nbits = GetBits(t,5);\r
309     m->sx = GetSBits(t,nbits);\r
310     m->sy = GetSBits(t,nbits);\r
311   }\r
312   else m->sx = m->sy = 0x10000;\r
313   \r
314   if (GetBits(t,1))\r
315   { nbits = GetBits(t,5);\r
316     m->r0 = GetSBits(t,nbits);\r
317     m->r1 = GetSBits(t,nbits);\r
318   }\r
319   else m->r0 = m->r1 = 0x0;\r
320 \r
321   nbits = GetBits(t,5);\r
322   m->tx = GetSBits(t,nbits);\r
323   m->ty = GetSBits(t,nbits);\r
324   \r
325   return 0;\r
326 }\r
327 \r
328 int SetMatrix(LPTAG t,LPMATRIX m)\r
329 { int nbits;\r
330   MATRIX ma;\r
331 \r
332   if (!m)\r
333   { m = &ma;\r
334     ma.sx = ma.sy = 0x10000;\r
335     ma.r0 = ma.r1 = 0;\r
336     ma.tx = ma.ty = 0;\r
337   }\r
338 \r
339   ResetBitcount(t);\r
340 \r
341   if ((m->sx==0x10000)&&(m->sy==0x10000)) SetBits(t,0,1);\r
342   else\r
343   { SetBits(t,1,1);\r
344     nbits = CountBits(m->sx,0);\r
345     nbits = CountBits(m->sy,nbits);\r
346     SetBits(t,nbits,5);\r
347     SetBits(t,m->sx,nbits);\r
348     SetBits(t,m->sy,nbits);\r
349   }\r
350 \r
351   if ((!m->r0)&&(!m->r1)) SetBits(t,0,1);\r
352   else\r
353   { SetBits(t,1,1);\r
354     nbits = CountBits(m->r0,0);\r
355     nbits = CountBits(m->r1,nbits);\r
356     SetBits(t,nbits,5);\r
357     SetBits(t,m->r0,nbits);\r
358     SetBits(t,m->r1,nbits);\r
359   }\r
360 \r
361   nbits = CountBits(m->tx,0);\r
362   nbits = CountBits(m->ty,nbits);\r
363   SetBits(t,nbits,5);\r
364   SetBits(t,m->tx,nbits);\r
365   SetBits(t,m->ty,nbits);\r
366 \r
367   return 0;\r
368 }\r
369 \r
370 int GetCXForm(LPTAG t,LPCXFORM cx,U8 alpha) //FIXME: alpha should be type bool\r
371 { CXFORM cxf;\r
372   int hasadd;\r
373   int hasmul;\r
374   int nbits;\r
375     \r
376   if (!cx) cx = &cxf;\r
377   \r
378   cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;\r
379   cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;\r
380 \r
381   if (!t) return 0;\r
382   \r
383   ResetBitmask(t);\r
384   hasadd = GetBits(t,1);\r
385   hasmul = GetBits(t,1);\r
386   nbits  = GetBits(t,4);\r
387 \r
388   if (hasmul)\r
389   { cx->r0 = (S16)GetSBits(t,nbits);\r
390     cx->g0 = (S16)GetSBits(t,nbits);\r
391     cx->b0 = (S16)GetSBits(t,nbits);\r
392     if (alpha)\r
393       cx->a0 = (S16)GetSBits(t,nbits);\r
394   }\r
395 \r
396   if (hasadd)\r
397   { cx->r1 = (S16)GetSBits(t,nbits);\r
398     cx->g1 = (S16)GetSBits(t,nbits);\r
399     cx->b1 = (S16)GetSBits(t,nbits);\r
400     if (alpha)\r
401       cx->a1 = (S16)GetSBits(t,nbits);\r
402   }\r
403   \r
404   return 0;\r
405 }\r
406 \r
407 int SetCXForm(LPTAG t,LPCXFORM cx,U8 alpha)\r
408 { CXFORM cxf;\r
409   int hasadd;\r
410   int hasmul;\r
411   int nbits;\r
412     \r
413   if (!cx)\r
414   { cx = &cxf;\r
415     cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;\r
416     cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;\r
417   }\r
418 \r
419   if (!alpha)\r
420   { cx->a0 = 256;\r
421     cx->a1 = 0;\r
422   }\r
423 \r
424   nbits = 0;\r
425 \r
426   hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);\r
427   hasadd = cx->a1|cx->r1|cx->g1|cx->b1;\r
428 \r
429   if (hasmul)\r
430   { if (alpha) nbits = CountBits((S32)cx->a0,nbits);\r
431     nbits = CountBits((S32)cx->r0,nbits);\r
432     nbits = CountBits((S32)cx->g0,nbits);\r
433     nbits = CountBits((S32)cx->b0,nbits);\r
434   }\r
435 \r
436   if (hasadd)\r
437   { if (alpha) nbits = CountBits((S32)cx->a1,nbits);\r
438     nbits = CountBits((S32)cx->r1,nbits);\r
439     nbits = CountBits((S32)cx->g1,nbits);\r
440     nbits = CountBits((S32)cx->b1,nbits);\r
441   }\r
442   \r
443   ResetBitcount(t);\r
444   SetBits(t,hasadd?1:0,1);\r
445   SetBits(t,hasmul?1:0,1);\r
446   SetBits(t,nbits,4);\r
447 \r
448   if (hasmul)\r
449   { SetBits(t,cx->r0,nbits);\r
450     SetBits(t,cx->g0,nbits);\r
451     SetBits(t,cx->b0,nbits);\r
452     if (alpha) SetBits(t,cx->a0,nbits);\r
453   }\r
454 \r
455   if (hasadd)\r
456   { SetBits(t,cx->r1,nbits);\r
457     SetBits(t,cx->g1,nbits);\r
458     SetBits(t,cx->b1,nbits);\r
459     if (alpha) SetBits(t,cx->a1,nbits);\r
460   }\r
461   \r
462   return 0;\r
463 }\r
464 \r
465 int GetPoint(LPTAG t,LPSPOINT p) { return 0; }\r
466 int SetPoint(LPTAG t,LPSPOINT p) { return 0; }\r
467 \r
468 // Tag List Manipulating Functions\r
469 \r
470 int RFXSWF_UpdateFrame(LPTAG t,S8 delta)\r
471 // returns number of frames\r
472 { int res = -1;\r
473   while (t)\r
474   { t->frame+=delta;\r
475     res = t->frame;\r
476     t = t->next;\r
477   }\r
478   return res;\r
479 }\r
480 \r
481 #define UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)\r
482 \r
483 LPTAG InsertTag(LPTAG after,U16 id)     // updates frames, if nescessary\r
484 { LPTAG t;\r
485 \r
486   t = (LPTAG)malloc(sizeof(TAG));\r
487   if (t)\r
488   { memset(t,0x00,sizeof(TAG));\r
489     t->id = id;\r
490     t->bitcount = 0x80;\r
491     \r
492     if (after)\r
493     { t->frame = after->frame;\r
494       t->prev  = after;\r
495       t->next  = after->next;\r
496       after->next = t;\r
497       if (t->next) t->next->prev = t;\r
498       \r
499       if (id==ST_SHOWFRAME) UpdateFrame(t->next,+1);\r
500     }\r
501   }\r
502   return t;\r
503 }\r
504 \r
505 int DeleteTag(LPTAG t)\r
506 { if (!t) return -1;\r
507 \r
508   if (t->id==ST_SHOWFRAME) UpdateFrame(t->next,-1);\r
509     \r
510   if (t->prev) t->prev->next = t->next;\r
511   if (t->next) t->next->prev = t->prev;\r
512 \r
513   if (t->data) free(t->data);\r
514   free(t);\r
515   return 0;\r
516 }\r
517 \r
518 LPTAG RFXSWF_ReadTag(int handle,LPTAG prev)\r
519 { LPTAG t;\r
520   U16 raw;\r
521   U32 len;\r
522   int id;\r
523 \r
524   if (read(handle,&raw,2)!=2) return NULL;\r
525 \r
526   len = raw&0x3f;\r
527   id  = raw>>6;\r
528 \r
529   if (len==0x3f)\r
530   { if (read(handle,&len,4)!=4) return NULL;\r
531   }\r
532 \r
533   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);\r
534   // Sprite handling fix: Flaten sprite tree\r
535 \r
536   t = (LPTAG)malloc(sizeof(TAG));\r
537   \r
538   if (!t)\r
539   {\r
540     #ifdef DEBUG_RFXSWF\r
541       fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");\r
542     #endif\r
543     return NULL;\r
544   }\r
545 \r
546   memset(t,0x00,sizeof(TAG));\r
547   \r
548   t->len = len;\r
549   t->id  = id;\r
550 \r
551   if (t->len)\r
552   { t->data = (U8*)malloc(t->len);\r
553     if (!t->data)\r
554     {\r
555       #ifdef DEBUG_RFXSWF\r
556         fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");\r
557       #endif\r
558       return NULL;\r
559     }\r
560     t->memsize = t->len;\r
561     if (read(handle,t->data,t->len)!=t->len) return NULL;\r
562   }\r
563 \r
564   if (prev)\r
565   { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);\r
566     t->prev  = prev;\r
567     prev->next = t;\r
568   }\r
569 \r
570   return t;\r
571 }\r
572 \r
573 int DefineSprite_GetRealSize(LPTAG t);\r
574 \r
575 int RFXSWF_WriteTag(int handle,LPTAG t)\r
576 // returns tag length in bytes (incl. Header), -1 = Error\r
577 // handle = -1 -> no output\r
578 { U16 raw[3];\r
579   U32 len;\r
580   int short_tag;\r
581 \r
582   if (!t) return -1;\r
583 \r
584   len = (t->id==ST_DEFINESPRITE)?DefineSprite_GetRealSize(t):t->len;\r
585 \r
586   short_tag = len<0x3f;\r
587 \r
588   if (handle>=0)\r
589   { if (short_tag)\r
590     { raw[0] = len|((t->id&0x3ff)<<6);\r
591       if (write(handle,raw,2)!=2)\r
592       {\r
593         #ifdef DEBUG_RFXSWF\r
594           fprintf(stderr,"WriteTag() failed: Short Header.\n");\r
595         #endif\r
596         return -1;\r
597       }\r
598     }\r
599     else\r
600     { raw[0] = (t->id<<6)|0x3f;\r
601       raw[1] = (U16)(len&0xffff);\r
602       raw[2] = (U16)(len>>16);\r
603       if (write(handle,raw,6)!=6)\r
604       {\r
605         #ifdef DEBUG_RFXSWF\r
606           fprintf(stderr,"WriteTag() failed: Long Header.\n");\r
607         #endif\r
608         return -1;\r
609       }\r
610     }\r
611     \r
612     if (t->data)\r
613     { if (write(handle,t->data,t->len)!=t->len)\r
614       {\r
615         #ifdef DEBUG_RFXSWF\r
616           fprintf(stderr,"WriteTag() failed: Data.\n");\r
617         #endif\r
618         return -1;\r
619       }\r
620     }\r
621     #ifdef DEBUG_RFXSWF\r
622       else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);\r
623     #endif\r
624   }\r
625 \r
626   return t->len+(short_tag?2:6);\r
627 }\r
628 \r
629 int DefineSprite_GetRealSize(LPTAG t)\r
630 // Sprite Handling: Helper function to pack DefineSprite-Tag\r
631 { U32 len = t->len;\r
632   do\r
633   { t = NextTag(t);\r
634     if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);\r
635     else t = NULL;\r
636   } while (t&&(t->id!=ST_END));\r
637   return len;\r
638 }\r
639 \r
640 #define ReadTag(a,b)  RFXSWF_ReadTag(a,b)\r
641 #define WriteTag(a,b) RFXSWF_WriteTag(a,b)\r
642 \r
643 // Movie Functions\r
644 \r
645 int ReadSWF(int handle,LPSWF swf)       // Reads SWF to memory (malloc'ed), returns length or <0 if fails\r
646 {     \r
647   if (!swf) return -1;\r
648   memset(swf,0x00,sizeof(SWF));\r
649 \r
650   { char b[32];                         // Header lesen\r
651     TAG t1;\r
652     LPTAG t;\r
653     \r
654     memset(&t1,0x00,sizeof(TAG));\r
655     \r
656     if ((t1.len=read(handle,b,32))<21) return -1;\r
657     t1.data = (U8*)b;\r
658 \r
659     if (GetU8(&t1)!=(U8)'F') return -1;\r
660     if (GetU8(&t1)!=(U8)'W') return -1;\r
661     if (GetU8(&t1)!=(U8)'S') return -1;\r
662 \r
663     swf->FileVersion = GetU8(&t1);\r
664     swf->FileSize    = GetU32(&t1);\r
665     GetRect(&t1,&swf->MovieSize);\r
666     swf->FrameRate   = GetU16(&t1);\r
667     swf->FrameCount  = GetU16(&t1);\r
668 \r
669     GetU8(&t1);\r
670     lseek(handle,GetTagPos(&t1)-1,SEEK_SET);\r
671   \r
672                                         // Tags lesen und verketten\r
673     t = &t1;\r
674     while (t) t = ReadTag(handle,t);\r
675     swf->FirstTag = t1.next;\r
676     t1.next->prev = NULL;\r
677   }\r
678   \r
679   return 0;\r
680 }\r
681 int  WriteSWF(int handle,LPSWF swf)     // Writes SWF to file, returns length or <0 if fails\r
682 { U32 len;\r
683   LPTAG t;\r
684     \r
685   if (!swf) return -1;\r
686 \r
687   // Insert REFLEX Tag\r
688 \r
689 #ifdef INSERT_RFX_TAG\r
690 \r
691   if (NextTag(swf->FirstTag))\r
692     if (GetTagID(NextTag(swf->FirstTag))!=ST_REFLEX)\r
693       SetBlock(InsertTag(swf->FirstTag,ST_REFLEX),"rfx",3);\r
694 \r
695 #endif // INSERT_RFX_TAG\r
696 \r
697   // Count Frames + File Size\r
698 \r
699   len = 0;\r
700   t = swf->FirstTag;\r
701   swf->FrameCount = 0;\r
702 \r
703   while(t)\r
704   { len += WriteTag(-1,t);\r
705     if (t->id==ST_SHOWFRAME) swf->FrameCount++;\r
706     t = NextTag(t);\r
707   }\r
708   \r
709   { TAG t1;\r
710     char b[64];\r
711     U32 l;\r
712 \r
713     memset(&t1,0x00,sizeof(TAG));\r
714     t1.data    = (U8*)b;\r
715     t1.memsize = 64;\r
716     \r
717     SetU8(&t1,'F');      \r
718     SetU8(&t1,'W');      \r
719     SetU8(&t1,'S');\r
720     SetU8(&t1,swf->FileVersion);\r
721     \r
722     SetU32(&t1,0);                      // Keep space for filesize\r
723     SetRect(&t1,&swf->MovieSize);\r
724     SetU16(&t1,swf->FrameRate);\r
725     SetU16(&t1,swf->FrameCount);\r
726 \r
727     l = GetDataSize(&t1);\r
728     swf->FileSize = l+len;\r
729     t1.len = 4;                         // bad & ugly trick !\r
730     SetU32(&t1,swf->FileSize);\r
731 \r
732     if (handle>=0)\r
733     { \r
734       int ret = write(handle,b,l);\r
735       if (ret!=l)\r
736       {\r
737         #ifdef DEBUG_RFXSWF\r
738           printf("ret:%d (fd:%d)\n",ret, handle);\r
739           perror("write:");\r
740           fprintf(stderr,"WriteSWF() failed: Header.\n");\r
741         #endif\r
742         return -1;\r
743       }\r
744 \r
745       t = swf->FirstTag;\r
746       while (t)\r
747       { if (WriteTag(handle,t)<0) return -1;\r
748         t = NextTag(t);\r
749       }\r
750     }\r
751   }\r
752   return (int)swf->FileSize;\r
753 }\r
754 \r
755 int WriteCGI(LPSWF swf)\r
756 { int len;\r
757   char s[1024];\r
758     \r
759   len = WriteSWF(-1,swf);\r
760 \r
761   if (len<0) return -1;\r
762 \r
763   sprintf(s,"Content-type: application/x-shockwave-flash\n"\r
764             "Accept-Ranges: bytes\n"\r
765             "Content-Length: %lu\n"\r
766             "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"\r
767             "\n",len);\r
768             \r
769   write(fileno(stdout),s,strlen(s));\r
770   return WriteSWF(fileno(stdout),swf);\r
771 }\r
772 \r
773 void FreeTags(LPSWF swf)                 // Frees all malloc'ed memory for tags\r
774 { LPTAG t = swf->FirstTag;\r
775 \r
776   while (t)\r
777   { LPTAG tnew = t->next;\r
778     if (t->data) free(t->data);\r
779     free(t);\r
780     t = tnew;\r
781   }\r
782 }\r
783 \r
784 // include advanced functions\r
785 \r
786 #ifdef __NT__\r
787 \r
788 #include "modules\swfdump.c"\r
789 #include "modules\swfshape.c"\r
790 #include "modules\swftext.c"\r
791 #include "modules\swfobject.c"\r
792 #include "modules\swfbutton.c"\r
793 #include "modules\swfbits.c"\r
794 #include "modules\swftools.c"\r
795 #include "modules\swfcgi.c"\r
796 \r
797 #else\r
798 \r
799 #include "modules/swfdump.c"\r
800 #include "modules/swfshape.c"\r
801 #include "modules/swftext.c"\r
802 #include "modules/swfobject.c"\r
803 #include "modules/swfbutton.c"\r
804 #include "modules/swfbits.c"\r
805 #include "modules/swftools.c"\r
806 #include "modules/swfcgi.c"\r
807 \r
808 #endif\r
809 \r
810 \r