#include "asn-config.h"
#include "asn-len.h"
#include "asn-tag.h"
#include "asn-real.h"
double pow PROTO ((double base, double exp));
#ifdef IEEE_REAL_LIB
extern int iszero (double);
extern int isinf (double);
extern int signbit (double);
extern int ilogb (double);
extern double scalbn (double, int);
#endif
AsnReal PLUS_INFINITY;
AsnReal MINUS_INFINITY;
#define ENC_PLUS_INFINITY 0x40
#define ENC_MINUS_INFINITY 0x41
#define REAL_BINARY 0x80
#define REAL_SIGN 0x40
#define REAL_EXPLEN_MASK 0x03
#define REAL_EXPLEN_1 0x00
#define REAL_EXPLEN_2 0x01
#define REAL_EXPLEN_3 0x02
#define REAL_EXPLEN_LONG 0x03
#define REAL_FACTOR_MASK 0x0c
#define REAL_BASE_MASK 0x30
#define REAL_BASE_2 0x00
#define REAL_BASE_8 0x10
#define REAL_BASE_16 0x20
unsigned int
SignedIntOctetLen PARAMS ((val),
long int val)
{
unsigned long int mask = (0x7f80L << ((sizeof (long int) - 2) * 8));
unsigned int retVal = sizeof (long int);
if (val < 0)
val = val ^ (~0L);
while ((retVal > 1) && ((val & mask) == 0))
{
mask >>= 8;
retVal--;
}
return retVal;
}
AsnLen
BEncAsnReal PARAMS ((b, data),
BUF_TYPE b _AND_
AsnReal *data)
{
AsnLen len;
len = BEncAsnRealContent (b, data);
len += BEncDefLen (b, len);
len += BEncTag1 (b, UNIV, PRIM, REAL_TAG_CODE);
return len;
}
void
BDecAsnReal PARAMS ((b, result, bytesDecoded, env),
BUF_TYPE b _AND_
AsnReal *result _AND_
AsnLen *bytesDecoded _AND_
jmp_buf env)
{
AsnTag tag;
AsnLen elmtLen;
if ((tag = BDecTag (b, bytesDecoded, env)) != MAKE_TAG_ID (UNIV, PRIM, REAL_TAG_CODE))
{
Asn1Error ("BDecAsnReal: ERROR wrong tag on REAL.\n");
longjmp (env, -40);
}
elmtLen = BDecLen (b, bytesDecoded, env);
BDecAsnRealContent (b, tag, elmtLen, result, bytesDecoded, env);
}
#ifdef IEEE_REAL_FMT
void
InitAsnInfinity()
{
unsigned char *c = (unsigned char *)&PLUS_INFINITY;
int i;
if (sizeof (double) != 8)
Asn1Error ("InitAsnInfinity: ERROR expected sizeof (AsnReal) to be 8");
#if WORDS_BIGENDIAN
c[0] = 0x7f;
c[1] = 0xf0;
for (i = 2; i < sizeof (double); i++)
c[i] = 0;
#else
c[7] = 0x7f;
c[6] = 0xf0;
for (i = 0; i < 6; i++)
c[i] = 0;
#endif
MINUS_INFINITY = -PLUS_INFINITY;
}
AsnLen
BEncAsnRealContent PARAMS ((b, value),
BUF_TYPE b _AND_
AsnReal *value)
{
int exponent;
int isNeg;
#if SIZEOF_LONG == 4
unsigned char *dbl;
unsigned long int *first4;
unsigned long int *second4;
#else
#if SIZEOF_LONG == 8
unsigned long mantissa, val, *p;
int i;
#endif
#endif
if (*value == 0.0)
return 0;
#if SIZEOF_LONG == 4
#if !WORDS_BIGENDIAN
#error sorry! this 32 bit code requires big endianess.
#endif
dbl = (unsigned char *) value;
first4 = (unsigned long int *) dbl;
second4 = (unsigned long int *) (dbl + sizeof (long int));
isNeg = dbl[0] & 0x80;
if (((*first4 & 0x7fffffff) == 0x7ff00000) && (*second4 == 0))
{
if (isNeg)
{
BufPutByteRvs (b, ENC_MINUS_INFINITY);
}
else
{
BufPutByteRvs (b, ENC_PLUS_INFINITY);
}
return 1;
}
else
{
exponent = (((*first4) >> 20) & 0x07ff);
BufPutSegRvs (b, (char *)(dbl+2), sizeof (double)-2);
if (exponent == 0)
{
BufPutByteRvs (b, dbl[1] & 0x0f);
exponent -= 52;
}
else
{
BufPutByteRvs (b, (dbl[1] & 0x0f) | 0x10);
exponent -= (1023 + 52);
}
#else
#if SIZEOF_LONG == 8
#if WORDS_BIGENDIAN
#error sorry! this 64 bit code requires little endianess.
#endif
p = (unsigned long *) value;
val = *p;
isNeg = (val >> 63) & 1;
if (!finite (*value))
{
if (isNeg)
{
BufPutByteRvs (b, ENC_MINUS_INFINITY);
}
else
{
BufPutByteRvs (b, ENC_PLUS_INFINITY);
}
return 1;
}
else
{
exponent = (val >> 52) & 0x7ff;
mantissa = (val & 0xfffffffffffffL) | 0x10000000000000L;
for (i = 0; i < 7; i++)
{
BufPutByteRvs (b, mantissa & 0xff);
mantissa >>= 8;
}
exponent -= (1023 + 52);
#else
#error long neither 8 nor 4 bytes in size?
#endif
#endif
BufPutByteRvs (b, exponent & 0xff);
BufPutByteRvs (b, exponent >> 8);
if (isNeg)
{
BufPutByteRvs (b, REAL_BINARY | REAL_EXPLEN_2 | REAL_SIGN);
}
else
{
BufPutByteRvs (b, REAL_BINARY | REAL_EXPLEN_2);
}
return sizeof (double) + 2;
}
}
#else
#ifdef IEEE_REAL_LIB
void
InitAsnInfinity()
{
PLUS_INFINITY = infinity();
MINUS_INFINITY = -PLUS_INFINITY;
}
AsnLen
BEncAsnRealContent PARAMS ((b, value),
BUF_TYPE b _AND_
AsnReal *value)
{
unsigned long int encLen;
double mantissa;
double tmpMantissa;
unsigned int truncatedMantissa;
int exponent;
unsigned int expLen;
int sign;
unsigned char buf[sizeof (double)];
int i, mantissaLen;
unsigned char firstOctet;
if (iszero (*value))
return 0;
if (isinf (*value))
{
if (signbit (*value))
BufPutByteRvs (b, ENC_MINUS_INFINITY);
else
BufPutByteRvs (b, ENC_PLUS_INFINITY);
encLen = 1;
}
else
{
if (signbit (*value))
sign = -1;
else
sign = 1;
exponent = ilogb (*value);
mantissa = scalbn (fabs (*value), -exponent-1);
tmpMantissa = mantissa;
for (i = 0; i < sizeof (double); i++)
{
tmpMantissa *= (1<<8);
truncatedMantissa = (unsigned int) tmpMantissa;
tmpMantissa -= truncatedMantissa;
buf[i] = truncatedMantissa;
if (truncatedMantissa)
mantissaLen = i+1;
}
firstOctet = REAL_BINARY;
if (signbit (*value))
firstOctet |= REAL_SIGN;
exponent++;
exponent -= (mantissaLen * 8);
expLen = SignedIntOctetLen (exponent);
switch (expLen)
{
case 1:
firstOctet |= REAL_EXPLEN_1;
break;
case 2:
firstOctet |= REAL_EXPLEN_2;
break;
case 3:
firstOctet |= REAL_EXPLEN_3;
break;
default:
firstOctet |= REAL_EXPLEN_LONG;
break;
}
encLen = mantissaLen + expLen + 1;
BufPutSegRvs (b, (char*)buf, mantissaLen);
for (i = expLen; i > 0; i--)
{
BufPutByteRvs (b, exponent);
exponent >>= 8;
}
if (expLen > 3)
{
encLen++;
BufPutByteRvs (b, expLen);
}
BufPutByteRvs (b, firstOctet);
}
return encLen;
}
#else
void
InitAsnInfinity()
{
unsigned char *c;
int i;
if (sizeof (double) != 8)
Asn1Error ("InitAsnInfinity: ERROR expected sizeof (AsnReal) to be 8");
c = (unsigned char*)&PLUS_INFINITY;
c[0] = 0x7f;
c[1] = 0xf0;
for (i = 2; i < sizeof (double); i++)
c[i] = 0;
MINUS_INFINITY = -PLUS_INFINITY;
}
AsnLen
BEncAsnRealContent PARAMS ((b, value),
BUF_TYPE b _AND_
AsnReal *value)
{
unsigned long int encLen;
double mantissa;
double tmpMantissa;
unsigned int truncatedMantissa;
int exponent;
unsigned int expLen;
int sign;
unsigned char buf[sizeof (double)];
int i, mantissaLen;
unsigned char firstOctet;
if (*value == 0.0)
return 0;
if (*value == MINUS_INFINITY)
{
BufPutByteRvs (b, ENC_MINUS_INFINITY);
encLen = 1;
}
else if (*value == PLUS_INFINITY)
{
BufPutByteRvs (b, ENC_PLUS_INFINITY);
encLen = 1;
}
else
{
mantissa = frexp (*value, &exponent);
if (mantissa < 0.0)
{
sign = -1;
mantissa *= -1;
}
else
sign = 1;
tmpMantissa = mantissa;
for (i = 0; i < sizeof (double); i++)
{
tmpMantissa *= (1<<8);
truncatedMantissa = (unsigned int) tmpMantissa;
tmpMantissa -= truncatedMantissa;
buf[i] = truncatedMantissa;
if (truncatedMantissa)
mantissaLen = i+1;
}
firstOctet = REAL_BINARY;
if (sign == -1)
firstOctet |= REAL_SIGN;
exponent -= (mantissaLen * 8);
expLen = SignedIntOctetLen (exponent);
switch (expLen)
{
case 1:
firstOctet |= REAL_EXPLEN_1;
break;
case 2:
firstOctet |= REAL_EXPLEN_2;
break;
case 3:
firstOctet |= REAL_EXPLEN_3;
break;
default:
firstOctet |= REAL_EXPLEN_LONG;
break;
}
encLen = mantissaLen + expLen + 1;
BufPutSegRvs (b, (char*)buf, mantissaLen);
for (i = expLen; i > 0; i--)
{
BufPutByteRvs (b, exponent);
exponent >>= 8;
}
if (expLen > 3)
{
encLen++;
BufPutByteRvs (b, expLen);
}
BufPutByteRvs (b, firstOctet);
}
return encLen;
}
#endif
#endif
void
BDecAsnRealContent PARAMS ((b, tagId, len, result, bytesDecoded, env),
BUF_TYPE b _AND_
AsnTag tagId _AND_
AsnLen len _AND_
AsnReal *result _AND_
AsnLen *bytesDecoded _AND_
jmp_buf env)
{
unsigned char firstOctet;
unsigned char firstExpOctet;
int i;
unsigned int expLen;
double mantissa;
unsigned short base;
long int exponent = 0;
double tmpBase;
double tmpExp;
if (len == 0)
{
*result = 0.0;
return;
}
firstOctet = BufGetByte (b);
if (len == 1)
{
(*bytesDecoded) += 1;
if (firstOctet == ENC_PLUS_INFINITY)
*result = PLUS_INFINITY;
else if (firstOctet == ENC_MINUS_INFINITY)
*result = MINUS_INFINITY;
else
{
Asn1Error ("BDecAsnRealContent: ERROR - unrecognized real number of length 1 octet.\n");
longjmp (env, -22);
}
}
else
{
if (firstOctet & REAL_BINARY)
{
firstExpOctet = BufGetByte (b);
if (firstExpOctet & 0x80)
exponent = -1;
switch (firstOctet & REAL_EXPLEN_MASK)
{
case REAL_EXPLEN_1:
expLen = 1;
exponent = (exponent << 8)| firstExpOctet;
break;
case REAL_EXPLEN_2:
expLen = 2;
exponent = (exponent << 16) |
(((unsigned long int) firstExpOctet) << 8) |
BufGetByte (b);
break;
case REAL_EXPLEN_3:
expLen = 3;
exponent = (exponent << 16) |
(((unsigned long int) firstExpOctet) << 8) |
BufGetByte (b);
exponent = (exponent << 8) | BufGetByte (b);
break;
default:
expLen = firstExpOctet +1;
i = firstExpOctet-1;
firstExpOctet = BufGetByte (b);
if (firstExpOctet & 0x80)
exponent = (-1 <<8) | firstExpOctet;
else
exponent = firstExpOctet;
for (;i > 0; firstExpOctet--)
exponent = (exponent << 8) | BufGetByte (b);
break;
}
mantissa = 0.0;
for (i = 1 + expLen; i < len; i++)
{
mantissa *= (1<<8);
mantissa += BufGetByte (b);
}
mantissa *= (1<<((firstOctet & REAL_FACTOR_MASK) >> 2));
switch (firstOctet & REAL_BASE_MASK)
{
case REAL_BASE_2:
base = 2;
break;
case REAL_BASE_8:
base = 8;
break;
case REAL_BASE_16:
base = 16;
break;
default:
Asn1Error ("BDecAsnRealContent: ERROR - unsupported base for a binary real number.\n");
longjmp (env, -23);
break;
}
tmpBase = base;
tmpExp = exponent;
*result = mantissa * pow ((double)base, (double)exponent);
if (firstOctet & REAL_SIGN)
*result = -*result;
(*bytesDecoded) += len;
}
else
{
Asn1Error ("BDecAsnRealContent: ERROR - decimal REAL form is not currently supported\n");
longjmp (env, -24);
}
}
}
void
PrintAsnReal PARAMS ((f, v, indent),
FILE *f _AND_
AsnReal *v _AND_
unsigned short int indent)
{
fprintf (f, "%.17E", *v);
}