5 Library for creating and reading SWF files or parts of it.
6 There's a module directory which provides some extended functionality.
7 Most modules are included at the bottom of this file.
9 Part of the swftools package.
11 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
13 This file is distributed under the GPL, see file COPYING for details
23 #define _JPEGLIB_INCLUDED_
24 #endif // HAVE_JPEGLIB_H
25 #endif // HAVE_LIBJPEG
30 #define _ZLIB_INCLUDED_
36 #define MALLOC_SIZE 128
37 #define INSERT_RFX_TAG
39 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
42 // inline wrapper functions
44 TAG * swf_NextTag(TAG * t) { return t->next; }
45 TAG * swf_PrevTag(TAG * t) { return t->prev; }
46 int swf_GetFrameNo(TAG * t) { return t->frame; }
47 U16 swf_GetTagID(TAG * t) { return t->id; }
48 U32 swf_GetTagLen(TAG * t) { return t->len; }
49 U8* swf_GetTagLenPtr(TAG * t) { return &(t->data[t->len]); }
50 U32 swf_GetTagPos(TAG * t) { return t->pos; }
52 // Basic Data Access Functions
54 #define swf_ResetReadBits(tag) if (tag->readBit) { tag->pos++; tag->readBit = 0; }
55 #define swf_ResetWriteBits(tag) if (tag->writeBit) { tag->writeBit = 0; }
57 // for future purpose: avoid high level lib functions to change tagpos/bitpos
59 #define swf_SaveTagPos(tag)
60 #define swf_RestoreTagPos(tag)
62 void swf_SetTagPos(TAG * t,U32 pos)
63 { swf_ResetReadBits(t);
64 if (pos<=t->len) t->pos = pos;
66 else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id);
71 { swf_ResetReadBits(t);
74 { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
78 return t->data[t->pos++];
81 U16 swf_GetU16(TAG * t)
85 if (t->pos>(t->len-2))
86 { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
90 res = t->data[t->pos] | (t->data[t->pos+1]<<8);
95 U32 swf_GetU32(TAG * t)
99 if (t->pos>(t->len-4))
100 { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
104 res = t->data[t->pos] | (t->data[t->pos+1]<<8) |
105 (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);
110 int swf_GetBlock(TAG * t,U8 * b,int l)
111 // returns number of bytes written (<=l)
112 // b = NULL -> skip data
113 { swf_ResetReadBits(t);
114 if ((t->len-t->pos)<l) l=t->len-t->pos;
115 if (b && l) memcpy(b,&t->data[t->pos],l);
120 int swf_SetBlock(TAG * t,U8 * b,int l)
121 // Appends Block to the end of Tagdata, returns size
122 { U32 newlen = t->len + l;
123 swf_ResetWriteBits(t);
124 if (newlen>t->memsize)
125 { U32 newmem = MEMSIZE(newlen);
126 U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem));
130 fprintf(stderr,"Fatal Error: malloc()/realloc() failed (1). (%d bytes)\n", newmem);
137 if (b) memcpy(&t->data[t->len],b,l);
138 else memset(&t->data[t->len],0x00,l);
143 int swf_SetU8(TAG * t,U8 v)
144 { swf_ResetWriteBits(t);
145 if ((t->len+1)>t->memsize) return (swf_SetBlock(t,&v,1)==1)?0:-1;
146 t->data[t->len++] = v;
150 int swf_SetU16(TAG * t,U16 v)
155 swf_ResetWriteBits(t);
156 if ((t->len+2)>t->memsize) return (swf_SetBlock(t,a,2)==2)?0:-1;
157 t->data[t->len++] = a[0];
158 t->data[t->len++] = a[1];
162 int swf_SetU32(TAG * t,U32 v)
164 a[0] = v&0xff; // to ensure correct handling of non-intel byteorder
169 swf_ResetWriteBits(t);
170 if ((t->len+4)>t->memsize) return (swf_SetBlock(t,a,4)==4)?0:-1;
171 t->data[t->len++] = a[0];
172 t->data[t->len++] = a[1];
173 t->data[t->len++] = a[2];
174 t->data[t->len++] = a[3];
178 U32 swf_GetBits(TAG * t,int nbits)
180 if (!nbits) return 0;
181 if (!t->readBit) t->readBit = 0x80;
184 if (t->data[t->pos]&t->readBit) res|=1;
188 { if (nbits) t->readBit = 0x80;
191 { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
201 /* reader/writer stuff - from ../src/bitio.c */
204 S32 swf_GetSBits(TAG * t,int nbits)
205 { U32 res = swf_GetBits(t,nbits);
206 if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);
210 U32 reader_GetBits(struct reader_t*reader, int nbits)
211 { return reader_readbits(reader, nbits);
213 S32 reader_GetSBits(struct reader_t*reader, int nbits)
214 { U32 res = reader_readbits(reader, nbits);
215 if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);
219 int swf_SetBits(TAG * t,U32 v,int nbits)
220 { U32 bm = 1<<(nbits-1);
224 { if (FAILED(swf_SetU8(t,0))) return -1;
227 if (v&bm) t->data[t->len-1] |= t->writeBit;
235 // Advanced Data Access Functions
237 int swf_SetRGB(TAG * t,RGBA * col)
240 { swf_SetU8(t,col->r);
243 } else swf_SetBlock(t,NULL,3);
246 void swf_GetRGB(TAG * t, RGBA * col)
251 col->r = swf_GetU8(t);
252 col->g = swf_GetU8(t);
253 col->b = swf_GetU8(t);
257 int swf_SetRGBA(TAG * t,RGBA * col)
260 { swf_SetU8(t,col->r);
264 } else swf_SetBlock(t,NULL,4);
267 void swf_GetRGBA(TAG * t, RGBA * col)
272 col->r = swf_GetU8(t);
273 col->g = swf_GetU8(t);
274 col->b = swf_GetU8(t);
275 col->a = swf_GetU8(t);
278 void swf_GetGradient(TAG * tag, GRADIENT * gradient, char alpha)
284 gradient->num = swf_GetU8(tag);
285 for(t=0;t<gradient->num;t++)
290 gradient->ratios[t] = swf_GetU8(tag);
292 swf_GetRGB(tag, &gradient->rgba[t]);
294 swf_GetRGBA(tag, &gradient->rgba[t]);
298 int swf_CountBits(U32 v,int nbits)
316 return (n>nbits)?n:nbits;
319 int swf_GetRect(TAG * t,SRECT * r)
323 nbits = (int) swf_GetBits(t,5);
324 r->xmin = swf_GetSBits(t,nbits);
325 r->xmax = swf_GetSBits(t,nbits);
326 r->ymin = swf_GetSBits(t,nbits);
327 r->ymax = swf_GetSBits(t,nbits);
331 int reader_GetRect(struct reader_t*reader,SRECT * r)
335 nbits = (int) reader_GetBits(reader,5);
336 r->xmin = reader_GetSBits(reader,nbits);
337 r->xmax = reader_GetSBits(reader,nbits);
338 r->ymin = reader_GetSBits(reader,nbits);
339 r->ymax = reader_GetSBits(reader,nbits);
343 int swf_SetRect(TAG * t,SRECT * r)
346 nbits = swf_CountBits(r->xmin,0);
347 nbits = swf_CountBits(r->xmax,nbits);
348 nbits = swf_CountBits(r->ymin,nbits);
349 nbits = swf_CountBits(r->ymax,nbits);
351 swf_SetBits(t,nbits,5);
352 swf_SetBits(t,r->xmin,nbits);
353 swf_SetBits(t,r->xmax,nbits);
354 swf_SetBits(t,r->ymin,nbits);
355 swf_SetBits(t,r->ymax,nbits);
360 int swf_GetMatrix(TAG * t,MATRIX * m)
367 { m->sx = m->sy = 0x10000;
373 swf_ResetReadBits(t);
375 if (swf_GetBits(t,1))
376 { nbits = swf_GetBits(t,5);
377 m->sx = swf_GetSBits(t,nbits);
378 m->sy = swf_GetSBits(t,nbits);
380 else m->sx = m->sy = 0x10000;
382 if (swf_GetBits(t,1))
383 { nbits = swf_GetBits(t,5);
384 m->r0 = swf_GetSBits(t,nbits);
385 m->r1 = swf_GetSBits(t,nbits);
387 else m->r0 = m->r1 = 0x0;
389 nbits = swf_GetBits(t,5);
390 m->tx = swf_GetSBits(t,nbits);
391 m->ty = swf_GetSBits(t,nbits);
396 int swf_SetMatrix(TAG * t,MATRIX * m)
402 ma.sx = ma.sy = 0x10000;
407 swf_ResetWriteBits(t);
409 if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
411 { swf_SetBits(t,1,1);
412 nbits = swf_CountBits(m->sx,0);
413 nbits = swf_CountBits(m->sy,nbits);
415 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
418 swf_SetBits(t,nbits,5);
419 swf_SetBits(t,m->sx,nbits);
420 swf_SetBits(t,m->sy,nbits);
423 if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
425 { swf_SetBits(t,1,1);
426 nbits = swf_CountBits(m->r0,0);
427 nbits = swf_CountBits(m->r1,nbits);
429 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
432 swf_SetBits(t,nbits,5);
433 swf_SetBits(t,m->r0,nbits);
434 swf_SetBits(t,m->r1,nbits);
437 nbits = swf_CountBits(m->tx,0);
438 nbits = swf_CountBits(m->ty,nbits);
440 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
443 swf_SetBits(t,nbits,5);
444 swf_SetBits(t,m->tx,nbits);
445 swf_SetBits(t,m->ty,nbits);
450 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool
458 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
459 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
463 swf_ResetReadBits(t);
464 hasadd = swf_GetBits(t,1);
465 hasmul = swf_GetBits(t,1);
466 nbits = swf_GetBits(t,4);
469 { cx->r0 = (S16)swf_GetSBits(t,nbits);
470 cx->g0 = (S16)swf_GetSBits(t,nbits);
471 cx->b0 = (S16)swf_GetSBits(t,nbits);
473 cx->a0 = (S16)swf_GetSBits(t,nbits);
477 { cx->r1 = (S16)swf_GetSBits(t,nbits);
478 cx->g1 = (S16)swf_GetSBits(t,nbits);
479 cx->b1 = (S16)swf_GetSBits(t,nbits);
481 cx->a1 = (S16)swf_GetSBits(t,nbits);
487 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
495 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
496 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
506 hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
507 hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
510 { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits);
511 nbits = swf_CountBits((S32)cx->r0,nbits);
512 nbits = swf_CountBits((S32)cx->g0,nbits);
513 nbits = swf_CountBits((S32)cx->b0,nbits);
517 { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits);
518 nbits = swf_CountBits((S32)cx->r1,nbits);
519 nbits = swf_CountBits((S32)cx->g1,nbits);
520 nbits = swf_CountBits((S32)cx->b1,nbits);
523 swf_ResetWriteBits(t);
524 swf_SetBits(t,hasadd?1:0,1);
525 swf_SetBits(t,hasmul?1:0,1);
526 swf_SetBits(t,nbits,4);
529 { swf_SetBits(t,cx->r0,nbits);
530 swf_SetBits(t,cx->g0,nbits);
531 swf_SetBits(t,cx->b0,nbits);
532 if (alpha) swf_SetBits(t,cx->a0,nbits);
536 { swf_SetBits(t,cx->r1,nbits);
537 swf_SetBits(t,cx->g1,nbits);
538 swf_SetBits(t,cx->b1,nbits);
539 if (alpha) swf_SetBits(t,cx->a1,nbits);
545 int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
546 int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
548 // Tag List Manipulating Functions
550 int swf_UpdateFrame(TAG * t,S8 delta)
551 // returns number of frames
561 TAG * swf_InsertTag(TAG * after,U16 id) // updates frames, if nescessary
564 t = (TAG *)malloc(sizeof(TAG));
566 { memset(t,0x00,sizeof(TAG));
570 { t->frame = after->frame;
572 t->next = after->next;
574 if (t->next) t->next->prev = t;
576 if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1);
582 int swf_DeleteTag(TAG * t)
585 if (t->id==ST_SHOWFRAME) swf_UpdateFrame(t->next,-1);
587 if (t->prev) t->prev->next = t->next;
588 if (t->next) t->next->prev = t->prev;
590 if (t->data) free(t->data);
595 TAG * swf_ReadTag(struct reader_t*reader, TAG * prev)
601 if (reader->read(reader, &raw, 2) !=2 ) return NULL;
609 if (reader->read(reader, &len, 4) != 4) return NULL;
613 if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
614 // Sprite handling fix: Flaten sprite tree
616 t = (TAG *)malloc(sizeof(TAG));
621 fprintf(stderr,"Fatal Error: malloc()/realloc() failed (2). (%d bytes)\n", sizeof(TAG));
626 memset(t,0x00,sizeof(TAG));
632 { t->data = (U8*)malloc(t->len);
636 fprintf(stderr,"Fatal Error: malloc()/realloc() failed (3). (%d bytes)\n", t->len);
641 if (reader->read(reader, t->data, t->len) != t->len) return NULL;
645 { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0);
653 int swf_DefineSprite_GetRealSize(TAG * t);
655 int swf_WriteTag2(struct writer_t*writer, TAG * t)
656 // returns tag length in bytes (incl. Header), -1 = Error
657 // writer = 0 -> no output
664 len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len;
666 short_tag = len<0x3f;
670 { raw[0] = SWAP16(len|((t->id&0x3ff)<<6));
671 if (writer->write(writer,raw,2)!=2)
674 fprintf(stderr,"WriteTag() failed: Short Header.\n");
681 raw[0] = SWAP16((t->id<<6)|0x3f);
682 if (writer->write(writer,raw,2)!=2)
685 fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
691 if (writer->write(writer,&len,4)!=4)
694 fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
701 { if (writer->write(writer,t->data,t->len)!=t->len)
704 fprintf(stderr,"WriteTag() failed: Data.\n");
710 else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
714 return t->len+(short_tag?2:6);
717 int swf_WriteTag(int handle, TAG * t)
719 struct writer_t writer;
721 return swf_WriteTag2(0, t);
722 writer_init_filewriter(&writer, handle);
723 return swf_WriteTag2(&writer, t);
726 int swf_DefineSprite_GetRealSize(TAG * t)
727 // Sprite Handling: Helper function to pack DefineSprite-Tag
729 if(len>4) { // folded sprite
733 { t = swf_NextTag(t);
734 if (t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t);
736 } while (t&&(t->id!=ST_END));
740 void swf_FoldSprite(TAG * t)
744 if(t->id!=ST_DEFINESPRITE)
747 fprintf(stderr, "Error: Sprite has no ID!");
753 //frames = swf_GetU16(t);
755 t->len = t->pos = t->memsize = 0;
762 if(t->id==ST_SHOWFRAME) frames++;
764 } while(t&&t!=ST_END);
766 t = swf_NextTag(sprtag);
767 swf_SetU16(sprtag, id);
768 swf_SetU16(sprtag, frames);
774 swf_SetU16(sprtag,t->len|(t->id<<6));
776 swf_SetU16(sprtag,0x3f|(t->id<<6));
777 swf_SetU32(sprtag,t->len);
780 swf_SetBlock(sprtag,t->data, t->len);
785 while (t&&(tmpid!=ST_END));
791 void swf_FoldAll(SWF*swf)
793 TAG*tag = swf->firstTag;
795 if(tag->id == ST_DEFINESPRITE)
797 tag = swf_NextTag(tag);
803 int swf_ReadSWF2(struct reader_t*reader2, SWF * swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails
806 memset(swf,0x00,sizeof(SWF));
808 { char b[32]; // read Header
812 struct reader_t zreader;
813 struct reader_t* reader;
815 if ((len = reader->read(reader ,b,8))<8) return -1;
817 if (b[0]!='F' && b[0]!='C') return -1;
818 if (b[1]!='W') return -1;
819 if (b[2]!='S') return -1;
820 swf->fileVersion = b[3];
821 swf->compressed = (b[0]=='C')?1:0;
822 swf->fileSize = GET32(&b[4]);
824 /* TODO: start decompression here */
825 if(swf->compressed) {
826 reader_init_zlibinflate(&zreader, reader2);
832 reader_GetRect(reader, &swf->movieSize);
833 reader->read(reader, &swf->frameRate, 2);
834 swf->frameRate = SWAP16(swf->frameRate);
835 reader->read(reader, &swf->frameCount, 2);
836 swf->frameCount = SWAP16(swf->frameCount);
838 /* read tags and connect to list */
840 while (t) t = swf_ReadTag(reader,t);
841 swf->firstTag = t1.next;
842 t1.next->prev = NULL;
848 int swf_ReadSWF(int handle, SWF * swf)
850 struct reader_t reader;
851 reader_init_filereader(&reader, handle);
852 return swf_ReadSWF2(&reader, swf);
855 int swf_WriteSWF2(struct writer_t*writer, SWF * swf) // Writes SWF to file, returns length or <0 if fails
863 #ifdef INSERT_RFX_TAG
865 if (swf->firstTag && swf_NextTag(swf->firstTag))
866 if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX)
867 swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3);
869 #endif // INSERT_RFX_TAG
871 // Count Frames + File Size
878 { len += swf_WriteTag(-1, t);
879 if (t->id==ST_SHOWFRAME) swf->frameCount++;
887 memset(&t1,0x00,sizeof(TAG));
894 swf_SetU8(&t1,swf->fileVersion);
896 swf_SetU32(&t1,swf->fileSize); // Keep space for filesize
897 swf_SetRect(&t1,&swf->movieSize);
898 swf_SetU16(&t1,swf->frameRate);
899 swf_SetU16(&t1,swf->frameCount);
901 l = swf_GetTagLen(&t1);
902 swf->fileSize = l+len;
904 t1.len = 4; // bad & ugly trick !
905 swf_SetU32(&t1,swf->fileSize);
910 int ret = writer->write(writer,b,l);
914 printf("ret:%d\n",ret);
916 fprintf(stderr,"WriteSWF() failed: Header.\n");
923 { if (swf_WriteTag2(writer, t)<0) return -1;
928 return (int)swf->fileSize;
931 int swf_WriteSWF(int handle, SWF * swf) // Writes SWF to file, returns length or <0 if fails
933 struct writer_t writer;
935 return swf_WriteSWF2(&writer, swf);
936 writer_init_filewriter(&writer, handle);
937 return swf_WriteSWF2(&writer, swf);
940 int swf_WriteHeader(int handle,SWF * swf)
943 memcpy(&myswf,swf,sizeof(SWF));
945 swf_WriteSWF(handle, &myswf);
949 int swf_WriteCGI(SWF * swf)
953 len = swf_WriteSWF(-1,swf);
955 if (len<0) return -1;
957 sprintf(s,"Content-type: application/x-shockwave-flash\n"
958 "Accept-Ranges: bytes\n"
959 "Content-Length: %lu\n"
960 "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
963 write(fileno(stdout),s,strlen(s));
964 return swf_WriteSWF(fileno(stdout),swf);
967 void swf_FreeTags(SWF * swf) // Frees all malloc'ed memory for tags
968 { TAG * t = swf->firstTag;
971 { TAG * tnew = t->next;
972 if (t->data) free(t->data);
978 // include advanced functions
980 #include "modules/swfdump.c"
981 #include "modules/swfshape.c"
982 #include "modules/swftext.c"
983 #include "modules/swfobject.c"
984 #include "modules/swfbutton.c"
985 #include "modules/swftools.c"
986 #include "modules/swfcgi.c"
987 #include "modules/swfbits.c"
988 #include "modules/swfaction.c"
989 #include "modules/swfsound.c"