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