1 #include "binarystream.hpp"
2 #include "serialization.hpp"
14 #define EWOULDBLOCK EAGAIN
19 void write_whole(int s
, const char* buf
, size_t size
)
24 if((size_t)maxw
> (size
- w
))
26 int r
= write(s
, buf
+ w
, maxw
);
27 if(r
< 0 && (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
))
31 (stringfmt() << strerror(err
)).throwex();
37 size_t whole_read(int s
, char* buf
, size_t size
)
42 if((size_t)maxr
> (size
- r
))
44 int x
= read(s
, buf
+ r
, maxr
);
45 if(x
< 0 && (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
))
49 (stringfmt() << strerror(err
)).throwex();
59 namespace binarystream
61 const uint32_t TAG_
= 0xaddb2d86;
73 void output::byte(uint8_t byte
)
75 write(reinterpret_cast<char*>(&byte
), 1);
78 void output::number(uint64_t number
)
83 bool cont
= (number
> 127);
84 data
[len
++] = (cont
? 0x80 : 0x00) | (number
& 0x7F);
90 size_t output::numberbytes(uint64_t number
)
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
)
109 serialization::u32b(data
, number
);
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
)
143 void output::extension(uint32_t tag
, std::function
<void(output
&)> fn
, bool even_empty
)
147 if(!even_empty
&& !tmp
.buf
.size())
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
)
162 number(size_precognition
);
166 void output::write(const char* ibuf
, size_t size
)
169 write_whole(strm
, ibuf
, size
);
171 size_t o
= buf
.size();
172 buf
.resize(o
+ size
);
173 memcpy(&buf
[o
], ibuf
, size
);
177 std::string
output::get()
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()
191 uint64_t input::number()
197 read(reinterpret_cast<char*>(&c
), 1);
198 s
|= (static_cast<uint64_t>(c
& 0x7F) << sh
);
204 uint32_t input::number32()
208 return serialization::u32b(c
);
211 std::string
input::string()
213 size_t sz
= number();
214 std::vector
<char> _r
;
216 read(&_r
[0], _r
.size());
217 std::string
r(_r
.begin(), _r
.end());
221 std::string
input::string_implicit()
224 throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams");
225 std::vector
<char> _r
;
228 std::string
r(_r
.begin(), _r
.end());
232 void input::blob_implicit(std::vector
<char>& blob
)
235 throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams");
237 read(&blob
[0], left
);
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
)
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
;
268 while(!parent
|| left
> 0) {
270 if(!read(c
, 4, true))
272 uint32_t tagid
= serialization::u32b(c
);
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
);
281 default_hdlr(tag
, ss
);
289 throw std::logic_error("binarystream::input::flush() can only be used in substreams");
292 read(buf
, min(left
, (uint64_t)256));
295 bool input::read(char* buf
, size_t size
, bool allow_none
)
298 if(left
== 0 && allow_none
)
301 std::runtime_error("Substream unexpected EOF");
302 parent
->read(buf
, size
, false);
305 size_t r
= whole_read(strm
, buf
, size
);
309 throw std::runtime_error("Unexpected EOF");
315 void null_default(uint32_t tag
, input
& s
)