mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-16 02:27: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:
42
sshbn.c
42
sshbn.c
@ -1624,12 +1624,12 @@ int ssh1_write_bignum(void *data, Bignum bn)
|
||||
|
||||
void BinarySink_put_mp_ssh1(BinarySink *bs, Bignum bn)
|
||||
{
|
||||
int len = ssh1_bignum_length(bn);
|
||||
int bits = bignum_bitcount(bn);
|
||||
int bytes = (bits + 7) / 8;
|
||||
int i;
|
||||
int bitc = bignum_bitcount(bn);
|
||||
|
||||
put_uint16(bs, bitc);
|
||||
for (i = len - 2; i--;)
|
||||
put_uint16(bs, bits);
|
||||
for (i = bytes; i--;)
|
||||
put_byte(bs, bignum_byte(bn, i));
|
||||
}
|
||||
|
||||
@ -1643,6 +1643,40 @@ void BinarySink_put_mp_ssh2(BinarySink *bs, Bignum bn)
|
||||
put_byte(bs, bignum_byte(bn, i));
|
||||
}
|
||||
|
||||
Bignum BinarySource_get_mp_ssh1(BinarySource *src)
|
||||
{
|
||||
unsigned bitc = get_uint16(src);
|
||||
ptrlen bytes = get_data(src, (bitc + 7) / 8);
|
||||
if (get_err(src)) {
|
||||
return bignum_from_long(0);
|
||||
} else {
|
||||
Bignum toret = bignum_from_bytes(bytes.ptr, bytes.len);
|
||||
if (bignum_bitcount(toret) != bitc) {
|
||||
src->err = BSE_INVALID;
|
||||
freebn(toret);
|
||||
toret = bignum_from_long(0);
|
||||
}
|
||||
return toret;
|
||||
}
|
||||
}
|
||||
|
||||
Bignum BinarySource_get_mp_ssh2(BinarySource *src)
|
||||
{
|
||||
ptrlen bytes = get_string(src);
|
||||
if (get_err(src)) {
|
||||
return bignum_from_long(0);
|
||||
} else {
|
||||
const unsigned char *p = bytes.ptr;
|
||||
if ((bytes.len > 0 &&
|
||||
((p[0] & 0x80) ||
|
||||
(p[0] == 0 && (bytes.len <= 1 || !(p[1] & 0x80)))))) {
|
||||
src->err = BSE_INVALID;
|
||||
return bignum_from_long(0);
|
||||
}
|
||||
return bignum_from_bytes(bytes.ptr, bytes.len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two bignums. Returns like strcmp.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user