]> git.tdb.fi Git - libs/datafile.git/blob - source/binaryparser.cpp
Update formatter.h -> format.h
[libs/datafile.git] / source / binaryparser.cpp
1 #include <sys/param.h>
2 #include <msp/strings/format.h>
3 #include "binaryparser.h"
4 #include "input.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace DataFile {
10
11 BinaryParser::BinaryParser(Input &i, const string &s):
12         ParserMode(i, s),
13         first(true)
14 {
15         dict[1] = DictEntry("__kwd", "iss");
16         dict[2] = DictEntry("__str", "is");
17 }
18
19 Statement BinaryParser::parse()
20 {
21         while(1)
22         {
23                 Statement st = parse_statement();
24                 if(st.keyword=="__kwd")
25                 {
26                         if(st.args.size()!=3)
27                                 throw_at(TypeError("Keyword definition must have three arguments"), src);
28
29                         const unsigned id = st.args[0].get<unsigned>();
30                         const string &kw = st.args[1].get<const string &>();
31                         const string &args = st.args[2].get<const string &>();
32                         dict[id] = DictEntry(kw, args);
33                 }
34                 else if(st.keyword=="__str")
35                 {
36                         if(st.args.size()!=2)
37                                 throw_at(TypeError("String definition must have two arguments"), src);
38
39                         const unsigned id = st.args[0].get<unsigned>();
40                         strings[id] = st.args[1].get<const string &>();
41                 }
42                 else
43                         return st;
44         }
45 }
46
47 Statement BinaryParser::parse_statement()
48 {
49         while(first && in.peek()=='\n')
50                 in.get();
51         first = false;
52
53         unsigned id = parse_int();
54         if(!in)
55                 return Statement();
56
57         Dictionary::const_iterator i = dict.find(id);
58         if(i==dict.end())
59                 throw_at(KeyError("Unknown statement ID", lexical_cast(id)), src);
60         const DictEntry &de = i->second;
61
62         Statement result;
63         result.keyword = de.keyword;
64         result.source = src;
65
66         for(unsigned j = 0; j<de.args.size(); ++j)
67         {
68                 switch(de.args[j])
69                 {
70                 case IntType::signature:
71                         result.args.push_back(parse_int());
72                         break;
73                 case FloatType::signature:
74                         result.args.push_back(parse_float());
75                         break;
76                 case StringType::signature:
77                         result.args.push_back(parse_string());
78                         break;
79                 case BoolType::signature:
80                         result.args.push_back(parse_bool());
81                         break;
82                 case SymbolType::signature:
83                         result.args.push_back(Symbol(parse_enum()));
84                         break;
85                 }
86         }
87
88         unsigned nsub = parse_int();
89         for(unsigned j = 0; j<nsub; ++j)
90                 result.sub.push_back(parse());
91
92         result.valid = true;
93
94         return result;
95 }
96
97 long long BinaryParser::parse_int()
98 {
99         long long result = 0;
100         unsigned bits = 0;
101
102         while(in)
103         {
104                 int c = in.get();
105
106                 result = (result<<7) | (c&0x7F);
107                 bits += 7;
108
109                 if(!(c&0x80))
110                         break;
111         }
112
113         const long long mask = 1LL<<(bits-1);
114         result = (result^mask)-mask;
115
116         return result;
117 }
118
119 float BinaryParser::parse_float()
120 {
121         union
122         {
123                 float f;
124                 char d[sizeof(float)];
125         };
126
127 #if BYTE_ORDER == LITTLE_ENDIAN
128         for(unsigned i = sizeof(float); i--;)
129                 d[i] = in.get();
130 #else
131         for(unsigned i = 0; i<sizeof(float); ++i)
132                 d[i] = in.get();
133 #endif
134
135         return f;
136 }
137
138 bool BinaryParser::parse_bool()
139 {
140         return in.get();
141 }
142
143 string BinaryParser::parse_string()
144 {
145         int len = parse_int();
146         if(len>=0)
147         {
148                 string result;
149                 result.reserve(len);
150                 for(int i = 0; i<len; ++i)
151                         result += in.get();
152                 return result;
153         }
154         else
155                 return lookup_string(-len);
156 }
157
158 string BinaryParser::parse_enum()
159 {
160         return lookup_string(parse_int());
161 }
162
163 const string &BinaryParser::lookup_string(unsigned id) const
164 {
165         StringMap::const_iterator i = strings.find(id);
166         if(i==strings.end())
167                 throw_at(KeyError("Unknown string", lexical_cast(id)), src);
168         return i->second;
169 }
170
171 } // namespace DataFile
172 } // namespace Msp