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