#include "fitz.h" #include "mupdf.h" typedef struct pdf_item_s pdf_item; struct pdf_item_s { void *drop_func; fz_obj *key; void *val; int age; pdf_item *next; }; struct refkey { void *drop_func; int num; int gen; }; struct pdf_store_s { fz_hash_table *hash; /* hash for num/gen keys */ pdf_item *root; /* linked list for everything else */ }; pdf_store * pdf_new_store(void) { pdf_store *store; store = fz_malloc(sizeof(pdf_store)); store->hash = fz_new_hash_table(4096, sizeof(struct refkey)); store->root = NULL; return store; } void pdf_store_item(pdf_store *store, void *keepfunc, void *drop_func, fz_obj *key, void *val) { pdf_item *item; if (!store) return; item = fz_malloc(sizeof(pdf_item)); item->drop_func = drop_func; item->key = fz_keep_obj(key); item->val = ((void*(*)(void*))keepfunc)(val); item->age = 0; item->next = NULL; if (fz_is_indirect(key)) { struct refkey refkey; refkey.drop_func = drop_func; refkey.num = fz_to_num(key); refkey.gen = fz_to_gen(key); fz_hash_insert(store->hash, &refkey, item); } else { item->next = store->root; store->root = item; } } void * pdf_find_item(pdf_store *store, void *drop_func, fz_obj *key) { struct refkey refkey; pdf_item *item; if (!store) return NULL; if (key == NULL) return NULL; if (fz_is_indirect(key)) { refkey.drop_func = drop_func; refkey.num = fz_to_num(key); refkey.gen = fz_to_gen(key); item = fz_hash_find(store->hash, &refkey); if (item) { item->age = 0; return item->val; } } else { for (item = store->root; item; item = item->next) { if (item->drop_func == drop_func && !fz_objcmp(item->key, key)) { item->age = 0; return item->val; } } } return NULL; } void pdf_remove_item(pdf_store *store, void *drop_func, fz_obj *key) { struct refkey refkey; pdf_item *item, *prev, *next; if (fz_is_indirect(key)) { refkey.drop_func = drop_func; refkey.num = fz_to_num(key); refkey.gen = fz_to_gen(key); item = fz_hash_find(store->hash, &refkey); if (item) { fz_hash_remove(store->hash, &refkey); ((void(*)(void*))item->drop_func)(item->val); fz_drop_obj(item->key); fz_free(item); } } else { prev = NULL; for (item = store->root; item; item = next) { next = item->next; if (item->drop_func == drop_func && !fz_objcmp(item->key, key)) { if (!prev) store->root = next; else prev->next = next; ((void(*)(void*))item->drop_func)(item->val); fz_drop_obj(item->key); fz_free(item); } else prev = item; } } } void pdf_age_store(pdf_store *store, int maxage) { struct refkey *refkey; pdf_item *item, *prev, *next; int i; for (i = 0; i < fz_hash_len(store->hash); i++) { refkey = fz_hash_get_key(store->hash, i); item = fz_hash_get_val(store->hash, i); if (item && ++item->age > maxage) { fz_hash_remove(store->hash, refkey); ((void(*)(void*))item->drop_func)(item->val); fz_drop_obj(item->key); fz_free(item); i--; /* items with same hash may move into place */ } } prev = NULL; for (item = store->root; item; item = next) { next = item->next; if (++item->age > maxage) { if (!prev) store->root = next; else prev->next = next; ((void(*)(void*))item->drop_func)(item->val); fz_drop_obj(item->key); fz_free(item); } else prev = item; } } void pdf_free_store(pdf_store *store) { pdf_age_store(store, 0); fz_free_hash(store->hash); fz_free(store); } void pdf_debug_store(pdf_store *store) { pdf_item *item; pdf_item *next; struct refkey *refkey; int i; printf("-- resource store contents --\n"); for (i = 0; i < fz_hash_len(store->hash); i++) { refkey = fz_hash_get_key(store->hash, i); item = fz_hash_get_val(store->hash, i); if (item) printf("store[%d] (%d %d R) = %p\n", i, refkey->num, refkey->gen, item->val); } for (item = store->root; item; item = next) { next = item->next; printf("store[*] "); fz_debug_obj(item->key); printf(" = %p\n", item->val); } }