Files
mars-tinyldap/fmt_asn1intpayload.c
2023-01-18 14:01:57 +00:00

63 lines
2.0 KiB
C

#include <asn1.h>
static size_t intpayloadlen(unsigned long l) {
size_t i;
/* We don't need to store the leading zero octets.
* So count the non-zero ones.
* We always need at least 1 octet, even if l comes in as 0.
* However the most significant encoded bit doubles as sign bit.
* If it is 1, the decoder will think it is a negative number.
* We can store 0x7f as 0x7f but need to store 0x80 as 0x0080.
* So we count how often we have to shift until the remainder
* is 0x7f or less. Put differently: Until (remainder>>7)==0.
* Finally we pull the >>7 out of the loop for efficiency. */
l >>= 7;
for (i=1; l>0; ++i) l >>= 8;
return i;
}
size_t fmt_asn1intpayload(char* dest,unsigned long l) {
size_t needed=intpayloadlen(l);
if (dest) {
size_t i,n;
/* need to store big endian */
/* n is the number of bits to shift right for the next octet */
for (i=0, n=(needed-1)*8; i<needed; ++i, n-=8)
// shifting by more bits than are in the type is undefined behavior :(
dest[i]= (n == sizeof(l)*8) ? 0 : (l >> n);
}
return needed;
}
#ifdef UNITTEST
#include <assert.h>
#include <string.h>
int main() {
assert(intpayloadlen(0)==1);
assert(intpayloadlen(0x7f)==1);
assert(intpayloadlen(0x80)==2);
assert(intpayloadlen(0x80000000)==5);
if (sizeof(long)==8) assert(intpayloadlen(0x8000000000000000ul)==9);
char buf[100];
buf[1]='!';
assert(fmt_asn1intpayload(buf,0)==1 && buf[0]==0 && buf[1]=='!');
assert(fmt_asn1intpayload(buf,0x7f)==1 && buf[0]==0x7f && buf[1]=='!');
buf[2]='!';
assert(fmt_asn1intpayload(buf,0x80)==2 && !memcmp(buf,"\x00\x80!",3));
buf[4]='!';
assert(fmt_asn1intpayload(buf,0x7fffffff)==4 && !memcmp(buf,"\x7f\xff\xff\xff!",5));
buf[5]='!';
assert(fmt_asn1intpayload(buf,0xfffffeff)==5 && !memcmp(buf,"\x00\xff\xff\xfe\xff!",6));
assert(fmt_asn1intpayload(NULL, 0)==1);
assert(fmt_asn1intpayload(NULL, 0x7f)==1);
assert(fmt_asn1intpayload(NULL, 0x80)==2);
assert(fmt_asn1intpayload(NULL, 0x7fffffff)==4);
assert(fmt_asn1intpayload(NULL, 0xffffffff)==5);
}
#endif