summaryrefslogtreecommitdiffstats
path: root/src/plist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plist.c')
-rw-r--r--src/plist.c87
1 files changed, 75 insertions, 12 deletions
diff --git a/src/plist.c b/src/plist.c
index a3d88b9..6a267eb 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -37,6 +37,7 @@
37 37
38#include <node.h> 38#include <node.h>
39#include <node_iterator.h> 39#include <node_iterator.h>
40#include <hashtable.h>
40 41
41extern void plist_xml_init(void); 42extern void plist_xml_init(void);
42extern void plist_xml_deinit(void); 43extern void plist_xml_deinit(void);
@@ -148,6 +149,31 @@ plist_data_t plist_new_plist_data(void)
148 return data; 149 return data;
149} 150}
150 151
152static unsigned int dict_key_hash(const void *data)
153{
154 plist_data_t keydata = (plist_data_t)data;
155 unsigned int hash = 5381;
156 size_t i;
157 char *str = keydata->strval;
158 for (i = 0; i < keydata->length; str++, i++) {
159 hash = ((hash << 5) + hash) + *str;
160 }
161 return hash;
162}
163
164static int dict_key_compare(const void* a, const void* b)
165{
166 plist_data_t data_a = (plist_data_t)a;
167 plist_data_t data_b = (plist_data_t)b;
168 if (data_a->strval == NULL || data_b->strval == NULL) {
169 return FALSE;
170 }
171 if (data_a->length != data_b->length) {
172 return FALSE;
173 }
174 return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
175}
176
151void plist_free_data(plist_data_t data) 177void plist_free_data(plist_data_t data)
152{ 178{
153 if (data) 179 if (data)
@@ -161,6 +187,9 @@ void plist_free_data(plist_data_t data)
161 case PLIST_DATA: 187 case PLIST_DATA:
162 free(data->buff); 188 free(data->buff);
163 break; 189 break;
190 case PLIST_DICT:
191 hash_table_destroy(data->hashtable);
192 break;
164 default: 193 default:
165 break; 194 break;
166 } 195 }
@@ -483,20 +512,27 @@ PLIST_API plist_t plist_dict_get_item(plist_t node, const char* key)
483 512
484 if (node && PLIST_DICT == plist_get_node_type(node)) 513 if (node && PLIST_DICT == plist_get_node_type(node))
485 { 514 {
486 515 plist_data_t data = plist_get_data(node);
487 plist_t current = NULL; 516 hashtable_t *ht = (hashtable_t*)data->hashtable;
488 for (current = (plist_t)node_first_child(node); 517 if (ht) {
518 struct plist_data_s sdata;
519 sdata.strval = (char*)key;
520 sdata.length = strlen(key);
521 ret = (plist_t)hash_table_lookup(ht, &sdata);
522 } else {
523 plist_t current = NULL;
524 for (current = (plist_t)node_first_child(node);
489 current; 525 current;
490 current = (plist_t)node_next_sibling(node_next_sibling(current))) 526 current = (plist_t)node_next_sibling(node_next_sibling(current)))
491 {
492
493 plist_data_t data = plist_get_data(current);
494 assert( PLIST_KEY == plist_get_node_type(current) );
495
496 if (data && !strcmp(key, data->strval))
497 { 527 {
498 ret = (plist_t)node_next_sibling(current); 528 data = plist_get_data(current);
499 break; 529 assert( PLIST_KEY == plist_get_node_type(current) );
530
531 if (data && !strcmp(key, data->strval))
532 {
533 ret = (plist_t)node_next_sibling(current);
534 break;
535 }
500 } 536 }
501 } 537 }
502 } 538 }
@@ -507,6 +543,7 @@ PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item)
507{ 543{
508 if (node && PLIST_DICT == plist_get_node_type(node)) { 544 if (node && PLIST_DICT == plist_get_node_type(node)) {
509 node_t* old_item = plist_dict_get_item(node, key); 545 node_t* old_item = plist_dict_get_item(node, key);
546 plist_t key_node = NULL;
510 if (old_item) { 547 if (old_item) {
511 int idx = plist_free_node(old_item); 548 int idx = plist_free_node(old_item);
512 if (idx < 0) { 549 if (idx < 0) {
@@ -514,10 +551,32 @@ PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item)
514 } else { 551 } else {
515 node_insert(node, idx, item); 552 node_insert(node, idx, item);
516 } 553 }
554 key_node = node_prev_sibling(item);
517 } else { 555 } else {
518 node_attach(node, plist_new_key(key)); 556 key_node = plist_new_key(key);
557 node_attach(node, key_node);
519 node_attach(node, item); 558 node_attach(node, item);
520 } 559 }
560
561 hashtable_t *ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
562 if (ht) {
563 /* store pointer to item in hash table */
564 hash_table_insert(ht, (plist_data_t)((node_t*)key_node)->data, item);
565 } else {
566 if (((node_t*)node)->count > 500) {
567 /* make new hash table */
568 ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
569 /* calculate the hashes for all entries we have so far */
570 plist_t current = NULL;
571 for (current = (plist_t)node_first_child(node);
572 ht && current;
573 current = (plist_t)node_next_sibling(node_next_sibling(current)))
574 {
575 hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
576 }
577 ((plist_data_t)((node_t*)node)->data)->hashtable = ht;
578 }
579 }
521 } 580 }
522 return; 581 return;
523} 582}
@@ -535,6 +594,10 @@ PLIST_API void plist_dict_remove_item(plist_t node, const char* key)
535 if (old_item) 594 if (old_item)
536 { 595 {
537 plist_t key_node = node_prev_sibling(old_item); 596 plist_t key_node = node_prev_sibling(old_item);
597 hashtable_t* ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
598 if (ht) {
599 hash_table_remove(ht, ((node_t*)key_node)->data);
600 }
538 plist_free(key_node); 601 plist_free(key_node);
539 plist_free(old_item); 602 plist_free(old_item);
540 } 603 }