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