mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-16 18:47:32 -05:00
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple of weeks ago, and provides the same type-genericity which will let me use the same get_* routines on an SSH packet, an SFTP packet or anything else that chooses to include an implementing substructure. However, unlike BinarySink which contained a (one-function) vtable, BinarySource contains only mutable data fields - so another thing you might very well want to do is to simply instantiate a bare one without any containing object at all. I couldn't quite coerce C into letting me use the same setup macro in both cases, so I've arranged a BinarySource_INIT you can use on larger implementing objects and a BinarySource_BARE_INIT you can use on a BinarySource not contained in anything. The API follows the general principle that even if decoding fails, the decode functions will always return _some_ kind of value, with the same dynamically-allocated-ness they would have used for a completely successful value. But they also set an error flag in the BinarySource which can be tested later. So instead of having to decode a 10-field packet by means of 10 separate 'if (!get_foo(src)) throw error' clauses, you can just write 10 'variable = get_foo(src)' statements followed by a single check of get_err(src), and if the error check fails, you have to do exactly the same set of frees you would have after a successful decode.
This commit is contained in:
141
marshal.c
141
marshal.c
@ -82,3 +82,144 @@ int BinarySink_put_pstring(BinarySink *bs, const char *str)
|
||||
bs->write(bs, str, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int BinarySource_data_avail(BinarySource *src, size_t wanted)
|
||||
{
|
||||
if (src->err)
|
||||
return FALSE;
|
||||
|
||||
if (wanted <= src->len - src->pos)
|
||||
return TRUE;
|
||||
|
||||
src->err = BSE_OUT_OF_DATA;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define avail(wanted) BinarySource_data_avail(src, wanted)
|
||||
#define advance(dist) (src->pos += dist)
|
||||
#define here ((const void *)((const unsigned char *)src->data + src->pos))
|
||||
#define consume(dist) \
|
||||
((const void *)((const unsigned char *)src->data + \
|
||||
((src->pos += dist) - dist)))
|
||||
|
||||
ptrlen BinarySource_get_data(BinarySource *src, size_t wanted)
|
||||
{
|
||||
if (!avail(wanted))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
return make_ptrlen(consume(wanted), wanted);
|
||||
}
|
||||
|
||||
unsigned char BinarySource_get_byte(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(1))
|
||||
return 0;
|
||||
|
||||
ucp = consume(1);
|
||||
return *ucp;
|
||||
}
|
||||
|
||||
int BinarySource_get_bool(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(1))
|
||||
return 0;
|
||||
|
||||
ucp = consume(1);
|
||||
return *ucp != 0;
|
||||
}
|
||||
|
||||
unsigned BinarySource_get_uint16(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(2))
|
||||
return 0;
|
||||
|
||||
ucp = consume(2);
|
||||
return GET_16BIT_MSB_FIRST(ucp);
|
||||
}
|
||||
|
||||
unsigned long BinarySource_get_uint32(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(4))
|
||||
return 0;
|
||||
|
||||
ucp = consume(4);
|
||||
return GET_32BIT_MSB_FIRST(ucp);
|
||||
}
|
||||
|
||||
uint64 BinarySource_get_uint64(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
uint64 toret;
|
||||
|
||||
if (!avail(8)) {
|
||||
toret.hi = toret.lo = 0;
|
||||
return toret;
|
||||
}
|
||||
|
||||
ucp = consume(8);
|
||||
toret.hi = GET_32BIT_MSB_FIRST(ucp);
|
||||
toret.lo = GET_32BIT_MSB_FIRST(ucp + 4);
|
||||
return toret;
|
||||
}
|
||||
|
||||
ptrlen BinarySource_get_string(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
size_t len;
|
||||
|
||||
if (!avail(4))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
ucp = consume(4);
|
||||
len = GET_32BIT_MSB_FIRST(ucp);
|
||||
|
||||
if (!avail(len))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
return make_ptrlen(consume(len), len);
|
||||
}
|
||||
|
||||
const char *BinarySource_get_asciz(BinarySource *src)
|
||||
{
|
||||
const char *start, *end;
|
||||
|
||||
if (src->err)
|
||||
return "";
|
||||
|
||||
start = here;
|
||||
end = memchr(start, '\0', src->len - src->pos);
|
||||
if (!end) {
|
||||
src->err = BSE_OUT_OF_DATA;
|
||||
return "";
|
||||
}
|
||||
|
||||
advance(end + 1 - start);
|
||||
return start;
|
||||
}
|
||||
|
||||
ptrlen BinarySource_get_pstring(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
size_t len;
|
||||
|
||||
if (!avail(1))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
ucp = consume(1);
|
||||
len = *ucp;
|
||||
|
||||
if (!avail(len))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
return make_ptrlen(consume(len), len);
|
||||
}
|
||||
|
Reference in New Issue
Block a user