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