--- /dev/null
+/* $Id$
+
+This file is part of libmspdatafile
+Copyright © 2006 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "binarywriter.h"
+#include "statement.h"
+
+using namespace std;
+
+namespace Msp {
+namespace DataFile {
+
+BinaryWriter::BinaryWriter(ostream &o):
+ WriterMode(o),
+ next_st_id(3),
+ next_enum_id(1)
+{
+ dict[DictEntry("__kw", "iss")]=1;
+ dict[DictEntry("__enum", "is")]=1;
+}
+
+void BinaryWriter::write(const Statement &st)
+{
+ collect_keywords(st);
+ write_(st);
+}
+
+void BinaryWriter::write_(const Statement &st)
+{
+ Dictionary::iterator i=dict.find(create_entry(st));
+ if(i==dict.end())
+ throw InvalidParameterValue("Unknown statement");
+
+ write_int(i->second);
+ for(ValueArray::const_iterator j=st.args.begin(); j!=st.args.end(); ++j)
+ switch(j->get_type())
+ {
+ case INTEGER: write_int (j->get<long long>()); break;
+ case STRING: write_string(j->get<const string &>()); break;
+ case BOOLEAN: write_int (j->get<bool>()); break;
+ case FLOAT: write_float (j->get<float>()); break;
+ case ENUM: write_enum (j->get_raw()); break;
+ }
+
+ write_int(st.sub.size());
+ for(list<Statement>::const_iterator j=st.sub.begin(); j!=st.sub.end(); ++j)
+ write(*j);
+}
+
+DictEntry BinaryWriter::create_entry(const Statement &st)
+{
+ static const char types[]="ifsbe";
+
+ string args;
+ for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i)
+ {
+ if(i->get_type()>=5)
+ throw InvalidParameterValue("Invalid argument type");
+ args+=types[i->get_type()];
+ }
+
+ return DictEntry(st.keyword, args);
+}
+
+void BinaryWriter::collect_keywords(const Statement &st)
+{
+ DictEntry de=create_entry(st);
+
+ if(!dict.count(de))
+ {
+ Statement kst;
+ kst.keyword="__kw";
+ kst.args.push_back(next_st_id);
+ kst.args.push_back(de.keyword);
+ kst.args.push_back(de.args);
+ write_(kst);
+
+ dict.insert(Dictionary::value_type(de, next_st_id++)).first;
+ }
+
+ for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i)
+ if(i->get_type()==ENUM && !enums.count(i->get_raw()))
+ {
+ Statement est;
+ est.keyword="__enum";
+ est.args.push_back(next_enum_id);
+ est.args.push_back(i->get_raw());
+ write_(est);
+
+ enums[i->get_raw()]=next_enum_id++;
+ }
+
+ for(list<Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
+ collect_keywords(*i);
+}
+
+void BinaryWriter::write_int(long long n)
+{
+ unsigned i=1;
+ for(; n>>(i*7); ++i);
+ for(; i--;)
+ out.put(n>>(i*7) & 0x7F | (i?0x80:0));
+}
+
+void BinaryWriter::write_string(const string &s)
+{
+ write_int(s.size());
+ out.write(s.data(), s.size());
+}
+
+void BinaryWriter::write_float(float f)
+{
+ union
+ {
+ 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
+}
+
+void BinaryWriter::write_enum(const string &e)
+{
+ EnumMap::const_iterator i=enums.find(e);
+ if(i==enums.end())
+ throw InvalidParameterValue("Unknown enum");
+ write_int(i->second);
+}
+
+} // namespace DataFile
+} // namespace Msp