#include "./bitio.h"
#include "./MD5.h"
+#include "./os.h"
// internal constants
U8 swf_GetU8(TAG * t)
{ swf_ResetReadBits(t);
#ifdef DEBUG_RFXSWF
- if (t->pos>=t->len)
+ if ((int)t->pos>=(int)t->len)
{ fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
+ *(int*)0=0;
return 0;
}
#endif
{ U16 res;
swf_ResetReadBits(t);
#ifdef DEBUG_RFXSWF
- if (t->pos>(t->len-2))
+ if ((int)t->pos>((int)t->len-2))
{ fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
return 0;
}
{ U32 res;
swf_ResetReadBits(t);
#ifdef DEBUG_RFXSWF
- if (t->pos>(t->len-4))
+ if ((int)t->pos>((int)t->len-4))
{ fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
return 0;
}
void swf_SetS16(TAG * t,int v)
{
if(v>32767 || v<-32768) {
+ #ifdef DEBUG_RFXSWF
fprintf(stderr, "Warning: S16 overflow: %d\n", v);
+ #endif
}
swf_SetU16(t, (S16)v);
}
if (!t->readBit) t->readBit = 0x80;
while (nbits)
{ res<<=1;
+#ifdef DEBUG_RFXSWF
+ if (t->pos>=t->len)
+ { fprintf(stderr,"GetBits() out of bounds: TagID = %i, pos=%d, len=%d\n",t->id, t->pos, t->len);
+ int i,m=t->len>10?10:t->len;
+ for(i=-1;i<m;i++) {
+ fprintf(stderr, "(%d)%02x ", i, t->data[i]);
+ }
+ fprintf(stderr, "\n");
+ return res;
+ }
+#endif
if (t->data[t->pos]&t->readBit) res|=1;
t->readBit>>=1;
nbits--;
if (!t->readBit)
{ if (nbits) t->readBit = 0x80;
- #ifdef DEBUG_RFXSWF
- if (t->pos>=t->len)
- { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id);
- return res;
- }
- #endif
t->pos++;
}
}
swf_SetU8(t, (U8)f - (f<0 && fr!=0));
}
+U32 swf_GetU30(TAG*tag)
+{
+ U32 shift = 0;
+ U32 s = 0;
+ int nr=0;
+ while(1) {
+ U8 b = swf_GetU8(tag);
+ nr++;
+ s|=(b&127)<<shift;
+ shift+=7;
+ if(!(b&128) || shift>=32)
+ break;
+ }
+ /*int nr2= swf_SetU30(0, s);
+ if(nr!=nr2) {
+ printf("Unsigned value %d stored in %d bytes, I'd store it in %d bytes\n", s, nr, nr2);
+ }*/
+ return s;
+}
+
+int swf_SetU30(TAG*tag, U32 u)
+{
+ int nr = 0;
+ do {
+ if(tag)
+ swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
+ u>>=7;
+ nr++;
+ } while(u);
+ return nr;
+}
+
+void swf_SetABCU32(TAG*tag, U32 u)
+{
+ do {
+ swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
+ u>>=7;
+ } while(u);
+}
+U32 swf_GetABCU32(TAG*tag)
+{
+ return swf_GetU30(tag);
+}
+void swf_SetABCS32(TAG*tag, S32 v)
+{
+ swf_SetABCU32(tag, v);
+}
+S32 swf_GetABCS32(TAG*tag)
+{
+ return swf_GetABCU32(tag);
+}
+
+#if 0
+
+/*The AVM2 spec is just plain wrong, claiming that S32 values are sign
+extended. They're not.
+This wastes up to 4 bytes for every negative value. */
+
+void swf_SetABCS32(TAG*tag, S32 s)
+{
+ printf("write S32: %d\n", s);
+ S32 neg = s<0?-1:0;
+ U8 sign = s<0?0x40:0;
+ while(1) {
+ U8 val = s&0x7f;
+ U8 vsign = s&0x40;
+ s>>=7;
+ neg>>=7;
+ if(s==neg && vsign==sign) {
+ /* if the value we now write has the same sign as s
+ and all the remaining bits are equal to the sign of s
+ too, stop writing */
+ swf_SetU8(tag, val);
+ printf("put %02x\n", val);
+ break;
+ } else {
+ swf_SetU8(tag, 0x80 | val);
+ printf("put %02x\n", 0x80|val);
+ }
+ };
+}
+int swf_GetS30(TAG*tag)
+{
+ U32 shift = 0;
+ U32 s = 0;
+ int nr=0;
+ while(1) {
+ U8 b = swf_GetU8(tag);
+ nr++;
+ nt i,m=t->len>10?10:t->len;
+ for(i=0;i<m;i++) {
+ fprintf(stderr, "%02x ", t->data[i]);
+ }
+ fprintf(stderr, "\n");
+ s|=(b&127)<<shift;
+ shift+=7;
+ if(!(b&128) || shift>=32) {
+ if(b&64) {
+ if(shift<32)
+ s|=0xffffffff<<shift;
+ }
+ break;
+ }
+ }
+ /* It's not uncommon for other applications (Flex for all negative numbers, and
+ Flash for -1) to generate a lot more bytes than would be necessary.
+ int nr2= swf_SetS30(0, s);
+ if(nr!=nr2) {
+ printf("Signed value %d stored in %d bytes, I'd store it in %d bytes\n", s, nr, nr2);
+ }*/
+ return s;
+}
+#endif
+
+int swf_SetU30String(TAG*tag, const char*str, int l)
+{
+ int len=0;
+ len+=swf_SetU30(tag, l);
+ len+=l;
+ swf_SetBlock(tag, (void*)str, l);
+ return len;
+}
+
+float swf_GetF16(TAG * t)
+{
+ U16 f1 = swf_GetU16(t);
+ if(!(f1&0x3ff)) return 0.0;
+
+ // IEEE 16 is 1-5-10
+ // IEEE 32 is 1-8-23
+ /* gcc 4.1.2 seems to require a union here. *(float*)u doesn't work */
+ union {
+ U32 u;
+ float f;
+ } f2;
+
+ U16 e = (f1>>10)&0x1f;
+ U16 m = f1&0x3ff;
+ /* find highest bit in mantissa */
+ int h=0;
+ while(!(m&0x400)) {
+ m<<=1;
+ h++;
+ }
+ m&=0x3ff;
+ e -= h;
+ e += 0x6f;
+
+ f2.u = (f1&0x8000)<<16; //sign
+ f2.u |= e<<23; //exponent
+ f2.u |= m<<13; //mantissa
+ return *(float*)&f2;
+}
+
+void swf_SetF16(TAG * t, float f)
+{
+ union {
+ U32 u;
+ float f;
+ } v;
+ v.f = f;
+
+ U16 result = (v.u>>16)&0x8000; //sign
+ int exp = ((v.u>>23)&0xff)-0x7f+0x10;
+ U16 m = (v.u>>13)&0x3ff;
+ //fprintf(stderr, "%f: %04x sign, %d exp, %04x mantissa\n", f, result, exp, m);
+ if(exp<-10) {
+ // underflow (clamp to 0.0)
+ exp = 0;
+ m = 0;
+ } else if(exp<0) {
+ // partial underflow- strip some bits
+ m = (m|0x400)>>-exp;
+ exp = 0;
+ } else if(exp>=32) {
+ exp = 31;
+ m = 0x3ff;
+ fprintf(stderr, "Exponent overflow in FLOAT16 encoding\n");
+ } else {
+ exp++;
+ m = (m>>1)|0x200;
+ }
+ result |= exp<<10;
+ result |= m;
+ swf_SetU16(t, result);
+}
+
+float F16toFloat(U16 x)
+{
+ TAG t;
+ t.data = (void*)&x;
+ t.readBit = 0;
+ t.pos = 0;
+ t.len = 2;
+ return swf_GetF16(&t);
+}
+
+float floatToF16(float f)
+{
+ U16 u = 0;
+ TAG t;
+ t.data = (void*)&u;
+ t.len = 0;
+ t.memsize = 2;
+ t.writeBit = 0;
+ swf_SetF16(&t, f);
+ return u;
+}
+
+double swf_GetD64(TAG*tag)
+{
+ /* FIXME: this is not big-endian compatible */
+ double value = *(double*)&tag->data[tag->pos];
+ swf_GetU32(tag);
+ swf_GetU32(tag);
+ return value;
+}
+int swf_SetD64(TAG*tag, double v)
+{
+ /* FIXME: this is not big-endian compatible */
+ swf_SetU32(tag, ((U32*)&v)[0]);
+ swf_SetU32(tag, ((U32*)&v)[1]);
+ return 8;
+}
+int swf_GetU24(TAG*tag)
+{
+ int b1 = swf_GetU8(tag);
+ int b2 = swf_GetU8(tag);
+ int b3 = swf_GetU8(tag);
+ return b3<<16|b2<<8|b1;
+}
+int swf_GetS24(TAG*tag)
+{
+ int b1 = swf_GetU8(tag);
+ int b2 = swf_GetU8(tag);
+ int b3 = swf_GetU8(tag);
+ if(b3&0x80) {
+ return -1-((b3<<16|b2<<8|b1)^0xffffff);
+ } else {
+ return b3<<16|b2<<8|b1;
+ }
+}
+int swf_SetU24(TAG*tag, U32 v)
+{
+ if(tag) {
+ if(v&0xff000000)
+ fprintf(stderr, "Error: Overflow in swf_SetU24()\n");
+ swf_SetU8(tag, v);
+ swf_SetU8(tag, v>>8);
+ swf_SetU8(tag, v>>16);
+ }
+ return 3;
+}
+int swf_SetS24(TAG*tag, U32 v)
+{
+ if(tag) {
+ if(!(v&0xff000000))
+ return swf_SetU24(tag, v);
+ if((v&0xff000000)!=0xff000000) {
+ fprintf(stderr, "Error: Overflow in swf_SetS24()\n");
+ }
+ swf_SetU8(tag, v);
+ swf_SetU8(tag, v>>8);
+ swf_SetU8(tag, v>>16);
+ }
+ return 3;
+}
+
+
int swf_SetRGB(TAG * t,RGBA * col)
{ if (!t) return -1;
if (col)
nbits = swf_CountBits(r->ymin,nbits);
nbits = swf_CountBits(r->ymax,nbits);
if(nbits>=32) {
+ #ifdef DEBUG_RFXSWF
fprintf(stderr, "rfxswf: Warning: num_bits overflow in swf_SetRect\n");
+ #endif
nbits=31;
}
nbits = swf_CountBits(m->sy,nbits);
if(nbits>=32) {
/* TODO: happens on AMD64 systems for normal values? */
+ #ifdef DEBUG_RFXSWF
fprintf(stderr,"rfxswf: Error: matrix values too large\n");
+ #endif
nbits = 31;
}
swf_SetBits(t,nbits,5);
nbits = swf_CountBits(m->r0,0);
nbits = swf_CountBits(m->r1,nbits);
if(nbits>=32) {
+ #ifdef DEBUG_RFXSWF
fprintf(stderr,"rfxswf: Error: matrix values too large\n");
+ #endif
nbits = 31;
}
swf_SetBits(t,nbits,5);
nbits = swf_CountBits(m->tx,0);
nbits = swf_CountBits(m->ty,nbits);
if(nbits>=32) {
+ #ifdef DEBUG_RFXSWF
fprintf(stderr,"rfxswf: Error: matrix values too large\n");
+ #endif
nbits = 31;
}
swf_SetBits(t,nbits,5);
md5string = crypt_md5(password, salt);
swf_SetU16(t,0);
- swf_SetString(t, (U8*)md5string);
+ swf_SetString(t, md5string);
+}
+
+void swf_SetString(TAG*t, const char* s)
+{
+ if(!s) {
+ swf_SetU8(t, 0);
+ } else {
+ swf_SetBlock(t,(U8*)s,strlen(s)+1);
+ }
}
int swf_VerifyPassword(TAG * t, const char * password)
{ t->data = (U8*)rfx_alloc(t->len);
t->memsize = t->len;
if (reader->read(reader, t->data, t->len) != t->len) {
+ #ifdef DEBUG_RFXSWF
fprintf(stderr, "rfxswf: Warning: Short read (tagid %d). File truncated?\n", t->id);
+ #endif
free(t->data);t->data=0;
free(t);
return NULL;
if(t->id!=ST_DEFINESPRITE)
return;
if(!t->len) {
+ #ifdef DEBUG_RFXSWF
fprintf(stderr, "Error: Sprite has no ID!");
+ #endif
return;
}
if(t->len>4) {
swf->frameCount = SWAP16(swf->frameCount);
/* read tags and connect to list */
+ t1.next = 0;
t = &t1;
- while (t) t = swf_ReadTag(reader,t);
+ while (t) {
+ t = swf_ReadTag(reader,t);
+ if(t && t->id == ST_FILEATTRIBUTES) {
+ swf->fileAttributes = swf_GetU32(t);
+ swf_ResetReadBits(t);
+ }
+ }
swf->firstTag = t1.next;
- t1.next->prev = NULL;
+ if(t1.next)
+ t1.next->prev = NULL;
}
return reader->pos;
}
+SWF* swf_OpenSWF(char*filename)
+{
+ int fi = open(filename, O_RDONLY|O_BINARY);
+ if(fi<0) {
+ fprintf(stderr, "Failed to open %s\n", filename);
+ return 0;
+ }
+ SWF* swf = rfx_alloc(sizeof(SWF));
+ swf_ReadSWF(fi, swf);
+ close(fi);
+ return swf;
+}
+
int swf_ReadSWF(int handle, SWF * swf)
{
reader_t reader;
return swf_ReadSWF2(&reader, swf);
}
+void swf_ReadABCfile(char*filename, SWF*swf)
+{
+ memset(swf, 0, sizeof(SWF));
+ swf->fileVersion=9;
+ swf->fileAttributes=FILEATTRIBUTE_AS3; //as3
+ TAG*tag = swf->firstTag = swf_InsertTag(0, ST_RAWABC);
+ memfile_t*file = memfile_open(filename);
+ swf_SetBlock(tag, file->data, file->len);
+ memfile_close(file);
+}
+
int no_extra_tags = 0;
+int WriteExtraTags(SWF*swf, writer_t*writer)
+{
+ TAG*t = swf->firstTag;
+ TAG* has_fileattributes=0;
+ int has_scenedescription=0;
+ int has_version_8_action=0;
+ int has_version_9_action=0;
+ int len = 0;
+ while(t) {
+ if(t->id == ST_FILEATTRIBUTES)
+ has_fileattributes = t;
+ if(t->id == ST_SCENEDESCRIPTION)
+ has_scenedescription = 1;
+ if(t->id == ST_DOABC)
+ has_version_9_action=1;
+ /* FIXME: this doesn't yet find actionscript in buttons */
+ if(t->id == ST_DOACTION || t->id == ST_DOINITACTION)
+ has_version_8_action=1;
+ if(t->id == ST_PLACEOBJECT2 && t->len && (t->data[0]&0x80))
+ has_version_8_action=1;
+ t = t->next;
+ }
+ if(has_version_8_action && has_version_9_action) {
+ fprintf(stderr, "Warning: File contains both flash 8 and flash 9 actionscript\n");
+ }
+
+ if(swf->fileVersion >= 9) {
+ if(!has_fileattributes) {
+ U32 flags = swf->fileAttributes|FILEATTRIBUTE_AS3; // 16 = has symbolclass tag | 8 = actionscript3 | 1 = usenetwork
+ if(has_version_8_action && !has_version_9_action)
+ flags &= ~FILEATTRIBUTE_AS3;
+ TAG*fileattrib = swf_InsertTag(0, ST_FILEATTRIBUTES);
+ swf_SetU32(fileattrib, flags);
+ if(writer) {
+ if(swf_WriteTag2(writer, fileattrib)<0)
+ return -1;
+ } else {
+ len += swf_WriteTag(-1,fileattrib);
+ }
+ swf_DeleteTag(0, fileattrib);
+ } else {
+ if(swf->fileAttributes) {
+ /* if we're writing a file out again where we might have possible
+ modified the fileattributes in the header, adjust the tag data */
+ TAG*tt = swf_CopyTag(0,has_fileattributes);
+ U32 flags = swf_GetU32(tt) | swf->fileAttributes;
+ swf_ResetTag(tt, tt->id);
+ swf_SetU32(tt, flags);
+ if(swf_WriteTag2(writer, has_fileattributes)<0) return -1;
+ swf_DeleteTag(0, tt);
+ } else {
+ if(swf_WriteTag2(writer, has_fileattributes)<0)
+ return -1;
+ }
+ }
+ if(0 && !has_scenedescription) {
+ TAG*scene = swf_InsertTag(0, ST_SCENEDESCRIPTION);
+ swf_SetU16(scene, 1);
+ swf_SetString(scene, "Scene 1");
+ swf_SetU8(scene, 0);
+ if(writer) {
+ if(swf_WriteTag2(writer, scene)<0)
+ return -1;
+ } else {
+ len += swf_WriteTag(-1,scene);
+ }
+ swf_DeleteTag(0, scene);
+ }
+ }
+ return len;
+}
+
int swf_WriteSWF2(writer_t*writer, SWF * swf) // Writes SWF to file, returns length or <0 if fails
{ U32 len;
TAG * t;
if(original_writer) writer_lastpos = original_writer->pos;
- // Insert REFLEX Tag
-
- if(!no_extra_tags) {
- /* this block needs a complete rewrite */
-
-#ifdef INSERT_RFX_TAG
-
- if ((swf->firstTag && swf->firstTag->id != ST_REFLEX) &&
- (!swf->firstTag->next || (swf->firstTag->next->id != ST_REFLEX &&
- (!swf->firstTag->next->next || (swf->firstTag->next->next->id!=ST_REFLEX)))))
- {
- swf_SetBlock(swf_InsertTagBefore(swf, swf->firstTag,ST_REFLEX),(U8*)"rfx",3);
- }
-
-#endif // INSERT_RFX_TAG
-
- if(swf->fileVersion >= 9) {
- if ((!swf->firstTag || swf->firstTag->id != ST_SCENEDESCRIPTION) &&
- (!swf->firstTag ||
- !swf->firstTag->next || swf->firstTag->next->id != ST_SCENEDESCRIPTION) &&
- (!swf->firstTag ||
- !swf->firstTag->next ||
- !swf->firstTag->next->next || swf->firstTag->next->next->id != ST_SCENEDESCRIPTION))
- {
- TAG*scene = swf_InsertTagBefore(swf, swf->firstTag,ST_SCENEDESCRIPTION);
- swf_SetU16(scene, 1);
- swf_SetString(scene, (U8*)"Scene 1");
- swf_SetU8(scene, 0);
- }
- }
-
- if(swf->fileVersion >= 9) {
- TAG*tag = swf->firstTag;
- U32 flags = 0x08; // 16 = has symbolclass tag | 8 = actionscript3 | 1 = usenetwork
- int has_version_8_action=0;
- int has_version_9_action=0;
- while(tag) {
- /* FIXME: this doesn't find actionscript in buttons */
- if(tag->id == ST_DOACTION || tag->id == ST_DOINITACTION)
- has_version_8_action=1;
- if(tag->id == ST_DOABC)
- has_version_9_action=1;
- tag = tag->next;
- }
- if(has_version_8_action && !has_version_9_action)
- flags = 0x00;
-
- if (swf->firstTag && swf->firstTag->id != ST_FILEATTRIBUTES)
- {
- swf_SetU32(swf_InsertTagBefore(swf, swf->firstTag,ST_FILEATTRIBUTES),flags);
- }
- }
- }
-
// Count Frames + File Size
len = 0;
t = swf->firstTag;
frameCount = 0;
+ if(swf->firstTag && !no_extra_tags) {
+ len += WriteExtraTags(swf, 0);
+ }
while(t) {
len += swf_WriteTag(-1,t);
if(t->id == ST_DEFINESPRITE && !swf_IsFolded(t)) inSprite++;
return -1;
}
+ if(swf->firstTag && !no_extra_tags) {
+ WriteExtraTags(swf, writer);
+ }
t = swf->firstTag;
- while (t)
- { if (swf_WriteTag2(writer, t)<0) return -1;
- t = swf_NextTag(t);
+
+ while (t) {
+ if(no_extra_tags || t->id != ST_FILEATTRIBUTES) {
+ if(swf_WriteTag2(writer, t)<0)
+ return -1;
+ }
+ t = t->next;
}
if(swf->compressed==1 || (swf->compressed==0 && swf->fileVersion>=6) || swf->compressed==8) {
if(swf->compressed != 8) {
}
}
+int swf_SaveSWF(SWF * swf, char*filename)
+{
+ int fi = open(filename, O_BINARY|O_RDWR|O_TRUNC|O_CREAT, 0777);
+ if(fi<0) {
+ perror(filename);
+ return 0;
+ }
+ if(swf_WriteSWF(fi, swf)<0) {
+ fprintf(stderr, "Unable to write output file: %s\n", filename);
+ return 0;
+ }
+ close(fi);
+ return 1;
+}
+
int swf_WriteSWF(int handle, SWF * swf) // Writes SWF to file, returns length or <0 if fails
{
writer_t writer;
sprintf(s,"Content-type: application/x-shockwave-flash\n"
"Accept-Ranges: bytes\n"
- "Content-Length: %lu\n"
+ "Content-Length: %d\n"
"Expires: Thu, 13 Apr 2000 23:59:59 GMT\n"
"\n",len);