-rw-r--r-- | lib/.gitignore | 7 | ||||
-rw-r--r-- | lib/MThd.cc | 38 | ||||
-rw-r--r-- | lib/MTrk.cc | 34 | ||||
-rw-r--r-- | lib/Makefile.am | 15 | ||||
-rw-r--r-- | lib/SMF.cc | 62 | ||||
-rw-r--r-- | lib/chunk.cc | 31 | ||||
-rw-r--r-- | lib/event.cc | 58 | ||||
-rw-r--r-- | lib/message.cc | 247 | ||||
-rw-r--r-- | lib/util.cc | 96 |
9 files changed, 588 insertions, 0 deletions
diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..dc5e416 --- a/dev/null +++ b/lib/.gitignore | |||
@@ -0,0 +1,7 @@ | |||
1 | *.lo | ||
2 | *.o | ||
3 | Makefile.in | ||
4 | .libs | ||
5 | .deps | ||
6 | Makefile | ||
7 | *.la | ||
diff --git a/lib/MThd.cc b/lib/MThd.cc new file mode 100644 index 0000000..110c98a --- a/dev/null +++ b/lib/MThd.cc | |||
@@ -0,0 +1,38 @@ | |||
1 | #include <midillo/MThd.h> | ||
2 | #include <midillo/util.h> | ||
3 | #include <midillo/exception.h> | ||
4 | |||
5 | namespace midillo { | ||
6 | using std::endl; | ||
7 | |||
8 | void MThd_t::load(istream& s) { | ||
9 | header.load(s); | ||
10 | if(header.id_number!=chunk_id_MThd) | ||
11 | throw exception_unexpected_input(CODEPOINT,"MThd chunk expected"); | ||
12 | if(header.length!=6) | ||
13 | throw exception_invalid_input(CODEPOINT,"MThd chunk is not 6 bytes long"); | ||
14 | load_data(s); | ||
15 | } | ||
16 | |||
17 | void MThd_t::load_data(istream& s) { | ||
18 | fmt = read16(s); | ||
19 | ntracks = read16(s); | ||
20 | division = read16(s); | ||
21 | } | ||
22 | |||
23 | void MThd_t::save(ostream& s) const { | ||
24 | header.save(s); | ||
25 | write16(s,fmt); | ||
26 | write16(s,ntracks); | ||
27 | write16(s,division); | ||
28 | } | ||
29 | |||
30 | void MThd_t::dump(ostream& s) const { | ||
31 | std::ios::fmtflags ff = s.flags(); | ||
32 | s.unsetf(std::ios::hex); s.setf(std::ios::dec); | ||
33 | s << " " << header << endl | ||
34 | << " fmt=" << fmt << ", " << ntracks << " track(s), division=" << division << endl; | ||
35 | s.flags(ff); | ||
36 | } | ||
37 | |||
38 | } | ||
diff --git a/lib/MTrk.cc b/lib/MTrk.cc new file mode 100644 index 0000000..fa1e0f8 --- a/dev/null +++ b/lib/MTrk.cc | |||
@@ -0,0 +1,34 @@ | |||
1 | #include <algorithm> | ||
2 | #include <iterator> | ||
3 | #include <midillo/MTrk.h> | ||
4 | #include <midillo/exception.h> | ||
5 | |||
6 | namespace midillo { | ||
7 | using std::copy; | ||
8 | using std::ostream_iterator; | ||
9 | using std::endl; | ||
10 | |||
11 | void MTrk_t::load(istream& s) { | ||
12 | header.load(s); | ||
13 | if(header.id_number!=chunk_id_MTrk) | ||
14 | throw exception_unexpected_input(CODEPOINT,"MTrk chunk expected"); | ||
15 | events.load(s); | ||
16 | } | ||
17 | |||
18 | void MTrk_t::save(ostream& s) const { | ||
19 | chunk_header_t h = header; | ||
20 | h.id_number = chunk_id_MTrk; | ||
21 | h.length = events.calculate_save_size(); | ||
22 | h.save(s); | ||
23 | events.save(s); | ||
24 | } | ||
25 | |||
26 | void MTrk_t::dump(ostream& s) const { | ||
27 | s << " " << header << endl | ||
28 | << " "; | ||
29 | copy( | ||
30 | events.begin(), events.end(), | ||
31 | ostream_iterator<event_t>(s,"\n ") ); | ||
32 | } | ||
33 | |||
34 | } | ||
diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..de49c97 --- a/dev/null +++ b/lib/Makefile.am | |||
@@ -0,0 +1,15 @@ | |||
1 | lib_LTLIBRARIES = libmidillo.la | ||
2 | |||
3 | INCLUDES = -I${top_srcdir}/include -I${top_srcdir} | ||
4 | AM_CXXFLAGS = ${KONFORKA_CFLAGS} | ||
5 | LDADD = ${KONFORKA_LIBS} | ||
6 | |||
7 | libmidillo_la_SOURCES = \ | ||
8 | util.cc \ | ||
9 | SMF.cc \ | ||
10 | chunk.cc \ | ||
11 | MThd.cc MTrk.cc \ | ||
12 | event.cc \ | ||
13 | message.cc | ||
14 | |||
15 | libmidillo_la_LDFLAGS = -version-info 0:0:0 | ||
diff --git a/lib/SMF.cc b/lib/SMF.cc new file mode 100644 index 0000000..ba3179d --- a/dev/null +++ b/lib/SMF.cc | |||
@@ -0,0 +1,62 @@ | |||
1 | #include <iostream> | ||
2 | #include <fstream> | ||
3 | #include <algorithm> | ||
4 | #include <iterator> | ||
5 | #include <midillo/SMF.h> | ||
6 | |||
7 | namespace midillo { | ||
8 | using std::ifstream; | ||
9 | using std::ofstream; | ||
10 | using std::cin; | ||
11 | using std::cout; | ||
12 | using std::copy; | ||
13 | using std::ostream_iterator; | ||
14 | using std::endl; | ||
15 | |||
16 | void SMF_t::load(const char *f,bool stdinable) { | ||
17 | if(stdinable && !strcmp(f,"-")) { | ||
18 | load(cin); | ||
19 | }else{ | ||
20 | ifstream s(f,std::ios::in|std::ios::binary); | ||
21 | load(s); | ||
22 | } | ||
23 | } | ||
24 | |||
25 | void SMF_t::load(istream& s) { | ||
26 | mthd.load(s); | ||
27 | tracks.resize(mthd.ntracks); | ||
28 | tracks_t::iterator i = tracks.begin(); | ||
29 | for(int t=0;t<mthd.ntracks;++t,++i) { | ||
30 | i->load(s); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | void SMF_t::save(const char *f,bool stdoutable) const { | ||
35 | if(stdoutable && !strcmp(f,"-")) { | ||
36 | save(cout); | ||
37 | }else{ | ||
38 | ofstream s(f,std::ios::out|std::ios::trunc|std::ios::binary); | ||
39 | save(s); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | void SMF_t::save(ostream& s) const { | ||
44 | mthd.save(s); | ||
45 | for(tracks_t::const_iterator i=tracks.begin();i!=tracks.end();++i) { | ||
46 | i->save(s); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | void SMF_t::dump(ostream& s) const { | ||
51 | std::ios::fmtflags ff = s.flags(); | ||
52 | s.unsetf(std::ios::hex); s.setf(std::ios::dec); | ||
53 | s | ||
54 | << "SMF with " << tracks.size() << " track(s)" << endl | ||
55 | << mthd << endl; | ||
56 | copy( | ||
57 | tracks.begin(), tracks.end(), | ||
58 | ostream_iterator<MTrk_t>(s,"\n") ); | ||
59 | s.flags(ff); | ||
60 | } | ||
61 | |||
62 | } | ||
diff --git a/lib/chunk.cc b/lib/chunk.cc new file mode 100644 index 0000000..7cc15ff --- a/dev/null +++ b/lib/chunk.cc | |||
@@ -0,0 +1,31 @@ | |||
1 | #include <midillo/chunk.h> | ||
2 | #include <midillo/util.h> | ||
3 | #include <midillo/exception.h> | ||
4 | |||
5 | namespace midillo { | ||
6 | |||
7 | void chunk_header_t::load(istream& s) { | ||
8 | s.read((char*)id_chars,sizeof(id_chars)); | ||
9 | if(!s.good()) | ||
10 | throw exception_input_error(CODEPOINT,"Error reading chunk header"); | ||
11 | length = read32(s); | ||
12 | } | ||
13 | |||
14 | void chunk_header_t::save(ostream& s) const { | ||
15 | s.write((char*)id_chars,sizeof(id_chars)); | ||
16 | if(!s.good()) | ||
17 | throw exception_output_error(CODEPOINT,"Error writing chunk header"); | ||
18 | write32(s,length); | ||
19 | } | ||
20 | |||
21 | void chunk_header_t::dump(ostream& s) const { | ||
22 | std::ios::fmtflags ff = s.flags(); | ||
23 | s.unsetf(std::ios::hex); s.setf(std::ios::dec); | ||
24 | s | ||
25 | << id_chars[0] << id_chars[1] | ||
26 | << id_chars[2] << id_chars[3] | ||
27 | << " chunk of " << length << " byte(s)"; | ||
28 | s.flags(ff); | ||
29 | } | ||
30 | |||
31 | } | ||
diff --git a/lib/event.cc b/lib/event.cc new file mode 100644 index 0000000..39438fa --- a/dev/null +++ b/lib/event.cc | |||
@@ -0,0 +1,58 @@ | |||
1 | #include <midillo/event.h> | ||
2 | #include <midillo/util.h> | ||
3 | |||
4 | namespace midillo { | ||
5 | |||
6 | void event_t::load(int& rs,istream& s) { | ||
7 | deltat = readVL(s); | ||
8 | message.load(rs,s); | ||
9 | } | ||
10 | |||
11 | void event_t::save(int& rs,ostream& s) const { | ||
12 | writeVL(s,deltat); | ||
13 | message.save(rs,s); | ||
14 | } | ||
15 | |||
16 | unsigned long event_t::calculate_save_size(int& rs) const { | ||
17 | return calcVLsize(deltat) + message.calculate_save_size(rs); | ||
18 | } | ||
19 | |||
20 | void event_t::dump(ostream& s) const { | ||
21 | std::ios::fmtflags ff = s.flags(); | ||
22 | s.unsetf(std::ios::hex); s.setf(std::ios::dec); | ||
23 | s << "deltat=" << deltat << " [" << message << "]"; | ||
24 | s.flags(ff); | ||
25 | } | ||
26 | |||
27 | |||
28 | events_t::iterator events_t::append_event() { | ||
29 | static event_t empty; | ||
30 | return insert(end(),empty); | ||
31 | } | ||
32 | |||
33 | void events_t::load(istream& s) { | ||
34 | int rs = -1; | ||
35 | for(;;) { | ||
36 | iterator i=append_event(); | ||
37 | i->load(rs,s); | ||
38 | if(i->message.is_meta(meta_EOT)) | ||
39 | break; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | void events_t::save(ostream& s) const { | ||
44 | int rs = -1; | ||
45 | for(const_iterator i=begin();i!=end();++i) { | ||
46 | i->save(rs,s); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | unsigned long events_t::calculate_save_size() const { | ||
51 | unsigned long rv = 0; | ||
52 | int rs = -1; | ||
53 | for(const_iterator i=begin();i!=end();++i) { | ||
54 | rv += i->calculate_save_size(rs); | ||
55 | } | ||
56 | return rv; | ||
57 | } | ||
58 | } | ||
diff --git a/lib/message.cc b/lib/message.cc new file mode 100644 index 0000000..8f9e68a --- a/dev/null +++ b/lib/message.cc | |||
@@ -0,0 +1,247 @@ | |||
1 | #include <algorithm> | ||
2 | #include <iterator> | ||
3 | #include <midillo/message.h> | ||
4 | #include <midillo/util.h> | ||
5 | #include <midillo/exception.h> | ||
6 | |||
7 | namespace midillo { | ||
8 | using std::copy; | ||
9 | using std::ostream_iterator; | ||
10 | |||
11 | unsigned long message_t::calculate_save_size(int& rs) const { | ||
12 | unsigned long rv = 0; | ||
13 | if(status!=rs) { | ||
14 | ++rv; | ||
15 | rs = status; | ||
16 | }else if((status&status_event_bits)==status_system) { | ||
17 | rs = -1; | ||
18 | ++rv; // XXX: is it really needed? | ||
19 | } | ||
20 | switch(status&status_event_bits) { | ||
21 | case status_note_off: | ||
22 | case status_note_on: | ||
23 | case status_polyphonic_key_pressure: // aka status_aftertouch | ||
24 | case status_control_change: | ||
25 | case status_pitch_wheel_change: | ||
26 | rv += 2; break; | ||
27 | case status_program_change: | ||
28 | case status_channel_pressure: | ||
29 | ++rv; break; | ||
30 | case status_system: | ||
31 | switch(status&status_system_bits) { | ||
32 | case status_system_sysex: | ||
33 | case status_system_end_of_sysex: | ||
34 | rv += data.size()+1; break; | ||
35 | case status_system_MTC_quarter_frame: | ||
36 | case status_system_song_select: | ||
37 | ++rv; break; | ||
38 | case status_system_song_position_pointer: | ||
39 | rv += 2; break; | ||
40 | case status_system_tune_request: | ||
41 | case status_system_timing_clock: // aka status_system_midi_clock | ||
42 | case status_system_midi_tick: | ||
43 | case status_system_start: // aka status_system_midi_start | ||
44 | case status_system_stop: // aka status_system_midi_stop | ||
45 | case status_system_continue: // aka status_system_midi_continue | ||
46 | case status_system_active_sense: | ||
47 | break; /* XXX: ensure there is no data? */ | ||
48 | case status_system_meta: // also reset, but not for the purpose of midi file | ||
49 | ++rv; | ||
50 | rv += calcVLsize(data.size()); | ||
51 | rv += data.size(); | ||
52 | break; | ||
53 | default: | ||
54 | throw exception(CODEPOINT,"Internal error"); | ||
55 | break; | ||
56 | } | ||
57 | break; | ||
58 | default: | ||
59 | throw exception(CODEPOINT,"Internal error"); | ||
60 | break; | ||
61 | } | ||
62 | return rv; | ||
63 | } | ||
64 | |||
65 | void message_t::save(int& rs,ostream& s) const { | ||
66 | if(status!=rs) { | ||
67 | s.put(status); | ||
68 | if(!s.good()) | ||
69 | throw exception_output_error(CODEPOINT,"Error writing midi status byte"); | ||
70 | rs = status; | ||
71 | }else if((status&status_event_bits)==status_system) { | ||
72 | rs = -1; | ||
73 | s.put(status); // XXX: is it really needed? | ||
74 | if(!s.good()) | ||
75 | throw exception_output_error(CODEPOINT,"Error writing midi system status byte"); | ||
76 | } | ||
77 | switch(status&status_event_bits) { | ||
78 | case status_note_off: | ||
79 | case status_note_on: | ||
80 | case status_polyphonic_key_pressure: // aka status_aftertouch | ||
81 | case status_control_change: | ||
82 | case status_pitch_wheel_change: | ||
83 | save_data(s,2); break; | ||
84 | case status_program_change: | ||
85 | case status_channel_pressure: | ||
86 | save_data(s,1); break; | ||
87 | case status_system: | ||
88 | switch(status&status_system_bits) { | ||
89 | case status_system_sysex: | ||
90 | case status_system_end_of_sysex: | ||
91 | save_sysex(s); break; | ||
92 | case status_system_MTC_quarter_frame: | ||
93 | case status_system_song_select: | ||
94 | save_data(s,1); break; | ||
95 | case status_system_song_position_pointer: | ||
96 | save_data(s,2); break; | ||
97 | case status_system_tune_request: | ||
98 | case status_system_timing_clock: // aka status_system_midi_clock | ||
99 | case status_system_midi_tick: | ||
100 | case status_system_start: // aka status_system_midi_start | ||
101 | case status_system_stop: // aka status_system_midi_stop | ||
102 | case status_system_continue: // aka status_system_midi_continue | ||
103 | case status_system_active_sense: | ||
104 | break; /* XXX: ensure there is no data? */ | ||
105 | case status_system_meta: // also reset, but not for the purpose of midi file | ||
106 | s.put(meta_status&0xFF); | ||
107 | if(!s.good()) | ||
108 | throw exception_output_error(CODEPOINT,"Error writing meta event"); | ||
109 | writeVL(s,data.size()); | ||
110 | save_data(s); | ||
111 | break; | ||
112 | default: | ||
113 | throw exception(CODEPOINT,"Internal error"); | ||
114 | break; | ||
115 | } | ||
116 | break; | ||
117 | default: | ||
118 | throw exception(CODEPOINT,"Internal error"); | ||
119 | break; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | void message_t::load(int& rs,istream& s) { | ||
124 | data.clear(); | ||
125 | status = s.get(); | ||
126 | if(!s.good()) | ||
127 | throw exception_input_error(CODEPOINT,"Error reading MIDI event status byte"); | ||
128 | if(status&status_bit) { | ||
129 | if((status&status_event_bits)!=status_system) | ||
130 | rs = status; | ||
131 | }else{ | ||
132 | if(rs<0) | ||
133 | throw exception_invalid_input(CODEPOINT,"Attempt to rely on the absent running status"); | ||
134 | data.push_back(status); | ||
135 | status = rs; | ||
136 | } | ||
137 | switch(status&status_event_bits) { | ||
138 | case status_note_off: | ||
139 | case status_note_on: | ||
140 | case status_polyphonic_key_pressure: // a.k.a. status_aftertouch | ||
141 | case status_control_change: | ||
142 | case status_pitch_wheel_change: | ||
143 | load_data(s,2); break; | ||
144 | case status_program_change: | ||
145 | case status_channel_pressure: | ||
146 | load_data(s,1); break; | ||
147 | case status_system: | ||
148 | switch(status&status_system_bits) { | ||
149 | case status_system_sysex: | ||
150 | case status_system_end_of_sysex: | ||
151 | load_sysex(s); break; | ||
152 | case status_system_MTC_quarter_frame: | ||
153 | case status_system_song_select: | ||
154 | load_data(s,1); break; | ||
155 | case status_system_song_position_pointer: | ||
156 | load_data(s,2); break; | ||
157 | case status_system_tune_request: | ||
158 | case status_system_timing_clock: // a.k.a. status_system_midi_clock | ||
159 | case status_system_midi_tick: | ||
160 | case status_system_start: // a.k.a. status_system_midi_start | ||
161 | case status_system_stop: // a.k.a. status_system_midi_stop | ||
162 | case status_system_continue: // a.k.a. status_system_midi_continue | ||
163 | case status_system_active_sense: | ||
164 | break; | ||
165 | case status_system_meta: // also, reset, but not in midi files | ||
166 | { | ||
167 | meta_status = s.get(); | ||
168 | if(!s.good()) | ||
169 | throw exception_input_error(CODEPOINT,"Error reading meta event type"); | ||
170 | int l = readVL(s); | ||
171 | load_data(s,l); | ||
172 | } | ||
173 | break; | ||
174 | default: | ||
175 | throw exception(CODEPOINT,"Internal error"); | ||
176 | break; | ||
177 | } | ||
178 | break; | ||
179 | default: | ||
180 | throw exception(CODEPOINT,"Internal error"); | ||
181 | break; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | void message_t::save_data(ostream& s,int c) const { | ||
186 | if(c!=data.size()) | ||
187 | throw exception(CODEPOINT,"Writing corrupt data"); | ||
188 | save_data(s); | ||
189 | } | ||
190 | |||
191 | void message_t::save_data(ostream& s) const { | ||
192 | for(bytes_t::const_iterator i=data.begin();i!=data.end();++i) | ||
193 | s.put(*i); | ||
194 | if(!s.good()) | ||
195 | throw exception_output_error(CODEPOINT,"Error writing MIDI message data"); | ||
196 | } | ||
197 | |||
198 | void message_t::load_data(istream& s,int c) { | ||
199 | c -= data.size(); | ||
200 | if(c<0) | ||
201 | throw exception(CODEPOINT,"Internal error"); | ||
202 | while(c-- > 0) { | ||
203 | data.push_back(s.get()); | ||
204 | if(!s.good()) | ||
205 | throw exception_input_error(CODEPOINT,"Error reading MIDI data"); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | void message_t::save_sysex(ostream& s) const { | ||
210 | save_data(s); | ||
211 | s.put(0xF7); /* XXX: Or is it better to put it into data? */ | ||
212 | if(!s.good()) | ||
213 | throw exception_output_error(CODEPOINT,"Error writing sysex data"); | ||
214 | } | ||
215 | |||
216 | void message_t::load_sysex(istream& s) { | ||
217 | int b = s.get(); | ||
218 | if(!s.good()) | ||
219 | throw exception_input_error(CODEPOINT,"Error reading sysex data"); | ||
220 | assert(!(b&0x80)); // manufacturer ought to be 7 bit. not sure if it belongs here, it may well be continuation. | ||
221 | do { | ||
222 | data.push_back(b); | ||
223 | b = s.get(); | ||
224 | if(!s.good()) | ||
225 | throw exception_input_error(CODEPOINT,"Error reading sysex data"); | ||
226 | }while(b!=0xF7); | ||
227 | } | ||
228 | |||
229 | void message_t::dump(ostream& s) const { | ||
230 | std::ios::fmtflags ff = s.flags(); | ||
231 | int w = s.width(2); | ||
232 | s.unsetf(std::ios::dec); s.setf(std::ios::hex); | ||
233 | s << "status=" << status; | ||
234 | if(is_meta()) { | ||
235 | s << ", meta_status=" << meta_status; | ||
236 | } | ||
237 | if(!data.empty()) { | ||
238 | s << ", data: "; | ||
239 | copy( | ||
240 | data.begin(), data.end(), | ||
241 | ostream_iterator<int>(s," ") ); | ||
242 | } | ||
243 | s.width(w); | ||
244 | s.flags(ff); | ||
245 | } | ||
246 | |||
247 | } | ||
diff --git a/lib/util.cc b/lib/util.cc new file mode 100644 index 0000000..4bbe6f3 --- a/dev/null +++ b/lib/util.cc | |||
@@ -0,0 +1,96 @@ | |||
1 | #include <midillo/util.h> | ||
2 | #include <midillo/exception.h> | ||
3 | |||
4 | namespace midillo { | ||
5 | |||
6 | unsigned long read32(istream& s) { | ||
7 | unsigned long rv = 0; | ||
8 | for(int t=0;t<4;++t) { | ||
9 | rv<<=8; | ||
10 | rv|=0xFF&s.get(); | ||
11 | if(!s.good()) | ||
12 | throw exception_input_error(CODEPOINT,"Input error"); | ||
13 | } | ||
14 | return rv; | ||
15 | } | ||
16 | |||
17 | unsigned int read16(istream& s) { | ||
18 | unsigned int rv = 0; | ||
19 | for(int t=0;t<2;++t) { | ||
20 | rv<<=8; | ||
21 | rv|=0xFF&s.get(); | ||
22 | if(!s.good()) | ||
23 | throw exception_input_error(CODEPOINT,"Input error"); | ||
24 | } | ||
25 | return rv; | ||
26 | } | ||
27 | |||
28 | unsigned long readVL(istream& s) { | ||
29 | unsigned long rv=s.get(); | ||
30 | if(!s.good()) | ||
31 | throw exception_input_error(CODEPOINT,"Error reading VLQ"); | ||
32 | int b; | ||
33 | if(rv&0x80) { | ||
34 | rv&=0x7F; | ||
35 | do { | ||
36 | rv = (rv<<7)|( (b=s.get())&0x7F ); | ||
37 | if(!s.good()) | ||
38 | throw exception_input_error(CODEPOINT,"Error reading VLQ"); | ||
39 | }while(b&0x80); | ||
40 | } | ||
41 | return rv; | ||
42 | } | ||
43 | |||
44 | void write32(ostream& s,unsigned long d) { | ||
45 | for(int t=3;t>=0;--t) { | ||
46 | s.put(((const char*)&d)[t]); | ||
47 | if(!s.good()) | ||
48 | throw exception_output_error(CODEPOINT,"Output error"); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | void write16(ostream& s,unsigned int d) { | ||
53 | for(int t=1;t>=0;--t) { | ||
54 | s.put(((const char*)&d)[t]); | ||
55 | if(!s.good()) | ||
56 | throw exception_output_error(CODEPOINT,"Output error"); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | void writeVL(ostream& s,unsigned long d) { | ||
61 | // TODO: I don't think this is perfectly written code | ||
62 | unsigned long tmp = d&0x7F; | ||
63 | while(d>>=7) { | ||
64 | tmp<<=8; | ||
65 | tmp |=((d&0x7F)|0x80); | ||
66 | } | ||
67 | for(;;) { | ||
68 | s.put(tmp&0xFF); | ||
69 | if(!s.good()) | ||
70 | throw exception_output_error(CODEPOINT,"Error writing VLQ"); | ||
71 | if(tmp&0x80) | ||
72 | tmp>>=8; | ||
73 | else | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | unsigned long calcVLsize(unsigned long d) { | ||
79 | unsigned long rv = 0; | ||
80 | // TODO: imperfect code revisited | ||
81 | unsigned long tmp = d&0x7F; | ||
82 | while(d>>=7) { | ||
83 | tmp<<=8; | ||
84 | tmp |=((d&0x7F)|0x80); | ||
85 | } | ||
86 | for(;;) { | ||
87 | ++rv; | ||
88 | if(tmp&0x80) | ||
89 | tmp>>=8; | ||
90 | else | ||
91 | break; | ||
92 | } | ||
93 | return rv; | ||
94 | } | ||
95 | |||
96 | } | ||