]> git.tdb.fi Git - libs/datafile.git/blob - source/binarywriter.cpp
Use libmspio instead of C++ iostreams
[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_st_id(3),
19         next_enum_id(1)
20 {
21         dict[DictEntry("__st", "iss")]=1;
22         dict[DictEntry("__enum", "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="__st";
76                 kst.args.push_back(next_st_id);
77                 kst.args.push_back(de.keyword);
78                 kst.args.push_back(de.args);
79                 write_(kst);
80
81                 dict[de]=next_st_id++;
82         }
83
84         for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i)
85                 if(i->get_type()==ENUM && !enums.count(i->get_raw()))
86                 {
87                         Statement est;
88                         est.keyword="__enum";
89                         est.args.push_back(next_enum_id);
90                         est.args.push_back(i->get_raw());
91                         write_(est);
92
93                         enums[i->get_raw()]=next_enum_id++;
94                 }
95
96         for(list<Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
97                 collect_keywords(*i);
98 }
99
100 void BinaryWriter::write_int(long long n)
101 {
102         unsigned i=sizeof(long long)-1;
103
104         if(n>=0)
105                 for(; (i>0 && (n>>(i*7-1))==0); --i);
106         else
107                 for(; (i>0 && (n>>(i*7-1))==-1); --i);
108
109         for(++i; i--;)
110                 out.put(n>>(i*7) & 0x7F | (i?0x80:0));
111 }
112
113 void BinaryWriter::write_string(const string &s)
114 {
115         write_int(s.size());
116         out.write(s.data(), s.size());
117 }
118
119 void BinaryWriter::write_float(float f)
120 {
121         union
122         {
123                 float v;
124                 char d[sizeof(float)];
125         };
126
127         v=f;
128 #if BYTE_ORDER == LITTLE_ENDIAN
129         for(unsigned i=sizeof(float); i--;)
130                 out.put(d[i]);
131 #else
132         for(unsigned i=0; i<sizeof(float); ++i)
133                 out.put(d[i]);
134 #endif
135 }
136
137 void BinaryWriter::write_enum(const string &e)
138 {
139         EnumMap::const_iterator i=enums.find(e);
140         if(i==enums.end())
141                 throw InvalidParameterValue("Unknown enum");
142         write_int(i->second);
143 }
144
145 } // namespace DataFile
146 } // namespace Msp