]> git.tdb.fi Git - libs/datafile.git/blobdiff - source/binarywriter.cpp
Don't use deprecated typedefs
[libs/datafile.git] / source / binarywriter.cpp
index 09e36c0085be33c8ad7c0ff0eb5c8a611ca33a95..0fbf8ce503058f5aaa89734250856777e083409e 100644 (file)
@@ -1,11 +1,8 @@
-/* $Id$
-
-This file is part of libmspdatafile
-Copyright © 2007-2008, 2010  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
+#include <limits>
+#include <msp/core/maputils.h>
 #include "binarywriter.h"
+#include "binfloat.h"
+#include "output.h"
 #include "statement.h"
 
 using namespace std;
@@ -13,13 +10,26 @@ using namespace std;
 namespace Msp {
 namespace DataFile {
 
-BinaryWriter::BinaryWriter(IO::Base &o):
+BinaryWriter::BinaryWriter(Output &o):
        WriterMode(o),
-       next_kwd_id(3),
-       next_str_id(1)
+       next_kwd_id(1),
+       next_str_id(1),
+       float_precision(32)
+{
+       dict[StatementKey("__kwd", "iss")] = -1;
+       dict[StatementKey("__str", "is")] = -2;
+       dict[StatementKey("__flt", "i")] = -3;
+}
+
+void BinaryWriter::set_float_precision(unsigned fp)
 {
-       dict[DictEntry("__kwd", "iss")] = 1;
-       dict[DictEntry("__str", "is")] = 2;
+       if(fp<16 || fp>64 || fp%8)
+               throw invalid_argument("BinaryWriter::set_float_precision");
+       float_precision = fp;
+       Statement fst;
+       fst.keyword = "__flt";
+       fst.args.push_back(float_precision);
+       write_(fst);
 }
 
 void BinaryWriter::write(const Statement &st)
@@ -30,11 +40,9 @@ void BinaryWriter::write(const Statement &st)
 
 void BinaryWriter::write_(const Statement &st)
 {
-       Dictionary::iterator i = dict.find(DictEntry(st.keyword, st.get_signature()));
-       if(i==dict.end())
-               throw InvalidParameterValue("Unknown statement");
+       int id = get_item(dict, StatementKey(st.keyword, st.get_signature()));
 
-       write_int(i->second);
+       write_int(id);
        for(Statement::Arguments::const_iterator j = st.args.begin(); j!=st.args.end(); ++j)
                switch(j->get_signature())
                {
@@ -42,7 +50,7 @@ void BinaryWriter::write_(const Statement &st)
                case StringType::signature: write_string(j->get<StringType::Store>()); break;
                case BoolType::signature:   write_int   (j->get<BoolType::Store>()); break;
                case FloatType::signature:  write_float (j->get<FloatType::Store>()); break;
-               case SymbolType::signature: write_enum  (j->get<SymbolType::Store>()); break;
+               case SymbolType::signature: write_symbol(j->get<SymbolType::Store>()); break;
                }
 
        write_int(st.sub.size());
@@ -52,21 +60,21 @@ void BinaryWriter::write_(const Statement &st)
 
 void BinaryWriter::collect_keywords(const Statement &st)
 {
-       DictEntry de(st.keyword, st.get_signature());
+       StatementKey key(st.keyword, st.get_signature());
 
-       if(!dict.count(de))
+       if(!dict.count(key))
        {
                Statement kst;
                kst.keyword = "__kwd";
                kst.args.push_back(next_kwd_id);
-               kst.args.push_back(de.keyword);
-               kst.args.push_back(de.args);
+               kst.args.push_back(key.keyword);
+               kst.args.push_back(key.signature);
                write_(kst);
 
-               dict[de] = next_kwd_id++;
+               dict[key] = next_kwd_id++;
        }
 
-       for(ValueArray::const_iterator i = st.args.begin(); i!=st.args.end(); ++i)
+       for(vector<Value>::const_iterator i = st.args.begin(); i!=st.args.end(); ++i)
        {
                char sig = i->get_signature();
                string str;
@@ -97,9 +105,9 @@ void BinaryWriter::collect_keywords(const Statement &st)
                collect_keywords(*i);
 }
 
-void BinaryWriter::write_int(long long n)
+void BinaryWriter::write_int(IntType::Store n)
 {
-       unsigned i = sizeof(long long)-1;
+       unsigned i = sizeof(IntType::Store)-1;
 
        if(n>=0)
                for(; (i>0 && (n>>(i*7-1))==0); --i) ;
@@ -110,7 +118,7 @@ void BinaryWriter::write_int(long long n)
                out.put((n>>(i*7) & 0x7F) | (i?0x80:0));
 }
 
-void BinaryWriter::write_string(const string &s)
+void BinaryWriter::write_string(const StringType::Store &s)
 {
        StringMap::const_iterator i = strings.find(s);
        if(i!=strings.end())
@@ -118,34 +126,55 @@ void BinaryWriter::write_string(const string &s)
        else
        {
                write_int(s.size());
-               out.write(s.data(), s.size());
+               out.write(s);
        }
 }
 
-void BinaryWriter::write_float(float f)
+void BinaryWriter::write_float(FloatType::Store f)
 {
-       union
+       BinFloat bf;
+
+       if(numeric_limits<FloatType::Store>::is_iec559)
+               bf = BinFloat::explode_iec559(f);
+       else
        {
-               float v;
-               char d[sizeof(float)];
-       };
-
-       v = f;
-#if BYTE_ORDER == LITTLE_ENDIAN
-       for(unsigned i = sizeof(float); i--;)
-               out.put(d[i]);
-#else
-       for(unsigned i = 0; i<sizeof(float); ++i)
-               out.put(d[i]);
-#endif
+               /* The structure of the float is unknown, so we must use arithmetic to
+               reduce it to components. */
+               bf.sign = f<0;
+               bf.exponent = 0;
+               bf.mantissa = 0;
+
+               if(f<0)
+                       f = -f;
+               if(!(f+f>f))
+                       bf.infinity = true;
+               else if(f!=0)
+               {
+                       for(; f<1; f*=2)
+                               --bf.exponent;
+                       for(; f>=2; f/=2)
+                               ++bf.exponent;
+                       for(unsigned i=0; i<64; ++i)
+                       {
+                               bf.mantissa <<= 1;
+                               if(f>=1)
+                               {
+                                       bf.mantissa |= 1;
+                                       f -= 1;
+                               }
+                               f *= 2;
+                       }
+               }
+       }
+
+       UInt64 encoded = bf.compose(float_precision);
+       for(unsigned i=float_precision/8; i--; )
+               out.put((encoded>>(i*8))&0xFF);
 }
 
-void BinaryWriter::write_enum(const string &e)
+void BinaryWriter::write_symbol(const SymbolType::Store &s)
 {
-       StringMap::const_iterator i = strings.find(e);
-       if(i==strings.end())
-               throw InvalidParameterValue("Unknown enum");
-       write_int(i->second);
+       write_int(get_item(strings, s.name));
 }
 
 } // namespace DataFile