From 8bc1cf90a9b6618a5bb1867cf5e27267c97d80f6 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 14 Jan 2008 17:15:28 +0100 Subject: [PATCH] Fix important bug in mangle_single_dir. --- src/ecma119_tree.c | 2 +- src/util.h | 29 +++++++++++++++++++++++-- src/util_htable.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/ecma119_tree.c b/src/ecma119_tree.c index d2ef869..9999447 100644 --- a/src/ecma119_tree.c +++ b/src/ecma119_tree.c @@ -569,7 +569,7 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len, "\"%s\" renamed to \"%s\"", children[k]->iso_name, new); - iso_htable_remove(table, children[k]->iso_name, NULL); + iso_htable_remove_ptr(table, children[k]->iso_name, NULL); free(children[k]->iso_name); children[k]->iso_name = new; iso_htable_add(table, new, new); diff --git a/src/util.h b/src/util.h index 132ba4f..161166c 100644 --- a/src/util.h +++ b/src/util.h @@ -249,8 +249,8 @@ typedef void (*hfree_data_t)(void *key, void *data); * two elements. * * @param compare - * A function to compare two elements. It takes a pointer to both elements - * and return 0, -1 or 1 if the first element is equal, less or greater + * A function to compare two keys. It takes a pointer to both keys + * and return 0, -1 or 1 if the first key is equal, less or greater * than the second one. * @param tree * Location where the tree structure will be stored. @@ -373,6 +373,31 @@ int iso_htable_get(IsoHTable *table, void *key, void **data); */ int iso_htable_remove(IsoHTable *table, void *key, hfree_data_t free_data); +/** + * Like remove, but instead of checking for key equality using the compare + * function, it just compare the key pointers. If the table allows duplicates, + * and you provide different keys (i.e. different pointers) to elements + * with same key (i.e. same content), this function ensure the exact element + * is removed. + * + * It has the problem that you must provide the same key pointer, and not just + * a key whose contents are equal. Moreover, if you use the same key (same + * pointer) to identify several objects, what of those are removed is + * undefined. + * + * @param table + * Hash table + * @param key + * Key of the element that will be removed + * @param free_data + * Function that will be called passing as parameters both the key and + * the element that will be deleted. The user can use it to free the + * element. You can pass NULL if you don't want to delete the item itself. + * @return + * 1 success, 0 no element exists with the given key, < 0 error + */ +int iso_htable_remove_ptr(IsoHTable *table, void *key, hfree_data_t free_data); + /** * Destroy the given hash table. * diff --git a/src/util_htable.c b/src/util_htable.c index c7b8f09..d083d8c 100644 --- a/src/util_htable.c +++ b/src/util_htable.c @@ -204,6 +204,60 @@ int iso_htable_remove(IsoHTable *table, void *key, hfree_data_t free_data) return 0; } +/** + * Like remove, but instead of checking for key equality using the compare + * function, it just compare the key pointers. If the table allows duplicates, + * and you provide different keys (i.e. different pointers) to elements + * with same key (i.e. same content), this function ensure the exact element + * is removed. + * + * It has the problem that you must provide the same key pointer, and not just + * a key whose contents are equal. Moreover, if you use the same key (same + * pointer) to identify several objects, what of those are removed is + * undefined. + * + * @param table + * Hash table + * @param key + * Key of the element that will be removed + * @param free_data + * Function that will be called passing as parameters both the key and + * the element that will be deleted. The user can use it to free the + * element. You can pass NULL if you don't want to delete the item itself. + * @return + * 1 success, 0 no element exists with the given key, < 0 error + */ +int iso_htable_remove_ptr(IsoHTable *table, void *key, hfree_data_t free_data) +{ + struct iso_hnode *node, *prev; + unsigned int hash; + + if (table == NULL || key == NULL) { + return ISO_NULL_POINTER; + } + + hash = table->hash(key) % table->cap; + node = table->table[hash]; + prev = NULL; + while (node) { + if (key == node->key) { + if (free_data) + free_data(node->key, node->data); + if (prev) { + prev->next = node->next; + } else { + table->table[hash] = node->next; + } + free(node); + table->size--; + return 1; + } + prev = node; + node = node->next; + } + return 0; +} + /** * Hash function suitable for keys that are char strings. */