2015-02-21 19:11:12 +01:00
|
|
|
/* Copyright (c) 2013, Vsevolod Stakhov
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
|
|
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ucl_internal.h"
|
|
|
|
#include "ucl_hash.h"
|
|
|
|
#include "khash.h"
|
2021-08-22 19:23:31 +02:00
|
|
|
#include "utlist.h"
|
2015-02-21 19:11:12 +01:00
|
|
|
|
2016-12-08 14:49:30 +01:00
|
|
|
#include "cryptobox.h"
|
|
|
|
#include "libutil/str_util.h"
|
2019-07-08 14:01:08 +02:00
|
|
|
#include "ucl.h"
|
2016-12-08 14:49:30 +01:00
|
|
|
|
2015-04-28 15:39:25 +02:00
|
|
|
#include <time.h>
|
2015-05-17 17:10:29 +02:00
|
|
|
#include <limits.h>
|
2015-04-28 15:39:25 +02:00
|
|
|
|
2015-02-21 19:11:12 +01:00
|
|
|
struct ucl_hash_elt {
|
|
|
|
const ucl_object_t *obj;
|
2021-08-22 19:23:31 +02:00
|
|
|
struct ucl_hash_elt *prev, *next;
|
2015-02-21 19:11:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ucl_hash_struct {
|
|
|
|
void *hash;
|
2021-08-22 19:23:31 +02:00
|
|
|
struct ucl_hash_elt *head;
|
2015-02-21 19:11:12 +01:00
|
|
|
bool caseless;
|
|
|
|
};
|
|
|
|
|
2015-04-28 15:39:25 +02:00
|
|
|
static uint64_t
|
|
|
|
ucl_hash_seed (void)
|
|
|
|
{
|
|
|
|
static uint64_t seed;
|
|
|
|
if (seed == 0) {
|
2015-08-18 14:17:16 +02:00
|
|
|
#ifdef UCL_RANDOM_FUNCTION
|
|
|
|
seed = UCL_RANDOM_FUNCTION;
|
|
|
|
#else
|
2015-04-28 15:39:25 +02:00
|
|
|
/* Not very random but can be useful for our purposes */
|
|
|
|
seed = time (NULL);
|
2015-08-18 14:17:16 +02:00
|
|
|
#endif
|
2015-04-28 15:39:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return seed;
|
|
|
|
}
|
|
|
|
|
2016-12-08 14:49:30 +01:00
|
|
|
extern const guchar lc_map[256];
|
2015-08-18 14:17:16 +02:00
|
|
|
|
2015-05-17 17:10:29 +02:00
|
|
|
static inline uint32_t
|
|
|
|
ucl_hash_func (const ucl_object_t *o)
|
|
|
|
{
|
2019-08-12 19:35:59 +02:00
|
|
|
return (uint32_t)rspamd_cryptobox_fast_hash (o->key, o->keylen, 0xb9a1ef83c4561c95ULL);
|
2015-05-17 17:10:29 +02:00
|
|
|
}
|
2015-02-21 19:11:12 +01:00
|
|
|
|
|
|
|
static inline int
|
|
|
|
ucl_hash_equal (const ucl_object_t *k1, const ucl_object_t *k2)
|
|
|
|
{
|
|
|
|
if (k1->keylen == k2->keylen) {
|
2016-02-18 12:42:50 +01:00
|
|
|
return memcmp (k1->key, k2->key, k1->keylen) == 0;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-08-23 11:10:33 +02:00
|
|
|
KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt *, 1,
|
2015-02-21 19:11:12 +01:00
|
|
|
ucl_hash_func, ucl_hash_equal)
|
|
|
|
|
|
|
|
static inline uint32_t
|
|
|
|
ucl_hash_caseless_func (const ucl_object_t *o)
|
|
|
|
{
|
2015-04-28 15:39:25 +02:00
|
|
|
unsigned len = o->keylen;
|
|
|
|
unsigned leftover = o->keylen % 4;
|
|
|
|
unsigned fp, i;
|
|
|
|
const uint8_t* s = (const uint8_t*)o->key;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
unsigned char c1, c2, c3, c4;
|
|
|
|
} c;
|
|
|
|
uint32_t pp;
|
|
|
|
} u;
|
2019-03-06 15:39:34 +01:00
|
|
|
uint64_t h = 0xe5ae6ab1ef9f3b54ULL;
|
|
|
|
rspamd_cryptobox_fast_hash_state_t hst;
|
2015-04-28 15:39:25 +02:00
|
|
|
|
|
|
|
fp = len - leftover;
|
2019-03-06 15:39:34 +01:00
|
|
|
rspamd_cryptobox_fast_hash_init (&hst, h);
|
2015-04-28 15:39:25 +02:00
|
|
|
|
|
|
|
for (i = 0; i != fp; i += 4) {
|
|
|
|
u.c.c1 = s[i], u.c.c2 = s[i + 1], u.c.c3 = s[i + 2], u.c.c4 = s[i + 3];
|
|
|
|
u.c.c1 = lc_map[u.c.c1];
|
|
|
|
u.c.c2 = lc_map[u.c.c2];
|
|
|
|
u.c.c3 = lc_map[u.c.c3];
|
|
|
|
u.c.c4 = lc_map[u.c.c4];
|
2019-03-06 15:39:34 +01:00
|
|
|
rspamd_cryptobox_fast_hash_update (&hst, &u, sizeof (u));
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
2015-04-28 15:39:25 +02:00
|
|
|
u.pp = 0;
|
|
|
|
switch (leftover) {
|
|
|
|
case 3:
|
|
|
|
u.c.c3 = lc_map[(unsigned char)s[i++]];
|
|
|
|
case 2:
|
2019-03-06 15:39:34 +01:00
|
|
|
/* fallthrough */
|
2015-04-28 15:39:25 +02:00
|
|
|
u.c.c2 = lc_map[(unsigned char)s[i++]];
|
|
|
|
case 1:
|
2019-03-06 15:39:34 +01:00
|
|
|
/* fallthrough */
|
2015-04-28 15:39:25 +02:00
|
|
|
u.c.c1 = lc_map[(unsigned char)s[i]];
|
2019-03-06 15:39:34 +01:00
|
|
|
rspamd_cryptobox_fast_hash_update (&hst, &u, sizeof (u));
|
2015-04-28 15:39:25 +02:00
|
|
|
break;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
2019-08-12 19:35:59 +02:00
|
|
|
return (uint32_t)rspamd_cryptobox_fast_hash_final (&hst);
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
2015-05-17 17:10:29 +02:00
|
|
|
|
2015-02-21 19:11:12 +01:00
|
|
|
|
2019-03-06 15:39:34 +01:00
|
|
|
static inline bool
|
2015-02-21 19:11:12 +01:00
|
|
|
ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
|
|
|
|
{
|
|
|
|
if (k1->keylen == k2->keylen) {
|
2016-12-08 14:49:30 +01:00
|
|
|
return rspamd_lc_cmp (k1->key, k2->key, k1->keylen) == 0;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
2019-03-06 15:39:34 +01:00
|
|
|
return false;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
2021-08-23 11:10:33 +02:00
|
|
|
KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt *, 1,
|
2015-02-21 19:11:12 +01:00
|
|
|
ucl_hash_caseless_func, ucl_hash_caseless_equal)
|
|
|
|
|
|
|
|
ucl_hash_t*
|
|
|
|
ucl_hash_create (bool ignore_case)
|
|
|
|
{
|
|
|
|
ucl_hash_t *new;
|
|
|
|
|
|
|
|
new = UCL_ALLOC (sizeof (ucl_hash_t));
|
|
|
|
if (new != NULL) {
|
2019-04-25 13:13:09 +02:00
|
|
|
void *h;
|
2021-08-22 19:23:31 +02:00
|
|
|
new->head = NULL;
|
2015-02-21 19:11:12 +01:00
|
|
|
new->caseless = ignore_case;
|
|
|
|
if (ignore_case) {
|
2019-04-25 13:13:09 +02:00
|
|
|
h = (void *)kh_init (ucl_hash_caseless_node);
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
else {
|
2019-04-25 13:13:09 +02:00
|
|
|
h = (void *)kh_init (ucl_hash_node);
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
2019-04-25 13:13:09 +02:00
|
|
|
if (h == NULL) {
|
|
|
|
UCL_FREE (sizeof (ucl_hash_t), new);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
new->hash = h;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2016-02-08 19:26:58 +01:00
|
|
|
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)
|
2015-02-21 19:11:12 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
if (hashlin == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (func != NULL) {
|
|
|
|
/* Iterate over the hash first */
|
|
|
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
|
|
hashlin->hash;
|
|
|
|
khiter_t k;
|
2021-08-23 11:10:33 +02:00
|
|
|
const ucl_object_t *cur, *tmp;
|
2015-02-21 19:11:12 +01:00
|
|
|
|
|
|
|
for (k = kh_begin (h); k != kh_end (h); ++k) {
|
|
|
|
if (kh_exist (h, k)) {
|
2021-08-23 11:10:33 +02:00
|
|
|
cur = (kh_value (h, k))->obj;
|
2015-02-21 19:11:12 +01:00
|
|
|
while (cur != NULL) {
|
|
|
|
tmp = cur->next;
|
|
|
|
func (__DECONST (ucl_object_t *, cur));
|
|
|
|
cur = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hashlin->caseless) {
|
|
|
|
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
2019-04-25 13:13:09 +02:00
|
|
|
hashlin->hash;
|
2015-02-21 19:11:12 +01:00
|
|
|
kh_destroy (ucl_hash_caseless_node, h);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
2019-04-25 13:13:09 +02:00
|
|
|
hashlin->hash;
|
2015-02-21 19:11:12 +01:00
|
|
|
kh_destroy (ucl_hash_node, h);
|
|
|
|
}
|
|
|
|
|
2021-08-23 11:10:33 +02:00
|
|
|
struct ucl_hash_elt *cur, *tmp;
|
|
|
|
|
|
|
|
DL_FOREACH_SAFE(hashlin->head, cur, tmp) {
|
|
|
|
UCL_FREE(sizeof(*cur), cur);
|
|
|
|
}
|
|
|
|
|
2015-02-21 19:11:12 +01:00
|
|
|
UCL_FREE (sizeof (*hashlin), hashlin);
|
|
|
|
}
|
|
|
|
|
2019-04-25 13:13:09 +02:00
|
|
|
bool
|
2015-02-21 19:11:12 +01:00
|
|
|
ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
2019-04-25 13:13:09 +02:00
|
|
|
const char *key, unsigned keylen)
|
2015-02-21 19:11:12 +01:00
|
|
|
{
|
|
|
|
khiter_t k;
|
|
|
|
int ret;
|
2021-08-23 11:10:33 +02:00
|
|
|
struct ucl_hash_elt **pelt, *elt;
|
2015-02-21 19:11:12 +01:00
|
|
|
|
|
|
|
if (hashlin == NULL) {
|
2019-04-25 13:13:09 +02:00
|
|
|
return false;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hashlin->caseless) {
|
|
|
|
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
|
|
|
hashlin->hash;
|
|
|
|
k = kh_put (ucl_hash_caseless_node, h, obj, &ret);
|
|
|
|
if (ret > 0) {
|
2021-08-23 11:10:33 +02:00
|
|
|
elt = UCL_ALLOC(sizeof(*elt));
|
|
|
|
pelt = &kh_value (h, k);
|
|
|
|
*pelt = elt;
|
2021-08-22 19:23:31 +02:00
|
|
|
DL_APPEND(hashlin->head, elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
elt->obj = obj;
|
|
|
|
}
|
2021-08-23 11:10:33 +02:00
|
|
|
else if (ret < 0) {
|
|
|
|
goto e0;
|
|
|
|
}
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
|
|
hashlin->hash;
|
|
|
|
k = kh_put (ucl_hash_node, h, obj, &ret);
|
|
|
|
if (ret > 0) {
|
2021-08-23 11:10:33 +02:00
|
|
|
elt = UCL_ALLOC(sizeof(*elt));
|
|
|
|
pelt = &kh_value (h, k);
|
|
|
|
*pelt = elt;
|
2021-08-22 19:23:31 +02:00
|
|
|
DL_APPEND(hashlin->head, elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
elt->obj = obj;
|
2019-04-25 13:13:09 +02:00
|
|
|
} else if (ret < 0) {
|
|
|
|
goto e0;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-25 13:13:09 +02:00
|
|
|
return true;
|
|
|
|
e0:
|
|
|
|
return false;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
|
2019-04-25 13:13:09 +02:00
|
|
|
const ucl_object_t *new)
|
2015-02-21 19:11:12 +01:00
|
|
|
{
|
|
|
|
khiter_t k;
|
|
|
|
int ret;
|
2021-08-23 11:10:33 +02:00
|
|
|
struct ucl_hash_elt *elt, *nelt;
|
2015-02-21 19:11:12 +01:00
|
|
|
|
|
|
|
if (hashlin == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hashlin->caseless) {
|
|
|
|
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
|
|
|
hashlin->hash;
|
|
|
|
k = kh_put (ucl_hash_caseless_node, h, old, &ret);
|
|
|
|
if (ret == 0) {
|
2021-08-23 11:10:33 +02:00
|
|
|
elt = kh_value(h, k);
|
2015-02-21 19:11:12 +01:00
|
|
|
kh_del (ucl_hash_caseless_node, h, k);
|
|
|
|
k = kh_put (ucl_hash_caseless_node, h, new, &ret);
|
2021-08-23 11:10:33 +02:00
|
|
|
nelt = UCL_ALLOC(sizeof(*nelt));
|
|
|
|
nelt->obj = new;
|
|
|
|
kh_value(h, k) = nelt;
|
|
|
|
DL_REPLACE_ELEM(hashlin->head, elt, nelt);
|
|
|
|
UCL_FREE(sizeof(*elt), elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
|
|
hashlin->hash;
|
|
|
|
k = kh_put (ucl_hash_node, h, old, &ret);
|
|
|
|
if (ret == 0) {
|
|
|
|
elt = kh_value (h, k);
|
|
|
|
kh_del (ucl_hash_node, h, k);
|
|
|
|
k = kh_put (ucl_hash_node, h, new, &ret);
|
2021-08-23 11:10:33 +02:00
|
|
|
nelt = UCL_ALLOC(sizeof(*nelt));
|
|
|
|
nelt->obj = new;
|
|
|
|
kh_value(h, k) = nelt;
|
|
|
|
DL_REPLACE_ELEM(hashlin->head, elt, nelt);
|
|
|
|
UCL_FREE(sizeof(*elt), elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ucl_hash_real_iter {
|
2021-08-22 19:23:31 +02:00
|
|
|
const struct ucl_hash_elt *cur;
|
2015-02-21 19:11:12 +01:00
|
|
|
};
|
|
|
|
|
2019-04-25 13:13:09 +02:00
|
|
|
#define UHI_SETERR(ep, ern) {if (ep != NULL) *ep = (ern);}
|
|
|
|
|
2015-02-21 19:11:12 +01:00
|
|
|
const void*
|
2019-04-25 13:13:09 +02:00
|
|
|
ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep)
|
2015-02-21 19:11:12 +01:00
|
|
|
{
|
|
|
|
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter);
|
|
|
|
const ucl_object_t *ret = NULL;
|
|
|
|
|
|
|
|
if (hashlin == NULL) {
|
2019-04-25 13:13:09 +02:00
|
|
|
UHI_SETERR(ep, EINVAL);
|
2015-02-21 19:11:12 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (it == NULL) {
|
|
|
|
it = UCL_ALLOC (sizeof (*it));
|
2015-07-28 17:57:15 +02:00
|
|
|
|
|
|
|
if (it == NULL) {
|
2019-04-25 13:13:09 +02:00
|
|
|
UHI_SETERR(ep, ENOMEM);
|
2015-07-28 17:57:15 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-08-22 19:23:31 +02:00
|
|
|
it->cur = hashlin->head;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
2019-04-25 13:13:09 +02:00
|
|
|
UHI_SETERR(ep, 0);
|
2021-08-22 19:23:31 +02:00
|
|
|
if (it->cur) {
|
|
|
|
ret = it->cur->obj;
|
|
|
|
it->cur = it->cur->next;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
UCL_FREE (sizeof (*it), it);
|
|
|
|
*iter = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*iter = it;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter)
|
|
|
|
{
|
|
|
|
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(iter);
|
|
|
|
|
2021-08-22 19:23:31 +02:00
|
|
|
return it->cur != NULL;
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const ucl_object_t*
|
|
|
|
ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
|
|
|
|
{
|
|
|
|
khiter_t k;
|
|
|
|
const ucl_object_t *ret = NULL;
|
|
|
|
ucl_object_t search;
|
|
|
|
struct ucl_hash_elt *elt;
|
|
|
|
|
|
|
|
search.key = key;
|
|
|
|
search.keylen = keylen;
|
|
|
|
|
|
|
|
if (hashlin == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hashlin->caseless) {
|
|
|
|
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
2019-04-25 13:13:09 +02:00
|
|
|
hashlin->hash;
|
2015-02-21 19:11:12 +01:00
|
|
|
|
|
|
|
k = kh_get (ucl_hash_caseless_node, h, &search);
|
|
|
|
if (k != kh_end (h)) {
|
2021-08-23 11:10:33 +02:00
|
|
|
elt = kh_value (h, k);
|
2015-02-21 19:11:12 +01:00
|
|
|
ret = elt->obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
2019-04-25 13:13:09 +02:00
|
|
|
hashlin->hash;
|
2015-02-21 19:11:12 +01:00
|
|
|
k = kh_get (ucl_hash_node, h, &search);
|
|
|
|
if (k != kh_end (h)) {
|
2021-08-23 11:10:33 +02:00
|
|
|
elt = kh_value (h, k);
|
2015-02-21 19:11:12 +01:00
|
|
|
ret = elt->obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
|
|
|
|
{
|
|
|
|
khiter_t k;
|
|
|
|
struct ucl_hash_elt *elt;
|
|
|
|
|
|
|
|
if (hashlin == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hashlin->caseless) {
|
|
|
|
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
2019-04-25 13:13:09 +02:00
|
|
|
hashlin->hash;
|
2015-02-21 19:11:12 +01:00
|
|
|
|
|
|
|
k = kh_get (ucl_hash_caseless_node, h, obj);
|
|
|
|
if (k != kh_end (h)) {
|
2021-08-23 11:10:33 +02:00
|
|
|
elt = kh_value (h, k);
|
2021-08-22 19:23:31 +02:00
|
|
|
DL_DELETE(hashlin->head, elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
kh_del (ucl_hash_caseless_node, h, k);
|
2021-08-23 11:10:33 +02:00
|
|
|
UCL_FREE(sizeof(*elt), elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
2019-04-25 13:13:09 +02:00
|
|
|
hashlin->hash;
|
2015-02-21 19:11:12 +01:00
|
|
|
k = kh_get (ucl_hash_node, h, obj);
|
|
|
|
if (k != kh_end (h)) {
|
2021-08-23 11:10:33 +02:00
|
|
|
elt = kh_value (h, k);
|
2021-08-22 19:23:31 +02:00
|
|
|
DL_DELETE(hashlin->head, elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
kh_del (ucl_hash_node, h, k);
|
2021-08-23 11:10:33 +02:00
|
|
|
UCL_FREE(sizeof(*elt), elt);
|
2015-02-21 19:11:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-14 12:42:36 +01:00
|
|
|
|
2019-04-25 13:13:09 +02:00
|
|
|
bool
|
|
|
|
ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)
|
2018-02-14 12:42:36 +01:00
|
|
|
{
|
|
|
|
if (hashlin == NULL) {
|
2019-04-25 13:13:09 +02:00
|
|
|
return false;
|
2018-02-14 12:42:36 +01:00
|
|
|
}
|
|
|
|
|
2021-08-22 19:23:31 +02:00
|
|
|
if (sz > kh_size((khash_t(ucl_hash_node) *)hashlin->hash)) {
|
2018-02-14 12:42:36 +01:00
|
|
|
if (hashlin->caseless) {
|
|
|
|
khash_t(ucl_hash_caseless_node) *h = (khash_t(
|
|
|
|
ucl_hash_caseless_node) *)
|
|
|
|
hashlin->hash;
|
2018-02-14 15:44:17 +01:00
|
|
|
kh_resize (ucl_hash_caseless_node, h, sz * 2);
|
2018-02-14 12:42:36 +01:00
|
|
|
} else {
|
|
|
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
|
|
hashlin->hash;
|
2018-02-14 15:44:17 +01:00
|
|
|
kh_resize (ucl_hash_node, h, sz * 2);
|
2018-02-14 12:42:36 +01:00
|
|
|
}
|
|
|
|
}
|
2021-08-22 19:23:31 +02:00
|
|
|
|
2019-04-25 13:13:09 +02:00
|
|
|
return true;
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ucl_hash_cmp_icase (const void *a, const void *b)
|
|
|
|
{
|
2021-08-22 19:23:31 +02:00
|
|
|
const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *)a,
|
|
|
|
*ob = (const struct ucl_hash_elt *)b;
|
2019-07-08 14:01:08 +02:00
|
|
|
|
2021-08-22 19:23:31 +02:00
|
|
|
if (oa->obj->keylen == ob->obj->keylen) {
|
|
|
|
return rspamd_lc_cmp (oa->obj->key, ob->obj->key, oa->obj->keylen);
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
|
2021-08-22 19:23:31 +02:00
|
|
|
return ((int)(oa->obj->keylen)) - ob->obj->keylen;
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ucl_hash_cmp_case_sens (const void *a, const void *b)
|
|
|
|
{
|
2021-08-22 19:23:31 +02:00
|
|
|
const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *)a,
|
|
|
|
*ob = (const struct ucl_hash_elt *)b;
|
2019-07-08 14:01:08 +02:00
|
|
|
|
2021-08-22 19:23:31 +02:00
|
|
|
if (oa->obj->keylen == ob->obj->keylen) {
|
|
|
|
return memcmp (oa->obj->key, ob->obj->key, oa->obj->keylen);
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
|
2021-08-22 19:23:31 +02:00
|
|
|
return ((int)(oa->obj->keylen)) - ob->obj->keylen;
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ucl_hash_sort (ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (fl & UCL_SORT_KEYS_ICASE) {
|
2021-08-22 19:23:31 +02:00
|
|
|
DL_SORT(hashlin->head, ucl_hash_cmp_icase);
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-08-22 19:23:31 +02:00
|
|
|
DL_SORT(hashlin->head, ucl_hash_cmp_case_sens);
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fl & UCL_SORT_KEYS_RECURSIVE) {
|
2021-08-22 19:23:31 +02:00
|
|
|
struct ucl_hash_elt *elt;
|
|
|
|
|
|
|
|
DL_FOREACH(hashlin->head, elt) {
|
|
|
|
if (ucl_object_type (elt->obj) == UCL_OBJECT) {
|
|
|
|
ucl_hash_sort (elt->obj->value.ov, fl);
|
2019-07-08 14:01:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-14 12:42:36 +01:00
|
|
|
}
|