fix crashes reported by Debian Cylab Mayhem Team
[swftools.git] / lib / rfxswf.c
blob41988db08d8666fe4c4e61a7b8bca44729a06e99
1 /* vi: set sts=2 sw=2 :*/
2 /* rfxswf.c
4 Library for creating and reading SWF files or parts of it.
5 There's a module directory which provides some extended functionality.
6 Most modules are included at the bottom of this file.
8 Part of the swftools package.
10 Copyright (c) 2000-2003 Rainer Böhme <rfxswf@reflex-studio.de>
11 Copyright (c) 2003 Matthias Kramm <kramm@quiss.org>
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
27 #include "mem.h"
28 #include "rfxswf.h"
29 #ifdef HAVE_ZLIB
30 #include <zlib.h>
31 #endif // HAVE_ZLIB
33 #ifndef RFXSWF_DISABLESOUND
34 #ifdef HAVE_LAME
35 #include "lame/lame.h"
36 #endif
37 #endif
39 #ifdef HAVE_TIME_H
40 #include <time.h>
41 #endif
43 #ifdef HAVE_IO_H
44 #include <io.h>
45 #endif
47 #include "./bitio.h"
48 #include "./os.h"
50 // internal constants
52 #define MALLOC_SIZE 128
53 #define INSERT_RFX_TAG
55 #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE)
57 // inline wrapper functions
59 TAG * swf_NextTag(TAG * t) { return t->next; }
60 TAG * swf_PrevTag(TAG * t) { return t->prev; }
61 U16 swf_GetTagID(TAG * t) { return t->id; }
62 U32 swf_GetTagLen(TAG * t) { return t->len; }
63 U8* swf_GetTagLenPtr(TAG * t) { return &(t->data[t->len]); }
64 U32 swf_GetTagPos(TAG * t) { return t->pos; }
66 void swf_SetTagPos(TAG * t,U32 pos)
67 { swf_ResetReadBits(t);
68 if (pos<=t->len) t->pos = pos;
69 else {
70 #ifdef DEBUG_RFXSWF
71 fprintf(stderr,"SetTagPos(%d) out of bounds: TagID = %i\n",pos, t->id);
72 #endif
76 char* swf_GetString(TAG*t)
78 int pos = t->pos;
79 while(t->pos < t->len && swf_GetU8(t));
80 /* make sure we always have a trailing zero byte */
81 if(t->pos == t->len) {
82 if(t->len == t->memsize) {
83 swf_ResetWriteBits(t);
84 swf_SetU8(t, 0);
85 t->len = t->pos;
87 t->data[t->len] = 0;
89 return (char*)&(t->data[pos]);
92 U8 swf_GetU8(TAG * t)
93 { swf_ResetReadBits(t);
94 #ifdef DEBUG_RFXSWF
95 if ((int)t->pos>=(int)t->len)
96 { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
97 return 0;
99 #endif
100 return t->data[t->pos++];
103 U16 swf_GetU16(TAG * t)
104 { U16 res;
105 swf_ResetReadBits(t);
106 #ifdef DEBUG_RFXSWF
107 if ((int)t->pos>((int)t->len-2))
108 { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
109 return 0;
111 #endif
112 res = t->data[t->pos] | (t->data[t->pos+1]<<8);
113 t->pos+=2;
114 return res;
117 U32 swf_GetU32(TAG * t)
118 { U32 res;
119 swf_ResetReadBits(t);
120 #ifdef DEBUG_RFXSWF
121 if ((int)t->pos>((int)t->len-4))
122 { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
123 return 0;
125 #endif
126 res = t->data[t->pos] | (t->data[t->pos+1]<<8) |
127 (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24);
128 t->pos+=4;
129 return res;
132 int swf_GetBlock(TAG * t,U8 * b,int l)
133 // returns number of bytes written (<=l)
134 // b = NULL -> skip data
135 { swf_ResetReadBits(t);
136 if ((t->len-t->pos)<l) l=t->len-t->pos;
137 if (b && l) memcpy(b,&t->data[t->pos],l);
138 t->pos+=l;
139 return l;
142 int swf_SetBlock(TAG * t,const U8 * b,int l)
143 // Appends Block to the end of Tagdata, returns size
144 { U32 newlen = t->len + l;
145 swf_ResetWriteBits(t);
146 if (newlen>t->memsize)
147 { U32 newmem = MEMSIZE(newlen);
148 U8 * newdata = (U8*)(rfx_realloc(t->data,newmem));
149 t->memsize = newmem;
150 t->data = newdata;
152 if (b) memcpy(&t->data[t->len],b,l);
153 else memset(&t->data[t->len],0x00,l);
154 t->len+=l;
155 return l;
158 int swf_SetU8(TAG * t,U8 v)
159 { swf_ResetWriteBits(t);
160 if ((t->len+1)>t->memsize) return (swf_SetBlock(t,&v,1)==1)?0:-1;
161 t->data[t->len++] = v;
162 return 0;
165 int swf_SetU16(TAG * t,U16 v)
166 { U8 a[2];
167 a[0] = v&0xff;
168 a[1] = v>>8;
170 swf_ResetWriteBits(t);
171 if ((t->len+2)>t->memsize) return (swf_SetBlock(t,a,2)==2)?0:-1;
172 t->data[t->len++] = a[0];
173 t->data[t->len++] = a[1];
174 return 0;
176 void swf_SetS16(TAG * t,int v)
178 if(v>32767 || v<-32768) {
179 #ifdef DEBUG_RFXSWF
180 fprintf(stderr, "Warning: S16 overflow: %d\n", v);
181 #endif
183 swf_SetU16(t, (S16)v);
186 int swf_SetU32(TAG * t,U32 v)
187 { U8 a[4];
188 a[0] = v&0xff; // to ensure correct handling of non-intel byteorder
189 a[1] = (v>>8)&0xff;
190 a[2] = (v>>16)&0xff;
191 a[3] = (v>>24)&0xff;
193 swf_ResetWriteBits(t);
194 if ((t->len+4)>t->memsize) return (swf_SetBlock(t,a,4)==4)?0:-1;
195 t->data[t->len++] = a[0];
196 t->data[t->len++] = a[1];
197 t->data[t->len++] = a[2];
198 t->data[t->len++] = a[3];
199 return 0;
202 U32 swf_GetBits(TAG * t,int nbits)
203 { U32 res = 0;
204 if (!nbits) return 0;
205 if (!t->readBit) t->readBit = 0x80;
206 while (nbits)
207 { res<<=1;
208 #ifdef DEBUG_RFXSWF
209 if (t->pos>=t->len)
210 { fprintf(stderr,"GetBits() out of bounds: TagID = %i, pos=%d, len=%d\n",t->id, t->pos, t->len);
211 int i,m=t->len>10?10:t->len;
212 for(i=-1;i<m;i++) {
213 fprintf(stderr, "(%d)%02x ", i, t->data[i]);
215 fprintf(stderr, "\n");
216 return res;
218 #endif
219 if (t->data[t->pos]&t->readBit) res|=1;
220 t->readBit>>=1;
221 nbits--;
222 if (!t->readBit)
223 { if (nbits) t->readBit = 0x80;
224 t->pos++;
227 return res;
230 S32 swf_GetSBits(TAG * t,int nbits)
231 { U32 res = swf_GetBits(t,nbits);
232 if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);
233 return (S32)res;
236 U32 reader_GetBits(reader_t*reader, int nbits)
237 { return reader_readbits(reader, nbits);
239 S32 reader_GetSBits(reader_t*reader, int nbits)
240 { U32 res = reader_readbits(reader, nbits);
241 if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);
242 return (S32)res;
245 int swf_SetBits(TAG * t,U32 v,int nbits)
246 { U32 bm = 1<<(nbits-1);
248 while (nbits)
249 { if (!t->writeBit)
250 { if (FAILED(swf_SetU8(t,0))) return -1;
251 t->writeBit = 0x80;
253 if (v&bm) t->data[t->len-1] |= t->writeBit;
254 bm>>=1;
255 t->writeBit>>=1;
256 nbits--;
258 return 0;
261 // Advanced Data Access Functions
263 double swf_GetFixed(TAG * t)
265 U16 low = swf_GetU16(t);
266 U16 high = swf_GetU16(t);
267 return high + low*(1/65536.0);
269 void swf_SetFixed(TAG * t, double f)
271 U16 fr = (U16)((f-(int)f)*65536);
272 swf_SetU16(t, fr);
273 swf_SetU16(t, (U16)f - (f<0 && fr!=0));
275 float swf_GetFixed8(TAG * t)
277 U8 low = swf_GetU8(t);
278 U8 high = swf_GetU8(t);
279 return (float)(high + low*(1/256.0));
281 void swf_SetFixed8(TAG * t, float f)
283 U8 fr = (U8)((f-(int)f)*256);
284 swf_SetU8(t, fr);
285 swf_SetU8(t, (U8)f - (f<0 && fr!=0));
288 U32 swf_GetU30(TAG*tag)
290 U32 shift = 0;
291 U32 s = 0;
292 int nr=0;
293 while(1) {
294 U8 b = swf_GetU8(tag);
295 nr++;
296 s|=(b&127)<<shift;
297 shift+=7;
298 if(!(b&128) || shift>=32)
299 break;
301 /*int nr2= swf_SetU30(0, s);
302 if(nr!=nr2) {
303 printf("Unsigned value %d stored in %d bytes, I'd store it in %d bytes\n", s, nr, nr2);
305 return s;
308 int swf_SetU30(TAG*tag, U32 u)
310 int nr = 0;
311 do {
312 if(tag)
313 swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
314 u>>=7;
315 nr++;
316 } while(u);
317 return nr;
320 void swf_SetABCU32(TAG*tag, U32 u)
322 do {
323 swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
324 u>>=7;
325 } while(u);
327 U32 swf_GetABCU32(TAG*tag)
329 return swf_GetU30(tag);
331 void swf_SetABCS32(TAG*tag, S32 v)
333 swf_SetABCU32(tag, v);
335 S32 swf_GetABCS32(TAG*tag)
337 return swf_GetABCU32(tag);
340 #if 0
342 /*The AVM2 spec is just plain wrong, claiming that S32 values are sign
343 extended. They're not.
344 This wastes up to 4 bytes for every negative value. */
346 void swf_SetABCS32(TAG*tag, S32 s)
348 printf("write S32: %d\n", s);
349 S32 neg = s<0?-1:0;
350 U8 sign = s<0?0x40:0;
351 while(1) {
352 U8 val = s&0x7f;
353 U8 vsign = s&0x40;
354 s>>=7;
355 neg>>=7;
356 if(s==neg && vsign==sign) {
357 /* if the value we now write has the same sign as s
358 and all the remaining bits are equal to the sign of s
359 too, stop writing */
360 swf_SetU8(tag, val);
361 printf("put %02x\n", val);
362 break;
363 } else {
364 swf_SetU8(tag, 0x80 | val);
365 printf("put %02x\n", 0x80|val);
369 int swf_GetS30(TAG*tag)
371 U32 shift = 0;
372 U32 s = 0;
373 int nr=0;
374 while(1) {
375 U8 b = swf_GetU8(tag);
376 nr++;
377 nt i,m=t->len>10?10:t->len;
378 for(i=0;i<m;i++) {
379 fprintf(stderr, "%02x ", t->data[i]);
381 fprintf(stderr, "\n");
382 s|=(b&127)<<shift;
383 shift+=7;
384 if(!(b&128) || shift>=32) {
385 if(b&64) {
386 if(shift<32)
387 s|=0xffffffff<<shift;
389 break;
392 /* It's not uncommon for other applications (Flex for all negative numbers, and
393 Flash for -1) to generate a lot more bytes than would be necessary.
394 int nr2= swf_SetS30(0, s);
395 if(nr!=nr2) {
396 printf("Signed value %d stored in %d bytes, I'd store it in %d bytes\n", s, nr, nr2);
398 return s;
400 #endif
402 int swf_SetU30String(TAG*tag, const char*str, int l)
404 int len=0;
405 len+=swf_SetU30(tag, l);
406 len+=l;
407 swf_SetBlock(tag, (void*)str, l);
408 return len;
411 float swf_GetF16(TAG * t)
413 U16 f1 = swf_GetU16(t);
414 if(!(f1&0x3ff)) return 0.0;
416 // IEEE 16 is 1-5-10
417 // IEEE 32 is 1-8-23
418 /* gcc 4.1.2 seems to require a union here. *(float*)u doesn't work */
419 union {
420 U32 u;
421 float f;
422 } f2;
424 U16 e = (f1>>10)&0x1f;
425 U16 m = f1&0x3ff;
426 /* find highest bit in mantissa */
427 int h=0;
428 while(!(m&0x400)) {
429 m<<=1;
430 h++;
432 m&=0x3ff;
433 e -= h;
434 e += 0x6f;
436 f2.u = (f1&0x8000)<<16; //sign
437 f2.u |= e<<23; //exponent
438 f2.u |= m<<13; //mantissa
439 return *(float*)&f2;
442 void swf_SetF16(TAG * t, float f)
444 union {
445 U32 u;
446 float f;
447 } v;
448 v.f = f;
450 U16 result = (v.u>>16)&0x8000; //sign
451 int exp = ((v.u>>23)&0xff)-0x7f+0x10;
452 U16 m = (v.u>>13)&0x3ff;
453 //fprintf(stderr, "%f: %04x sign, %d exp, %04x mantissa\n", f, result, exp, m);
454 if(exp<-10) {
455 // underflow (clamp to 0.0)
456 exp = 0;
457 m = 0;
458 } else if(exp<0) {
459 // partial underflow- strip some bits
460 m = (m|0x400)>>-exp;
461 exp = 0;
462 } else if(exp>=32) {
463 exp = 31;
464 m = 0x3ff;
465 fprintf(stderr, "Exponent overflow in FLOAT16 encoding\n");
466 } else {
467 exp++;
468 m = (m>>1)|0x200;
470 result |= exp<<10;
471 result |= m;
472 swf_SetU16(t, result);
475 float F16toFloat(U16 x)
477 TAG t;
478 t.data = (void*)&x;
479 t.readBit = 0;
480 t.pos = 0;
481 t.len = 2;
482 return swf_GetF16(&t);
485 float floatToF16(float f)
487 U16 u = 0;
488 TAG t;
489 t.data = (void*)&u;
490 t.len = 0;
491 t.memsize = 2;
492 t.writeBit = 0;
493 swf_SetF16(&t, f);
494 return u;
497 float swf_GetFloat(TAG *tag)
499 union {
500 U32 uint_bits;
501 float float_bits;
502 } f;
503 f.uint_bits = swf_GetU32(tag);
504 return f.float_bits;
507 void swf_SetFloat(TAG *tag, float v)
509 union {
510 U32 uint_bits;
511 float float_bits;
512 } f;
513 f.float_bits = v;
514 swf_SetU32(tag, f.uint_bits);
517 double swf_GetD64(TAG*tag)
519 /* FIXME: this is not big-endian compatible */
520 double value = *(double*)&tag->data[tag->pos];
521 swf_GetU32(tag);
522 swf_GetU32(tag);
523 return value;
525 int swf_SetD64(TAG*tag, double v)
527 /* FIXME: this is not big-endian compatible */
528 swf_SetU32(tag, ((U32*)&v)[0]);
529 swf_SetU32(tag, ((U32*)&v)[1]);
530 return 8;
532 int swf_GetU24(TAG*tag)
534 int b1 = swf_GetU8(tag);
535 int b2 = swf_GetU8(tag);
536 int b3 = swf_GetU8(tag);
537 return b3<<16|b2<<8|b1;
539 int swf_GetS24(TAG*tag)
541 int b1 = swf_GetU8(tag);
542 int b2 = swf_GetU8(tag);
543 int b3 = swf_GetU8(tag);
544 if(b3&0x80) {
545 return -1-((b3<<16|b2<<8|b1)^0xffffff);
546 } else {
547 return b3<<16|b2<<8|b1;
550 int swf_SetU24(TAG*tag, U32 v)
552 if(tag) {
553 if(v&0xff000000)
554 fprintf(stderr, "Error: Overflow in swf_SetU24()\n");
555 swf_SetU8(tag, v);
556 swf_SetU8(tag, v>>8);
557 swf_SetU8(tag, v>>16);
559 return 3;
561 int swf_SetS24(TAG*tag, U32 v)
563 if(tag) {
564 if(!(v&0xff000000))
565 return swf_SetU24(tag, v);
566 if((v&0xff000000)!=0xff000000) {
567 fprintf(stderr, "Error: Overflow in swf_SetS24()\n");
569 swf_SetU8(tag, v);
570 swf_SetU8(tag, v>>8);
571 swf_SetU8(tag, v>>16);
573 return 3;
577 int swf_SetRGB(TAG * t,RGBA * col)
578 { if (!t) return -1;
579 if (col)
580 { swf_SetU8(t,col->r);
581 swf_SetU8(t,col->g);
582 swf_SetU8(t,col->b);
583 } else swf_SetBlock(t,NULL,3);
584 return 0;
586 void swf_GetRGB(TAG * t, RGBA * col)
588 RGBA dummy;
589 if(!col)
590 col = &dummy;
591 col->r = swf_GetU8(t);
592 col->g = swf_GetU8(t);
593 col->b = swf_GetU8(t);
594 col->a = 255;
597 int swf_SetRGBA(TAG * t,RGBA * col)
598 { if (!t) return -1;
599 if (col)
600 { swf_SetU8(t,col->r);
601 swf_SetU8(t,col->g);
602 swf_SetU8(t,col->b);
603 swf_SetU8(t,col->a);
604 } else swf_SetBlock(t,NULL,4);
605 return 0;
607 void swf_GetRGBA(TAG * t, RGBA * col)
609 RGBA dummy;
610 if(!col)
611 col = &dummy;
612 col->r = swf_GetU8(t);
613 col->g = swf_GetU8(t);
614 col->b = swf_GetU8(t);
615 col->a = swf_GetU8(t);
618 void swf_GetGradient(TAG * tag, GRADIENT * gradient, char alpha)
620 int t;
621 if(!tag) {
622 memset(gradient, 0, sizeof(GRADIENT));
623 return;
625 U8 num = swf_GetU8(tag) & 15;
626 if(gradient) {
627 gradient->num = num;
628 gradient->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient->num);
629 gradient->ratios = (U8*)rfx_calloc(sizeof(gradient->ratios[0])*gradient->num);
631 for(t=0;t<num;t++)
633 U8 ratio = swf_GetU8(tag);
634 RGBA color;
635 if(!alpha)
636 swf_GetRGB(tag, &color);
637 else
638 swf_GetRGBA(tag, &color);
639 if(gradient) {
640 gradient->ratios[t] = ratio;
641 gradient->rgba[t] = color;
646 void swf_SetGradient(TAG * tag, GRADIENT * gradient, char alpha)
648 int t;
649 if(!tag) {
650 memset(gradient, 0, sizeof(GRADIENT));
651 return;
653 swf_SetU8(tag, gradient->num);
654 for(t=0; t<8 && t<gradient->num; t++)
656 swf_SetU8(tag, gradient->ratios[t]);
657 if(!alpha)
658 swf_SetRGB(tag, &gradient->rgba[t]);
659 else
660 swf_SetRGBA(tag, &gradient->rgba[t]);
664 void swf_FreeGradient(GRADIENT* gradient)
666 if(gradient->ratios)
667 rfx_free(gradient->ratios);
668 if(gradient->rgba)
669 rfx_free(gradient->rgba);
670 memset(gradient, 0, sizeof(GRADIENT));
673 int swf_CountUBits(U32 v,int nbits)
674 { int n = 32;
675 U32 m = 0x80000000;
676 if(v == 0x00000000) n = 0;
677 else
678 while (!(v&m))
679 { n--;
680 m>>=1;
682 return (n>nbits)?n:nbits;
685 int swf_CountBits(U32 v,int nbits)
686 { int n = 33;
687 U32 m = 0x80000000;
688 if (v&m)
689 { if(v == 0xffffffff) n = 1;
690 else
691 while (v&m)
692 { n--;
693 m>>=1;
696 else
697 { if(v == 0x00000000) n = 0;
698 else
699 while (!(v&m))
700 { n--;
701 m>>=1;
704 return (n>nbits)?n:nbits;
707 int swf_GetRect(TAG * t,SRECT * r)
708 { int nbits;
709 SRECT dummy;
710 if(!t) {r->xmin=r->xmax=r->ymin=r->ymax=0;return 0;}
711 if (!r) r = &dummy;
712 nbits = (int) swf_GetBits(t,5);
713 r->xmin = swf_GetSBits(t,nbits);
714 r->xmax = swf_GetSBits(t,nbits);
715 r->ymin = swf_GetSBits(t,nbits);
716 r->ymax = swf_GetSBits(t,nbits);
717 return 0;
720 int reader_GetRect(reader_t*reader,SRECT * r)
721 { int nbits;
722 SRECT dummy;
723 if (!r) r = &dummy;
724 nbits = (int) reader_GetBits(reader,5);
725 r->xmin = reader_GetSBits(reader,nbits);
726 r->xmax = reader_GetSBits(reader,nbits);
727 r->ymin = reader_GetSBits(reader,nbits);
728 r->ymax = reader_GetSBits(reader,nbits);
729 return 0;
732 int swf_SetRect(TAG * t,SRECT * r)
733 { int nbits;
735 nbits = swf_CountBits(r->xmin,0);
736 nbits = swf_CountBits(r->xmax,nbits);
737 nbits = swf_CountBits(r->ymin,nbits);
738 nbits = swf_CountBits(r->ymax,nbits);
739 if(nbits>=32) {
740 #ifdef DEBUG_RFXSWF
741 fprintf(stderr, "rfxswf: Warning: num_bits overflow in swf_SetRect\n");
742 #endif
743 nbits=31;
746 swf_SetBits(t,nbits,5);
747 swf_SetBits(t,r->xmin,nbits);
748 swf_SetBits(t,r->xmax,nbits);
749 swf_SetBits(t,r->ymin,nbits);
750 swf_SetBits(t,r->ymax,nbits);
752 return 0;
755 SRECT swf_ClipRect(SRECT border, SRECT r)
757 if(r.xmax > border.xmax) r.xmax = border.xmax;
758 if(r.ymax > border.ymax) r.ymax = border.ymax;
759 if(r.xmax < border.xmin) r.xmax = border.xmin;
760 if(r.ymax < border.ymin) r.ymax = border.ymin;
762 if(r.xmin > border.xmax) r.xmin = border.xmax;
763 if(r.ymin > border.ymax) r.ymin = border.ymax;
764 if(r.xmin < border.xmin) r.xmin = border.xmin;
765 if(r.ymin < border.ymin) r.ymin = border.ymin;
766 return r;
769 void swf_ExpandRect(SRECT*src, SPOINT add)
771 if((src->xmin | src->ymin | src->xmax | src->ymax)==0) {
772 src->xmin = add.x;
773 src->ymin = add.y;
774 src->xmax = add.x;
775 src->ymax = add.y;
776 if((add.x|add.y) == 0) src->xmax++; //make sure the bbox is not NULL anymore
777 return;
779 if(add.x < src->xmin)
780 src->xmin = add.x;
781 if(add.x > src->xmax)
782 src->xmax = add.x;
783 if(add.y < src->ymin)
784 src->ymin = add.y;
785 if(add.y > src->ymax)
786 src->ymax = add.y;
788 void swf_ExpandRect2(SRECT*src, SRECT*add)
790 if((add->xmin | add->ymin | add->xmax | add->ymax)==0)
791 return;
792 if((src->xmin | src->ymin | src->xmax | src->ymax)==0)
793 *src = *add;
794 if(add->xmin < src->xmin)
795 src->xmin = add->xmin;
796 if(add->ymin < src->ymin)
797 src->ymin = add->ymin;
798 if(add->xmax > src->xmax)
799 src->xmax = add->xmax;
800 if(add->ymax > src->ymax)
801 src->ymax = add->ymax;
803 void swf_ExpandRect3(SRECT*src, SPOINT center, int radius)
805 if((src->xmin | src->ymin | src->xmax | src->ymax)==0) {
806 src->xmin = center.x-radius;
807 src->ymin = center.y-radius;
808 src->xmax = center.x+radius;
809 src->ymax = center.y+radius;
810 if((center.x|center.y|radius) == 0) src->xmax++; //make sure the bbox is not NULL anymore
811 return;
813 if(center.x - radius < src->xmin)
814 src->xmin = center.x - radius;
815 if(center.x + radius > src->xmax)
816 src->xmax = center.x + radius;
817 if(center.y - radius < src->ymin)
818 src->ymin = center.y - radius;
819 if(center.y + radius > src->ymax)
820 src->ymax = center.y + radius;
822 SPOINT swf_TurnPoint(SPOINT p, MATRIX* m)
824 SPOINT r;
825 r.x = (int)(m->sx*(1/65536.0)*p.x + m->r1*(1/65536.0)*p.y + 0.5) + m->tx;
826 r.y = (int)(m->r0*(1/65536.0)*p.x + m->sy*(1/65536.0)*p.y + 0.5) + m->ty;
827 return r;
829 SRECT swf_TurnRect(SRECT r, MATRIX* m)
831 SRECT g;
832 SPOINT p1,p2,p3,p4,pp1,pp2,pp3,pp4;
833 if(!m)
834 return r;
835 p1.x = r.xmin;p1.y = r.ymin;
836 p2.x = r.xmax;p2.y = r.ymin;
837 p3.x = r.xmin;p3.y = r.ymax;
838 p4.x = r.xmax;p4.y = r.ymax;
839 pp1 = swf_TurnPoint(p1, m);
840 pp2 = swf_TurnPoint(p2, m);
841 pp3 = swf_TurnPoint(p3, m);
842 pp4 = swf_TurnPoint(p4, m);
843 g.xmin = g.xmax = pp1.x;
844 g.ymin = g.ymax = pp1.y;
845 swf_ExpandRect(&g, pp2);
846 swf_ExpandRect(&g, pp3);
847 swf_ExpandRect(&g, pp4);
848 return g;
852 int swf_GetMatrix(TAG * t,MATRIX * m)
853 { MATRIX dummy;
854 int nbits;
856 if (!m) m = &dummy;
858 if (!t)
859 { m->sx = m->sy = 0x10000;
860 m->r0 = m->r1 = 0;
861 m->tx = m->ty = 0;
862 return -1;
865 swf_ResetReadBits(t);
867 if (swf_GetBits(t,1))
868 { nbits = swf_GetBits(t,5);
869 m->sx = swf_GetSBits(t,nbits);
870 m->sy = swf_GetSBits(t,nbits);
872 else m->sx = m->sy = 0x10000;
874 if (swf_GetBits(t,1))
875 { nbits = swf_GetBits(t,5);
876 m->r0 = swf_GetSBits(t,nbits);
877 m->r1 = swf_GetSBits(t,nbits);
879 else m->r0 = m->r1 = 0x0;
881 nbits = swf_GetBits(t,5);
882 m->tx = swf_GetSBits(t,nbits);
883 m->ty = swf_GetSBits(t,nbits);
885 return 0;
888 int swf_SetMatrix(TAG * t,MATRIX * m)
889 { int nbits;
890 MATRIX ma;
892 if (!m)
893 { m = &ma;
894 ma.sx = ma.sy = 0x10000;
895 ma.r0 = ma.r1 = 0;
896 ma.tx = ma.ty = 0;
899 swf_ResetWriteBits(t);
901 if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1);
902 else
903 { swf_SetBits(t,1,1);
904 nbits = swf_CountBits(m->sx,0);
905 nbits = swf_CountBits(m->sy,nbits);
906 if(nbits>=32) {
907 /* TODO: happens on AMD64 systems for normal values? */
908 #ifdef DEBUG_RFXSWF
909 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
910 #endif
911 nbits = 31;
913 swf_SetBits(t,nbits,5);
914 swf_SetBits(t,m->sx,nbits);
915 swf_SetBits(t,m->sy,nbits);
918 if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1);
919 else
920 { swf_SetBits(t,1,1);
921 nbits = swf_CountBits(m->r0,0);
922 nbits = swf_CountBits(m->r1,nbits);
923 if(nbits>=32) {
924 #ifdef DEBUG_RFXSWF
925 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
926 #endif
927 nbits = 31;
929 swf_SetBits(t,nbits,5);
930 swf_SetBits(t,m->r0,nbits);
931 swf_SetBits(t,m->r1,nbits);
934 nbits = swf_CountBits(m->tx,0);
935 nbits = swf_CountBits(m->ty,nbits);
936 if(nbits>=32) {
937 #ifdef DEBUG_RFXSWF
938 fprintf(stderr,"rfxswf: Error: matrix values too large\n");
939 #endif
940 nbits = 31;
942 swf_SetBits(t,nbits,5);
943 swf_SetBits(t,m->tx,nbits);
944 swf_SetBits(t,m->ty,nbits);
946 return 0;
949 int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha)
950 { CXFORM cxf;
951 int hasadd;
952 int hasmul;
953 int nbits;
955 if (!cx) cx = &cxf;
957 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
958 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
960 if (!t) return 0;
962 swf_ResetReadBits(t);
963 hasadd = swf_GetBits(t,1);
964 hasmul = swf_GetBits(t,1);
965 nbits = swf_GetBits(t,4);
967 if (hasmul)
968 { cx->r0 = (S16)swf_GetSBits(t,nbits);
969 cx->g0 = (S16)swf_GetSBits(t,nbits);
970 cx->b0 = (S16)swf_GetSBits(t,nbits);
971 if (alpha)
972 cx->a0 = (S16)swf_GetSBits(t,nbits);
975 if (hasadd)
976 { cx->r1 = (S16)swf_GetSBits(t,nbits);
977 cx->g1 = (S16)swf_GetSBits(t,nbits);
978 cx->b1 = (S16)swf_GetSBits(t,nbits);
979 if (alpha)
980 cx->a1 = (S16)swf_GetSBits(t,nbits);
983 return 0;
986 int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
987 { CXFORM cxf;
988 int hasadd;
989 int hasmul;
990 int nbits;
992 if (!cx)
993 { cx = &cxf;
994 cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256;
995 cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0;
998 if (!alpha)
999 { cx->a0 = 256;
1000 cx->a1 = 0;
1003 nbits = 0;
1005 hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256);
1006 hasadd = cx->a1|cx->r1|cx->g1|cx->b1;
1008 if (hasmul)
1009 { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits);
1010 nbits = swf_CountBits((S32)cx->r0,nbits);
1011 nbits = swf_CountBits((S32)cx->g0,nbits);
1012 nbits = swf_CountBits((S32)cx->b0,nbits);
1015 if (hasadd)
1016 { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits);
1017 nbits = swf_CountBits((S32)cx->r1,nbits);
1018 nbits = swf_CountBits((S32)cx->g1,nbits);
1019 nbits = swf_CountBits((S32)cx->b1,nbits);
1022 swf_ResetWriteBits(t);
1023 swf_SetBits(t,hasadd?1:0,1);
1024 swf_SetBits(t,hasmul?1:0,1);
1025 swf_SetBits(t,nbits,4);
1027 if (hasmul)
1028 { swf_SetBits(t,cx->r0,nbits);
1029 swf_SetBits(t,cx->g0,nbits);
1030 swf_SetBits(t,cx->b0,nbits);
1031 if (alpha) swf_SetBits(t,cx->a0,nbits);
1034 if (hasadd)
1035 { swf_SetBits(t,cx->r1,nbits);
1036 swf_SetBits(t,cx->g1,nbits);
1037 swf_SetBits(t,cx->b1,nbits);
1038 if (alpha) swf_SetBits(t,cx->a1,nbits);
1041 return 0;
1044 //int swf_GetPoint(TAG * t,SPOINT * p) { return 0; }
1045 //int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
1047 void swf_SetPassword(TAG * t, const char * password)
1049 #ifdef HAVE_MD5
1050 /* WARNING: crypt_md5 is not reentrant */
1051 char salt[3];
1052 char* md5string;
1054 #if defined(HAVE_LRAND48) && defined(HAVE_SRAND48) && defined(HAVE_TIME_H) && defined(HAVE_TIME)
1055 salt[0] = "abcdefghijklmnopqrstuvwxyz0123456789"[lrand48()%36];
1056 salt[1] = "abcdefghijklmnopqrstuvwxyz0123456789"[lrand48()%36];
1057 #else
1058 salt[0] = 'l';
1059 salt[1] = '8';
1060 fprintf(stderr, "rfxswf: Warning- no usable random generator found\n");
1061 fprintf(stderr, "Your password will be vulnerable to dictionary attacks\n");
1062 #endif
1063 salt[2] = 0;
1065 md5string = crypt_md5(password, salt);
1067 swf_SetU16(t,0);
1068 swf_SetString(t, md5string);
1069 #else
1070 fprintf(stderr, "Error: No MD5 compiled in");
1071 #endif
1074 void swf_SetString(TAG*t, const char* s)
1076 if(!s) {
1077 swf_SetU8(t, 0);
1078 } else {
1079 swf_SetBlock(t,(U8*)s,strlen(s)+1);
1083 int swf_VerifyPassword(TAG * t, const char * password)
1085 #ifdef HAVE_MD5
1086 char*md5string1, *md5string2;
1087 char*x;
1088 char*salt;
1089 int n;
1091 if(t->len >= 5 && t->pos==0 &&
1092 t->data[0] == 0 &&
1093 t->data[1] == 0) {
1094 swf_GetU16(t);
1095 } else {
1096 printf("%d %d %d %d\n", t->len, t->pos, t->data[0], t->data[1]);
1099 md5string1 = swf_GetString(t);
1101 if(strncmp(md5string1, "$1$",3 )) {
1102 fprintf(stderr, "rfxswf: no salt in pw string\n");
1103 return 0;
1105 x = strchr(md5string1+3, '$');
1106 if(!x) {
1107 fprintf(stderr, "rfxswf: invalid salt format in pw string\n");
1108 return 0;
1110 n = x-(md5string1+3);
1111 salt = (char*)rfx_alloc(n+1);
1112 memcpy(salt, md5string1+3, n);
1113 salt[n] = 0;
1115 md5string2 = crypt_md5(password, salt);
1116 rfx_free(salt);
1117 if(strcmp(md5string1, md5string2) != 0)
1118 return 0;
1119 return 1;
1120 #else
1121 fprintf(stderr, "Error: No MD5 compiled in");
1122 return 1;
1123 #endif
1126 // Tag List Manipulating Functions
1128 TAG * swf_InsertTag(TAG * after,U16 id)
1129 { TAG * t;
1131 t = (TAG *)rfx_calloc(sizeof(TAG));
1132 t->id = id;
1134 if (after)
1136 t->prev = after;
1137 t->next = after->next;
1138 after->next = t;
1139 if (t->next) t->next->prev = t;
1141 return t;
1144 TAG * swf_InsertTagBefore(SWF* swf, TAG * before,U16 id)
1145 { TAG * t;
1147 t = (TAG *)rfx_calloc(sizeof(TAG));
1148 t->id = id;
1150 if (before)
1152 t->next = before;
1153 t->prev = before->prev;
1154 before->prev = t;
1155 if (t->prev) t->prev->next = t;
1157 if(swf && swf->firstTag == before) {
1158 swf->firstTag = t;
1160 return t;
1163 void swf_ClearTag(TAG * t)
1165 if (t->data) rfx_free(t->data);
1166 t->data = 0;
1167 t->pos = 0;
1168 t->len = 0;
1169 t->readBit = 0;
1170 t->writeBit = 0;
1171 t->memsize = 0;
1174 void swf_ResetTag(TAG*tag, U16 id)
1176 tag->len = tag->pos = tag->readBit = tag->writeBit = 0;
1177 tag->id = id;
1180 TAG* swf_CopyTag(TAG*tag, TAG*to_copy)
1182 tag = swf_InsertTag(tag, to_copy->id);
1183 swf_SetBlock(tag, to_copy->data, to_copy->len);
1184 return tag;
1187 TAG* swf_DeleteTag(SWF*swf, TAG * t)
1189 TAG*next = t->next;
1191 if (swf && swf->firstTag==t)
1192 swf->firstTag = t->next;
1193 if (t->prev) t->prev->next = t->next;
1194 if (t->next) t->next->prev = t->prev;
1196 if (t->data) rfx_free(t->data);
1197 rfx_free(t);
1198 return next;
1201 TAG * swf_ReadTag(reader_t*reader, TAG * prev)
1202 { TAG * t;
1203 U16 raw;
1204 U32 len;
1205 int id;
1207 if (reader->read(reader, &raw, 2) !=2 ) return NULL;
1208 raw = LE_16_TO_NATIVE(raw);
1210 len = raw&0x3f;
1211 id = raw>>6;
1213 if (len==0x3f)
1215 len = reader_readU32(reader);
1218 if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
1219 // Sprite handling fix: Flatten sprite tree
1221 t = (TAG *)rfx_calloc(sizeof(TAG));
1223 t->len = len;
1224 t->id = id;
1226 if (t->len)
1227 { t->data = (U8*)rfx_alloc(t->len);
1228 t->memsize = t->len;
1229 if (reader->read(reader, t->data, t->len) != t->len) {
1230 #ifdef DEBUG_RFXSWF
1231 fprintf(stderr, "rfxswf: Warning: Short read (tagid %d). File truncated?\n", t->id);
1232 #endif
1233 free(t->data);t->data=0;
1234 free(t);
1235 return NULL;
1239 if (prev)
1241 t->prev = prev;
1242 prev->next = t;
1245 return t;
1248 int swf_DefineSprite_GetRealSize(TAG * t);
1250 int swf_WriteTag2(writer_t*writer, TAG * t)
1251 // returns tag length in bytes (incl. Header), -1 = Error
1252 // writer = 0 -> no output
1253 { U16 raw[3];
1254 U32 len;
1255 int short_tag;
1257 if (!t) return -1;
1259 len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len;
1261 short_tag = len<0x3f&&
1262 (t->id!=ST_DEFINEBITSLOSSLESS&&t->id!=ST_DEFINEBITSLOSSLESS2&&t->id!=ST_SOUNDSTREAMBLOCK&&
1263 t->id!=ST_DEFINEBITSJPEG&&t->id!=ST_DEFINEBITSJPEG2&&t->id!=ST_DEFINEBITSJPEG3);
1265 if (writer)
1267 #ifdef MEASURE
1268 int oldpos = writer->pos;
1269 #endif
1271 if (short_tag)
1272 { raw[0] = LE_16_TO_NATIVE(len|((t->id&0x3ff)<<6));
1273 if (writer->write(writer,raw,2)!=2)
1275 #ifdef DEBUG_RFXSWF
1276 fprintf(stderr,"WriteTag() failed: Short Header.\n");
1277 #endif
1278 return -1;
1281 else
1283 raw[0] = LE_16_TO_NATIVE((t->id<<6)|0x3f);
1284 if (writer->write(writer,raw,2)!=2)
1286 #ifdef DEBUG_RFXSWF
1287 fprintf(stderr,"WriteTag() failed: Long Header (1).\n");
1288 #endif
1289 return -1;
1292 writer_writeU32(writer, len);
1295 if (t->data)
1296 { if (writer->write(writer,t->data,t->len)!=t->len)
1298 #ifdef DEBUG_RFXSWF
1299 fprintf(stderr,"WriteTag() failed: Data.\n");
1300 #endif
1301 return -1;
1304 #ifdef DEBUG_RFXSWF
1305 else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id);
1306 #endif
1308 #ifdef MEASURE
1309 writer->flush(writer);
1310 printf("TAG %s costs %d bytes\n", swf_TagGetName(t), writer->pos-oldpos);
1311 #endif
1314 return t->len+(short_tag?2:6);
1317 int swf_WriteTag(int handle, TAG * t)
1319 writer_t writer;
1320 int len = 0;
1321 if(handle<0)
1322 return swf_WriteTag2(0, t);
1323 writer_init_filewriter(&writer, handle);
1324 len = swf_WriteTag2(&writer, t);
1325 writer.finish(&writer);
1326 return len;
1329 int swf_DefineSprite_GetRealSize(TAG * t)
1330 // Sprite Handling: Helper function to pack DefineSprite-Tag
1331 { U32 len = t->len;
1332 if(len>4) { // folded sprite
1333 return t->len;
1336 { t = swf_NextTag(t);
1337 if (t && t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t);
1338 else t = NULL;
1339 } while (t&&(t->id!=ST_END));
1340 return len;
1343 void swf_UnFoldSprite(TAG * t)
1345 U16 id,tmp;
1346 U32 len;
1347 TAG*next = t;
1348 U16 spriteid,spriteframes;
1349 int level;
1350 if(t->id!=ST_DEFINESPRITE)
1351 return;
1352 if(t->len<=4) // not folded
1353 return;
1355 swf_SetTagPos(t,0);
1357 spriteid = swf_GetU16(t); //id
1358 spriteframes = swf_GetU16(t); //frames
1360 level = 1;
1362 while(1)
1364 TAG*it = 0;
1365 tmp = swf_GetU16(t);
1366 len = tmp&0x3f;
1367 id = tmp>>6;
1368 if(id == ST_END)
1369 level--;
1370 if(id == ST_DEFINESPRITE && len<=4)
1371 level++;
1373 if (len==0x3f)
1374 len = swf_GetU32(t);
1375 it = swf_InsertTag(next, id);
1376 next = it;
1377 it->len = len;
1378 it->id = id;
1379 if (it->len)
1380 { it->data = (U8*)rfx_alloc(it->len);
1381 it->memsize = it->len;
1382 swf_GetBlock(t, it->data, it->len);
1385 if(!level)
1386 break;
1389 rfx_free(t->data); t->data = 0;
1390 t->memsize = t->len = t->pos = 0;
1392 swf_SetU16(t, spriteid);
1393 swf_SetU16(t, spriteframes);
1396 void swf_FoldSprite(TAG * t)
1398 TAG*sprtag=t,*tmp;
1399 U16 id,frames;
1400 int level;
1401 if(t->id!=ST_DEFINESPRITE)
1402 return;
1403 if(!t->len) {
1404 #ifdef DEBUG_RFXSWF
1405 fprintf(stderr, "Error: Sprite has no ID!");
1406 #endif
1407 return;
1409 if(t->len>4) {
1410 /* sprite is already folded */
1411 return;
1414 t->pos = 0;
1415 id = swf_GetU16(t);
1416 rfx_free(t->data);
1417 t->len = t->pos = t->memsize = 0;
1418 t->data = 0;
1420 frames = 0;
1422 t = swf_NextTag(sprtag);
1423 level = 1;
1427 if(t->id==ST_SHOWFRAME) frames++;
1428 if(t->id == ST_DEFINESPRITE && t->len<=4)
1429 level++;
1430 if(t->id == ST_END)
1431 level--;
1432 t = swf_NextTag(t);
1433 } while(t && level);
1434 if(level)
1435 fprintf(stderr, "rfxswf error: sprite doesn't end(1)\n");
1437 swf_SetU16(sprtag, id);
1438 swf_SetU16(sprtag, frames);
1440 t = swf_NextTag(sprtag);
1441 level = 1;
1445 if(t->len<0x3f&&
1446 (t->id!=ST_DEFINEBITSLOSSLESS&&t->id!=ST_DEFINEBITSLOSSLESS2&&t->id!=ST_SOUNDSTREAMBLOCK&&
1447 t->id!=ST_DEFINEBITSJPEG&&t->id!=ST_DEFINEBITSJPEG2&&t->id!=ST_DEFINEBITSJPEG3)
1449 swf_SetU16(sprtag,t->len|(t->id<<6));
1450 } else {
1451 swf_SetU16(sprtag,0x3f|(t->id<<6));
1452 swf_SetU32(sprtag,t->len);
1454 if(t->len)
1455 swf_SetBlock(sprtag,t->data, t->len);
1456 tmp = t;
1457 if(t->id == ST_DEFINESPRITE && t->len<=4)
1458 level++;
1459 if(t->id == ST_END)
1460 level--;
1461 t = swf_NextTag(t);
1462 swf_DeleteTag(0, tmp);
1464 while (t && level);
1465 if(level)
1466 fprintf(stderr, "rfxswf error: sprite doesn't end(2)\n");
1468 // sprtag->next = t;
1469 // t->prev = sprtag;
1472 int swf_IsFolded(TAG * t)
1474 return (t->id == ST_DEFINESPRITE && t->len>4);
1477 void swf_FoldAll(SWF*swf)
1479 TAG*tag = swf->firstTag;
1480 //swf_DumpSWF(stdout, swf);
1481 while(tag) {
1482 if(tag->id == ST_DEFINESPRITE) {
1483 swf_FoldSprite(tag);
1484 //swf_DumpSWF(stdout, swf);
1486 tag = swf_NextTag(tag);
1490 void swf_UnFoldAll(SWF*swf)
1492 TAG*tag = swf->firstTag;
1493 while(tag) {
1494 if(tag->id == ST_DEFINESPRITE)
1495 swf_UnFoldSprite(tag);
1496 tag = tag->next;
1500 void swf_OptimizeTagOrder(SWF*swf)
1502 TAG*tag,*next;
1503 TAG*level0;
1504 int level;
1505 int changes;
1506 swf_UnFoldAll(swf);
1507 /* at the moment, we don't actually do optimizing,
1508 only fixing of non-spec-conformant things like
1509 sprite tags */
1511 do {
1512 changes = 0;
1513 level = 0;
1514 level0 = 0;
1515 tag = swf->firstTag;
1516 while(tag) {
1517 next = tag->next;
1518 if(tag->id == ST_DEFINESPRITE) {
1519 if(tag->len>4) {
1520 /* ??? all sprites are supposed to be unfolded */
1521 fprintf(stderr, "librfxswf error - internal error in OptimizeTagOrder/UnfoldAll\n");
1523 level++;
1524 if(level==1) {
1525 level0 = tag;
1526 tag = next;
1527 continue;
1530 if(level>=1) {
1531 /* move non-sprite tags out of sprite */
1532 if(!swf_isAllowedSpriteTag(tag) || level>=2) {
1533 /* remove tag from current position */
1534 tag->prev->next = tag->next;
1535 if(tag->next)
1536 tag->next->prev = tag->prev;
1538 /* insert before tag level0 */
1539 tag->next = level0;
1540 tag->prev = level0->prev;
1541 level0->prev = tag;
1542 if(tag->prev)
1543 tag->prev->next = tag;
1544 else
1545 swf->firstTag = tag;
1546 changes = 1;
1549 if(tag->id == ST_END) {
1550 level--;
1553 tag = next;
1555 } while(changes);
1558 // Movie Functions
1560 int swf_ReadSWF2(reader_t*reader, SWF * swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails
1562 if (!swf) return -1;
1563 memset(swf,0x00,sizeof(SWF));
1565 { char b[32]; // read Header
1566 int len;
1567 TAG * t;
1568 TAG t1;
1569 reader_t zreader;
1571 if ((len = reader->read(reader ,b,8))<8) return -1;
1573 if (b[0]!='F' && b[0]!='C') return -1;
1574 if (b[1]!='W') return -1;
1575 if (b[2]!='S') return -1;
1576 swf->fileVersion = b[3];
1577 swf->compressed = (b[0]=='C')?1:0;
1578 swf->fileSize = GET32(&b[4]);
1580 if(swf->compressed) {
1581 reader_init_zlibinflate(&zreader, reader);
1582 reader = &zreader;
1584 swf->compressed = 0; // derive from version number from now on
1586 reader_GetRect(reader, &swf->movieSize);
1587 reader->read(reader, &swf->frameRate, 2);
1588 swf->frameRate = LE_16_TO_NATIVE(swf->frameRate);
1589 reader->read(reader, &swf->frameCount, 2);
1590 swf->frameCount = LE_16_TO_NATIVE(swf->frameCount);
1592 /* read tags and connect to list */
1593 t1.next = 0;
1594 t = &t1;
1595 while (t) {
1596 t = swf_ReadTag(reader,t);
1597 if(t && t->id == ST_FILEATTRIBUTES) {
1598 swf->fileAttributes = swf_GetU32(t);
1599 swf_ResetReadBits(t);
1602 swf->firstTag = t1.next;
1603 if(t1.next)
1604 t1.next->prev = NULL;
1607 return reader->pos;
1610 SWF* swf_OpenSWF(char*filename)
1612 int fi = open(filename, O_RDONLY|O_BINARY);
1613 if(fi<0) {
1614 fprintf(stderr, "Failed to open %s\n", filename);
1615 return 0;
1617 SWF* swf = rfx_alloc(sizeof(SWF));
1618 swf_ReadSWF(fi, swf);
1619 close(fi);
1620 return swf;
1623 int swf_ReadSWF(int handle, SWF * swf)
1625 reader_t reader;
1626 reader_init_filereader(&reader, handle);
1627 return swf_ReadSWF2(&reader, swf);
1630 void swf_ReadABCfile(char*filename, SWF*swf)
1632 memset(swf, 0, sizeof(SWF));
1633 swf->fileVersion=9;
1634 swf->fileAttributes=FILEATTRIBUTE_AS3; //as3
1635 TAG*tag = swf->firstTag = swf_InsertTag(0, ST_RAWABC);
1636 memfile_t*file = memfile_open(filename);
1637 swf_SetBlock(tag, file->data, file->len);
1638 memfile_close(file);
1641 int no_extra_tags = 0;
1643 int WriteExtraTags(SWF*swf, writer_t*writer)
1645 TAG*t = swf->firstTag;
1646 TAG* has_fileattributes=0;
1647 int has_scenedescription=0;
1648 int has_version_8_action=0;
1649 int has_version_9_action=0;
1650 int len = 0;
1651 while(t) {
1652 if(t->id == ST_FILEATTRIBUTES)
1653 has_fileattributes = t;
1654 if(t->id == ST_SCENEDESCRIPTION)
1655 has_scenedescription = 1;
1656 if(t->id == ST_DOABC)
1657 has_version_9_action=1;
1658 /* FIXME: this doesn't yet find actionscript in buttons */
1659 if(t->id == ST_DOACTION || t->id == ST_DOINITACTION)
1660 has_version_8_action=1;
1661 if(t->id == ST_PLACEOBJECT2 && t->len && (t->data[0]&0x80))
1662 has_version_8_action=1;
1663 t = t->next;
1665 if(has_version_8_action && has_version_9_action) {
1666 fprintf(stderr, "Warning: File contains both flash 8 and flash 9 actionscript\n");
1669 if(swf->fileVersion >= 9) {
1670 if(!has_fileattributes) {
1671 U32 flags = swf->fileAttributes|FILEATTRIBUTE_AS3; // 16 = has symbolclass tag | 8 = actionscript3 | 1 = usenetwork
1672 if(has_version_8_action && !has_version_9_action)
1673 flags &= ~FILEATTRIBUTE_AS3;
1674 TAG*fileattrib = swf_InsertTag(0, ST_FILEATTRIBUTES);
1675 swf_SetU32(fileattrib, flags);
1676 if(writer) {
1677 if(swf_WriteTag2(writer, fileattrib)<0)
1678 return -1;
1679 } else {
1680 len += swf_WriteTag(-1,fileattrib);
1682 swf_DeleteTag(0, fileattrib);
1683 } else {
1684 if(swf->fileAttributes) {
1685 /* if we're writing a file out again where we might have possible
1686 modified the fileattributes in the header, adjust the tag data */
1687 TAG*tt = swf_CopyTag(0,has_fileattributes);
1688 U32 flags = swf_GetU32(tt) | swf->fileAttributes;
1689 swf_ResetTag(tt, tt->id);
1690 swf_SetU32(tt, flags);
1691 if(swf_WriteTag2(writer, has_fileattributes)<0) return -1;
1692 swf_DeleteTag(0, tt);
1693 } else {
1694 if(swf_WriteTag2(writer, has_fileattributes)<0)
1695 return -1;
1698 if(0 && !has_scenedescription) {
1699 TAG*scene = swf_InsertTag(0, ST_SCENEDESCRIPTION);
1700 swf_SetU16(scene, 1);
1701 swf_SetString(scene, "Scene 1");
1702 swf_SetU8(scene, 0);
1703 if(writer) {
1704 if(swf_WriteTag2(writer, scene)<0)
1705 return -1;
1706 } else {
1707 len += swf_WriteTag(-1,scene);
1709 swf_DeleteTag(0, scene);
1712 return len;
1715 int swf_WriteSWF2(writer_t*writer, SWF * swf) // Writes SWF to file, returns length or <0 if fails
1716 { U32 len;
1717 TAG * t;
1718 int frameCount=0;
1719 writer_t zwriter;
1720 int fileSize = 0;
1721 int inSprite = 0;
1722 int ret;
1723 writer_t*original_writer = writer;
1724 int writer_lastpos = 0;
1726 if (!swf) return -1;
1727 if (!writer) return -1; // the caller should provide a nullwriter, not 0, for querying SWF size
1729 if(original_writer) writer_lastpos = original_writer->pos;
1731 // Count Frames + File Size
1733 len = 0;
1734 t = swf->firstTag;
1735 frameCount = 0;
1737 if(swf->firstTag && !no_extra_tags) {
1738 len += WriteExtraTags(swf, 0);
1740 while(t) {
1741 len += swf_WriteTag(-1,t);
1742 if(t->id == ST_DEFINESPRITE && !swf_IsFolded(t)) inSprite++;
1743 else if(t->id == ST_END && inSprite) inSprite--;
1744 else if(t->id == ST_END && !inSprite) {
1745 if(t->prev && t->prev->id!=ST_SHOWFRAME)
1746 frameCount++;
1748 else if(t->id == ST_SHOWFRAME && !inSprite) frameCount++;
1749 t = swf_NextTag(t);
1752 { TAG t1;
1753 char b[64],b4[4];
1754 U32 l;
1756 memset(&t1,0x00,sizeof(TAG));
1757 t1.data = (U8*)b;
1758 t1.memsize = 64;
1760 { // measure header file size
1761 TAG t2;
1762 char b2[64];
1763 memset(&t2,0x00,sizeof(TAG));
1764 t2.data = (U8*)b2;
1765 t2.memsize = 64;
1766 swf_SetRect(&t2, &swf->movieSize);
1767 swf_SetU16(&t2, swf->frameRate);
1768 swf_SetU16(&t2, swf->frameCount);
1769 l = swf_GetTagLen(&t2)+8;
1771 if(swf->compressed == 8) {
1772 l -= 8;
1775 fileSize = l+len;
1776 if(len) {// don't touch headers without tags
1777 swf->fileSize = fileSize;
1778 swf->frameCount = frameCount;
1781 if(swf->compressed != 8) {
1782 /* compressed flag set to 8 means "skip first 8
1783 header bytes". This is necessary if the caller wants to
1784 create compressed SWFs himself .
1785 It also means that we don't initialize our own zlib
1786 writer, but assume the caller provided one.
1788 if(swf->compressed==1 || (swf->compressed==0 && swf->fileVersion>=6)) {
1789 char*id = "CWS";
1790 writer->write(writer, id, 3);
1791 } else {
1792 char*id = "FWS";
1793 writer->write(writer, id, 3);
1796 writer->write(writer, &swf->fileVersion, 1);
1797 PUT32(b4, swf->fileSize);
1798 writer->write(writer, b4, 4);
1800 if(swf->compressed==1 || (swf->compressed==0 && swf->fileVersion>=6)) {
1801 writer_init_zlibdeflate(&zwriter, writer);
1802 writer = &zwriter;
1806 swf_SetRect(&t1,&swf->movieSize);
1807 swf_SetU16(&t1,swf->frameRate);
1808 swf_SetU16(&t1,swf->frameCount);
1810 ret = writer->write(writer,b,swf_GetTagLen(&t1));
1811 if (ret!=swf_GetTagLen(&t1))
1813 #ifdef DEBUG_RFXSWF
1814 fprintf(stderr, "ret:%d\n",ret);
1815 perror("write:");
1816 fprintf(stderr,"WriteSWF() failed: Header.\n");
1817 #endif
1818 return -1;
1821 if(swf->firstTag && !no_extra_tags) {
1822 WriteExtraTags(swf, writer);
1824 t = swf->firstTag;
1826 while (t) {
1827 if(no_extra_tags || t->id != ST_FILEATTRIBUTES) {
1828 if(swf_WriteTag2(writer, t)<0)
1829 return -1;
1831 t = t->next;
1833 if(swf->compressed==1 || (swf->compressed==0 && swf->fileVersion>=6) || swf->compressed==8) {
1834 if(swf->compressed != 8) {
1835 zwriter.finish(&zwriter);
1836 return original_writer->pos - writer_lastpos;
1838 return (int)fileSize;
1839 } else {
1840 return (int)fileSize;
1845 int swf_SaveSWF(SWF * swf, char*filename)
1847 int fi = open(filename, O_BINARY|O_RDWR|O_TRUNC|O_CREAT, 0777);
1848 if(fi<0) {
1849 perror(filename);
1850 return 0;
1852 if(swf_WriteSWF(fi, swf)<0) {
1853 fprintf(stderr, "Unable to write output file: %s\n", filename);
1854 return 0;
1856 close(fi);
1857 return 1;
1860 int swf_WriteSWF(int handle, SWF * swf) // Writes SWF to file, returns length or <0 if fails
1862 writer_t writer;
1863 int len = 0;
1865 if(handle<0) {
1866 writer_init_nullwriter(&writer);
1867 len = swf_WriteSWF2(&writer, swf);
1868 return len;
1870 writer_init_filewriter(&writer, handle);
1871 len = swf_WriteSWF2(&writer, swf);
1872 writer.finish(&writer);
1873 return len;
1876 int swf_WriteHeader2(writer_t*writer,SWF * swf)
1878 SWF myswf;
1879 memcpy(&myswf,swf,sizeof(SWF));
1880 myswf.firstTag = 0;
1881 return swf_WriteSWF2(writer, &myswf);
1884 int swf_WriteHeader(int handle,SWF * swf)
1886 SWF myswf;
1887 memcpy(&myswf,swf,sizeof(SWF));
1888 myswf.firstTag = 0;
1889 return swf_WriteSWF(handle, &myswf);
1892 int swf_WriteCGI(SWF * swf)
1893 { int len;
1894 char s[1024];
1896 len = swf_WriteSWF(-1,swf);
1898 if (len<0) return -1;
1900 sprintf(s,"Content-type: application/x-shockwave-flash\n"
1901 "Accept-Ranges: bytes\n"
1902 "Content-Length: %d\n"
1903 "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
1904 "\n",len);
1906 write(fileno(stdout),s,strlen(s));
1907 return swf_WriteSWF(fileno(stdout),swf);
1910 SWF* swf_CopySWF(SWF*swf)
1912 SWF*nswf = (SWF*)rfx_alloc(sizeof(SWF));
1913 TAG*tag, *ntag;
1914 memcpy(nswf, swf, sizeof(SWF));
1915 nswf->firstTag = 0;
1916 tag = swf->firstTag;
1917 ntag = 0;
1918 while(tag) {
1919 ntag = swf_CopyTag(ntag, tag);
1920 if(!nswf->firstTag)
1921 nswf->firstTag = ntag;
1922 tag = tag->next;
1924 return nswf;
1927 void swf_FreeTags(SWF * swf) // Frees all malloc'ed memory for tags
1928 { TAG * t = swf->firstTag;
1930 while (t)
1931 { TAG * tnew = t->next;
1932 if (t->data) rfx_free(t->data);
1933 rfx_free(t);
1934 t = tnew;
1936 swf->firstTag = 0;
1939 // include advanced functions
1941 //#include "modules/swfdump.c"
1942 //#include "modules/swfshape.c"
1943 //#include "modules/swftext.c"
1944 //#include "modules/swffont.c"
1945 //#include "modules/swfobject.c"
1946 //#include "modules/swfbutton.c"
1947 //#include "modules/swftools.c"
1948 //#include "modules/swfcgi.c"
1949 //#include "modules/swfbits.c"
1950 //#include "modules/swfaction.c"
1951 //#include "modules/swfabc.c"
1952 //#include "modules/swfsound.c"
1953 //#include "modules/swfdraw.c"
1954 //#include "modules/swfrender.c"
1955 //#include "modules/swffilter.c"