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
7 Part of the swftools package.
\r
9 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
\r
11 This file is distributed under the GPL, see file COPYING for details
\r
18 #ifdef HAVE_JPEGLIB_H
\r
19 #include <jpeglib.h>
\r
20 #define _JPEGLIB_INCLUDED_
\r
21 #endif //HAVE_JPEGLIB_H
\r
22 #endif //HAVE_LIBJPEG
\r
24 // Win32 support may be broken since it was only tested in an older version for Watcom C
\r
27 # include <malloc.h>
\r
28 # include <string.h>
\r
29 # ifdef DEBUG_RFXSWF
\r
35 // internal constants
\r
37 #define MALLOC_SIZE 128
\r
38 #define INSERT_RFX_TAG
\r
40 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
\r
42 // inline wrapper functions
\r
44 LPTAG NextTag(LPTAG t) { return t->next; }
\r
45 LPTAG PrevTag(LPTAG t) { return t->prev; }
\r
46 int GetFrameNo(LPTAG t) { return t->frame; }
\r
47 U16 GetTagID(LPTAG t) { return t->id; }
\r
48 U32 GetDataSize(LPTAG t) { return t->len; }
\r
49 U8* GetDataSizePtr(LPTAG t) { return &(t->data[t->len]); }
\r
50 U32 GetTagPos(LPTAG t) { return t->pos; }
\r
52 // Basic Data Access Functions
\r
54 #define ResetBitmask(tag) if (tag->bitmask) { tag->pos++; tag->bitmask = 0; }
\r
55 #define ResetBitcount(tag) if (tag->bitcount) { tag->bitcount = 0; }
\r
57 // for future purpose: avoid high level lib functions to change tagpos/bitcount
\r
59 #define SaveTagPos(tag)
\r
60 #define RestoreTagPos(tag)
\r
62 void SetTagPos(LPTAG t,U32 pos)
\r
64 if (pos<=t->len) t->pos = pos;
\r
66 else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
\r
73 if (t->pos>=t->len)
\r
74 { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
\r
78 return t->data[t->pos++];
\r
85 if (t->pos>(t->len-2))
\r
86 { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
\r
90 res = t->data[t->pos] | (t->data[t->pos+1]<<8);
\r
99 if (t->pos>(t->len-4))
\r
100 { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
\r
104 res = t->data[t->pos] | (t->data[t->pos+1]<<8) |
\r
105 (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);
\r
110 int GetBlock(LPTAG t,U8 * b,int l)
\r
111 // returns number of bytes written (<=l)
\r
112 // b = NULL -> skip data
\r
114 if ((t->len-t->pos)<l) l=t->len-t->pos;
\r
115 if (b && l) memcpy(b,&t->data[t->pos],l);
\r
120 int SetBlock(LPTAG t,U8 * b,int l)
\r
121 // Appends Block to the end of Tagdata, returns size
\r
122 { U32 newlen = t->len + l;
\r
124 if (newlen>t->memsize)
\r
125 { U32 newmem = MEMSIZE(newlen);
\r
126 U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem));
\r
129 #ifdef DEBUG_RFXSWF
\r
130 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
\r
134 t->memsize = newmem;
\r
137 if (b) memcpy(&t->data[t->len],b,l);
\r
138 else memset(&t->data[t->len],0x00,l);
\r
143 int SetU8(LPTAG t,U8 v)
\r
144 { ResetBitcount(t);
\r
145 if ((t->len+1)>t->memsize) return (SetBlock(t,&v,1)==1)?0:-1;
\r
146 t->data[t->len++] = v;
\r
150 int SetU16(LPTAG t,U16 v)
\r
156 if ((t->len+2)>t->memsize) return (SetBlock(t,a,2)==2)?0:-1;
\r
157 t->data[t->len++] = a[0];
\r
158 t->data[t->len++] = a[1];
\r
162 int SetU32(LPTAG t,U32 v)
\r
164 a[0] = v&0xff; // to ensure correct handling of non-intel byteorder
\r
165 a[1] = (v>>8)&0xff;
\r
166 a[2] = (v>>16)&0xff;
\r
167 a[3] = (v>>24)&0xff;
\r
170 if ((t->len+4)>t->memsize) return (SetBlock(t,a,4)==4)?0:-1;
\r
171 t->data[t->len++] = a[0];
\r
172 t->data[t->len++] = a[1];
\r
173 t->data[t->len++] = a[2];
\r
174 t->data[t->len++] = a[3];
\r
178 U32 GetBits(LPTAG t,int nbits)
\r
180 if (!nbits) return 0;
\r
181 if (!t->bitmask) t->bitmask = 0x80;
\r
184 if (t->data[t->pos]&t->bitmask) res|=1;
\r
188 { if (nbits) t->bitmask = 0x80;
\r
189 #ifdef DEBUG_RFXSWF
\r
190 if (t->pos>=t->len)
\r
191 { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
\r
201 S32 GetSBits(LPTAG t,int nbits)
\r
202 { U32 res = GetBits(t,nbits);
\r
203 if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);
\r
207 int SetBits(LPTAG t,U32 v,int nbits)
\r
208 { U32 bm = 1<<(nbits-1);
\r
211 { if (!t->bitcount)
\r
212 { if (FAILED(SetU8(t,0))) return -1;
\r
213 t->bitcount = 0x80;
\r
215 if (v&bm) t->data[t->len-1] |= t->bitcount;
\r
223 // Advanced Data Access Functions
\r
225 int SetRGB(LPTAG t,LPRGBA col)
\r
226 { if (!t) return -1;
\r
231 } else SetBlock(t,NULL,3);
\r
235 int SetRGBA(LPTAG t,LPRGBA col)
\r
236 { if (!t) return -1;
\r
242 } else SetBlock(t,NULL,4);
\r
246 int CountBits(U32 v,int nbits)
\r
248 U32 m = 0x80000000;
\r
249 if (!v) n = 0; else
\r
264 return (n>nbits)?n:nbits;
\r
267 int GetRect(LPTAG t,LPSRECT r)
\r
270 if (!r) r = &dummy;
\r
271 nbits = (int) GetBits(t,5);
\r
272 r->xmin = GetSBits(t,nbits);
\r
273 r->xmax = GetSBits(t,nbits);
\r
274 r->ymin = GetSBits(t,nbits);
\r
275 r->ymax = GetSBits(t,nbits);
\r
279 int SetRect(LPTAG t,LPSRECT r)
\r
282 nbits = CountBits(r->xmin,0);
\r
283 nbits = CountBits(r->xmax,nbits);
\r
284 nbits = CountBits(r->ymin,nbits);
\r
285 nbits = CountBits(r->ymax,nbits);
\r
287 SetBits(t,nbits,5);
\r
288 SetBits(t,r->xmin,nbits);
\r
289 SetBits(t,r->xmax,nbits);
\r
290 SetBits(t,r->ymin,nbits);
\r
291 SetBits(t,r->ymax,nbits);
\r
296 int GetMatrix(LPTAG t,LPMATRIX m)
\r
300 if (!m) m = &dummy;
\r
303 { m->sx = m->sy = 0x10000;
\r
312 { nbits = GetBits(t,5);
\r
313 m->sx = GetSBits(t,nbits);
\r
314 m->sy = GetSBits(t,nbits);
\r
316 else m->sx = m->sy = 0x10000;
\r
319 { nbits = GetBits(t,5);
\r
320 m->r0 = GetSBits(t,nbits);
\r
321 m->r1 = GetSBits(t,nbits);
\r
323 else m->r0 = m->r1 = 0x0;
\r
325 nbits = GetBits(t,5);
\r
326 m->tx = GetSBits(t,nbits);
\r
327 m->ty = GetSBits(t,nbits);
\r
332 int SetMatrix(LPTAG t,LPMATRIX m)
\r
338 ma.sx = ma.sy = 0x10000;
\r
345 if ((m->sx==0x10000)&&(m->sy==0x10000)) SetBits(t,0,1);
\r
348 nbits = CountBits(m->sx,0);
\r
349 nbits = CountBits(m->sy,nbits);
\r
350 SetBits(t,nbits,5);
\r
351 SetBits(t,m->sx,nbits);
\r
352 SetBits(t,m->sy,nbits);
\r
355 if ((!m->r0)&&(!m->r1)) SetBits(t,0,1);
\r
358 nbits = CountBits(m->r0,0);
\r
359 nbits = CountBits(m->r1,nbits);
\r
360 SetBits(t,nbits,5);
\r
361 SetBits(t,m->r0,nbits);
\r
362 SetBits(t,m->r1,nbits);
\r
365 nbits = CountBits(m->tx,0);
\r
366 nbits = CountBits(m->ty,nbits);
\r
367 SetBits(t,nbits,5);
\r
368 SetBits(t,m->tx,nbits);
\r
369 SetBits(t,m->ty,nbits);
\r
374 int GetCXForm(LPTAG t,LPCXFORM cx,U8 alpha) //FIXME: alpha should be type bool
\r
380 if (!cx) cx = &cxf;
\r
382 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
\r
383 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
\r
388 hasadd = GetBits(t,1);
\r
389 hasmul = GetBits(t,1);
\r
390 nbits = GetBits(t,4);
\r
393 { cx->r0 = (S16)GetSBits(t,nbits);
\r
394 cx->g0 = (S16)GetSBits(t,nbits);
\r
395 cx->b0 = (S16)GetSBits(t,nbits);
\r
397 cx->a0 = (S16)GetSBits(t,nbits);
\r
401 { cx->r1 = (S16)GetSBits(t,nbits);
\r
402 cx->g1 = (S16)GetSBits(t,nbits);
\r
403 cx->b1 = (S16)GetSBits(t,nbits);
\r
405 cx->a1 = (S16)GetSBits(t,nbits);
\r
411 int SetCXForm(LPTAG t,LPCXFORM cx,U8 alpha)
\r
419 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
\r
420 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
\r
430 hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
\r
431 hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
\r
434 { if (alpha) nbits = CountBits((S32)cx->a0,nbits);
\r
435 nbits = CountBits((S32)cx->r0,nbits);
\r
436 nbits = CountBits((S32)cx->g0,nbits);
\r
437 nbits = CountBits((S32)cx->b0,nbits);
\r
441 { if (alpha) nbits = CountBits((S32)cx->a1,nbits);
\r
442 nbits = CountBits((S32)cx->r1,nbits);
\r
443 nbits = CountBits((S32)cx->g1,nbits);
\r
444 nbits = CountBits((S32)cx->b1,nbits);
\r
448 SetBits(t,hasadd?1:0,1);
\r
449 SetBits(t,hasmul?1:0,1);
\r
450 SetBits(t,nbits,4);
\r
453 { SetBits(t,cx->r0,nbits);
\r
454 SetBits(t,cx->g0,nbits);
\r
455 SetBits(t,cx->b0,nbits);
\r
456 if (alpha) SetBits(t,cx->a0,nbits);
\r
460 { SetBits(t,cx->r1,nbits);
\r
461 SetBits(t,cx->g1,nbits);
\r
462 SetBits(t,cx->b1,nbits);
\r
463 if (alpha) SetBits(t,cx->a1,nbits);
\r
469 int GetPoint(LPTAG t,LPSPOINT p) { return 0; }
\r
470 int SetPoint(LPTAG t,LPSPOINT p) { return 0; }
\r
472 // Tag List Manipulating Functions
\r
474 int RFXSWF_UpdateFrame(LPTAG t,S8 delta)
\r
475 // returns number of frames
\r
485 #define UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)
\r
487 LPTAG InsertTag(LPTAG after,U16 id) // updates frames, if nescessary
\r
490 t = (LPTAG)malloc(sizeof(TAG));
\r
492 { memset(t,0x00,sizeof(TAG));
\r
494 t->bitcount = 0x80;
\r
497 { t->frame = after->frame;
\r
499 t->next = after->next;
\r
501 if (t->next) t->next->prev = t;
\r
503 if (id==ST_SHOWFRAME) UpdateFrame(t->next,+1);
\r
509 int DeleteTag(LPTAG t)
\r
510 { if (!t) return -1;
\r
512 if (t->id==ST_SHOWFRAME) UpdateFrame(t->next,-1);
\r
514 if (t->prev) t->prev->next = t->next;
\r
515 if (t->next) t->next->prev = t->prev;
\r
517 if (t->data) free(t->data);
\r
522 LPTAG RFXSWF_ReadTag(int handle,LPTAG prev)
\r
528 if (read(handle,&raw,2)!=2) return NULL;
\r
534 { if (read(handle,&len,4)!=4) return NULL;
\r
537 if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
\r
538 // Sprite handling fix: Flaten sprite tree
\r
540 t = (LPTAG)malloc(sizeof(TAG));
\r
544 #ifdef DEBUG_RFXSWF
\r
545 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
\r
550 memset(t,0x00,sizeof(TAG));
\r
556 { t->data = (U8*)malloc(t->len);
\r
559 #ifdef DEBUG_RFXSWF
\r
560 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
\r
564 t->memsize = t->len;
\r
565 if (read(handle,t->data,t->len)!=t->len) return NULL;
\r
569 { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
\r
577 int DefineSprite_GetRealSize(LPTAG t);
\r
579 int RFXSWF_WriteTag(int handle,LPTAG t)
\r
580 // returns tag length in bytes (incl. Header), -1 = Error
\r
581 // handle = -1 -> no output
\r
588 len = (t->id==ST_DEFINESPRITE)?DefineSprite_GetRealSize(t):t->len;
\r
590 short_tag = len<0x3f;
\r
594 { raw[0] = len|((t->id&0x3ff)<<6);
\r
595 if (write(handle,raw,2)!=2)
\r
597 #ifdef DEBUG_RFXSWF
\r
598 fprintf(stderr,"WriteTag() failed: Short Header.\n");
\r
604 { raw[0] = (t->id<<6)|0x3f;
\r
605 raw[1] = (U16)(len&0xffff);
\r
606 raw[2] = (U16)(len>>16);
\r
607 if (write(handle,raw,6)!=6)
\r
609 #ifdef DEBUG_RFXSWF
\r
610 fprintf(stderr,"WriteTag() failed: Long Header.\n");
\r
617 { if (write(handle,t->data,t->len)!=t->len)
\r
619 #ifdef DEBUG_RFXSWF
\r
620 fprintf(stderr,"WriteTag() failed: Data.\n");
\r
625 #ifdef DEBUG_RFXSWF
\r
626 else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
\r
630 return t->len+(short_tag?2:6);
\r
633 int DefineSprite_GetRealSize(LPTAG t)
\r
634 // Sprite Handling: Helper function to pack DefineSprite-Tag
\r
635 { U32 len = t->len;
\r
638 if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
\r
640 } while (t&&(t->id!=ST_END));
\r
644 #define ReadTag(a,b) RFXSWF_ReadTag(a,b)
\r
645 #define WriteTag(a,b) RFXSWF_WriteTag(a,b)
\r
649 int ReadSWF(int handle,LPSWF swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails
\r
651 if (!swf) return -1;
\r
652 memset(swf,0x00,sizeof(SWF));
\r
654 { char b[32]; // Header lesen
\r
658 memset(&t1,0x00,sizeof(TAG));
\r
660 if ((t1.len=read(handle,b,32))<21) return -1;
\r
663 if (GetU8(&t1)!=(U8)'F') return -1;
\r
664 if (GetU8(&t1)!=(U8)'W') return -1;
\r
665 if (GetU8(&t1)!=(U8)'S') return -1;
\r
667 swf->FileVersion = GetU8(&t1);
\r
668 swf->FileSize = GetU32(&t1);
\r
669 GetRect(&t1,&swf->MovieSize);
\r
670 swf->FrameRate = GetU16(&t1);
\r
671 swf->FrameCount = GetU16(&t1);
\r
674 lseek(handle,GetTagPos(&t1)-1,SEEK_SET);
\r
676 // Tags lesen und verketten
\r
678 while (t) t = ReadTag(handle,t);
\r
679 swf->FirstTag = t1.next;
\r
680 t1.next->prev = NULL;
\r
685 int WriteSWF(int handle,LPSWF swf) // Writes SWF to file, returns length or <0 if fails
\r
689 if (!swf) return -1;
\r
691 // Insert REFLEX Tag
\r
693 #ifdef INSERT_RFX_TAG
\r
695 if (NextTag(swf->FirstTag))
\r
696 if (GetTagID(NextTag(swf->FirstTag))!=ST_REFLEX)
\r
697 SetBlock(InsertTag(swf->FirstTag,ST_REFLEX),"rfx",3);
\r
699 #endif // INSERT_RFX_TAG
\r
701 // Count Frames + File Size
\r
705 swf->FrameCount = 0;
\r
708 { len += WriteTag(-1,t);
\r
709 if (t->id==ST_SHOWFRAME) swf->FrameCount++;
\r
717 memset(&t1,0x00,sizeof(TAG));
\r
724 SetU8(&t1,swf->FileVersion);
\r
726 SetU32(&t1,0); // Keep space for filesize
\r
727 SetRect(&t1,&swf->MovieSize);
\r
728 SetU16(&t1,swf->FrameRate);
\r
729 SetU16(&t1,swf->FrameCount);
\r
731 l = GetDataSize(&t1);
\r
732 swf->FileSize = l+len;
\r
733 t1.len = 4; // bad & ugly trick !
\r
734 SetU32(&t1,swf->FileSize);
\r
738 int ret = write(handle,b,l);
\r
741 #ifdef DEBUG_RFXSWF
\r
742 printf("ret:%d (fd:%d)\n",ret, handle);
\r
744 fprintf(stderr,"WriteSWF() failed: Header.\n");
\r
751 { if (WriteTag(handle,t)<0) return -1;
\r
756 return (int)swf->FileSize;
\r
759 int WriteCGI(LPSWF swf)
\r
763 len = WriteSWF(-1,swf);
\r
765 if (len<0) return -1;
\r
767 sprintf(s,"Content-type: application/x-shockwave-flash\n"
\r
768 "Accept-Ranges: bytes\n"
\r
769 "Content-Length: %lu\n"
\r
770 "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
\r
773 write(fileno(stdout),s,strlen(s));
\r
774 return WriteSWF(fileno(stdout),swf);
\r
777 void FreeTags(LPSWF swf) // Frees all malloc'ed memory for tags
\r
778 { LPTAG t = swf->FirstTag;
\r
781 { LPTAG tnew = t->next;
\r
782 if (t->data) free(t->data);
\r
788 // include advanced functions
\r
792 #include "modules\swfdump.c"
\r
793 #include "modules\swfshape.c"
\r
794 #include "modules\swftext.c"
\r
795 #include "modules\swfobject.c"
\r
796 #include "modules\swfbutton.c"
\r
797 #include "modules\swftools.c"
\r
798 #include "modules\swfcgi.c"
\r
799 #include "modules\swfbits.c"
\r
803 #include "modules/swfdump.c"
\r
804 #include "modules/swfshape.c"
\r
805 #include "modules/swftext.c"
\r
806 #include "modules/swfobject.c"
\r
807 #include "modules/swfbutton.c"
\r
808 #include "modules/swftools.c"
\r
809 #include "modules/swfcgi.c"
\r
810 #include "modules/swfbits.c"
\r