]> git.tdb.fi Git - libs/datafile.git/blob - source/binaryparser.cpp
81a86ea9a3b66b7ae9c9a6ba0a3dfff4f134ff17
[libs/datafile.git] / source / binaryparser.cpp
1 #include <sys/param.h>
2 #include <msp/core/maputils.h>
3 #include <msp/strings/format.h>
4 #include "binaryparser.h"
5 #include "input.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace DataFile {
11
12 class bad_definition: public runtime_error
13 {
14 public:
15         bad_definition(const std::string &w):
16                 runtime_error(w)
17         { }
18
19         virtual ~bad_definition() throw() { }
20 };
21
22
23 BinaryParser::BinaryParser(Input &i, const string &s):
24         ParserMode(i, s),
25         first(true)
26 {
27         dict[-1] = DictEntry("__kwd", "iss");
28         dict[-2] = DictEntry("__str", "is");
29 }
30
31 Statement BinaryParser::parse()
32 {
33         while(1)
34         {
35                 Statement st = parse_statement();
36                 if(st.keyword=="__kwd")
37                 {
38                         if(st.args.size()!=3)
39                                 throw bad_definition("__kwd");
40
41                         const int id = st.args[0].get<unsigned>();
42                         const string &kw = st.args[1].get<const string &>();
43                         const string &args = st.args[2].get<const string &>();
44                         dict[id] = DictEntry(kw, args);
45                 }
46                 else if(st.keyword=="__str")
47                 {
48                         if(st.args.size()!=2)
49                                 throw bad_definition("__str");
50
51                         const unsigned id = st.args[0].get<unsigned>();
52                         strings[id] = st.args[1].get<const string &>();
53                 }
54                 else
55                         return st;
56         }
57 }
58
59 Statement BinaryParser::parse_statement()
60 {
61         while(first && in.peek()=='\n')
62                 in.get();
63         first = false;
64
65         int id = parse_int();
66         if(!in)
67                 return Statement();
68
69         const DictEntry &de = get_item(dict, id);
70
71         Statement result;
72         result.keyword = de.keyword;
73         result.source = src;
74
75         for(unsigned j = 0; j<de.args.size(); ++j)
76         {
77                 switch(de.args[j])
78                 {
79                 case IntType::signature:
80                         result.args.push_back(parse_int());
81                         break;
82                 case FloatType::signature:
83                         result.args.push_back(parse_float());
84                         break;
85                 case StringType::signature:
86                         result.args.push_back(parse_string());
87                         break;
88                 case BoolType::signature:
89                         result.args.push_back(parse_bool());
90                         break;
91                 case SymbolType::signature:
92                         result.args.push_back(parse_symbol());
93                         break;
94                 }
95         }
96
97         unsigned nsub = parse_int();
98         for(unsigned j = 0; j<nsub; ++j)
99                 result.sub.push_back(parse());
100
101         result.valid = true;
102
103         return result;
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         union
131         {
132                 float f;
133                 char d[sizeof(float)];
134         };
135
136 #if BYTE_ORDER == LITTLE_ENDIAN
137         for(unsigned i = sizeof(float); i--;)
138                 d[i] = in.get();
139 #else
140         for(unsigned i = 0; i<sizeof(float); ++i)
141                 d[i] = in.get();
142 #endif
143
144         return f;
145 }
146
147 BoolType::Store BinaryParser::parse_bool()
148 {
149         return in.get();
150 }
151
152 StringType::Store BinaryParser::parse_string()
153 {
154         int len = parse_int();
155         if(len>=0)
156         {
157                 string result;
158                 result.reserve(len);
159                 for(int i = 0; i<len; ++i)
160                         result += in.get();
161                 return result;
162         }
163         else
164                 return get_item(strings, -len);
165 }
166
167 SymbolType::Store BinaryParser::parse_symbol()
168 {
169         return get_item(strings, parse_int());
170 }
171
172 } // namespace DataFile
173 } // namespace Msp