]> git.tdb.fi Git - libs/datafile.git/blobdiff - source/binaryparser.cpp
Use custom encoding for floats in binary format
[libs/datafile.git] / source / binaryparser.cpp
index 81a86ea9a3b66b7ae9c9a6ba0a3dfff4f134ff17..fa99a7e47708ba3c1d4991c16d605d9ae77c7b28 100644 (file)
@@ -1,7 +1,9 @@
+#include <limits>
 #include <sys/param.h>
 #include <msp/core/maputils.h>
 #include <msp/strings/format.h>
 #include "binaryparser.h"
+#include "binfloat.h"
 #include "input.h"
 
 using namespace std;
@@ -22,10 +24,12 @@ public:
 
 BinaryParser::BinaryParser(Input &i, const string &s):
        ParserMode(i, s),
-       first(true)
+       first(true),
+       float_precision(32)
 {
        dict[-1] = DictEntry("__kwd", "iss");
        dict[-2] = DictEntry("__str", "is");
+       dict[-3] = DictEntry("__flt", "i");
 }
 
 Statement BinaryParser::parse()
@@ -51,6 +55,8 @@ Statement BinaryParser::parse()
                        const unsigned id = st.args[0].get<unsigned>();
                        strings[id] = st.args[1].get<const string &>();
                }
+               else if(st.keyword=="__flt")
+                       float_precision = st.args[0].get<unsigned>();
                else
                        return st;
        }
@@ -127,21 +133,47 @@ IntType::Store BinaryParser::parse_int()
 
 FloatType::Store BinaryParser::parse_float()
 {
-       union
+       UInt64 encoded = 0;
+       for(unsigned i=0; i<float_precision; i+=8)
        {
-               float f;
-               char d[sizeof(float)];
-       };
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-       for(unsigned i = sizeof(float); i--;)
-               d[i] = in.get();
-#else
-       for(unsigned i = 0; i<sizeof(float); ++i)
-               d[i] = in.get();
-#endif
-
-       return f;
+               int c = in.get();
+               encoded = (encoded<<8) | (c&0xFF);
+       }
+
+       BinFloat bf = BinFloat::explode(encoded, float_precision);
+
+       if(numeric_limits<FloatType::Store>::is_iec559)
+               return bf.compose_iec559<FloatType::Store>();
+       else
+       {
+               /* Put the float together with arithmetic since we don't know its
+               internal layout */
+               FloatType::Store f = 0;
+               if(bf.infinity)
+               {
+                       if(numeric_limits<FloatType::Store>::has_infinity)
+                               f = numeric_limits<FloatType::Store>::infinity();
+                       else
+                               f = numeric_limits<FloatType::Store>::max();
+               }
+               else
+               {
+                       for(unsigned i=0; i<64; ++i)
+                       {
+                               f /= 2;
+                               if(bf.mantissa&1)
+                                       f += 1;
+                               bf.mantissa >>= 1;
+                       }
+                       for(int i=0; i<bf.exponent; ++i)
+                               f *= 2;
+                       for(int i=0; i>bf.exponent; --i)
+                               f /= 2;
+               }
+               if(bf.sign)
+                       f = -f;
+               return f;
+       }
 }
 
 BoolType::Store BinaryParser::parse_bool()