]> git.tdb.fi Git - libs/datafile.git/blob - source/binarywriter.cpp
Refactor symbol handling in binary format
[libs/datafile.git] / source / binarywriter.cpp
1 #include <msp/core/maputils.h>
2 #include "binarywriter.h"
3 #include "statement.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace DataFile {
9
10 BinaryWriter::BinaryWriter(IO::Base &o):
11         WriterMode(o),
12         next_kwd_id(3),
13         next_str_id(1)
14 {
15         dict[DictEntry("__kwd", "iss")] = 1;
16         dict[DictEntry("__str", "is")] = 2;
17 }
18
19 void BinaryWriter::write(const Statement &st)
20 {
21         collect_keywords(st);
22         write_(st);
23 }
24
25 void BinaryWriter::write_(const Statement &st)
26 {
27         unsigned id = get_item(dict, DictEntry(st.keyword, st.get_signature()));
28
29         write_int(id);
30         for(Statement::Arguments::const_iterator j = st.args.begin(); j!=st.args.end(); ++j)
31                 switch(j->get_signature())
32                 {
33                 case IntType::signature:    write_int   (j->get<IntType::Store>()); break;
34                 case StringType::signature: write_string(j->get<StringType::Store>()); break;
35                 case BoolType::signature:   write_int   (j->get<BoolType::Store>()); break;
36                 case FloatType::signature:  write_float (j->get<FloatType::Store>()); break;
37                 case SymbolType::signature: write_symbol(j->get<SymbolType::Store>()); break;
38                 }
39
40         write_int(st.sub.size());
41         for(list<Statement>::const_iterator j = st.sub.begin(); j!=st.sub.end(); ++j)
42                 write(*j);
43 }
44
45 void BinaryWriter::collect_keywords(const Statement &st)
46 {
47         DictEntry de(st.keyword, st.get_signature());
48
49         if(!dict.count(de))
50         {
51                 Statement kst;
52                 kst.keyword = "__kwd";
53                 kst.args.push_back(next_kwd_id);
54                 kst.args.push_back(de.keyword);
55                 kst.args.push_back(de.args);
56                 write_(kst);
57
58                 dict[de] = next_kwd_id++;
59         }
60
61         for(ValueArray::const_iterator i = st.args.begin(); i!=st.args.end(); ++i)
62         {
63                 char sig = i->get_signature();
64                 string str;
65                 if(sig==SymbolType::signature)
66                         str = i->get<Symbol>().name;
67                 else if(sig==StringType::signature)
68                 {
69                         str = i->get<string>();
70                         if(str.size()>32)
71                                 continue;
72                 }
73                 else
74                         continue;
75
76                 if(strings.count(str))
77                         continue;
78
79                 Statement sst;
80                 sst.keyword = "__str";
81                 sst.args.push_back(next_str_id);
82                 sst.args.push_back(str);
83                 write_(sst);
84
85                 strings[str] = next_str_id++;
86         }
87
88         for(list<Statement>::const_iterator i = st.sub.begin(); i!=st.sub.end(); ++i)
89                 collect_keywords(*i);
90 }
91
92 void BinaryWriter::write_int(long long n)
93 {
94         unsigned i = sizeof(long long)-1;
95
96         if(n>=0)
97                 for(; (i>0 && (n>>(i*7-1))==0); --i) ;
98         else
99                 for(; (i>0 && (n>>(i*7-1))==-1); --i) ;
100
101         for(++i; i--;)
102                 out.put((n>>(i*7) & 0x7F) | (i?0x80:0));
103 }
104
105 void BinaryWriter::write_string(const string &s)
106 {
107         StringMap::const_iterator i = strings.find(s);
108         if(i!=strings.end())
109                 write_int(-static_cast<int>(i->second));
110         else
111         {
112                 write_int(s.size());
113                 out.write(s.data(), s.size());
114         }
115 }
116
117 void BinaryWriter::write_float(float f)
118 {
119         union
120         {
121                 float v;
122                 char d[sizeof(float)];
123         };
124
125         v = f;
126 #if BYTE_ORDER == LITTLE_ENDIAN
127         for(unsigned i = sizeof(float); i--;)
128                 out.put(d[i]);
129 #else
130         for(unsigned i = 0; i<sizeof(float); ++i)
131                 out.put(d[i]);
132 #endif
133 }
134
135 void BinaryWriter::write_symbol(const Symbol &s)
136 {
137         write_int(get_item(strings, s.name));
138 }
139
140 } // namespace DataFile
141 } // namespace Msp