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