]> git.tdb.fi Git - libs/datafile.git/blob - source/binarywriter.cpp
Add reverse name lookup to Collection
[libs/datafile.git] / source / binarywriter.cpp
1 /* $Id$
2
3 This file is part of libmspdatafile
4 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include "binarywriter.h"
9 #include "statement.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace DataFile {
15
16 BinaryWriter::BinaryWriter(IO::Base &o):
17         WriterMode(o),
18         next_kwd_id(3),
19         next_str_id(1)
20 {
21         dict[DictEntry("__kwd", "iss")]=1;
22         dict[DictEntry("__str", "is")]=2;
23 }
24
25 void BinaryWriter::write(const Statement &st)
26 {
27         collect_keywords(st);
28         write_(st);
29 }
30
31 void BinaryWriter::write_(const Statement &st)
32 {
33         Dictionary::iterator i=dict.find(create_entry(st));
34         if(i==dict.end())
35                 throw InvalidParameterValue("Unknown statement");
36
37         write_int(i->second);
38         for(ValueArray::const_iterator j=st.args.begin(); j!=st.args.end(); ++j)
39                 switch(j->get_type())
40                 {
41                 case INTEGER: write_int   (j->get<long long>()); break;
42                 case STRING:  write_string(j->get<const string &>()); break;
43                 case BOOLEAN: write_int   (j->get<bool>()); break;
44                 case FLOAT:   write_float (j->get<float>()); break;
45                 case ENUM:    write_enum  (j->get_raw()); break;
46                 }
47
48         write_int(st.sub.size());
49         for(list<Statement>::const_iterator j=st.sub.begin(); j!=st.sub.end(); ++j)
50                 write(*j);
51 }
52
53 DictEntry BinaryWriter::create_entry(const Statement &st)
54 {
55         static const char types[]="ifsbe";
56
57         string args;
58         for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i)
59         {
60                 if(i->get_type()>=5)
61                         throw InvalidParameterValue("Invalid argument type");
62                 args+=types[i->get_type()];
63         }
64
65         return DictEntry(st.keyword, args);
66 }
67
68 void BinaryWriter::collect_keywords(const Statement &st)
69 {
70         DictEntry de=create_entry(st);
71
72         if(!dict.count(de))
73         {
74                 Statement kst;
75                 kst.keyword="__kwd";
76                 kst.args.push_back(next_kwd_id);
77                 kst.args.push_back(de.keyword);
78                 kst.args.push_back(de.args);
79                 write_(kst);
80
81                 dict[de]=next_kwd_id++;
82         }
83
84         for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i)
85         {
86                 const Type t=i->get_type();
87                 const string &r=i->get_raw();
88                 if((t==ENUM || (t==STRING && r.size()<32)) && !strings.count(r))
89                 {
90                         Statement sst;
91                         sst.keyword="__str";
92                         sst.args.push_back(next_str_id);
93                         sst.args.push_back(r);
94                         write_(sst);
95
96                         strings[r]=next_str_id++;
97                 }
98         }
99
100         for(list<Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
101                 collect_keywords(*i);
102 }
103
104 void BinaryWriter::write_int(long long n)
105 {
106         unsigned i=sizeof(long long)-1;
107
108         if(n>=0)
109                 for(; (i>0 && (n>>(i*7-1))==0); --i) ;
110         else
111                 for(; (i>0 && (n>>(i*7-1))==-1); --i) ;
112
113         for(++i; i--;)
114                 out.put((n>>(i*7) & 0x7F) | (i?0x80:0));
115 }
116
117 void BinaryWriter::write_string(const string &s)
118 {
119         StringMap::const_iterator i=strings.find(s);
120         if(i!=strings.end())
121                 write_int(-static_cast<int>(i->second));
122         else
123         {
124                 write_int(s.size());
125                 out.write(s.data(), s.size());
126         }
127 }
128
129 void BinaryWriter::write_float(float f)
130 {
131         union
132         {
133                 float v;
134                 char d[sizeof(float)];
135         };
136
137         v=f;
138 #if BYTE_ORDER == LITTLE_ENDIAN
139         for(unsigned i=sizeof(float); i--;)
140                 out.put(d[i]);
141 #else
142         for(unsigned i=0; i<sizeof(float); ++i)
143                 out.put(d[i]);
144 #endif
145 }
146
147 void BinaryWriter::write_enum(const string &e)
148 {
149         StringMap::const_iterator i=strings.find(e);
150         if(i==strings.end())
151                 throw InvalidParameterValue("Unknown enum");
152         write_int(i->second);
153 }
154
155 } // namespace DataFile
156 } // namespace Msp