]> git.tdb.fi Git - libs/datafile.git/blob - source/binarywriter.cpp
Cosmetic changes
[libs/datafile.git] / source / binarywriter.cpp
1 #include <limits>
2 #include <msp/core/maputils.h>
3 #include "binarywriter.h"
4 #include "binfloat.h"
5 #include "output.h"
6 #include "statement.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace DataFile {
12
13 BinaryWriter::BinaryWriter(Output &o):
14         WriterMode(o)
15 {
16         dict[StatementKey("__kwd", "iss")] = -1;
17         dict[StatementKey("__str", "is")] = -2;
18         dict[StatementKey("__flt", "i")] = -3;
19 }
20
21 void BinaryWriter::set_float_precision(unsigned fp)
22 {
23         if(fp<16 || fp>64 || fp%8)
24                 throw invalid_argument("BinaryWriter::set_float_precision");
25         float_precision = fp;
26         Statement fst;
27         fst.keyword = "__flt";
28         fst.args.push_back(float_precision);
29         write_(fst);
30 }
31
32 void BinaryWriter::write(const Statement &st)
33 {
34         collect_keywords(st);
35         write_(st);
36 }
37
38 void BinaryWriter::write_(const Statement &st)
39 {
40         int id = get_item(dict, StatementKey(st.keyword, st.get_signature()));
41
42         write_int(id);
43         for(const Value &a: st.args)
44                 switch(a.get_signature())
45                 {
46                 case IntType::signature:    write_int   (a.get<IntType::Store>()); break;
47                 case StringType::signature: write_string(a.get<StringType::Store>()); break;
48                 case BoolType::signature:   write_int   (a.get<BoolType::Store>()); break;
49                 case FloatType::signature:  write_float (a.get<FloatType::Store>()); break;
50                 case SymbolType::signature: write_symbol(a.get<SymbolType::Store>()); break;
51                 }
52
53         write_int(st.sub.size());
54         for(const Statement &s: st.sub)
55                 write(s);
56 }
57
58 void BinaryWriter::collect_keywords(const Statement &st)
59 {
60         StatementKey key(st.keyword, st.get_signature());
61
62         if(!dict.count(key))
63         {
64                 Statement kst;
65                 kst.keyword = "__kwd";
66                 kst.args.push_back(next_kwd_id);
67                 kst.args.push_back(key.keyword);
68                 kst.args.push_back(key.signature);
69                 write_(kst);
70
71                 dict[key] = next_kwd_id++;
72         }
73
74         for(const Value &a: st.args)
75         {
76                 char sig = a.get_signature();
77                 string str;
78                 if(sig==SymbolType::signature)
79                         str = a.get<Symbol>().name;
80                 else if(sig==StringType::signature)
81                 {
82                         str = a.get<string>();
83                         if(str.size()>32)
84                                 continue;
85                 }
86                 else
87                         continue;
88
89                 if(strings.count(str))
90                         continue;
91
92                 Statement sst;
93                 sst.keyword = "__str";
94                 sst.args.push_back(next_str_id);
95                 sst.args.push_back(str);
96                 write_(sst);
97
98                 strings[str] = next_str_id++;
99         }
100
101         for(const Statement &s: st.sub)
102                 collect_keywords(s);
103 }
104
105 void BinaryWriter::write_int(IntType::Store n)
106 {
107         unsigned i = sizeof(IntType::Store)-1;
108
109         if(n>=0)
110                 for(; (i>0 && (n>>(i*7-1))==0); --i) ;
111         else
112                 for(; (i>0 && (n>>(i*7-1))==-1); --i) ;
113
114         for(++i; i--;)
115                 out.put((n>>(i*7) & 0x7F) | (i?0x80:0));
116 }
117
118 void BinaryWriter::write_string(const StringType::Store &s)
119 {
120         StringMap::const_iterator i = strings.find(s);
121         if(i!=strings.end())
122                 write_int(-static_cast<int>(i->second));
123         else
124         {
125                 write_int(s.size());
126                 out.write(s);
127         }
128 }
129
130 void BinaryWriter::write_float(FloatType::Store f)
131 {
132         BinFloat bf;
133
134         if(numeric_limits<FloatType::Store>::is_iec559)
135                 bf = BinFloat::explode_iec559(f);
136         else
137         {
138                 /* The structure of the float is unknown, so we must use arithmetic to
139                 reduce it to components. */
140                 bf.sign = f<0;
141                 bf.exponent = 0;
142                 bf.mantissa = 0;
143
144                 if(f<0)
145                         f = -f;
146                 if(!(f+f>f))
147                         bf.infinity = true;
148                 else if(f!=0)
149                 {
150                         for(; f<1; f*=2)
151                                 --bf.exponent;
152                         for(; f>=2; f/=2)
153                                 ++bf.exponent;
154                         for(unsigned i=0; i<64; ++i)
155                         {
156                                 bf.mantissa <<= 1;
157                                 if(f>=1)
158                                 {
159                                         bf.mantissa |= 1;
160                                         f -= 1;
161                                 }
162                                 f *= 2;
163                         }
164                 }
165         }
166
167         uint64_t encoded = bf.compose(float_precision);
168         for(unsigned i=float_precision/8; i--; )
169                 out.put((encoded>>(i*8))&0xFF);
170 }
171
172 void BinaryWriter::write_symbol(const SymbolType::Store &s)
173 {
174         write_int(get_item(strings, s.name));
175 }
176
177 } // namespace DataFile
178 } // namespace Msp