summaryrefslogtreecommitdiff
path: root/fitz/obj_dict.c
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2009-02-28 13:00:34 +0100
committerTor Andersson <tor@ghostscript.com>2009-02-28 13:00:34 +0100
commitf744dace3f0f91b8505979bf244453c9ec713b4b (patch)
tree86fed467944886a17d4d22038990a8fd8d2e3be8 /fitz/obj_dict.c
parentd0631f32c95f656d30c90d28c15a56b09fcc86ee (diff)
downloadmupdf-f744dace3f0f91b8505979bf244453c9ec713b4b.tar.xz
Moved Fitz files into one directory.
Diffstat (limited to 'fitz/obj_dict.c')
-rw-r--r--fitz/obj_dict.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/fitz/obj_dict.c b/fitz/obj_dict.c
new file mode 100644
index 00000000..236c8a1a
--- /dev/null
+++ b/fitz/obj_dict.c
@@ -0,0 +1,399 @@
+#include "fitz-base.h"
+#include "fitz-stream.h"
+
+/* keep either names or strings in the dict. don't mix & match. */
+
+static int keyvalcmp(const void *ap, const void *bp)
+{
+ const fz_keyval *a = ap;
+ const fz_keyval *b = bp;
+ if (fz_isname(a->k))
+ return strcmp(fz_toname(a->k), fz_toname(b->k));
+ if (fz_isstring(a->k))
+ return strcmp(fz_tostrbuf(a->k), fz_tostrbuf(b->k));
+ return -1;
+}
+
+static inline int keystrcmp(fz_obj *key, char *s)
+{
+ if (fz_isname(key))
+ return strcmp(fz_toname(key), s);
+ if (fz_isstring(key))
+ return strcmp(fz_tostrbuf(key), s);
+ return -1;
+}
+
+fz_error *
+fz_newdict(fz_obj **op, int initialcap)
+{
+ fz_obj *obj;
+ int i;
+
+ obj = *op = fz_malloc(sizeof (fz_obj));
+ if (!obj)
+ return fz_throw("outofmem: dict struct");
+
+ obj->refs = 1;
+ obj->kind = FZ_DICT;
+
+ obj->u.d.sorted = 1;
+ obj->u.d.len = 0;
+ obj->u.d.cap = initialcap > 0 ? initialcap : 10;
+
+ obj->u.d.items = fz_malloc(sizeof(fz_keyval) * obj->u.d.cap);
+ if (!obj->u.d.items)
+ {
+ fz_free(obj);
+ return fz_throw("outofmem: dict item buffer");
+ }
+
+ for (i = 0; i < obj->u.d.cap; i++)
+ {
+ obj->u.d.items[i].k = nil;
+ obj->u.d.items[i].v = nil;
+ }
+
+ return fz_okay;
+}
+
+fz_error *
+fz_copydict(fz_obj **op, fz_obj *obj)
+{
+ fz_error *error;
+ fz_obj *new;
+ int i;
+
+ if (!fz_isdict(obj))
+ return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj));
+
+ error = fz_newdict(&new, obj->u.d.cap);
+ if (error)
+ return fz_rethrow(error, "cannot create new dict");
+
+ for (i = 0; i < fz_dictlen(obj); i++)
+ {
+ error = fz_dictput(new, fz_dictgetkey(obj, i), fz_dictgetval(obj, i));
+ if (error)
+ {
+ fz_dropobj(new);
+ return fz_rethrow(error, "cannot copy dict entry");
+ }
+ }
+
+ *op = new;
+ return fz_okay;
+}
+
+fz_error *
+fz_deepcopydict(fz_obj **op, fz_obj *obj)
+{
+ fz_error *error;
+ fz_obj *new;
+ fz_obj *val;
+ int i;
+
+ if (!fz_isdict(obj))
+ return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj));
+
+ error = fz_newdict(&new, obj->u.d.cap);
+ if (error)
+ return fz_rethrow(error, "cannot create new dict");
+
+ for (i = 0; i < fz_dictlen(obj); i++)
+ {
+ val = fz_dictgetval(obj, i);
+
+ if (fz_isarray(val))
+ {
+ error = fz_deepcopyarray(&val, val);
+ if (error)
+ {
+ fz_dropobj(new);
+ return fz_rethrow(error, "cannot deep copy item");
+ }
+ error = fz_dictput(new, fz_dictgetkey(obj, i), val);
+ if (error)
+ {
+ fz_dropobj(val);
+ fz_dropobj(new);
+ return fz_rethrow(error, "cannot add copied dict entry");
+ }
+ fz_dropobj(val);
+ }
+
+ else if (fz_isdict(val))
+ {
+ error = fz_deepcopydict(&val, val);
+ if (error)
+ {
+ fz_dropobj(new);
+ return fz_rethrow(error, "cannot deep copy item");
+ }
+ error = fz_dictput(new, fz_dictgetkey(obj, i), val);
+ if (error)
+ {
+ fz_dropobj(val);
+ fz_dropobj(new);
+ return fz_rethrow(error, "cannot add copied dict entry");
+ }
+ fz_dropobj(val);
+ }
+
+ else
+ {
+ error = fz_dictput(new, fz_dictgetkey(obj, i), val);
+ if (error)
+ {
+ fz_dropobj(new);
+ return fz_rethrow(error, "cannot copy dict entry");
+ }
+ }
+ }
+
+ *op = new;
+ return fz_okay;
+}
+
+static fz_error *
+growdict(fz_obj *obj)
+{
+ fz_keyval *newitems;
+ int newcap;
+ int i;
+
+ newcap = obj->u.d.cap * 2;
+
+ newitems = fz_realloc(obj->u.d.items, sizeof(fz_keyval) * newcap);
+ if (!newitems)
+ return fz_throw("outofmem: resize item buffer");
+
+ obj->u.d.items = newitems;
+ for (i = obj->u.d.cap; i < newcap; i++)
+ {
+ obj->u.d.items[i].k = nil;
+ obj->u.d.items[i].v = nil;
+ }
+ obj->u.d.cap = newcap;
+
+ return fz_okay;
+}
+
+int
+fz_dictlen(fz_obj *obj)
+{
+ if (!fz_isdict(obj))
+ return 0;
+ return obj->u.d.len;
+}
+
+fz_obj *
+fz_dictgetkey(fz_obj *obj, int i)
+{
+ if (!fz_isdict(obj))
+ return nil;
+
+ if (i < 0 || i >= obj->u.d.len)
+ return nil;
+
+ return obj->u.d.items[i].k;
+}
+
+fz_obj *
+fz_dictgetval(fz_obj *obj, int i)
+{
+ if (!fz_isdict(obj))
+ return nil;
+
+ if (i < 0 || i >= obj->u.d.len)
+ return nil;
+
+ return obj->u.d.items[i].v;
+}
+
+static inline int dictfinds(fz_obj *obj, char *key)
+{
+ if (obj->u.d.sorted)
+ {
+ int l = 0;
+ int r = obj->u.d.len - 1;
+ while (l <= r)
+ {
+ int m = (l + r) >> 1;
+ int c = -keystrcmp(obj->u.d.items[m].k, key);
+ if (c < 0)
+ r = m - 1;
+ else if (c > 0)
+ l = m + 1;
+ else
+ return m;
+ }
+ }
+
+ else
+ {
+ int i;
+ for (i = 0; i < obj->u.d.len; i++)
+ if (keystrcmp(obj->u.d.items[i].k, key) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+fz_obj *
+fz_dictgets(fz_obj *obj, char *key)
+{
+ int i;
+
+ if (!fz_isdict(obj))
+ return nil;
+
+ i = dictfinds(obj, key);
+ if (i >= 0)
+ return obj->u.d.items[i].v;
+
+ return nil;
+}
+
+fz_obj *
+fz_dictget(fz_obj *obj, fz_obj *key)
+{
+ if (fz_isname(key))
+ return fz_dictgets(obj, fz_toname(key));
+ if (fz_isstring(key))
+ return fz_dictgets(obj, fz_tostrbuf(key));
+ return nil;
+}
+
+fz_obj *
+fz_dictgetsa(fz_obj *obj, char *key, char *abbrev)
+{
+ fz_obj *v;
+ v = fz_dictgets(obj, key);
+ if (v)
+ return v;
+ return fz_dictgets(obj, abbrev);
+}
+
+fz_error *
+fz_dictput(fz_obj *obj, fz_obj *key, fz_obj *val)
+{
+ fz_error *error;
+ char *s;
+ int i;
+
+ if (!fz_isdict(obj))
+ return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj));
+
+ if (fz_isname(key))
+ s = fz_toname(key);
+ else if (fz_isstring(key))
+ s = fz_tostrbuf(key);
+ else
+ return fz_throw("assert: key is not string or name (%s)", fz_objkindstr(obj));
+
+ i = dictfinds(obj, s);
+ if (i >= 0)
+ {
+ fz_dropobj(obj->u.d.items[i].v);
+ obj->u.d.items[i].v = fz_keepobj(val);
+ return fz_okay;
+ }
+
+ if (obj->u.d.len + 1 > obj->u.d.cap)
+ {
+ error = growdict(obj);
+ if (error)
+ return fz_rethrow(error, "cannot grow dict item buffer");
+ }
+
+ /* borked! */
+ if (obj->u.d.len)
+ if (keystrcmp(obj->u.d.items[obj->u.d.len - 1].k, s) > 0)
+ obj->u.d.sorted = 0;
+
+ obj->u.d.items[obj->u.d.len].k = fz_keepobj(key);
+ obj->u.d.items[obj->u.d.len].v = fz_keepobj(val);
+ obj->u.d.len ++;
+
+ return fz_okay;
+}
+
+fz_error *
+fz_dictputs(fz_obj *obj, char *key, fz_obj *val)
+{
+ fz_error *error;
+ fz_obj *keyobj;
+ error = fz_newname(&keyobj, key);
+ if (error)
+ return fz_rethrow(error, "cannot create dict key");
+ error = fz_dictput(obj, keyobj, val);
+ fz_dropobj(keyobj);
+ if (error)
+ return fz_rethrow(error, "cannot insert dict entry");
+ return fz_okay;
+}
+
+fz_error *
+fz_dictdels(fz_obj *obj, char *key)
+{
+ int i;
+
+ if (!fz_isdict(obj))
+ return fz_throw("assert: not a dict (%s)", fz_objkindstr(obj));
+
+ i = dictfinds(obj, key);
+ if (i >= 0)
+ {
+ fz_dropobj(obj->u.d.items[i].k);
+ fz_dropobj(obj->u.d.items[i].v);
+ obj->u.d.sorted = 0;
+ obj->u.d.items[i] = obj->u.d.items[obj->u.d.len-1];
+ obj->u.d.len --;
+ }
+
+ return fz_okay;
+}
+
+fz_error *
+fz_dictdel(fz_obj *obj, fz_obj *key)
+{
+ if (fz_isname(key))
+ return fz_dictdels(obj, fz_toname(key));
+ else if (fz_isstring(key))
+ return fz_dictdels(obj, fz_tostrbuf(key));
+ else
+ return fz_throw("assert: key is not string or name (%s)", fz_objkindstr(obj));
+}
+
+void
+fz_dropdict(fz_obj *obj)
+{
+ int i;
+
+ if (!fz_isdict(obj))
+ return;
+
+ for (i = 0; i < obj->u.d.len; i++) {
+ if (obj->u.d.items[i].k)
+ fz_dropobj(obj->u.d.items[i].k);
+ if (obj->u.d.items[i].v)
+ fz_dropobj(obj->u.d.items[i].v);
+ }
+
+ fz_free(obj->u.d.items);
+ fz_free(obj);
+}
+
+void
+fz_sortdict(fz_obj *obj)
+{
+ if (!fz_isdict(obj))
+ return;
+ if (!obj->u.d.sorted)
+ {
+ qsort(obj->u.d.items, obj->u.d.len, sizeof(fz_keyval), keyvalcmp);
+ obj->u.d.sorted = 1;
+ }
+}
+