1 #include "binarystream.hpp"
2 #include "serialization.hpp"
13 #define EWOULDBLOCK EAGAIN
18 void write_whole(int s
, const char* buf
, size_t size
)
23 if((size_t)maxw
> (size
- w
))
25 int r
= write(s
, buf
+ w
, maxw
);
26 if(r
< 0 && (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
))
30 (stringfmt() << strerror(err
)).throwex();
36 size_t whole_read(int s
, char* buf
, size_t size
)
41 if((size_t)maxr
> (size
- r
))
43 int x
= read(s
, buf
+ r
, maxr
);
44 if(x
< 0 && (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
))
48 (stringfmt() << strerror(err
)).throwex();
58 namespace binarystream
60 const uint32_t TAG_
= 0xaddb2d86;
72 void output::byte(uint8_t byte
)
74 write(reinterpret_cast<char*>(&byte
), 1);
77 void output::number(uint64_t number
)
82 bool cont
= (number
> 127);
83 data
[len
++] = (cont
? 0x80 : 0x00) | (number
& 0x7F);
89 size_t output::numberbytes(uint64_t number
)
99 size_t output::stringbytes(const std::string
& string
)
101 size_t slen
= string
.length();
102 return numberbytes(slen
) + slen
;
105 void output::number32(uint32_t number
)
108 serialization::u32b(data
, number
);
112 void output::string(const std::string
& string
)
114 number(string
.length());
115 std::vector
<char> tmp(string
.begin(), string
.end());
116 write(&tmp
[0], tmp
.size());
119 void output::string_implicit(const std::string
& string
)
121 std::vector
<char> tmp(string
.begin(), string
.end());
122 write(&tmp
[0], tmp
.size());
125 void output::blob_implicit(const std::vector
<char>& blob
)
127 write(&blob
[0], blob
.size());
130 void output::raw(const void* buf
, size_t bufsize
)
132 write(reinterpret_cast<const char*>(buf
), bufsize
);
135 void output::write_extension_tag(uint32_t tag
, uint64_t size
)
142 void output::extension(uint32_t tag
, std::function
<void(output
&)> fn
, bool even_empty
)
146 if(!even_empty
&& !tmp
.buf
.size())
150 number(tmp
.buf
.size());
151 blob_implicit(tmp
.buf
);
154 void output::extension(uint32_t tag
, std::function
<void(output
&)> fn
, bool even_empty
,
155 size_t size_precognition
)
157 if(!even_empty
&& !size_precognition
)
161 number(size_precognition
);
165 void output::write(const char* ibuf
, size_t size
)
168 write_whole(strm
, ibuf
, size
);
170 size_t o
= buf
.size();
171 buf
.resize(o
+ size
);
172 memcpy(&buf
[o
], ibuf
, size
);
176 std::string
output::get()
179 throw std::logic_error("Get can only be used without explicit sink");
180 return std::string(buf
.begin(), buf
.end());
183 uint8_t input::byte()
190 uint64_t input::number()
196 read(reinterpret_cast<char*>(&c
), 1);
197 s
|= (static_cast<uint64_t>(c
& 0x7F) << sh
);
203 uint32_t input::number32()
207 return serialization::u32b(c
);
210 std::string
input::string()
212 size_t sz
= number();
213 std::vector
<char> _r
;
215 read(&_r
[0], _r
.size());
216 std::string
r(_r
.begin(), _r
.end());
220 std::string
input::string_implicit()
223 throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams");
224 std::vector
<char> _r
;
227 std::string
r(_r
.begin(), _r
.end());
231 void input::blob_implicit(std::vector
<char>& blob
)
234 throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams");
236 read(&blob
[0], left
);
240 : parent(NULL
), strm(s
), left(0)
244 input::input(input
& s
, uint64_t len
)
245 : parent(&s
), strm(s
.strm
), left(len
)
247 if(parent
->parent
&& left
> parent
->left
)
248 throw std::runtime_error("Substream length greater than its parent");
251 void input::raw(void* buf
, size_t bufsize
)
253 read(reinterpret_cast<char*>(buf
), bufsize
);
256 void input::extension(std::function
<void(uint32_t tag
, input
& s
)> fn
)
261 void input::extension(std::initializer_list
<binary_tag_handler
> funcs
,
262 std::function
<void(uint32_t tag
, input
& s
)> default_hdlr
)
264 std::map
<uint32_t, std::function
<void(input
& s
)>> fn
;
267 while(!parent
|| left
> 0) {
269 if(!read(c
, 4, true))
271 uint32_t tagid
= serialization::u32b(c
);
273 throw std::runtime_error("Binary file packet structure desync");
274 uint32_t tag
= number32();
275 uint64_t size
= number();
276 input
ss(*this, size
);
280 default_hdlr(tag
, ss
);
288 throw std::logic_error("binarystream::input::flush() can only be used in substreams");
291 read(buf
, min(left
, (uint64_t)256));
294 bool input::read(char* buf
, size_t size
, bool allow_none
)
297 if(left
== 0 && allow_none
)
300 std::runtime_error("Substream unexpected EOF");
301 parent
->read(buf
, size
, false);
304 size_t r
= whole_read(strm
, buf
, size
);
308 throw std::runtime_error("Unexpected EOF");
314 void null_default(uint32_t tag
, input
& s
)