]> git.tdb.fi Git - libs/datafile.git/blob - source/binaryparser.cpp
Use default member initializers for constant initial values
[libs/datafile.git] / source / binaryparser.cpp
1 #include <limits>
2 #include <msp/core/maputils.h>
3 #include <msp/strings/format.h>
4 #include "argumentstore.h"
5 #include "binaryparser.h"
6 #include "binfloat.h"
7 #include "except.h"
8 #include "input.h"
9 #include "loaderaction.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace DataFile {
15
16 BinaryParser::BinaryParser(Input &i, const string &s):
17         ParserMode(i, s)
18 {
19         dict[-1] = StatementInfo("__kwd", "iss");
20         dict[-2] = StatementInfo("__str", "is");
21         dict[-3] = StatementInfo("__flt", "i");
22 }
23
24 Statement BinaryParser::parse()
25 {
26         const StatementKey *key;
27         if(cur_info)
28         {
29                 key = &cur_info->key;
30                 cur_info = nullptr;
31         }
32         else
33         {
34                 int id = parse_int();
35                 if(!in)
36                         return Statement();
37
38                 key = &get_item(dict, id).key;
39         }
40
41         Statement result;
42         result.keyword = key->keyword;
43         result.source = src;
44
45         for(unsigned j=0; j<key->signature.size(); ++j)
46         {
47                 switch(key->signature[j])
48                 {
49                 case IntType::signature:
50                         result.args.push_back(parse_int());
51                         break;
52                 case FloatType::signature:
53                         result.args.push_back(parse_float());
54                         break;
55                 case StringType::signature:
56                         result.args.push_back(parse_string());
57                         break;
58                 case BoolType::signature:
59                         result.args.push_back(parse_bool());
60                         break;
61                 case SymbolType::signature:
62                         result.args.push_back(Value(parse_symbol()));
63                         break;
64                 }
65         }
66
67         unsigned upper_nsub = (sub_remaining.empty() ? 0 : sub_remaining.back());
68
69         unsigned nsub = parse_int();
70         for(unsigned j = 0; j<nsub; ++j)
71                 result.sub.push_back(parse());
72
73         if(upper_nsub>0)
74                 sub_remaining.back() = upper_nsub-1;
75
76         result.valid = true;
77
78         return result;
79 }
80
81 void BinaryParser::process_control_statement(const Statement &st)
82 {
83         if(st.keyword=="__kwd")
84         {
85                 int id = st.args[0].get<int>();
86                 if(id<=0)
87                         throw bad_definition("__kwd");
88
89                 const string &kw = st.args[1].get<const string &>();
90                 const string &args = st.args[2].get<const string &>();
91                 for(char c: args)
92                         for(unsigned j=0; valid_signatures[j]!=c; ++j)
93                                 if(!valid_signatures[j])
94                                         throw bad_definition("__kwd");
95
96                 dict[id] = StatementInfo(kw, args);
97         }
98         else if(st.keyword=="__str")
99         {
100                 int id = st.args[0].get<int>();
101                 if(id<=0)
102                         throw bad_definition("__str");
103
104                 strings[id] = st.args[1].get<const string &>();
105         }
106         else if(st.keyword=="__flt")
107                 float_precision = st.args[0].get<unsigned>();
108 }
109
110 const StatementKey *BinaryParser::peek(unsigned level)
111 {
112         if(level>sub_remaining.size())
113                 throw nesting_error("bad level");
114         while(level<sub_remaining.size())
115         {
116                 // Discard any substatements that haven't been parsed yet
117                 for(unsigned i=sub_remaining.back(); i-->0; )
118                         parse();
119                 sub_remaining.pop_back();
120                 cur_info = nullptr;
121         }
122
123         if(!sub_remaining.empty() && sub_remaining.back()==0)
124         {
125                 // No more substatements on this level
126                 cur_info = nullptr;
127                 return nullptr;
128         }
129
130         if(cur_info)
131                 return &cur_info->key;
132
133         int id = parse_int();
134         if(!in)
135                 return nullptr;
136
137         cur_info = &get_item(dict, id);
138         return &cur_info->key;
139 }
140
141 bool BinaryParser::parse_and_load(unsigned level, Loader &ldr, const LoaderAction &act)
142 {
143         if(!cur_info && !peek(level))
144                 return false;
145
146         ArgumentStore args(*cur_info);
147         for(unsigned i=0; i<cur_info->key.signature.size(); ++i)
148                 switch(cur_info->key.signature[i])
149                 {
150                 case IntType::signature:
151                         args.set(i, parse_int());
152                         break;
153                 case FloatType::signature:
154                         args.set(i, parse_float());
155                         break;
156                 case BoolType::signature:
157                         args.set(i, parse_bool());
158                         break;
159                 case StringType::signature:
160                         args.set(i, parse_string());
161                         break;
162                 case SymbolType::signature:
163                         args.set(i, parse_symbol());
164                         break;
165                 }
166
167         if(!sub_remaining.empty())
168                 --sub_remaining.back();
169         sub_remaining.push_back(parse_int());
170         cur_info = nullptr;
171
172         act.execute(ldr, args);
173
174         return true;
175 }
176
177 IntType::Store BinaryParser::parse_int()
178 {
179         IntType::Store result = 0;
180         unsigned bits = 0;
181
182         while(in)
183         {
184                 int c = in.get();
185
186                 result = (result<<7) | (c&0x7F);
187                 bits += 7;
188
189                 if(!(c&0x80))
190                         break;
191         }
192
193         const IntType::Store mask = 1LL<<(bits-1);
194         result = (result^mask)-mask;
195
196         return result;
197 }
198
199 FloatType::Store BinaryParser::parse_float()
200 {
201         uint64_t encoded = 0;
202         for(unsigned i=0; i<float_precision; i+=8)
203         {
204                 int c = in.get();
205                 encoded = (encoded<<8) | (c&0xFF);
206         }
207
208         BinFloat bf = BinFloat::explode(encoded, float_precision);
209
210         if(numeric_limits<FloatType::Store>::is_iec559)
211                 return bf.compose_iec559<FloatType::Store>();
212         else
213         {
214                 /* Put the float together with arithmetic since we don't know its
215                 internal layout */
216                 FloatType::Store f = 0;
217                 if(bf.infinity)
218                 {
219                         if(numeric_limits<FloatType::Store>::has_infinity)
220                                 f = numeric_limits<FloatType::Store>::infinity();
221                         else
222                                 f = numeric_limits<FloatType::Store>::max();
223                 }
224                 else
225                 {
226                         for(unsigned i=0; i<64; ++i)
227                         {
228                                 f /= 2;
229                                 if(bf.mantissa&1)
230                                         f += 1;
231                                 bf.mantissa >>= 1;
232                         }
233                         for(int i=0; i<bf.exponent; ++i)
234                                 f *= 2;
235                         for(int i=0; i>bf.exponent; --i)
236                                 f /= 2;
237                 }
238                 if(bf.sign)
239                         f = -f;
240                 return f;
241         }
242 }
243
244 BoolType::Store BinaryParser::parse_bool()
245 {
246         return in.get();
247 }
248
249 StringType::Store BinaryParser::parse_string()
250 {
251         int len = parse_int();
252         if(len>=0)
253         {
254                 string result;
255                 result.reserve(len);
256                 for(int i = 0; i<len; ++i)
257                         result += in.get();
258                 return result;
259         }
260         else
261                 return get_item(strings, -len);
262 }
263
264 SymbolType::Store BinaryParser::parse_symbol()
265 {
266         return get_item(strings, parse_int());
267 }
268
269 } // namespace DataFile
270 } // namespace Msp