]> git.tdb.fi Git - libs/datafile.git/blob - source/binaryparser.cpp
Restructure control statement processing
[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 "binaryparser.h"
6 #include "binfloat.h"
7 #include "input.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace DataFile {
13
14 class bad_definition: public runtime_error
15 {
16 public:
17         bad_definition(const std::string &w):
18                 runtime_error(w)
19         { }
20
21         virtual ~bad_definition() throw() { }
22 };
23
24
25 BinaryParser::BinaryParser(Input &i, const string &s):
26         ParserMode(i, s),
27         first(true),
28         float_precision(32)
29 {
30         dict[-1] = StatementKey("__kwd", "iss");
31         dict[-2] = StatementKey("__str", "is");
32         dict[-3] = StatementKey("__flt", "i");
33 }
34
35 Statement BinaryParser::parse()
36 {
37         while(first && in.peek()=='\n')
38                 in.get();
39         first = false;
40
41         int id = parse_int();
42         if(!in)
43                 return Statement();
44
45         const StatementKey &key = get_item(dict, id);
46
47         Statement result;
48         result.keyword = key.keyword;
49         result.source = src;
50
51         for(unsigned j=0; j<key.signature.size(); ++j)
52         {
53                 switch(key.signature[j])
54                 {
55                 case IntType::signature:
56                         result.args.push_back(parse_int());
57                         break;
58                 case FloatType::signature:
59                         result.args.push_back(parse_float());
60                         break;
61                 case StringType::signature:
62                         result.args.push_back(parse_string());
63                         break;
64                 case BoolType::signature:
65                         result.args.push_back(parse_bool());
66                         break;
67                 case SymbolType::signature:
68                         result.args.push_back(parse_symbol());
69                         break;
70                 }
71         }
72
73         unsigned nsub = parse_int();
74         for(unsigned j = 0; j<nsub; ++j)
75                 result.sub.push_back(parse());
76
77         result.valid = true;
78
79         return result;
80 }
81
82 void BinaryParser::process_control_statement(const Statement &st)
83 {
84         if(st.keyword=="__kwd")
85         {
86                 int id = st.args[0].get<int>();
87                 if(id<=0)
88                         throw bad_definition("__kwd");
89
90                 const string &kw = st.args[1].get<const string &>();
91                 const string &args = st.args[2].get<const string &>();
92                 for(string::const_iterator i=args.begin(); i!=args.end(); ++i)
93                         for(unsigned j=0; valid_signatures[j]!=*i; ++j)
94                                 if(!valid_signatures[j])
95                                         throw bad_definition("__kwd");
96
97                 dict[id] = StatementKey(kw, args);
98         }
99         else if(st.keyword=="__str")
100         {
101                 int id = st.args[0].get<int>();
102                 if(id<=0)
103                         throw bad_definition("__str");
104
105                 strings[id] = st.args[1].get<const string &>();
106         }
107         else if(st.keyword=="__flt")
108                 float_precision = st.args[0].get<unsigned>();
109 }
110
111 IntType::Store BinaryParser::parse_int()
112 {
113         IntType::Store result = 0;
114         unsigned bits = 0;
115
116         while(in)
117         {
118                 int c = in.get();
119
120                 result = (result<<7) | (c&0x7F);
121                 bits += 7;
122
123                 if(!(c&0x80))
124                         break;
125         }
126
127         const IntType::Store mask = 1LL<<(bits-1);
128         result = (result^mask)-mask;
129
130         return result;
131 }
132
133 FloatType::Store BinaryParser::parse_float()
134 {
135         UInt64 encoded = 0;
136         for(unsigned i=0; i<float_precision; i+=8)
137         {
138                 int c = in.get();
139                 encoded = (encoded<<8) | (c&0xFF);
140         }
141
142         BinFloat bf = BinFloat::explode(encoded, float_precision);
143
144         if(numeric_limits<FloatType::Store>::is_iec559)
145                 return bf.compose_iec559<FloatType::Store>();
146         else
147         {
148                 /* Put the float together with arithmetic since we don't know its
149                 internal layout */
150                 FloatType::Store f = 0;
151                 if(bf.infinity)
152                 {
153                         if(numeric_limits<FloatType::Store>::has_infinity)
154                                 f = numeric_limits<FloatType::Store>::infinity();
155                         else
156                                 f = numeric_limits<FloatType::Store>::max();
157                 }
158                 else
159                 {
160                         for(unsigned i=0; i<64; ++i)
161                         {
162                                 f /= 2;
163                                 if(bf.mantissa&1)
164                                         f += 1;
165                                 bf.mantissa >>= 1;
166                         }
167                         for(int i=0; i<bf.exponent; ++i)
168                                 f *= 2;
169                         for(int i=0; i>bf.exponent; --i)
170                                 f /= 2;
171                 }
172                 if(bf.sign)
173                         f = -f;
174                 return f;
175         }
176 }
177
178 BoolType::Store BinaryParser::parse_bool()
179 {
180         return in.get();
181 }
182
183 StringType::Store BinaryParser::parse_string()
184 {
185         int len = parse_int();
186         if(len>=0)
187         {
188                 string result;
189                 result.reserve(len);
190                 for(int i = 0; i<len; ++i)
191                         result += in.get();
192                 return result;
193         }
194         else
195                 return get_item(strings, -len);
196 }
197
198 SymbolType::Store BinaryParser::parse_symbol()
199 {
200         return get_item(strings, parse_int());
201 }
202
203 } // namespace DataFile
204 } // namespace Msp