]> git.tdb.fi Git - libs/datafile.git/blob - binarywriter.cpp
09e36c0085be33c8ad7c0ff0eb5c8a611ca33a95
[libs/datafile.git] / binarywriter.cpp
1 /* $Id$
2
3 This file is part of libmspdatafile
4 Copyright © 2007-2008, 2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include "binarywriter.h"
9 #include "statement.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace DataFile {
15
16 BinaryWriter::BinaryWriter(IO::Base &o):
17         WriterMode(o),
18         next_kwd_id(3),
19         next_str_id(1)
20 {
21         dict[DictEntry("__kwd", "iss")] = 1;
22         dict[DictEntry("__str", "is")] = 2;
23 }
24
25 void BinaryWriter::write(const Statement &st)
26 {
27         collect_keywords(st);
28         write_(st);
29 }
30
31 void BinaryWriter::write_(const Statement &st)
32 {
33         Dictionary::iterator i = dict.find(DictEntry(st.keyword, st.get_signature()));
34         if(i==dict.end())
35                 throw InvalidParameterValue("Unknown statement");
36
37         write_int(i->second);
38         for(Statement::Arguments::const_iterator j = st.args.begin(); j!=st.args.end(); ++j)
39                 switch(j->get_signature())
40                 {
41                 case IntType::signature:    write_int   (j->get<IntType::Store>()); break;
42                 case StringType::signature: write_string(j->get<StringType::Store>()); break;
43                 case BoolType::signature:   write_int   (j->get<BoolType::Store>()); break;
44                 case FloatType::signature:  write_float (j->get<FloatType::Store>()); break;
45                 case SymbolType::signature: write_enum  (j->get<SymbolType::Store>()); break;
46                 }
47
48         write_int(st.sub.size());
49         for(list<Statement>::const_iterator j = st.sub.begin(); j!=st.sub.end(); ++j)
50                 write(*j);
51 }
52
53 void BinaryWriter::collect_keywords(const Statement &st)
54 {
55         DictEntry de(st.keyword, st.get_signature());
56
57         if(!dict.count(de))
58         {
59                 Statement kst;
60                 kst.keyword = "__kwd";
61                 kst.args.push_back(next_kwd_id);
62                 kst.args.push_back(de.keyword);
63                 kst.args.push_back(de.args);
64                 write_(kst);
65
66                 dict[de] = next_kwd_id++;
67         }
68
69         for(ValueArray::const_iterator i = st.args.begin(); i!=st.args.end(); ++i)
70         {
71                 char sig = i->get_signature();
72                 string str;
73                 if(sig==SymbolType::signature)
74                         str = i->get<Symbol>().name;
75                 else if(sig==StringType::signature)
76                 {
77                         str = i->get<string>();
78                         if(str.size()>32)
79                                 continue;
80                 }
81                 else
82                         continue;
83
84                 if(strings.count(str))
85                         continue;
86
87                 Statement sst;
88                 sst.keyword = "__str";
89                 sst.args.push_back(next_str_id);
90                 sst.args.push_back(str);
91                 write_(sst);
92
93                 strings[str] = next_str_id++;
94         }
95
96         for(list<Statement>::const_iterator i = st.sub.begin(); i!=st.sub.end(); ++i)
97                 collect_keywords(*i);
98 }
99
100 void BinaryWriter::write_int(long long n)
101 {
102         unsigned i = sizeof(long long)-1;
103
104         if(n>=0)
105                 for(; (i>0 && (n>>(i*7-1))==0); --i) ;
106         else
107                 for(; (i>0 && (n>>(i*7-1))==-1); --i) ;
108
109         for(++i; i--;)
110                 out.put((n>>(i*7) & 0x7F) | (i?0x80:0));
111 }
112
113 void BinaryWriter::write_string(const string &s)
114 {
115         StringMap::const_iterator i = strings.find(s);
116         if(i!=strings.end())
117                 write_int(-static_cast<int>(i->second));
118         else
119         {
120                 write_int(s.size());
121                 out.write(s.data(), s.size());
122         }
123 }
124
125 void BinaryWriter::write_float(float f)
126 {
127         union
128         {
129                 float v;
130                 char d[sizeof(float)];
131         };
132
133         v = f;
134 #if BYTE_ORDER == LITTLE_ENDIAN
135         for(unsigned i = sizeof(float); i--;)
136                 out.put(d[i]);
137 #else
138         for(unsigned i = 0; i<sizeof(float); ++i)
139                 out.put(d[i]);
140 #endif
141 }
142
143 void BinaryWriter::write_enum(const string &e)
144 {
145         StringMap::const_iterator i = strings.find(e);
146         if(i==strings.end())
147                 throw InvalidParameterValue("Unknown enum");
148         write_int(i->second);
149 }
150
151 } // namespace DataFile
152 } // namespace Msp