Add <functional> to files that use std::function
[lsnes.git] / src / library / binarystream.cpp
bloba5f1b96284c50fa84c8a502dc59c545bd46eebf2
1 #include "binarystream.hpp"
2 #include "serialization.hpp"
3 #include "minmax.hpp"
4 #include "string.hpp"
5 #include <functional>
6 #include <algorithm>
7 #include <iostream>
8 #include <iterator>
9 #include <map>
10 #include <unistd.h>
12 //Damn Windows.
13 #ifndef EWOULDBLOCK
14 #define EWOULDBLOCK EAGAIN
15 #endif
17 namespace
19 void write_whole(int s, const char* buf, size_t size)
21 size_t w = 0;
22 while(w < size) {
23 int maxw = 32767;
24 if((size_t)maxw > (size - w))
25 maxw = size - w;
26 int r = write(s, buf + w, maxw);
27 if(r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
28 continue;
29 if(r < 0) {
30 int err = errno;
31 (stringfmt() << strerror(err)).throwex();
33 w += r;
37 size_t whole_read(int s, char* buf, size_t size)
39 size_t r = 0;
40 while(r < size) {
41 int maxr = 32767;
42 if((size_t)maxr > (size - r))
43 maxr = size - r;
44 int x = read(s, buf + r, maxr);
45 if(x < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
46 continue;
47 if(x < 0) {
48 int err = errno;
49 (stringfmt() << strerror(err)).throwex();
51 if(x == 0)
52 break; //EOF.
53 r += x;
55 return r;
59 namespace binarystream
61 const uint32_t TAG_ = 0xaddb2d86;
63 output::output()
64 : strm(-1)
68 output::output(int s)
69 : strm(s)
73 void output::byte(uint8_t byte)
75 write(reinterpret_cast<char*>(&byte), 1);
78 void output::number(uint64_t number)
80 char data[10];
81 size_t len = 0;
82 do {
83 bool cont = (number > 127);
84 data[len++] = (cont ? 0x80 : 0x00) | (number & 0x7F);
85 number >>= 7;
86 } while(number);
87 write(data, len);
90 size_t output::numberbytes(uint64_t number)
92 size_t o = 0;
93 do {
94 o++;
95 number >>= 7;
96 } while(number);
97 return o;
100 size_t output::stringbytes(const std::string& string)
102 size_t slen = string.length();
103 return numberbytes(slen) + slen;
106 void output::number32(uint32_t number)
108 char data[4];
109 serialization::u32b(data, number);
110 write(data, 4);
113 void output::string(const std::string& string)
115 number(string.length());
116 std::vector<char> tmp(string.begin(), string.end());
117 write(&tmp[0], tmp.size());
120 void output::string_implicit(const std::string& string)
122 std::vector<char> tmp(string.begin(), string.end());
123 write(&tmp[0], tmp.size());
126 void output::blob_implicit(const std::vector<char>& blob)
128 write(&blob[0], blob.size());
131 void output::raw(const void* buf, size_t bufsize)
133 write(reinterpret_cast<const char*>(buf), bufsize);
136 void output::write_extension_tag(uint32_t tag, uint64_t size)
138 number32(TAG_);
139 number32(tag);
140 number(size);
143 void output::extension(uint32_t tag, std::function<void(output&)> fn, bool even_empty)
145 output tmp;
146 fn(tmp);
147 if(!even_empty && !tmp.buf.size())
148 return;
149 number32(TAG_);
150 number32(tag);
151 number(tmp.buf.size());
152 blob_implicit(tmp.buf);
155 void output::extension(uint32_t tag, std::function<void(output&)> fn, bool even_empty,
156 size_t size_precognition)
158 if(!even_empty && !size_precognition)
159 return;
160 number32(TAG_);
161 number32(tag);
162 number(size_precognition);
163 fn(*this);
166 void output::write(const char* ibuf, size_t size)
168 if(strm >= 0)
169 write_whole(strm, ibuf, size);
170 else {
171 size_t o = buf.size();
172 buf.resize(o + size);
173 memcpy(&buf[o], ibuf, size);
177 std::string output::get()
179 if(strm >= 0)
180 throw std::logic_error("Get can only be used without explicit sink");
181 return std::string(buf.begin(), buf.end());
184 uint8_t input::byte()
186 char byte;
187 read(&byte, 1);
188 return byte;
191 uint64_t input::number()
193 uint64_t s = 0;
194 int sh = 0;
195 uint8_t c;
196 do {
197 read(reinterpret_cast<char*>(&c), 1);
198 s |= (static_cast<uint64_t>(c & 0x7F) << sh);
199 sh += 7;
200 } while(c & 0x80);
201 return s;
204 uint32_t input::number32()
206 char c[4];
207 read(c, 4);
208 return serialization::u32b(c);
211 std::string input::string()
213 size_t sz = number();
214 std::vector<char> _r;
215 _r.resize(sz);
216 read(&_r[0], _r.size());
217 std::string r(_r.begin(), _r.end());
218 return r;
221 std::string input::string_implicit()
223 if(!parent)
224 throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams");
225 std::vector<char> _r;
226 _r.resize(left);
227 read(&_r[0], left);
228 std::string r(_r.begin(), _r.end());
229 return r;
232 void input::blob_implicit(std::vector<char>& blob)
234 if(!parent)
235 throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams");
236 blob.resize(left);
237 read(&blob[0], left);
240 input::input(int s)
241 : parent(NULL), strm(s), left(0)
245 input::input(input& s, uint64_t len)
246 : parent(&s), strm(s.strm), left(len)
248 if(parent->parent && left > parent->left)
249 throw std::runtime_error("Substream length greater than its parent");
252 void input::raw(void* buf, size_t bufsize)
254 read(reinterpret_cast<char*>(buf), bufsize);
257 void input::extension(std::function<void(uint32_t tag, input& s)> fn)
259 extension({}, fn);
262 void input::extension(std::initializer_list<binary_tag_handler> funcs,
263 std::function<void(uint32_t tag, input& s)> default_hdlr)
265 std::map<uint32_t, std::function<void(input& s)>> fn;
266 for(auto i : funcs)
267 fn[i.tag] = i.fn;
268 while(!parent || left > 0) {
269 char c[4];
270 if(!read(c, 4, true))
271 break;
272 uint32_t tagid = serialization::u32b(c);
273 if(tagid != TAG_)
274 throw std::runtime_error("Binary file packet structure desync");
275 uint32_t tag = number32();
276 uint64_t size = number();
277 input ss(*this, size);
278 if(fn.count(tag))
279 fn[tag](ss);
280 else
281 default_hdlr(tag, ss);
282 ss.flush();
286 void input::flush()
288 if(!parent)
289 throw std::logic_error("binarystream::input::flush() can only be used in substreams");
290 char buf[256];
291 while(left)
292 read(buf, min(left, (uint64_t)256));
295 bool input::read(char* buf, size_t size, bool allow_none)
297 if(parent) {
298 if(left == 0 && allow_none)
299 return false;
300 if(size > left)
301 std::runtime_error("Substream unexpected EOF");
302 parent->read(buf, size, false);
303 left -= size;
304 } else {
305 size_t r = whole_read(strm, buf, size);
306 if(r < size) {
307 if(!r && allow_none)
308 return false;
309 throw std::runtime_error("Unexpected EOF");
312 return true;
315 void null_default(uint32_t tag, input& s)
317 //no-op