unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
+unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
+ SLAP_INDEX_INTLEN_DEFAULT );
ldap_pvt_thread_mutex_t ad_undef_mutex;
ldap_pvt_thread_mutex_t oc_undef_mutex;
return LDAP_SUCCESS;
}
+/* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
+#define INDEX_INTLEN_CHOP 7
+#define INDEX_INTLEN_CHOPBYTES 3
+
static int
integerVal2Key(
- struct berval *val,
+ struct berval *in,
struct berval *key,
- struct berval *tmp
-)
+ struct berval *tmp,
+ void *ctx )
{
- struct berval iv;
- int neg;
+ /* index format:
+ * only if too large: one's complement <sign*exponent (chopped bytes)>,
+ * two's complement value (sign-extended or chopped as needed),
+ * however the top <number of exponent-bytes + 1> bits of first byte
+ * above is the inverse sign. The next bit is the sign as delimiter.
+ */
+ ber_slen_t k = index_intlen_strlen;
+ ber_len_t chop = 0;
+ unsigned signmask = ~0x7fU;
+ unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
+ struct berval val = *in, itmp = *tmp;
- iv = *tmp;
- if ( lutil_str2bin( val, &iv )) {
- return LDAP_INVALID_SYNTAX;
+ if ( val.bv_val[0] != '-' ) {
+ neg = 0;
+ --k;
}
- neg = iv.bv_val[0] & 0x80;
-
- /* Omit leading 0 pad byte */
- if ( !iv.bv_val[0] ) {
- iv.bv_val++;
- iv.bv_len--;
+ /* Chop least significant digits, increase length instead */
+ if ( val.bv_len > (ber_len_t) k ) {
+ chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
+ val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
+ chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
}
- /* If too small, sign-extend */
- if ( iv.bv_len < index_intlen ) {
- int j, k, pad;
- key->bv_val[0] = index_intlen;
- k = index_intlen - iv.bv_len + 1;
- if ( neg )
- pad = 0xff;
- else
- pad = 0;
- for ( j=1; j<k; j++)
- key->bv_val[j] = pad;
- for ( j = 0; j<iv.bv_len; j++ )
- key->bv_val[j+k] = iv.bv_val[j];
- } else {
- key->bv_val[0] = iv.bv_len;
- memcpy( key->bv_val+1, iv.bv_val, index_intlen );
- }
- if ( neg ) {
- key->bv_val[0] = -key->bv_val[0];
+ if ( lutil_str2bin( &val, &itmp, ctx )) {
+ return LDAP_INVALID_SYNTAX;
}
- /* convert signed to unsigned */
- key->bv_val[0] ^= 0x80;
+
+ /* Omit leading sign byte */
+ if ( itmp.bv_val[0] == neg ) {
+ itmp.bv_val++;
+ itmp.bv_len--;
+ }
+
+ k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
+ if ( k > 0 ) {
+ assert( chop == 0 );
+ memset( key->bv_val, neg, k ); /* sign-extend */
+ } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
+ lenp = lenbuf + sizeof(lenbuf);
+ chop = - (ber_len_t) k;
+ do {
+ *--lenp = ((unsigned char) chop & 0xff) ^ neg;
+ signmask >>= 1;
+ } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
+ /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
+ * are 1, and the top n+2 bits of lenp[] are the sign bit. */
+ k = (lenbuf + sizeof(lenbuf)) - lenp;
+ if ( k > (ber_slen_t) index_intlen )
+ k = index_intlen;
+ memcpy( key->bv_val, lenp, k );
+ itmp.bv_len = index_intlen - k;
+ }
+ memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
+ key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
return 0;
}
char ibuf[64];
struct berval itmp;
BerVarray keys;
+ ber_len_t vlen;
int i, rc;
+ unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
- for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
- /* just count them */
+ /* count the values and find max needed length */
+ vlen = 0;
+ for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
+ if ( vlen < values[i].bv_len )
+ vlen = values[i].bv_len;
}
+ if ( vlen > maxstrlen )
+ vlen = maxstrlen;
/* we should have at least one value at this point */
assert( i > 0 );
keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
- keys[i].bv_len = index_intlen+1;
- keys[i].bv_val = slap_sl_malloc( index_intlen+1, ctx );
+ keys[i].bv_len = index_intlen;
+ keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
}
keys[i].bv_len = 0;
keys[i].bv_val = NULL;
- itmp.bv_val = ibuf;
+ if ( vlen > sizeof(ibuf) ) {
+ itmp.bv_val = slap_sl_malloc( vlen, ctx );
+ } else {
+ itmp.bv_val = ibuf;
+ }
itmp.bv_len = sizeof(ibuf);
for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
- if ( values[i].bv_len > itmp.bv_len ) {
+ if ( itmp.bv_val != ibuf ) {
itmp.bv_len = values[i].bv_len;
- if ( itmp.bv_val == ibuf ) {
- itmp.bv_val = slap_sl_malloc( itmp.bv_len, ctx );
- } else {
- itmp.bv_val = slap_sl_realloc( itmp.bv_val, itmp.bv_len, ctx );
- }
+ if ( itmp.bv_len <= sizeof(ibuf) )
+ itmp.bv_len = sizeof(ibuf);
+ else if ( itmp.bv_len > maxstrlen )
+ itmp.bv_len = maxstrlen;
}
- rc = integerVal2Key( &values[i], &keys[i], &itmp );
+ rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
if ( rc )
goto leave;
}
keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
- keys[0].bv_len = index_intlen + 1;
- keys[0].bv_val = slap_sl_malloc( index_intlen+1, ctx );
+ keys[0].bv_len = index_intlen;
+ keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
- if ( value->bv_len > sizeof( ibuf )) {
- iv.bv_val = slap_sl_malloc( value->bv_len, ctx );
- iv.bv_len = value->bv_len;
+ iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
+ ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
+ if ( iv.bv_len > (int) sizeof(ibuf) ) {
+ iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
} else {
iv.bv_val = ibuf;
iv.bv_len = sizeof(ibuf);
}
- rc = integerVal2Key( value, keys, &iv );
+ rc = integerVal2Key( value, keys, &iv, ctx );
if ( rc == 0 )
*keysp = keys;
}
sn2.bv_val = stmp;
sn2.bv_len = sn.bv_len;
- if ( lutil_str2bin( &sn, &sn2 )) {
+ if ( lutil_str2bin( &sn, &sn2, ctx )) {
rc = LDAP_INVALID_SYNTAX;
goto leave;
}