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
17 #include <jpeglib.h>
\r
18 #define _JPEGLIB_INCLUDED_
\r
20 // Win32 support may be broken since it was only tested in an older version for Watcom C
\r
23 # include <malloc.h>
\r
24 # include <string.h>
\r
25 # ifdef DEBUG_RFXSWF
\r
31 // internal constants
\r
33 #define MALLOC_SIZE 128
\r
34 #define INSERT_RFX_TAG
\r
36 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
\r
38 // inline wrapper functions
\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
48 // Basic Data Access Functions
\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
53 // for future purpose: avoid high level lib functions to change tagpos/bitcount
\r
55 #define SaveTagPos(tag)
\r
56 #define RestoreTagPos(tag)
\r
58 void SetTagPos(LPTAG t,U32 pos)
\r
60 if (pos<=t->len) t->pos = pos;
\r
62 else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
\r
69 if (t->pos>=t->len)
\r
70 { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
\r
74 return t->data[t->pos++];
\r
81 if (t->pos>(t->len-2))
\r
82 { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
\r
86 res = t->data[t->pos] | (t->data[t->pos+1]<<8);
\r
95 if (t->pos>(t->len-4))
\r
96 { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
\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
106 int GetBlock(LPTAG t,U8 * b,int l)
\r
107 // returns number of bytes written (<=l)
\r
108 // b = NULL -> skip data
\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
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
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
125 #ifdef DEBUG_RFXSWF
\r
126 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
\r
130 t->memsize = newmem;
\r
133 if (b) memcpy(&t->data[t->len],b,l);
\r
134 else memset(&t->data[t->len],0x00,l);
\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
146 int SetU16(LPTAG t,U16 v)
\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
158 int SetU32(LPTAG t,U32 v)
\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
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
174 U32 GetBits(LPTAG t,int nbits)
\r
176 if (!nbits) return 0;
\r
177 if (!t->bitmask) t->bitmask = 0x80;
\r
180 if (t->data[t->pos]&t->bitmask) res|=1;
\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
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
203 int SetBits(LPTAG t,U32 v,int nbits)
\r
204 { U32 bm = 1<<(nbits-1);
\r
207 { if (!t->bitcount)
\r
208 { if (FAILED(SetU8(t,0))) return -1;
\r
209 t->bitcount = 0x80;
\r
211 if (v&bm) t->data[t->len-1] |= t->bitcount;
\r
219 // Advanced Data Access Functions
\r
221 int SetRGB(LPTAG t,LPRGBA col)
\r
222 { if (!t) return -1;
\r
227 } else SetBlock(t,NULL,3);
\r
231 int SetRGBA(LPTAG t,LPRGBA col)
\r
232 { if (!t) return -1;
\r
238 } else SetBlock(t,NULL,4);
\r
242 int CountBits(U32 v,int nbits)
\r
244 U32 m = 0x80000000;
\r
245 if (!v) n = 0; else
\r
260 return (n>nbits)?n:nbits;
\r
263 int GetRect(LPTAG t,LPSRECT r)
\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
275 int SetRect(LPTAG t,LPSRECT r)
\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
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
292 int GetMatrix(LPTAG t,LPMATRIX m)
\r
296 if (!m) m = &dummy;
\r
299 { m->sx = m->sy = 0x10000;
\r
308 { nbits = GetBits(t,5);
\r
309 m->sx = GetSBits(t,nbits);
\r
310 m->sy = GetSBits(t,nbits);
\r
312 else m->sx = m->sy = 0x10000;
\r
315 { nbits = GetBits(t,5);
\r
316 m->r0 = GetSBits(t,nbits);
\r
317 m->r1 = GetSBits(t,nbits);
\r
319 else m->r0 = m->r1 = 0x0;
\r
321 nbits = GetBits(t,5);
\r
322 m->tx = GetSBits(t,nbits);
\r
323 m->ty = GetSBits(t,nbits);
\r
328 int SetMatrix(LPTAG t,LPMATRIX m)
\r
334 ma.sx = ma.sy = 0x10000;
\r
341 if ((m->sx==0x10000)&&(m->sy==0x10000)) SetBits(t,0,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
351 if ((!m->r0)&&(!m->r1)) SetBits(t,0,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
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
370 int GetCXForm(LPTAG t,LPCXFORM cx,U8 alpha) //FIXME: alpha should be type bool
\r
376 if (!cx) cx = &cxf;
\r
378 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
\r
379 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
\r
384 hasadd = GetBits(t,1);
\r
385 hasmul = GetBits(t,1);
\r
386 nbits = GetBits(t,4);
\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
393 cx->a0 = (S16)GetSBits(t,nbits);
\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
401 cx->a1 = (S16)GetSBits(t,nbits);
\r
407 int SetCXForm(LPTAG t,LPCXFORM cx,U8 alpha)
\r
415 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
\r
416 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
\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
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
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
444 SetBits(t,hasadd?1:0,1);
\r
445 SetBits(t,hasmul?1:0,1);
\r
446 SetBits(t,nbits,4);
\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
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
465 int GetPoint(LPTAG t,LPSPOINT p) { return 0; }
\r
466 int SetPoint(LPTAG t,LPSPOINT p) { return 0; }
\r
468 // Tag List Manipulating Functions
\r
470 int RFXSWF_UpdateFrame(LPTAG t,S8 delta)
\r
471 // returns number of frames
\r
481 #define UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)
\r
483 LPTAG InsertTag(LPTAG after,U16 id) // updates frames, if nescessary
\r
486 t = (LPTAG)malloc(sizeof(TAG));
\r
488 { memset(t,0x00,sizeof(TAG));
\r
490 t->bitcount = 0x80;
\r
493 { t->frame = after->frame;
\r
495 t->next = after->next;
\r
497 if (t->next) t->next->prev = t;
\r
499 if (id==ST_SHOWFRAME) UpdateFrame(t->next,+1);
\r
505 int DeleteTag(LPTAG t)
\r
506 { if (!t) return -1;
\r
508 if (t->id==ST_SHOWFRAME) UpdateFrame(t->next,-1);
\r
510 if (t->prev) t->prev->next = t->next;
\r
511 if (t->next) t->next->prev = t->prev;
\r
513 if (t->data) free(t->data);
\r
518 LPTAG RFXSWF_ReadTag(int handle,LPTAG prev)
\r
524 if (read(handle,&raw,2)!=2) return NULL;
\r
530 { if (read(handle,&len,4)!=4) return NULL;
\r
533 if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
\r
534 // Sprite handling fix: Flaten sprite tree
\r
536 t = (LPTAG)malloc(sizeof(TAG));
\r
540 #ifdef DEBUG_RFXSWF
\r
541 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
\r
546 memset(t,0x00,sizeof(TAG));
\r
552 { t->data = (U8*)malloc(t->len);
\r
555 #ifdef DEBUG_RFXSWF
\r
556 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
\r
560 t->memsize = t->len;
\r
561 if (read(handle,t->data,t->len)!=t->len) return NULL;
\r
565 { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
\r
573 int DefineSprite_GetRealSize(LPTAG t);
\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
584 len = (t->id==ST_DEFINESPRITE)?DefineSprite_GetRealSize(t):t->len;
\r
586 short_tag = len<0x3f;
\r
590 { raw[0] = len|((t->id&0x3ff)<<6);
\r
591 if (write(handle,raw,2)!=2)
\r
593 #ifdef DEBUG_RFXSWF
\r
594 fprintf(stderr,"WriteTag() failed: Short Header.\n");
\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
605 #ifdef DEBUG_RFXSWF
\r
606 fprintf(stderr,"WriteTag() failed: Long Header.\n");
\r
613 { if (write(handle,t->data,t->len)!=t->len)
\r
615 #ifdef DEBUG_RFXSWF
\r
616 fprintf(stderr,"WriteTag() failed: Data.\n");
\r
621 #ifdef DEBUG_RFXSWF
\r
622 else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
\r
626 return t->len+(short_tag?2:6);
\r
629 int DefineSprite_GetRealSize(LPTAG t)
\r
630 // Sprite Handling: Helper function to pack DefineSprite-Tag
\r
631 { U32 len = t->len;
\r
634 if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
\r
636 } while (t&&(t->id!=ST_END));
\r
640 #define ReadTag(a,b) RFXSWF_ReadTag(a,b)
\r
641 #define WriteTag(a,b) RFXSWF_WriteTag(a,b)
\r
645 int ReadSWF(int handle,LPSWF swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails
\r
647 if (!swf) return -1;
\r
648 memset(swf,0x00,sizeof(SWF));
\r
650 { char b[32]; // Header lesen
\r
654 memset(&t1,0x00,sizeof(TAG));
\r
656 if ((t1.len=read(handle,b,32))<21) return -1;
\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
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
670 lseek(handle,GetTagPos(&t1)-1,SEEK_SET);
\r
672 // Tags lesen und verketten
\r
674 while (t) t = ReadTag(handle,t);
\r
675 swf->FirstTag = t1.next;
\r
676 t1.next->prev = NULL;
\r
681 int WriteSWF(int handle,LPSWF swf) // Writes SWF to file, returns length or <0 if fails
\r
685 if (!swf) return -1;
\r
687 // Insert REFLEX Tag
\r
689 #ifdef INSERT_RFX_TAG
\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
695 #endif // INSERT_RFX_TAG
\r
697 // Count Frames + File Size
\r
701 swf->FrameCount = 0;
\r
704 { len += WriteTag(-1,t);
\r
705 if (t->id==ST_SHOWFRAME) swf->FrameCount++;
\r
713 memset(&t1,0x00,sizeof(TAG));
\r
720 SetU8(&t1,swf->FileVersion);
\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
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
734 int ret = write(handle,b,l);
\r
737 #ifdef DEBUG_RFXSWF
\r
738 printf("ret:%d (fd:%d)\n",ret, handle);
\r
740 fprintf(stderr,"WriteSWF() failed: Header.\n");
\r
747 { if (WriteTag(handle,t)<0) return -1;
\r
752 return (int)swf->FileSize;
\r
755 int WriteCGI(LPSWF swf)
\r
759 len = WriteSWF(-1,swf);
\r
761 if (len<0) return -1;
\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
769 write(fileno(stdout),s,strlen(s));
\r
770 return WriteSWF(fileno(stdout),swf);
\r
773 void FreeTags(LPSWF swf) // Frees all malloc'ed memory for tags
\r
774 { LPTAG t = swf->FirstTag;
\r
777 { LPTAG tnew = t->next;
\r
778 if (t->data) free(t->data);
\r
784 // include advanced functions
\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
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