+#ifdef HAVE_LONG_LONG
+#if defined(HAVE_STRTOLL) || defined(HAVE_STRTOQ)
+int
+lutil_atollx( long long *v, const char *s, int x )
+{
+ char *next;
+ long long ll;
+ int save_errno;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ if ( isspace( s[ 0 ] ) ) {
+ return -1;
+ }
+
+ errno = 0;
+#ifdef HAVE_STRTOLL
+ ll = strtoll( s, &next, x );
+#else /* HAVE_STRTOQ */
+ ll = (unsigned long long)strtoq( s, &next, x );
+#endif /* HAVE_STRTOQ */
+ save_errno = errno;
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ /* LLONG_MIN, LLONG_MAX are C99 only */
+#if defined (LLONG_MIN) && defined(LLONG_MAX)
+ if ( ( ll == LLONG_MIN || ll == LLONG_MAX ) && save_errno != 0 ) {
+ return -1;
+ }
+#endif /* LLONG_MIN && LLONG_MAX */
+
+ *v = ll;
+
+ return 0;
+}
+#endif /* HAVE_STRTOLL || HAVE_STRTOQ */
+
+#if defined(HAVE_STRTOULL) || defined(HAVE_STRTOUQ)
+int
+lutil_atoullx( unsigned long long *v, const char *s, int x )
+{
+ char *next;
+ unsigned long long ull;
+ int save_errno;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ /* strtoull() has an odd interface */
+ if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) {
+ return -1;
+ }
+
+ errno = 0;
+#ifdef HAVE_STRTOULL
+ ull = strtoull( s, &next, x );
+#else /* HAVE_STRTOUQ */
+ ull = (unsigned long long)strtouq( s, &next, x );
+#endif /* HAVE_STRTOUQ */
+ save_errno = errno;
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ /* ULLONG_MAX is C99 only */
+#if defined(ULLONG_MAX)
+ if ( ( ull == 0 || ull == ULLONG_MAX ) && save_errno != 0 ) {
+ return -1;
+ }
+#endif /* ULLONG_MAX */
+
+ *v = ull;
+
+ return 0;
+}
+#endif /* HAVE_STRTOULL || HAVE_STRTOUQ */
+#endif /* HAVE_LONG_LONG */
+
+/* Multiply an integer by 100000000 and add new */
+typedef struct lutil_int_decnum {
+ unsigned char *buf;
+ int bufsiz;
+ int beg;
+ int len;
+} lutil_int_decnum;
+
+#define FACTOR1 (100000000&0xffff)
+#define FACTOR2 (100000000>>16)
+
+static void
+scale( int new, lutil_int_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;
+ i = 0;
+ do {
+ i--;
+ new += out[i];
+ out[i] = new & 0xff;
+ new >>= 8;
+ } while ( new );
+ i = -i;
+ if ( prev->len < i ) {
+ prev->beg = prev->bufsiz - i;
+ prev->len = i;
+ }
+ 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"
+ *
+ * Note: High bit of binary form is always the sign bit. If the number
+ * is supposed to be positive but has the high bit set, a zero byte
+ * is prepended. It is assumed that this has already been handled on
+ * any hex input.
+ */
+int
+lutil_str2bin( struct berval *in, struct berval *out, void *ctx )
+{
+ char *pin, *pout;
+ char *end;
+ 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))
+ unsigned long l;
+ char tbuf[HEXMAX+1];
+
+ /* Convert a longword at a time, but handle leading
+ * odd bytes first
+ */
+ chunk = len % HEXMAX;
+ if ( !chunk )
+ chunk = HEXMAX;
+
+ while ( len ) {
+ int ochunk;
+ memcpy( tbuf, pin, chunk );
+ tbuf[chunk] = '\0';
+ errno = 0;
+ l = strtoul( tbuf, &end, 16 );
+ if ( errno )
+ return -1;
+ ochunk = (chunk + 1)/2;
+ for ( i = ochunk - 1; i >= 0; i-- ) {
+ pout[i] = l & 0xff;
+ l >>= 8;
+ }
+ pin += chunk;
+ pout += ochunk;
+ len -= chunk;
+ chunk = HEXMAX;
+ }
+ out->bv_len = pout - out->bv_val;
+ } else {
+ /* Decimal */
+#define DECMAX 8 /* 8 digits at a time */
+ char tmpbuf[64], *tmp;
+ lutil_int_decnum num;
+ int neg = 0;
+ long l;
+ char tbuf[DECMAX+1];
+
+ len = in->bv_len;
+ pin = in->bv_val;
+ num.buf = (unsigned char *)out->bv_val;
+ num.bufsiz = out->bv_len;
+ num.beg = num.bufsiz-1;
+ num.len = 0;
+ if ( pin[0] == '-' ) {
+ neg = 0xff;
+ len--;
+ pin++;
+ }
+
+ /* tmp must be at least as large as outbuf */
+ if ( out->bv_len > sizeof(tmpbuf)) {
+ tmp = ber_memalloc_x( out->bv_len, ctx );
+ } else {
+ tmp = tmpbuf;
+ }
+ chunk = len & (DECMAX-1);
+ if ( !chunk )
+ chunk = DECMAX;
+
+ while ( len ) {
+ memcpy( tbuf, pin, chunk );
+ tbuf[chunk] = '\0';
+ errno = 0;
+ l = strtol( tbuf, &end, 10 );
+ if ( errno ) {
+ rc = -1;
+ goto decfail;
+ }
+ scale( l, &num, (unsigned char *)tmp );
+ pin += chunk;
+ len -= chunk;
+ chunk = DECMAX;
+ }
+ /* Negate the result */
+ if ( neg ) {
+ unsigned char *ptr;
+
+ ptr = num.buf+num.beg;
+
+ /* flip all bits */
+ for ( i=0; i<num.len; i++ )
+ ptr[i] ^= 0xff;
+
+ /* add 1, with carry - overflow handled below */
+ while ( i-- && ! (ptr[i] = (ptr[i] + 1) & 0xff )) ;
+ }
+ /* Prepend sign byte if wrong sign bit */
+ if (( num.buf[num.beg] ^ neg ) & 0x80 ) {
+ num.beg--;
+ num.len++;
+ num.buf[num.beg] = neg;
+ }
+ if ( num.beg )
+ AC_MEMCPY( num.buf, num.buf+num.beg, num.len );
+ out->bv_len = num.len;
+decfail:
+ if ( tmp != tmpbuf ) {
+ ber_memfree_x( tmp, ctx );
+ }
+ }
+ return rc;
+}
+