X-Git-Url: http://git.tdb.fi/?p=libs%2Fdatafile.git;a=blobdiff_plain;f=source%2Fbinarywriter.cpp;h=0fbf8ce503058f5aaa89734250856777e083409e;hp=e89def35a8eeac9dc7cab2c55202ef251e8701b8;hb=9d97c6c5d3f125dd0ed23ccfa4bf0bb728a753fa;hpb=27630d44298cb67e075c166f4421288cc8ca117e diff --git a/source/binarywriter.cpp b/source/binarywriter.cpp index e89def3..0fbf8ce 100644 --- a/source/binarywriter.cpp +++ b/source/binarywriter.cpp @@ -1,11 +1,8 @@ -/* $Id$ - -This file is part of libmspdatafile -Copyright © 2006 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - +#include +#include #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(ostream &o): +BinaryWriter::BinaryWriter(Output &o): WriterMode(o), - next_st_id(3), - next_enum_id(1) + next_kwd_id(1), + next_str_id(1), + float_precision(32) { - dict[DictEntry("__kw", "iss")]=1; - dict[DictEntry("__enum", "is")]=1; + dict[StatementKey("__kwd", "iss")] = -1; + dict[StatementKey("__str", "is")] = -2; + dict[StatementKey("__flt", "i")] = -3; +} + +void BinaryWriter::set_float_precision(unsigned fp) +{ + 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,111 +40,141 @@ void BinaryWriter::write(const Statement &st) void BinaryWriter::write_(const Statement &st) { - Dictionary::iterator i=dict.find(create_entry(st)); - if(i==dict.end()) - throw InvalidParameterValue("Unknown statement"); + int id = get_item(dict, StatementKey(st.keyword, st.get_signature())); - write_int(i->second); - for(ValueArray::const_iterator j=st.args.begin(); j!=st.args.end(); ++j) - switch(j->get_type()) + write_int(id); + for(Statement::Arguments::const_iterator j = st.args.begin(); j!=st.args.end(); ++j) + switch(j->get_signature()) { - case INTEGER: write_int (j->get()); break; - case STRING: write_string(j->get()); break; - case BOOLEAN: write_int (j->get()); break; - case FLOAT: write_float (j->get()); break; - case ENUM: write_enum (j->get_raw()); break; + case IntType::signature: write_int (j->get()); break; + case StringType::signature: write_string(j->get()); break; + case BoolType::signature: write_int (j->get()); break; + case FloatType::signature: write_float (j->get()); break; + case SymbolType::signature: write_symbol(j->get()); break; } write_int(st.sub.size()); - for(list::const_iterator j=st.sub.begin(); j!=st.sub.end(); ++j) + for(list::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); + StatementKey key(st.keyword, st.get_signature()); - if(!dict.count(de)) + if(!dict.count(key)) { Statement kst; - kst.keyword="__kw"; - kst.args.push_back(next_st_id); - kst.args.push_back(de.keyword); - kst.args.push_back(de.args); + kst.keyword = "__kwd"; + kst.args.push_back(next_kwd_id); + kst.args.push_back(key.keyword); + kst.args.push_back(key.signature); write_(kst); - dict.insert(Dictionary::value_type(de, next_st_id++)).first; + dict[key] = next_kwd_id++; } - for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i) - if(i->get_type()==ENUM && !enums.count(i->get_raw())) + for(vector::const_iterator i = st.args.begin(); i!=st.args.end(); ++i) + { + char sig = i->get_signature(); + string str; + if(sig==SymbolType::signature) + str = i->get().name; + else if(sig==StringType::signature) { - 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++; + str = i->get(); + if(str.size()>32) + continue; } + else + continue; - for(list::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i) + if(strings.count(str)) + continue; + + Statement sst; + sst.keyword = "__str"; + sst.args.push_back(next_str_id); + sst.args.push_back(str); + write_(sst); + + strings[str] = next_str_id++; + } + + for(list::const_iterator i = st.sub.begin(); i!=st.sub.end(); ++i) collect_keywords(*i); } -void BinaryWriter::write_int(long long n) +void BinaryWriter::write_int(IntType::Store n) { - unsigned i=1; - for(; n>>(i*7); ++i); - for(; i--;) - out.put(n>>(i*7) & 0x7F | (i?0x80:0)); + unsigned i = sizeof(IntType::Store)-1; + + if(n>=0) + for(; (i>0 && (n>>(i*7-1))==0); --i) ; + else + for(; (i>0 && (n>>(i*7-1))==-1); --i) ; + + for(++i; i--;) + out.put((n>>(i*7) & 0x7F) | (i?0x80:0)); } -void BinaryWriter::write_string(const string &s) +void BinaryWriter::write_string(const StringType::Store &s) { - write_int(s.size()); - out.write(s.data(), s.size()); + StringMap::const_iterator i = strings.find(s); + if(i!=strings.end()) + write_int(-static_cast(i->second)); + else + { + write_int(s.size()); + out.write(s); + } } -void BinaryWriter::write_float(float f) +void BinaryWriter::write_float(FloatType::Store f) { - union + BinFloat bf; + + if(numeric_limits::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; if)) + 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) { - EnumMap::const_iterator i=enums.find(e); - if(i==enums.end()) - throw InvalidParameterValue("Unknown enum"); - write_int(i->second); + write_int(get_item(strings, s.name)); } } // namespace DataFile