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);
242 void swf_GetRGB(TAG * t, RGBA * col)
247 col->r = swf_GetU8(t);
248 col->g = swf_GetU8(t);
249 col->b = swf_GetU8(t);
253 int swf_SetRGBA(TAG * t,RGBA * col)
256 { swf_SetU8(t,col->r);
260 } else swf_SetBlock(t,NULL,4);
263 void swf_GetRGBA(TAG * t, RGBA * col)
268 col->r = swf_GetU8(t);
269 col->g = swf_GetU8(t);
270 col->b = swf_GetU8(t);
271 col->a = swf_GetU8(t);
274 void swf_GetGradient(TAG * tag, GRADIENT * gradient, char alpha)
280 gradient->num = swf_GetU8(tag);
281 for(t=0;t<gradient->num;t++)
286 gradient->ratios[t] = swf_GetU8(tag);
288 swf_GetRGB(tag, &gradient->rgba[t]);
290 swf_GetRGBA(tag, &gradient->rgba[t]);
294 int swf_CountBits(U32 v,int nbits)
312 return (n>nbits)?n:nbits;
315 int swf_GetRect(TAG * t,SRECT * r)
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);
327 int swf_SetRect(TAG * t,SRECT * r)
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);
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);
344 int swf_GetMatrix(TAG * t,MATRIX * m)
351 { m->sx = m->sy = 0x10000;
357 swf_ResetReadBits(t);
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);
364 else m->sx = m->sy = 0x10000;
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);
371 else m->r0 = m->r1 = 0x0;
373 nbits = swf_GetBits(t,5);
374 m->tx = swf_GetSBits(t,nbits);
375 m->ty = swf_GetSBits(t,nbits);
380 int swf_SetMatrix(TAG * t,MATRIX * m)
386 ma.sx = ma.sy = 0x10000;
391 swf_ResetWriteBits(t);
393 if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
395 { swf_SetBits(t,1,1);
396 nbits = swf_CountBits(m->sx,0);
397 nbits = swf_CountBits(m->sy,nbits);
399 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
402 swf_SetBits(t,nbits,5);
403 swf_SetBits(t,m->sx,nbits);
404 swf_SetBits(t,m->sy,nbits);
407 if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
409 { swf_SetBits(t,1,1);
410 nbits = swf_CountBits(m->r0,0);
411 nbits = swf_CountBits(m->r1,nbits);
413 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
416 swf_SetBits(t,nbits,5);
417 swf_SetBits(t,m->r0,nbits);
418 swf_SetBits(t,m->r1,nbits);
421 nbits = swf_CountBits(m->tx,0);
422 nbits = swf_CountBits(m->ty,nbits);
424 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
427 swf_SetBits(t,nbits,5);
428 swf_SetBits(t,m->tx,nbits);
429 swf_SetBits(t,m->ty,nbits);
434 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool
442 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
443 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
447 swf_ResetReadBits(t);
448 hasadd = swf_GetBits(t,1);
449 hasmul = swf_GetBits(t,1);
450 nbits = swf_GetBits(t,4);
453 { cx->r0 = (S16)swf_GetSBits(t,nbits);
454 cx->g0 = (S16)swf_GetSBits(t,nbits);
455 cx->b0 = (S16)swf_GetSBits(t,nbits);
457 cx->a0 = (S16)swf_GetSBits(t,nbits);
461 { cx->r1 = (S16)swf_GetSBits(t,nbits);
462 cx->g1 = (S16)swf_GetSBits(t,nbits);
463 cx->b1 = (S16)swf_GetSBits(t,nbits);
465 cx->a1 = (S16)swf_GetSBits(t,nbits);
471 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
479 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
480 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
490 hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
491 hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
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);
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);
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);
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);
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);
529 int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
530 int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
532 // Tag List Manipulating Functions
534 int RFXSWF_UpdateFrame(TAG * t,S8 delta)
535 // returns number of frames
545 #define swf_UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)
547 TAG * swf_InsertTag(TAG * after,U16 id) // updates frames, if nescessary
550 t = (TAG *)malloc(sizeof(TAG));
552 { memset(t,0x00,sizeof(TAG));
556 { t->frame = after->frame;
558 t->next = after->next;
560 if (t->next) t->next->prev = t;
562 if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1);
568 int swf_DeleteTag(TAG * t)
571 if (t->id==ST_SHOWFRAME) swf_UpdateFrame(t->next,-1);
573 if (t->prev) t->prev->next = t->next;
574 if (t->next) t->next->prev = t->prev;
576 if (t->data) free(t->data);
581 TAG * RFXSWF_ReadTag(int handle,TAG * prev)
587 if (read(handle,&raw,2)!=2) return NULL;
595 if (read(handle,&len,4)!=4) return NULL;
599 if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
600 // Sprite handling fix: Flaten sprite tree
602 t = (TAG *)malloc(sizeof(TAG));
607 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
612 memset(t,0x00,sizeof(TAG));
618 { t->data = (U8*)malloc(t->len);
622 fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
627 if (read(handle,t->data,t->len)!=t->len) return NULL;
631 { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
639 int RFXSWF_DefineSprite_GetRealSize(TAG * t);
641 int RFXSWF_WriteTag(int handle,TAG * t)
642 // returns tag length in bytes (incl. Header), -1 = Error
643 // handle = -1 -> no output
650 len = (t->id==ST_DEFINESPRITE)?RFXSWF_DefineSprite_GetRealSize(t):t->len;
652 short_tag = len<0x3f;
656 { raw[0] = SWAP16(len|((t->id&0x3ff)<<6));
657 if (write(handle,raw,2)!=2)
660 fprintf(stderr,"WriteTag() failed: Short Header.\n");
667 raw[0] = SWAP16((t->id<<6)|0x3f);
668 if (write(handle,raw,2)!=2)
671 fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
677 if (write(handle,&len,4)!=4)
680 fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
687 { if (write(handle,t->data,t->len)!=t->len)
690 fprintf(stderr,"WriteTag() failed: Data.\n");
696 else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
700 return t->len+(short_tag?2:6);
703 int swf_WriteTag(int handle,TAG * t)
705 return RFXSWF_WriteTag(handle, t);
708 int RFXSWF_DefineSprite_GetRealSize(TAG * t)
709 // Sprite Handling: Helper function to pack DefineSprite-Tag
711 if(len>4) { // folded sprite
715 { t = swf_NextTag(t);
716 if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
718 } while (t&&(t->id!=ST_END));
722 void swf_FoldSprite(TAG * t)
726 if(t->id!=ST_DEFINESPRITE)
729 fprintf(stderr, "Error: Sprite has no ID!");
735 //frames = swf_GetU16(t);
737 t->len = t->pos = t->memsize = 0;
744 if(t->id==ST_SHOWFRAME) frames++;
746 } while(t&&t!=ST_END);
748 t = swf_NextTag(sprtag);
749 swf_SetU16(sprtag, id);
750 swf_SetU16(sprtag, frames);
756 swf_SetU16(sprtag,t->len|(t->id<<6));
758 swf_SetU16(sprtag,0x3f|(t->id<<6));
759 swf_SetU32(sprtag,t->len);
762 swf_SetBlock(sprtag,t->data, t->len);
767 while (t&&(tmpid!=ST_END));
773 void swf_FoldAll(SWF*swf)
775 TAG*tag = swf->firstTag;
777 if(tag->id == ST_DEFINESPRITE)
779 tag = swf_NextTag(tag);
783 #define swf_ReadTag(a,b) RFXSWF_ReadTag(a,b)
784 #define swf_WriteTag(a,b) RFXSWF_WriteTag(a,b)
788 int swf_InitSWF(void*data, int length, SWF * swf) /* copy a swf in memory into SWF struct */
796 memset(swf,0x00,sizeof(SWF));
797 memset(&reader,0x00,sizeof(TAG));
799 reader.len = reader.memsize = length;
801 { char b[32]; // read Header
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;
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);
815 while (t) t = swf_ReadTag(handle,t);
816 swf->firstTag = t1.next;
817 t1.next->prev = NULL;*/
822 int swf_ReadSWF(int handle,SWF * swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails
825 memset(swf,0x00,sizeof(SWF));
827 { char b[32]; // read Header
831 memset(&t1,0x00,sizeof(TAG));
833 if ((t1.len=read(handle,b,32))<21) return -1;
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;
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);
847 lseek(handle,swf_GetTagPos(&t1)-1,SEEK_SET);
849 // reda tags and connect to list
851 while (t) t = swf_ReadTag(handle,t);
852 swf->firstTag = t1.next;
853 t1.next->prev = NULL;
859 int swf_WriteSWF(int handle,SWF * swf) // Writes SWF to file, returns length or <0 if fails
867 #ifdef INSERT_RFX_TAG
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);
873 #endif // INSERT_RFX_TAG
875 // Count Frames + File Size
882 { len += swf_WriteTag(-1,t);
883 if (t->id==ST_SHOWFRAME) swf->frameCount++;
891 memset(&t1,0x00,sizeof(TAG));
898 swf_SetU8(&t1,swf->fileVersion);
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);
905 l = swf_GetTagLen(&t1);
906 swf->fileSize = l+len;
908 t1.len = 4; // bad & ugly trick !
909 swf_SetU32(&t1,swf->fileSize);
914 int ret = write(handle,b,l);
918 printf("ret:%d (fd:%d)\n",ret, handle);
920 fprintf(stderr,"WriteSWF() failed: Header.\n");
927 { if (swf_WriteTag(handle,t)<0) return -1;
932 return (int)swf->fileSize;
935 int swf_WriteHeader(int handle,SWF * swf)
938 memcpy(&myswf,swf,sizeof(SWF));
940 swf_WriteSWF(handle, &myswf);
944 int swf_WriteCGI(SWF * swf)
948 len = swf_WriteSWF(-1,swf);
950 if (len<0) return -1;
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"
958 write(fileno(stdout),s,strlen(s));
959 return swf_WriteSWF(fileno(stdout),swf);
962 void swf_FreeTags(SWF * swf) // Frees all malloc'ed memory for tags
963 { TAG * t = swf->firstTag;
966 { TAG * tnew = t->next;
967 if (t->data) free(t->data);
973 // include advanced functions
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"
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"