#include <string.h>
#include "binio.h"
#if BINIO_WITH_MATH
#include <math.h>
#ifdef __QNXNTO__
#define pow std::powf
#endif
#ifndef HUGE_VAL
# define HUGE_VAL HUGE
#endif
#endif
#if BINIO_ENABLE_STRING
#define STRINGBUFSIZE 256
#endif
const binio::Flags binio::system_flags = binio::detect_system_flags();
const binio::Flags binio::detect_system_flags()
{
Flags f = 0;
union {
int word;
Byte byte;
} endian_test;
endian_test.word = 1;
if(endian_test.byte != 1) f |= BigEndian;
float fl = 6.5;
Byte *dat = (Byte *)&fl;
if(sizeof(float) == 4 && sizeof(double) == 8) {
if(f & BigEndian) {
if(dat[0] == 0x40 && dat[1] == 0xD0 && !dat[2] && !dat[3])
f |= FloatIEEE;
} else {
if(dat[3] == 0x40 && dat[2] == 0xD0 && !dat[1] && !dat[0])
f |= FloatIEEE;
}
}
return f;
}
binio::binio()
: my_flags(system_flags), err(NoError)
{
}
binio::~binio()
{
}
void binio::setFlag(Flag f, bool set)
{
if(set)
my_flags |= f;
else
my_flags &= !f;
}
bool binio::getFlag(Flag f)
{
return (my_flags & f ? true : false);
}
binio::Error binio::error()
{
Error e = err;
err = NoError;
return e;
}
bool binio::eof()
{
return (err & Eof ? true : false);
}
binistream::binistream()
{
}
binistream::~binistream()
{
}
binistream::Int binistream::readInt(unsigned int size)
{
unsigned int i;
Int val = 0, in;
if(size > sizeof(Int)) {
err |= Unsupported;
return 0;
}
for(i = 0; i < size; i++) {
in = getByte();
if(getFlag(BigEndian))
val <<= 8;
else
in <<= i * 8;
val |= in;
}
return val;
}
binistream::Float binistream::readFloat(FType ft)
{
if(getFlag(FloatIEEE)) { unsigned int i, size;
Byte in[8];
bool swap;
switch(ft) {
case Single: size = 4; break; case Double: size = 8; break; }
if(system_flags & FloatIEEE)
swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
else
swap = !getFlag(BigEndian);
for(i = 0; i < size; i++)
if(swap)
in[size - i - 1] = getByte();
else
in[i] = getByte();
if(system_flags & FloatIEEE) {
switch(ft) {
case Single: return *(float *)in;
case Double: return *(double *)in;
}
} else { switch(ft) {
case Single: return ieee_single2float(in);
case Double: return ieee_double2float(in);
}
}
}
err |= Unsupported; return 0.0;
}
binistream::Float binistream::ieee_single2float(Byte *data)
{
signed int sign = data[0] >> 7 ? -1 : 1;
unsigned int exp = ((data[0] << 1) & 0xff) | ((data[1] >> 7) & 1),
fracthi7 = data[1] & 0x7f;
Float fract = fracthi7 * 65536.0 + data[2] * 256.0 + data[3];
if(!exp && !fracthi7 && !data[2] && !data[3]) return sign * 0.0;
if(exp == 255)
if(!fracthi7 && !data[2] && !data[3]) {
#ifdef HUGE_VAL
if(sign == -1) return -HUGE_VAL; else return HUGE_VAL;
#else
err |= Unsupported;
if(sign == -1) return -1.0; else return 1.0;
#endif
} else { #ifdef NAN
return NAN;
#else
err |= Unsupported; return 0.0;
#endif
}
if(!exp) return sign * pow(2.0, -126.0) * fract * pow(2.0, -23.0);
else return sign * pow(2.0, exp - 127.0) * (fract * pow(2.0, -23.0) + 1);
err |= Fatal; return 0.0;
}
binistream::Float binistream::ieee_double2float(Byte *data)
{
signed int sign = data[0] >> 7 ? -1 : 1;
unsigned int exp = ((unsigned int)(data[0] & 0x7f) << 4) | (data[1] >> 4),
fracthi4 = data[1] & 0xf;
Float fract = fracthi4 * pow(2.0, 48.0) + data[2] * pow(2.0, 40.0) + data[3] *
pow(2.0, 32.0) + data[4] * pow(2.0, 24.0) + data[5] * pow(2.0, 16.0) + data[6] *
pow(2.0, 8.0) + data[7];
if(!exp && !fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] &&
!data[6] && !data[7]) return sign * 0.0;
if(exp == 2047)
if(!fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] && !data[6] &&
!data[7]) {
#ifdef HUGE_VAL
if(sign == -1) return -HUGE_VAL; else return HUGE_VAL;
#else
err |= Unsupported;
if(sign == -1) return -1.0; else return 1.0;
#endif
} else { #ifdef NAN
return NAN;
#else
err |= Unsupported; return 0.0;
#endif
}
if(!exp) return sign * pow(2.0, -1022.0) * fract * pow(2.0, -52.0);
else return sign * pow(2.0, exp - 1023.0) * (fract * pow(2.0, -52.0) + 1);
err |= Fatal; return 0.0;
}
#if !BINIO_WITH_MATH
binio::Float binio::pow(Float base, signed int exp)
{
int i;
Float val = base;
if(!exp) return 1.0;
for(i = 1; i < (exp < 0 ? -exp : exp); i++)
val *= base;
if(exp < 0) val = 1.0 / val;
return val;
}
#endif
unsigned long binistream::readString(char *str, unsigned long maxlen)
{
unsigned long i;
for(i = 0; i < maxlen; i++) {
str[i] = (char)getByte();
if(err) { str[i] = '\0'; return i; }
}
return maxlen;
}
unsigned long binistream::readString(char *str, unsigned long maxlen,
const char delim)
{
unsigned long i;
for(i = 0; i < maxlen; i++) {
str[i] = (char)getByte();
if(str[i] == delim || err) { str[i] = '\0'; return i; }
}
str[maxlen] = '\0';
return maxlen;
}
#if BINIO_ENABLE_STRING
std::string binistream::readString(const char delim)
{
char buf[STRINGBUFSIZE + 1];
std::string tempstr;
unsigned long read;
do {
read = readString(buf, STRINGBUFSIZE, delim);
tempstr.append(buf, read);
} while(read == STRINGBUFSIZE);
return tempstr;
}
#endif
binistream::Int binistream::peekInt(unsigned int size)
{
Int val = readInt(size);
if(!err) seek(-(long)size, Add);
return val;
}
binistream::Float binistream::peekFloat(FType ft)
{
Float val = readFloat(ft);
if(!err)
switch(ft) {
case Single: seek(-4, Add); break;
case Double: seek(-8, Add); break;
}
return val;
}
bool binistream::ateof()
{
Error olderr = err; bool eof_then;
peekInt(1);
eof_then = eof(); err = olderr; return eof_then;
}
void binistream::ignore(unsigned long amount)
{
unsigned long i;
for(i = 0; i < amount; i++)
getByte();
}
binostream::binostream()
{
}
binostream::~binostream()
{
}
void binostream::writeInt(Int val, unsigned int size)
{
unsigned int i;
if(size > sizeof(Int)) { err |= Unsupported; return; }
for(i = 0; i < size; i++) {
if(getFlag(BigEndian))
putByte((val >> (size - i - 1) * 8) & 0xff);
else {
putByte(val & 0xff);
val >>= 8;
}
}
}
void binostream::writeFloat(Float f, FType ft)
{
if(getFlag(FloatIEEE)) { unsigned int i, size;
Byte *out;
bool swap;
if(system_flags & FloatIEEE) {
float outf = f;
double outd = f;
swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
switch(ft) {
case Single: size = 4; out = (Byte *)&outf; break; case Double: size = 8; out = (Byte *)&outd; break; }
} else {
#if BINIO_WITH_MATH
Byte buf[8];
swap = !getFlag(BigEndian);
switch(ft) {
case Single: size = 4; float2ieee_single(f, buf); break;
case Double: size = 8; float2ieee_double(f, buf); break;
}
out = buf; #else
err |= Unsupported; return;
#endif
}
if(swap) out += size - 1;
for(i = 0; i < size; i++) {
putByte(*out);
if(swap) out--; else out++;
}
return; }
err |= Unsupported;
}
#ifdef BINIO_WITH_MATH
#ifdef applec
# define FloatToUnsigned(f) ((unsigned long)(f))
#else
# define FloatToUnsigned(f) ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
#endif
#define SEXP_MAX 255
#define SEXP_OFFSET 127
#define SEXP_SIZE 8
#define SEXP_POSITION (32-SEXP_SIZE-1)
void binostream::float2ieee_single(Float num, Byte *bytes)
{
long sign;
long bits;
if (num < 0) {
sign = 0x80000000;
num *= -1;
} else {
sign = 0;
}
if (num == 0) {
bits = 0;
} else {
Float fMant;
int expon;
fMant = frexp(num, &expon);
if ((expon > (SEXP_MAX-SEXP_OFFSET+1)) || !(fMant < 1)) {
bits = sign | 0x7F800000;
}
else {
long mantissa;
if (expon < -(SEXP_OFFSET-2)) {
int shift = (SEXP_POSITION+1) + (SEXP_OFFSET-2) + expon;
if (shift < 0) {
bits = sign;
}
else {
mantissa = (long)(fMant * (1L << shift));
bits = sign | mantissa;
}
}
else {
mantissa = (long)floor(fMant * (1L << (SEXP_POSITION+1)));
mantissa -= (1L << SEXP_POSITION);
bits = sign | ((long)((expon + SEXP_OFFSET - 1)) << SEXP_POSITION) | mantissa;
}
}
}
bytes[0] = bits >> 24;
bytes[1] = bits >> 16;
bytes[2] = bits >> 8;
bytes[3] = bits;
}
#define DEXP_MAX 2047
#define DEXP_OFFSET 1023
#define DEXP_SIZE 11
#define DEXP_POSITION (32-DEXP_SIZE-1)
void binostream::float2ieee_double(Float num, Byte *bytes)
{
long sign;
long first, second;
if (num < 0) {
sign = 0x80000000;
num *= -1;
} else {
sign = 0;
}
if (num == 0) {
first = 0;
second = 0;
} else {
Float fMant, fsMant;
int expon;
fMant = frexp(num, &expon);
if ((expon > (DEXP_MAX-DEXP_OFFSET+1)) || !(fMant < 1)) {
first = sign | 0x7FF00000;
second = 0;
}
else {
long mantissa;
if (expon < -(DEXP_OFFSET-2)) {
int shift = (DEXP_POSITION+1) + (DEXP_OFFSET-2) + expon;
if (shift < 0) {
first = sign;
shift += 32;
if (shift < 0) {
second = 0;
}
else {
second = FloatToUnsigned(floor(ldexp(fMant, shift)));
}
}
else {
fsMant = ldexp(fMant, shift);
mantissa = (long)floor(fsMant);
first = sign | mantissa;
second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
}
}
else {
fsMant = ldexp(fMant, DEXP_POSITION+1);
mantissa = (long)floor(fsMant);
mantissa -= (1L << DEXP_POSITION);
fsMant -= (1L << DEXP_POSITION);
first = sign | ((long)((expon + DEXP_OFFSET - 1)) << DEXP_POSITION) | mantissa;
second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
}
}
}
bytes[0] = first >> 24;
bytes[1] = first >> 16;
bytes[2] = first >> 8;
bytes[3] = first;
bytes[4] = second >> 24;
bytes[5] = second >> 16;
bytes[6] = second >> 8;
bytes[7] = second;
}
#endif
unsigned long binostream::writeString(const char *str, unsigned long amount)
{
unsigned int i;
if(!amount) amount = strlen(str);
for(i = 0; i < amount; i++) {
putByte(str[i]);
if(err) return i;
}
return amount;
}
#if BINIO_ENABLE_STRING
unsigned long binostream::writeString(const std::string &str)
{
return writeString(str.c_str());
}
#endif