#include "includes.h"
#include "ldb/include/includes.h"
+#include "system/locale.h"
/*
default handler that just copies a ldb_val.
/*
a case folding copy handler, removing leading and trailing spaces and
multiple internal spaces
+
+ We exploit the fact that utf8 never uses the space octet except for
+ the space itself
*/
static int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
- uint8_t *s1, *s2;
- out->data = talloc_size(mem_ctx, strlen((char *)in->data)+1);
+ char *s, *t;
+ int l;
+ if (!in || !out || !(in->data)) {
+ return -1;
+ }
+
+ out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data));
if (out->data == NULL) {
- ldb_oom(ldb);
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data);
return -1;
}
- s1 = in->data;
- s2 = out->data;
- while (*s1 == ' ') s1++;
- while (*s1) {
- *s2 = toupper(*s1);
- if (s1[0] == ' ') {
- while (s1[0] == s1[1]) s1++;
+
+ s = (char *)(out->data);
+
+ /* remove trailing spaces if any */
+ l = strlen(s);
+ while (l > 0 && s[l - 1] == ' ') l--;
+ s[l] = '\0';
+
+ /* remove leading spaces if any */
+ if (*s == ' ') {
+ for (t = s; *s == ' '; s++) ;
+
+ /* remove leading spaces by moving down the string */
+ memmove(t, s, l);
+
+ s = t;
+ }
+
+ /* check middle spaces */
+ while ((t = strchr(s, ' ')) != NULL) {
+ for (s = t; *s == ' '; s++) ;
+
+ if ((s - t) > 1) {
+ l = strlen(s);
+
+ /* remove all spaces but one by moving down the string */
+ memmove(t + 1, s, l);
}
- s2++; s1++;
}
- *s2 = 0;
+
out->length = strlen((char *)out->data);
return 0;
}
+
/*
canonicalise a ldap Integer
rfc2252 specifies it should be in decimal form
}
/*
- compare two case insensitive strings, ignoring multiple whitespace
- and leading and trailing whitespace
+ compare two case insensitive strings, ignoring multiple whitespaces
+ and leading and trailing whitespaces
see rfc2252 section 8.1
+
+ try to optimize for the ascii case,
+ but if we find out an utf8 codepoint revert to slower but correct function
*/
static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
+ const char *u1, *u2;
+ char *b1, *b2;
+ int ret;
while (*s1 == ' ') s1++;
while (*s2 == ' ') s2++;
/* TODO: make utf8 safe, possibly with helper function from application */
while (*s1 && *s2) {
+ /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
+ * never appear in multibyte sequences */
+ if (((unsigned char)s1[0]) & 0x80) goto utf8str;
+ if (((unsigned char)s2[0]) & 0x80) goto utf8str;
if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
break;
if (*s1 == ' ') {
s1++; s2++;
}
if (! (*s1 && *s2)) {
- /* remove trailing spaces only if one of the pointers
+ /* check for trailing spaces only if one of the pointers
* has reached the end of the strings otherwise we
* can mistakenly match.
* ex. "domain users" <-> "domainUpdates"
while (*s2 == ' ') s2++;
}
return (int)(toupper(*s1)) - (int)(toupper(*s2));
+
+utf8str:
+ /* no need to recheck from the start, just from the first utf8 char found */
+ b1 = ldb_casefold(ldb, mem_ctx, s1);
+ b2 = ldb_casefold(ldb, mem_ctx, s2);
+
+ if (b1 && b2) {
+ /* Both strings converted correctly */
+
+ u1 = b1;
+ u2 = b2;
+ } else {
+ /* One of the strings was not UTF8, so we have no options but to do a binary compare */
+
+ u1 = s1;
+ u2 = s2;
+ }
+
+ while (*u1 & *u2) {
+ if (*u1 != *u2)
+ break;
+ if (*u1 == ' ') {
+ while (u1[0] == u1[1]) u1++;
+ while (u2[0] == u2[1]) u2++;
+ }
+ u1++; u2++;
+ }
+ if (! (*u1 && *u2)) {
+ while (*u1 == ' ') u1++;
+ while (*u2 == ' ') u2++;
+ }
+ ret = (int)(*u1 - *u2);
+
+ talloc_free(b1);
+ talloc_free(b2);
+
+ return ret;
}
/*
out->length = 0;
out->data = NULL;
- dn = ldb_dn_explode_casefold(ldb, (char *)in->data);
- if (dn == NULL) {
+ dn = ldb_dn_new(ldb, mem_ctx, (char *)in->data);
+ if ( ! ldb_dn_validate(dn)) {
return -1;
}
- out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
+ out->data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, dn);
if (out->data == NULL) {
goto done;
}
struct ldb_dn *dn1 = NULL, *dn2 = NULL;
int ret;
- dn1 = ldb_dn_explode_casefold(mem_ctx, (char *)v1->data);
- if (dn1 == NULL) return -1;
+ dn1 = ldb_dn_new(ldb, mem_ctx, (char *)v1->data);
+ if ( ! ldb_dn_validate(dn1)) return -1;
- dn2 = ldb_dn_explode_casefold(mem_ctx, (char *)v2->data);
- if (dn2 == NULL) {
+ dn2 = ldb_dn_new(ldb, mem_ctx, (char *)v2->data);
+ if ( ! ldb_dn_validate(dn2)) {
talloc_free(dn1);
return -1;
}
- ret = ldb_dn_compare(ldb, dn1, dn2);
+ ret = ldb_dn_compare(dn1, dn2);
talloc_free(dn1);
talloc_free(dn2);