summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Kramm <kramm@quiss.org>2009-10-20 15:58:12 -0700
committerMatthias Kramm <kramm@quiss.org>2009-10-20 15:58:12 -0700
commitd2ea72a8f8a8e1d2bc8d1e86fde1d7db449b1ded (patch)
tree02c3e6cfacb2a63517e3d29ccbfbf8f7b009ddab
parentfc3df0f53530963da1dd423e2454ac31318169ed (diff)
refactored F16 implementation
-rw-r--r--lib/rfxswf.c131
1 files changed, 42 insertions, 89 deletions
diff --git a/lib/rfxswf.c b/lib/rfxswf.c
index a729f6d7..bba220fd 100644
--- a/lib/rfxswf.c
+++ b/lib/rfxswf.c
@@ -410,115 +410,68 @@ int swf_SetU30String(TAG*tag, const char*str, int l)
float swf_GetF16(TAG * t)
{
- U16 f1 = swf_GetU16(t);
- if(!f1) return 0;
-#if 0
- // D16 is 1-5-10
- // D32 is 1-8-23
+ 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;
- f2.u = (f1&0x8000)<<16; //sign
- f2.u |= ((f1&0x7c00)<<13)+(0x40000000-(0x4000<<13)); //exp
- f2.u |= (f1&0x03ff)<<13; //mantissa
- return *(float*)&f2;
-#endif
- double d = (f1 & 32768L) != 1L ? 1.0 : -1.0;
- int i = (int)((f1 & 0x7c00) >> 10) - 16;
- double d1 = (double)(f1 & 1023) / 1024.0;
- //FloatingPointValue floatingpointvalue = new FloatingPointValue(d1, i);
- double value = d1 * pow(2, i);
-
-#if 0
- if(t->id != 0) {
- TAG*tag = swf_InsertTag(0, 0);
- //swf_SetF16(tag, value);
- swf_SetF16(tag, 84.0/1024.0);
- U16 f = swf_GetU16(tag);
- tag->pos = 0;
- fprintf(stderr, "%04x -> %f -> %04x -> %f\n", (int)f1, d*value, f, swf_GetF16(tag)*1024.0);
- swf_DeleteTag(0,tag);
+ U16 e = (f1>>10)&0x1f;
+ U16 m = f1&0x3ff;
+ /* find highest bit in mantissa */
+ int h=0;
+ while(!(m&0x400)) {
+ m<<=1;
+ h++;
}
-#endif
+ m&=0x3ff;
+ e -= h;
+ e += 0x6f;
- return (float)(d*value);
+ 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)
{
-#if 0
- U32 f1 = *(U32*)&f;
- U16 f2 = (f1>>16)&0x8000;
- int exp = ((f1>>23)&0xff)-0x80+0x10;
- if(exp<0) {
- if(exp!=(16-128)) {
- fprintf(stderr, "Exponent underflow in FLOAT16 encoding %d\n", exp);
- }
+ 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");
- }
- f2 |= exp<<10;
- f2 |= (f1>>13)&0x3ff;
- swf_SetU16(t, f2);
-#endif
-
- if(f == 0.0F)
- {
- swf_SetU16(t, 0);
- return;
- }
- union {
- double value;
- long long l;
- } x;
- x.value = (double)f;
-
- double mantissa;
- double exp;
- if(x.value == 0.0)
- {
- exp = 0;
- mantissa = 0.0;
- } else {
- union {
- double d;
- long long l;
- } u;
- u.l = (0x800fffffffffffffLL & x.l) | 0x3fe0000000000000LL;
- mantissa = u.d;
- exp = (int)(((0x7ff0000000000000LL & x.l) >> 52) - 1022L);
- }
-
- double d = mantissa;
- int i = exp;
- int j = i + 16;
- if(j < 0 || j > 31)
- {
- fprintf(stderr, "too large or too small\n");
- swf_SetU16(t, 0);
- return;
- }
- U16 p;
- if(d >= 0.0) {
- p = 0;
} else {
- d *= -1;
- p = 32768;
+ exp++;
+ m = (m>>1)|0x200;
}
- p |= j << 10;
- p |= (int)(d * 1024);
-
- //fprintf(stderr, "%f/%f -> %04x\n", mantissa, exp, p);
-
- swf_SetU16(t, p);
+ result |= exp<<10;
+ result |= m;
+ swf_SetU16(t, result);
}
-
double swf_GetD64(TAG*tag)
{
/* FIXME: this is not big-endian compatible */