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.
7 Part of the swftools package.
9 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
11 This file is distributed under the GPL, see file COPYING for details
21 #define _JPEGLIB_INCLUDED_
22 #endif // HAVE_JPEGLIB_H
23 #endif // HAVE_LIBJPEG
28 #define _ZLIB_INCLUDED_
32 // Win32 support may be broken since it was only tested in an older version for Watcom C
45 #define MALLOC_SIZE 128
46 #define INSERT_RFX_TAG
48 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
50 // inline wrapper functions
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; }
60 // Basic Data Access Functions
62 #define swf_ResetReadBits(tag) if (tag->readBit) { tag->pos++; tag->readBit = 0; }
63 #define swf_ResetWriteBits(tag) if (tag->writeBit) { tag->writeBit = 0; }
65 // for future purpose: avoid high level lib functions to change tagpos/bitpos
67 #define swf_SaveTagPos(tag)
68 #define swf_RestoreTagPos(tag)
70 void swf_SetTagPos(TAG * t,U32 pos)
71 { swf_ResetReadBits(t);
72 if (pos<=t->len) t->pos = pos;
74 else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
79 { swf_ResetReadBits(t);
82 { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
86 return t->data[t->pos++];
89 U16 swf_GetU16(TAG * t)
93 if (t->pos>(t->len-2))
94 { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
98 res = t->data[t->pos] | (t->data[t->pos+1]<<8);
103 U32 swf_GetU32(TAG * t)
105 swf_ResetReadBits(t);
107 if (t->pos>(t->len-4))
108 { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
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);
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);
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));
138 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
145 if (b) memcpy(&t->data[t->len],b,l);
146 else memset(&t->data[t->len],0x00,l);
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;
158 int swf_SetU16(TAG * t,U16 v)
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];
170 int swf_SetU32(TAG * t,U32 v)
172 a[0] = v&0xff; // to ensure correct handling of non-intel byteorder
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];
186 U32 swf_GetBits(TAG * t,int nbits)
188 if (!nbits) return 0;
189 if (!t->readBit) t->readBit = 0x80;
192 if (t->data[t->pos]&t->readBit) res|=1;
196 { if (nbits) t->readBit = 0x80;
199 { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
209 S32 swf_GetSBits(TAG * t,int nbits)
210 { U32 res = swf_GetBits(t,nbits);
211 if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);
215 int swf_SetBits(TAG * t,U32 v,int nbits)
216 { U32 bm = 1<<(nbits-1);
220 { if (FAILED(swf_SetU8(t,0))) return -1;
223 if (v&bm) t->data[t->len-1] |= t->writeBit;
231 // Advanced Data Access Functions
233 int swf_SetRGB(TAG * t,RGBA * col)
236 { swf_SetU8(t,col->r);
239 } else swf_SetBlock(t,NULL,3);
243 int swf_SetRGBA(TAG * t,RGBA * col)
246 { swf_SetU8(t,col->r);
250 } else swf_SetBlock(t,NULL,4);
254 int swf_CountBits(U32 v,int nbits)
272 return (n>nbits)?n:nbits;
275 int swf_GetRect(TAG * t,SRECT * r)
279 nbits = (int) swf_GetBits(t,5);
280 r->xmin = swf_GetSBits(t,nbits);
281 r->xmax = swf_GetSBits(t,nbits);
282 r->ymin = swf_GetSBits(t,nbits);
283 r->ymax = swf_GetSBits(t,nbits);
287 int swf_SetRect(TAG * t,SRECT * r)
290 nbits = swf_CountBits(r->xmin,0);
291 nbits = swf_CountBits(r->xmax,nbits);
292 nbits = swf_CountBits(r->ymin,nbits);
293 nbits = swf_CountBits(r->ymax,nbits);
295 swf_SetBits(t,nbits,5);
296 swf_SetBits(t,r->xmin,nbits);
297 swf_SetBits(t,r->xmax,nbits);
298 swf_SetBits(t,r->ymin,nbits);
299 swf_SetBits(t,r->ymax,nbits);
304 int swf_GetMatrix(TAG * t,MATRIX * m)
311 { m->sx = m->sy = 0x10000;
317 swf_ResetReadBits(t);
319 if (swf_GetBits(t,1))
320 { nbits = swf_GetBits(t,5);
321 m->sx = swf_GetSBits(t,nbits);
322 m->sy = swf_GetSBits(t,nbits);
324 else m->sx = m->sy = 0x10000;
326 if (swf_GetBits(t,1))
327 { nbits = swf_GetBits(t,5);
328 m->r0 = swf_GetSBits(t,nbits);
329 m->r1 = swf_GetSBits(t,nbits);
331 else m->r0 = m->r1 = 0x0;
333 nbits = swf_GetBits(t,5);
334 m->tx = swf_GetSBits(t,nbits);
335 m->ty = swf_GetSBits(t,nbits);
340 int swf_SetMatrix(TAG * t,MATRIX * m)
346 ma.sx = ma.sy = 0x10000;
351 swf_ResetWriteBits(t);
353 if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
355 { swf_SetBits(t,1,1);
356 nbits = swf_CountBits(m->sx,0);
357 nbits = swf_CountBits(m->sy,nbits);
359 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
362 swf_SetBits(t,nbits,5);
363 swf_SetBits(t,m->sx,nbits);
364 swf_SetBits(t,m->sy,nbits);
367 if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
369 { swf_SetBits(t,1,1);
370 nbits = swf_CountBits(m->r0,0);
371 nbits = swf_CountBits(m->r1,nbits);
373 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
376 swf_SetBits(t,nbits,5);
377 swf_SetBits(t,m->r0,nbits);
378 swf_SetBits(t,m->r1,nbits);
381 nbits = swf_CountBits(m->tx,0);
382 nbits = swf_CountBits(m->ty,nbits);
384 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
387 swf_SetBits(t,nbits,5);
388 swf_SetBits(t,m->tx,nbits);
389 swf_SetBits(t,m->ty,nbits);
394 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool
402 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
403 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
407 swf_ResetReadBits(t);
408 hasadd = swf_GetBits(t,1);
409 hasmul = swf_GetBits(t,1);
410 nbits = swf_GetBits(t,4);
413 { cx->r0 = (S16)swf_GetSBits(t,nbits);
414 cx->g0 = (S16)swf_GetSBits(t,nbits);
415 cx->b0 = (S16)swf_GetSBits(t,nbits);
417 cx->a0 = (S16)swf_GetSBits(t,nbits);
421 { cx->r1 = (S16)swf_GetSBits(t,nbits);
422 cx->g1 = (S16)swf_GetSBits(t,nbits);
423 cx->b1 = (S16)swf_GetSBits(t,nbits);
425 cx->a1 = (S16)swf_GetSBits(t,nbits);
431 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
439 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
440 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
450 hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
451 hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
454 { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits);
455 nbits = swf_CountBits((S32)cx->r0,nbits);
456 nbits = swf_CountBits((S32)cx->g0,nbits);
457 nbits = swf_CountBits((S32)cx->b0,nbits);
461 { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits);
462 nbits = swf_CountBits((S32)cx->r1,nbits);
463 nbits = swf_CountBits((S32)cx->g1,nbits);
464 nbits = swf_CountBits((S32)cx->b1,nbits);
467 swf_ResetWriteBits(t);
468 swf_SetBits(t,hasadd?1:0,1);
469 swf_SetBits(t,hasmul?1:0,1);
470 swf_SetBits(t,nbits,4);
473 { swf_SetBits(t,cx->r0,nbits);
474 swf_SetBits(t,cx->g0,nbits);
475 swf_SetBits(t,cx->b0,nbits);
476 if (alpha) swf_SetBits(t,cx->a0,nbits);
480 { swf_SetBits(t,cx->r1,nbits);
481 swf_SetBits(t,cx->g1,nbits);
482 swf_SetBits(t,cx->b1,nbits);
483 if (alpha) swf_SetBits(t,cx->a1,nbits);
489 int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
490 int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
492 // Tag List Manipulating Functions
494 int RFXSWF_UpdateFrame(TAG * t,S8 delta)
495 // returns number of frames
505 #define swf_UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)
507 TAG * swf_InsertTag(TAG * after,U16 id) // updates frames, if nescessary
510 t = (TAG *)malloc(sizeof(TAG));
512 { memset(t,0x00,sizeof(TAG));
516 { t->frame = after->frame;
518 t->next = after->next;
520 if (t->next) t->next->prev = t;
522 if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1);
528 int swf_DeleteTag(TAG * t)
531 if (t->id==ST_SHOWFRAME) swf_UpdateFrame(t->next,-1);
533 if (t->prev) t->prev->next = t->next;
534 if (t->next) t->next->prev = t->prev;
536 if (t->data) free(t->data);
541 TAG * RFXSWF_ReadTag(int handle,TAG * prev)
547 if (read(handle,&raw,2)!=2) return NULL;
555 if (read(handle,&len,4)!=4) return NULL;
559 if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
560 // Sprite handling fix: Flaten sprite tree
562 t = (TAG *)malloc(sizeof(TAG));
567 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
572 memset(t,0x00,sizeof(TAG));
578 { t->data = (U8*)malloc(t->len);
582 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
587 if (read(handle,t->data,t->len)!=t->len) return NULL;
591 { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
599 int RFXSWF_DefineSprite_GetRealSize(TAG * t);
601 int RFXSWF_WriteTag(int handle,TAG * t)
602 // returns tag length in bytes (incl. Header), -1 = Error
603 // handle = -1 -> no output
610 len = (t->id==ST_DEFINESPRITE)?RFXSWF_DefineSprite_GetRealSize(t):t->len;
612 short_tag = len<0x3f;
616 { raw[0] = SWAP16(len|((t->id&0x3ff)<<6));
617 if (write(handle,raw,2)!=2)
620 fprintf(stderr,"WriteTag() failed: Short Header.\n");
627 raw[0] = SWAP16((t->id<<6)|0x3f);
628 if (write(handle,raw,2)!=2)
631 fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
637 if (write(handle,&len,4)!=4)
640 fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
647 { if (write(handle,t->data,t->len)!=t->len)
650 fprintf(stderr,"WriteTag() failed: Data.\n");
656 else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
660 return t->len+(short_tag?2:6);
663 int swf_WriteTag(int handle,TAG * t)
665 return RFXSWF_WriteTag(handle, t);
668 int RFXSWF_DefineSprite_GetRealSize(TAG * t)
669 // Sprite Handling: Helper function to pack DefineSprite-Tag
671 if(len>4) { // folded sprite
675 { t = swf_NextTag(t);
676 if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
678 } while (t&&(t->id!=ST_END));
682 void swf_FoldSprite(TAG * t)
686 if(t->id!=ST_DEFINESPRITE)
689 fprintf(stderr, "Error: Sprite has no ID!");
695 //frames = swf_GetU16(t);
697 t->len = t->pos = t->memsize = 0;
704 if(t->id==ST_SHOWFRAME) frames++;
706 } while(t&&t!=ST_END);
708 t = swf_NextTag(sprtag);
709 swf_SetU16(sprtag, id);
710 swf_SetU16(sprtag, frames);
716 swf_SetU16(sprtag,t->len|(t->id<<6));
718 swf_SetU16(sprtag,0x3f|(t->id<<6));
719 swf_SetU32(sprtag,t->len);
722 swf_SetBlock(sprtag,t->data, t->len);
727 while (t&&(tmpid!=ST_END));
733 void swf_FoldAll(SWF*swf)
735 TAG*tag = swf->firstTag;
737 if(tag->id == ST_DEFINESPRITE)
739 tag = swf_NextTag(tag);
743 #define swf_ReadTag(a,b) RFXSWF_ReadTag(a,b)
744 #define swf_WriteTag(a,b) RFXSWF_WriteTag(a,b)
748 int swf_InitSWF(void*data, int length, SWF * swf) /* copy a swf in memory into SWF struct */
756 memset(swf,0x00,sizeof(SWF));
757 memset(&reader,0x00,sizeof(TAG));
759 reader.len = reader.memsize = length;
761 { char b[32]; // read Header
764 if (swf_GetU8(&reader)!=(U8)'F') return -1;
765 if (swf_GetU8(&reader)!=(U8)'W') return -1;
766 if (swf_GetU8(&reader)!=(U8)'S') return -1;
768 swf->fileVersion = swf_GetU8(&reader);
769 swf->fileSize = swf_GetU32(&reader);
770 swf_GetRect(&reader,&swf->movieSize);
771 swf->frameRate = swf_GetU16(&reader);
772 swf->frameCount = swf_GetU16(&reader);
775 while (t) t = swf_ReadTag(handle,t);
776 swf->firstTag = t1.next;
777 t1.next->prev = NULL;*/
782 int swf_ReadSWF(int handle,SWF * swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails
785 memset(swf,0x00,sizeof(SWF));
787 { char b[32]; // read Header
791 memset(&t1,0x00,sizeof(TAG));
793 if ((t1.len=read(handle,b,32))<21) return -1;
796 if (swf_GetU8(&t1)!=(U8)'F') return -1;
797 if (swf_GetU8(&t1)!=(U8)'W') return -1;
798 if (swf_GetU8(&t1)!=(U8)'S') return -1;
800 swf->fileVersion = swf_GetU8(&t1);
801 swf->fileSize = swf_GetU32(&t1);
802 swf_GetRect(&t1,&swf->movieSize);
803 swf->frameRate = swf_GetU16(&t1);
804 swf->frameCount = swf_GetU16(&t1);
807 lseek(handle,swf_GetTagPos(&t1)-1,SEEK_SET);
809 // reda tags and connect to list
811 while (t) t = swf_ReadTag(handle,t);
812 swf->firstTag = t1.next;
813 t1.next->prev = NULL;
819 int swf_WriteSWF(int handle,SWF * swf) // Writes SWF to file, returns length or <0 if fails
827 #ifdef INSERT_RFX_TAG
829 if (swf->firstTag && swf_NextTag(swf->firstTag))
830 if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
831 swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
833 #endif // INSERT_RFX_TAG
835 // Count Frames + File Size
842 { len += swf_WriteTag(-1,t);
843 if (t->id==ST_SHOWFRAME) swf->frameCount++;
851 memset(&t1,0x00,sizeof(TAG));
858 swf_SetU8(&t1,swf->fileVersion);
860 swf_SetU32(&t1,swf->fileSize); // Keep space for filesize
861 swf_SetRect(&t1,&swf->movieSize);
862 swf_SetU16(&t1,swf->frameRate);
863 swf_SetU16(&t1,swf->frameCount);
865 l = swf_GetTagLen(&t1);
866 swf->fileSize = l+len;
868 t1.len = 4; // bad & ugly trick !
869 swf_SetU32(&t1,swf->fileSize);
874 int ret = write(handle,b,l);
878 printf("ret:%d (fd:%d)\n",ret, handle);
880 fprintf(stderr,"WriteSWF() failed: Header.\n");
887 { if (swf_WriteTag(handle,t)<0) return -1;
892 return (int)swf->fileSize;
895 int swf_WriteHeader(int handle,SWF * swf)
898 memcpy(&myswf,swf,sizeof(SWF));
900 swf_WriteSWF(handle, &myswf);
904 int swf_WriteCGI(SWF * swf)
908 len = swf_WriteSWF(-1,swf);
910 if (len<0) return -1;
912 sprintf(s,"Content-type: application/x-shockwave-flash\n"
913 "Accept-Ranges: bytes\n"
914 "Content-Length: %lu\n"
915 "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
918 write(fileno(stdout),s,strlen(s));
919 return swf_WriteSWF(fileno(stdout),swf);
922 void swf_FreeTags(SWF * swf) // Frees all malloc'ed memory for tags
923 { TAG * t = swf->firstTag;
926 { TAG * tnew = t->next;
927 if (t->data) free(t->data);
933 // include advanced functions
937 #include "modules\swfdump.c"
938 #include "modules\swfshape.c"
939 #include "modules\swftext.c"
940 #include "modules\swfobject.c"
941 #include "modules\swfbutton.c"
942 #include "modules\swftools.c"
943 #include "modules\swfcgi.c"
944 #include "modules\swfbits.c"
945 #include "modules\swfaction.c"
946 #include "modules\swfsound.c"
950 #include "modules/swfdump.c"
951 #include "modules/swfshape.c"
952 #include "modules/swftext.c"
953 #include "modules/swfobject.c"
954 #include "modules/swfbutton.c"
955 #include "modules/swftools.c"
956 #include "modules/swfcgi.c"
957 #include "modules/swfbits.c"
958 #include "modules/swfaction.c"
959 #include "modules/swfsound.c"