mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
Add lutil_str2bin() for arbitrary length decimal-to-binary conversion
This commit is contained in:
parent
6827d4b33a
commit
4d58197880
@ -304,6 +304,9 @@ lutil_atoulx( unsigned long *v, const char *s, int x );
|
||||
#define lutil_atol(v, s) lutil_atolx((v), (s), 10)
|
||||
#define lutil_atoul(v, s) lutil_atoulx((v), (s), 10)
|
||||
|
||||
LDAP_LUTIL_F (int)
|
||||
lutil_str2bin( struct berval *in, struct berval *out );
|
||||
|
||||
/* Parse and unparse time intervals */
|
||||
LDAP_LUTIL_F (int)
|
||||
lutil_parse_time( const char *in, unsigned long *tp );
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <ac/ctype.h>
|
||||
#include <ac/unistd.h>
|
||||
#include <ac/time.h>
|
||||
#include <ac/errno.h>
|
||||
#ifdef HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
@ -602,6 +603,169 @@ lutil_atoulx( unsigned long *v, const char *s, int x )
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Multiply an integer by 100000000 and add new */
|
||||
typedef struct _decnum {
|
||||
unsigned char *buf;
|
||||
int bufsiz;
|
||||
int beg;
|
||||
int len;
|
||||
} _decnum;
|
||||
|
||||
#define FACTOR1 (100000000&0xffff)
|
||||
#define FACTOR2 (100000000>>16)
|
||||
|
||||
static void
|
||||
scale( int new, _decnum *prev, unsigned char *tmp )
|
||||
{
|
||||
int i, j;
|
||||
unsigned char *in = prev->buf+prev->beg;
|
||||
unsigned int part;
|
||||
unsigned char *out = tmp + prev->bufsiz - prev->len;
|
||||
|
||||
memset( tmp, 0, prev->bufsiz );
|
||||
if ( prev->len ) {
|
||||
for ( i = prev->len-1; i>=0; i-- ) {
|
||||
part = in[i] * FACTOR1;
|
||||
for ( j = i; part; j-- ) {
|
||||
part += out[j];
|
||||
out[j] = part & 0xff;
|
||||
part >>= 8;
|
||||
}
|
||||
part = in[i] * FACTOR2;
|
||||
for ( j = i-2; part; j-- ) {
|
||||
part += out[j];
|
||||
out[j] = part & 0xff;
|
||||
part >>= 8;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
prev->beg += j;
|
||||
prev->len -= j;
|
||||
}
|
||||
|
||||
out = tmp + prev->bufsiz - 1;
|
||||
for ( i = 0; new ; i-- ) {
|
||||
new += out[i];
|
||||
out[i] = new & 0xff;
|
||||
new >>= 8;
|
||||
if (!new ) {
|
||||
if ( !prev->len ) {
|
||||
prev->beg += i;
|
||||
prev->len = -i;
|
||||
prev->len++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len );
|
||||
}
|
||||
|
||||
/* Convert unlimited length decimal or hex string to binary.
|
||||
* Output buffer must be provided, bv_len must indicate buffer size
|
||||
* Hex input can be "0x1234" or "'1234'H"
|
||||
*/
|
||||
int
|
||||
lutil_str2bin( struct berval *in, struct berval *out )
|
||||
{
|
||||
char *pin, *pout, ctmp;
|
||||
char *end;
|
||||
long l;
|
||||
int i, chunk, len, rc = 0, hex = 0;
|
||||
if ( !out || !out->bv_val || out->bv_len < in->bv_len )
|
||||
return -1;
|
||||
|
||||
pout = out->bv_val;
|
||||
/* Leading "0x" for hex input */
|
||||
if ( in->bv_len > 2 && in->bv_val[0] == '0' &&
|
||||
( in->bv_val[1] == 'x' || in->bv_val[1] == 'X' )) {
|
||||
len = in->bv_len - 2;
|
||||
pin = in->bv_val + 2;
|
||||
hex = 1;
|
||||
} else if ( in->bv_len > 3 && in->bv_val[0] == '\'' &&
|
||||
( in->bv_val[in->bv_len-2] == '\'' &&
|
||||
in->bv_val[in->bv_len-1] == 'H' )) {
|
||||
len = in->bv_len - 3;
|
||||
pin = in->bv_val + 1;
|
||||
hex = 1;
|
||||
}
|
||||
if ( hex ) {
|
||||
#define HEXMAX (2 * sizeof(long))
|
||||
/* Convert a longword at a time, but handle leading
|
||||
* odd bytes first
|
||||
*/
|
||||
chunk = len & (HEXMAX-1);
|
||||
if ( !chunk )
|
||||
chunk = HEXMAX;
|
||||
|
||||
while ( len ) {
|
||||
ctmp = pin[chunk];
|
||||
pin[chunk] = '\0';
|
||||
errno = 0;
|
||||
l = strtol( pin, &end, 16 );
|
||||
pin[chunk] = ctmp;
|
||||
if ( errno )
|
||||
return -1;
|
||||
chunk++;
|
||||
chunk >>= 1;
|
||||
for ( i = chunk; i>=0; i-- ) {
|
||||
pout[i] = l & 0xff;
|
||||
l >>= 8;
|
||||
}
|
||||
pin += chunk;
|
||||
pout += sizeof(long);
|
||||
len -= chunk;
|
||||
chunk = HEXMAX;
|
||||
}
|
||||
out->bv_len = pout + len - out->bv_val;
|
||||
} else {
|
||||
/* Decimal */
|
||||
char tmpbuf[64], *tmp;
|
||||
_decnum num;
|
||||
|
||||
len = in->bv_len;
|
||||
pin = in->bv_val;
|
||||
num.buf = out->bv_val;
|
||||
num.bufsiz = out->bv_len;
|
||||
num.beg = num.bufsiz-1;
|
||||
num.len = 0;
|
||||
|
||||
#define DECMAX 8 /* 8 digits at a time */
|
||||
|
||||
if ( len > sizeof(tmpbuf)) {
|
||||
tmp = ber_memalloc( len );
|
||||
} else {
|
||||
tmp = tmpbuf;
|
||||
}
|
||||
chunk = len & (DECMAX-1);
|
||||
if ( !chunk )
|
||||
chunk = DECMAX;
|
||||
|
||||
while ( len ) {
|
||||
ctmp = pin[chunk];
|
||||
pin[chunk] = '\0';
|
||||
errno = 0;
|
||||
l = strtol( pin, &end, 10 );
|
||||
pin[chunk] = ctmp;
|
||||
if ( errno ) {
|
||||
rc = -1;
|
||||
goto decfail;
|
||||
}
|
||||
scale( l, &num, tmp );
|
||||
pin += chunk;
|
||||
len -= chunk;
|
||||
chunk = HEXMAX;
|
||||
}
|
||||
if ( num.beg )
|
||||
AC_MEMCPY( num.buf, num.buf+num.beg, num.len );
|
||||
out->bv_len = num.len;
|
||||
decfail:
|
||||
if ( tmp != tmpbuf ) {
|
||||
ber_memfree( tmp );
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static char time_unit[] = "dhms";
|
||||
|
||||
/* Used to parse and unparse time intervals, not timestamps */
|
||||
|
Loading…
Reference in New Issue
Block a user