123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655 |
- /*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * binio.cpp - Binary stream I/O classes
- * Copyright (C) 2002, 2003 Simon Peter <dn.tlp@gmx.net>
- */
- #include <string.h>
- #include "binio.h"
- #if BINIO_WITH_MATH
- #include <math.h>
- #ifdef __QNXNTO__
- #define pow std::powf
- #endif // __QNXNTO__
- // If 'math.h' doesn't define HUGE_VAL, we try to use HUGE instead.
- #ifndef HUGE_VAL
- # define HUGE_VAL HUGE
- #endif
- #endif
- /***** Defines *****/
- #if BINIO_ENABLE_STRING
- // String buffer size for std::string readString() method
- #define STRINGBUFSIZE 256
- #endif
- /***** binio *****/
- const binio::Flags binio::system_flags = binio::detect_system_flags();
- const binio::Flags binio::detect_system_flags() {
- Flags f = 0;
- // Endian test
- union {
- int word;
- Byte byte;
- } endian_test;
- endian_test.word = 1;
- if (endian_test.byte != 1) f |= BigEndian;
- // IEEE-754 floating-point test
- 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() {
- }
- binistream::Int binistream::readInt(unsigned int size) {
- unsigned int i;
- Int val = 0, in;
- // Check if 'size' doesn't exceed our system's biggest type.
- 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)) { // Read IEEE-754 floating-point value
- unsigned int i, size = 0;
- Byte in[8];
- bool swap;
- // Determine appropriate size for given type.
- switch (ft) {
- case Single:
- size = 4;
- break; // 32 bits
- case Double:
- size = 8;
- break; // 64 bits
- }
- // Determine byte ordering, depending on what we do next
- if (system_flags & FloatIEEE)
- swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
- else
- swap = !getFlag(BigEndian);
- // Read the float byte by byte, converting endianess
- for (i = 0; i < size; i++)
- if (swap)
- in[size - i - 1] = getByte();
- else
- in[i] = getByte();
- if (system_flags & FloatIEEE) {
- // Compatible system, let the hardware do the conversion
- switch (ft) {
- case Single:
- return *reinterpret_cast<float *>(in);
- case Double:
- return *reinterpret_cast<double *>(in);
- }
- } else { // Incompatible system, convert manually
- switch (ft) {
- case Single:
- return ieee_single2float(in);
- case Double:
- return ieee_double2float(in);
- }
- }
- }
- // User tried to read a (yet) unsupported floating-point type. Bail out.
- 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];
- // Signed and unsigned zero
- if (!exp && !fracthi7 && !data[2] && !data[3]) return sign * 0.0;
- // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
- 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 { // Not a number (maybe unsupported on non-IEEE systems)
- #ifdef NAN
- return NAN;
- #else
- err |= Unsupported;
- return 0.0;
- #endif
- }
- }
- if (!exp) // Unnormalized float values
- return sign * pow(2.0f, -126.0f) * fract * pow(2.0f, -23.0f);
- else // Normalized float values
- return sign * pow(2.0f, exp - 127.0f) * (fract * pow(2.0f, -23.0f) + 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.0f, 48.0f) + data[2] * pow(2.0f, 40.0f) + data[3] *
- pow(2.0f, 32.0f) + data[4] * pow(2.0f, 24.0f) + data[5] * pow(2.0f, 16.0f) + data[6] *
- pow(2.0f, 8.0f) + data[7];
- // Signed and unsigned zero
- if (!exp && !fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] &&
- !data[6] && !data[7]) return sign * 0.0;
- // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
- 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 { // Not a number (maybe unsupported on non-IEEE systems)
- #ifdef NAN
- return NAN;
- #else
- err |= Unsupported;
- return 0.0;
- #endif
- }
- }
- if (!exp) // Unnormalized float values
- return sign * pow(2.0f, -1022.0f) * fract * pow(2.0f, -52.0f);
- else // Normalized float values
- return sign * pow(2.0f, exp - 1023.0f) * (fract * pow(2.0f, -52.0f) + 1);
- err |= Fatal;
- return 0.0;
- }
- #if !BINIO_WITH_MATH
- binio::Float binio::pow(Float base, signed int exp)
- /* Our own, stripped-down version of pow() for not having to depend on 'math.h'.
- * This one handles float values for the base and an integer exponent, both
- * positive and negative.
- */
- {
- 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; // Save current error state
- bool eof_then;
- peekInt(1);
- eof_then = eof(); // Get error state of next byte
- err = olderr; // Restore original error state
- return eof_then;
- }
- void binistream::ignore(unsigned long amount) {
- unsigned long i;
- for (i = 0; i < amount; i++)
- getByte();
- }
- /***** binostream *****/
- binostream::binostream() {
- }
- binostream::~binostream() {
- }
- void binostream::writeInt(Int val, unsigned int size) {
- unsigned int i;
- // Check if 'size' doesn't exceed our system's biggest type.
- 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)) { // Write IEEE-754 floating-point value
- unsigned int i, size = 0;
- Byte *out = NULL;
- bool swap;
- if (system_flags & FloatIEEE) {
- // compatible system, let the hardware do the conversion
- float outf = f;
- double outd = f;
- // Hardware could be big or little endian, convert appropriately
- swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
- // Determine appropriate size for given type and convert by hardware
- switch (ft) {
- case Single:
- size = 4;
- out = (Byte *)&outf;
- break; // 32 bits
- case Double:
- size = 8;
- out = (Byte *)&outd;
- break; // 64 bits
- }
- } else {
- #if BINIO_WITH_MATH
- // incompatible system, do the conversion manually
- Byte buf[8];
- // Our own value is always big endian, just check whether we have to
- // convert for a different stream format.
- swap = !getFlag(BigEndian);
- // Convert system's float to requested IEEE-754 float
- switch (ft) {
- case Single:
- size = 4;
- float2ieee_single(f, buf);
- break;
- case Double:
- size = 8;
- float2ieee_double(f, buf);
- break;
- }
- out = buf; // Make the value ready for writing
- #else
- // No necessary support routines to do the conversion, bail out!
- err |= Unsupported;
- return;
- #endif
- }
- // Write the float byte by byte, converting endianess
- if (swap) out += size - 1;
- for (i = 0; i < size; i++) {
- putByte(*out);
- if (swap) out--;
- else out++;
- }
- return; // We're done.
- }
- // User tried to write an unsupported floating-point type. Bail out.
- err |= Unsupported;
- }
- #ifdef BINIO_WITH_MATH
- /*
- * Single and double floating-point to IEEE-754 equivalent conversion functions
- * courtesy of Ken Turkowski.
- *
- * Copyright (C) 1989-1991 Ken Turkowski. <turk@computer.org>
- *
- * All rights reserved.
- *
- * Warranty Information
- * Even though I have reviewed this software, I make no warranty
- * or representation, either express or implied, with respect to this
- * software, its quality, accuracy, merchantability, or fitness for a
- * particular purpose. As a result, this software is provided "as is,"
- * and you, its user, are assuming the entire risk as to its quality
- * and accuracy.
- *
- * This code may be used and freely distributed as long as it includes
- * this copyright notice and the above warranty information.
- */
- /****************************************************************
- * The following two routines make up for deficiencies in many
- * compilers to convert properly between unsigned integers and
- * floating-point. Some compilers which have this bug are the
- * THINK_C compiler for the Macintosh and the C compiler for the
- * Silicon Graphics MIPS-based Iris.
- ****************************************************************/
- #ifdef applec /* The Apple C compiler works */
- # 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;
- register long bits;
- if (num < 0) { /* Can't distinguish a negative zero */
- 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)) {
- /* NaN's and infinities fail second test */
- bits = sign | 0x7F800000; /* +/- infinity */
- }
- else {
- long mantissa;
- if (expon < -(SEXP_OFFSET-2)) { /* Smaller than normalized */
- int shift = (SEXP_POSITION+1) + (SEXP_OFFSET-2) + expon;
- if (shift < 0) { /* Way too small: flush to zero */
- bits = sign;
- } else { /* Nonzero denormalized number */
- mantissa = (long)(fMant * (1L << shift));
- bits = sign | mantissa;
- }
- }
- else { /* Normalized number */
- mantissa = (long)floor(fMant * (1L << (SEXP_POSITION+1)));
- mantissa -= (1L << SEXP_POSITION); /* Hide MSB */
- bits = sign | ((long)((expon + SEXP_OFFSET - 1)) << SEXP_POSITION) | mantissa;
- }
- }
- }
- bytes[0] = bits >> 24; /* Copy to byte string */
- 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) { /* Can't distinguish a negative zero */
- 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)) {
- /* NaN's and infinities fail second test */
- first = sign | 0x7FF00000; /* +/- infinity */
- second = 0;
- }
- else {
- long mantissa;
- if (expon < -(DEXP_OFFSET-2)) { /* Smaller than normalized */
- int shift = (DEXP_POSITION+1) + (DEXP_OFFSET-2) + expon;
- if (shift < 0) { /* Too small for something in the MS word */
- first = sign;
- shift += 32;
- if (shift < 0) { /* Way too small: flush to zero */
- second = 0;
- } else { /* Pretty small demorn */
- second = FloatToUnsigned(floor(ldexp(fMant, shift)));
- }
- } else { /* Nonzero denormalized number */
- fsMant = ldexp(fMant, shift);
- mantissa = (long)floor(fsMant);
- first = sign | mantissa;
- second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
- }
- }
- else { /* Normalized number */
- fsMant = ldexp(fMant, DEXP_POSITION+1);
- mantissa = (long)floor(fsMant);
- mantissa -= (1L << DEXP_POSITION); /* Hide MSB */
- 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 // BINIO_WITH_MATH
- 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
|