diff options
Diffstat (limited to 'fitz/base_object.c')
-rw-r--r-- | fitz/base_object.c | 802 |
1 files changed, 802 insertions, 0 deletions
diff --git a/fitz/base_object.c b/fitz/base_object.c new file mode 100644 index 00000000..5c20767a --- /dev/null +++ b/fitz/base_object.c @@ -0,0 +1,802 @@ +#include "fitz.h" + +typedef enum fz_objkind_e +{ + FZ_NULL, + FZ_BOOL, + FZ_INT, + FZ_REAL, + FZ_STRING, + FZ_NAME, + FZ_ARRAY, + FZ_DICT, + FZ_INDIRECT +} fz_objkind; + +struct keyval +{ + fz_obj *k; + fz_obj *v; +}; + +struct fz_obj_s +{ + int refs; + fz_objkind kind; + union + { + int b; + int i; + float f; + struct { + unsigned short len; + char buf[1]; + } s; + char n[1]; + struct { + int len; + int cap; + fz_obj **items; + } a; + struct { + char sorted; + int len; + int cap; + struct keyval *items; + } d; + struct { + int num; + int gen; + struct pdf_xref_s *xref; + } r; + } u; +}; + +static fz_obj *fz_resolve_indirect_null(fz_obj *ref) +{ + return ref; +} + +fz_obj* (*fz_resolve_indirect)(fz_obj*) = fz_resolve_indirect_null; + +fz_obj * +fz_new_null(void) +{ + fz_obj *obj = fz_malloc(sizeof(fz_obj)); + obj->refs = 1; + obj->kind = FZ_NULL; + return obj; +} + +fz_obj * +fz_new_bool(int b) +{ + fz_obj *obj = fz_malloc(sizeof(fz_obj)); + obj->refs = 1; + obj->kind = FZ_BOOL; + obj->u.b = b; + return obj; +} + +fz_obj * +fz_new_int(int i) +{ + fz_obj *obj = fz_malloc(sizeof(fz_obj)); + obj->refs = 1; + obj->kind = FZ_INT; + obj->u.i = i; + return obj; +} + +fz_obj * +fz_new_real(float f) +{ + fz_obj *obj = fz_malloc(sizeof(fz_obj)); + obj->refs = 1; + obj->kind = FZ_REAL; + obj->u.f = f; + return obj; +} + +fz_obj * +fz_new_string(char *str, int len) +{ + fz_obj *obj = fz_malloc(offsetof(fz_obj, u.s.buf) + len + 1); + obj->refs = 1; + obj->kind = FZ_STRING; + obj->u.s.len = len; + memcpy(obj->u.s.buf, str, len); + obj->u.s.buf[len] = '\0'; + return obj; +} + +fz_obj * +fz_new_name(char *str) +{ + fz_obj *obj = fz_malloc(offsetof(fz_obj, u.n) + strlen(str) + 1); + obj->refs = 1; + obj->kind = FZ_NAME; + strcpy(obj->u.n, str); + return obj; +} + +fz_obj * +fz_new_indirect(int num, int gen, void *xref) +{ + fz_obj *obj = fz_malloc(sizeof(fz_obj)); + obj->refs = 1; + obj->kind = FZ_INDIRECT; + obj->u.r.num = num; + obj->u.r.gen = gen; + obj->u.r.xref = xref; + return obj; +} + +fz_obj * +fz_keep_obj(fz_obj *obj) +{ + assert(obj != NULL); + obj->refs ++; + return obj; +} + +int fz_is_indirect(fz_obj *obj) +{ + return obj ? obj->kind == FZ_INDIRECT : 0; +} + +int fz_is_null(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_NULL : 0; +} + +int fz_is_bool(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_BOOL : 0; +} + +int fz_is_int(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_INT : 0; +} + +int fz_is_real(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_REAL : 0; +} + +int fz_is_string(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_STRING : 0; +} + +int fz_is_name(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_NAME : 0; +} + +int fz_is_array(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_ARRAY : 0; +} + +int fz_is_dict(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + return obj ? obj->kind == FZ_DICT : 0; +} + +int fz_to_bool(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (fz_is_bool(obj)) + return obj->u.b; + return 0; +} + +int fz_to_int(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (fz_is_int(obj)) + return obj->u.i; + if (fz_is_real(obj)) + return obj->u.f; + return 0; +} + +float fz_to_real(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (fz_is_real(obj)) + return obj->u.f; + if (fz_is_int(obj)) + return obj->u.i; + return 0; +} + +char *fz_to_name(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (fz_is_name(obj)) + return obj->u.n; + return ""; +} + +char *fz_to_str_buf(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (fz_is_string(obj)) + return obj->u.s.buf; + return ""; +} + +int fz_to_str_len(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (fz_is_string(obj)) + return obj->u.s.len; + return 0; +} + +/* for use by pdf_crypt_obj_imp to decrypt AES string in place */ +void fz_set_str_len(fz_obj *obj, int newlen) +{ + obj = fz_resolve_indirect(obj); + if (fz_is_string(obj)) + if (newlen < obj->u.s.len) + obj->u.s.len = newlen; +} + +int fz_to_num(fz_obj *obj) +{ + if (fz_is_indirect(obj)) + return obj->u.r.num; + return 0; +} + +int fz_to_gen(fz_obj *obj) +{ + if (fz_is_indirect(obj)) + return obj->u.r.gen; + return 0; +} + +void *fz_get_indirect_xref(fz_obj *obj) +{ + if (fz_is_indirect(obj)) + return obj->u.r.xref; + return NULL; +} + +int +fz_objcmp(fz_obj *a, fz_obj *b) +{ + int i; + + if (a == b) + return 0; + + if (!a || !b) + return 1; + + if (a->kind != b->kind) + return 1; + + switch (a->kind) + { + case FZ_NULL: + return 0; + + case FZ_BOOL: + return a->u.b - b->u.b; + + case FZ_INT: + return a->u.i - b->u.i; + + case FZ_REAL: + if (a->u.f < b->u.f) + return -1; + if (a->u.f > b->u.f) + return 1; + return 0; + + case FZ_STRING: + if (a->u.s.len < b->u.s.len) + { + if (memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len) <= 0) + return -1; + return 1; + } + if (a->u.s.len > b->u.s.len) + { + if (memcmp(a->u.s.buf, b->u.s.buf, b->u.s.len) >= 0) + return 1; + return -1; + } + return memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len); + + case FZ_NAME: + return strcmp(a->u.n, b->u.n); + + case FZ_INDIRECT: + if (a->u.r.num == b->u.r.num) + return a->u.r.gen - b->u.r.gen; + return a->u.r.num - b->u.r.num; + + case FZ_ARRAY: + if (a->u.a.len != b->u.a.len) + return a->u.a.len - b->u.a.len; + for (i = 0; i < a->u.a.len; i++) + if (fz_objcmp(a->u.a.items[i], b->u.a.items[i])) + return 1; + return 0; + + case FZ_DICT: + if (a->u.d.len != b->u.d.len) + return a->u.d.len - b->u.d.len; + for (i = 0; i < a->u.d.len; i++) + { + if (fz_objcmp(a->u.d.items[i].k, b->u.d.items[i].k)) + return 1; + if (fz_objcmp(a->u.d.items[i].v, b->u.d.items[i].v)) + return 1; + } + return 0; + + } + return 1; +} + +static char * +fz_objkindstr(fz_obj *obj) +{ + if (obj == NULL) + return "<NULL>"; + switch (obj->kind) + { + case FZ_NULL: return "null"; + case FZ_BOOL: return "boolean"; + case FZ_INT: return "integer"; + case FZ_REAL: return "real"; + case FZ_STRING: return "string"; + case FZ_NAME: return "name"; + case FZ_ARRAY: return "array"; + case FZ_DICT: return "dictionary"; + case FZ_INDIRECT: return "reference"; + } + return "<unknown>"; +} + +fz_obj * +fz_new_array(int initialcap) +{ + fz_obj *obj; + int i; + + obj = fz_malloc(sizeof(fz_obj)); + obj->refs = 1; + obj->kind = FZ_ARRAY; + + obj->u.a.len = 0; + obj->u.a.cap = initialcap > 1 ? initialcap : 6; + + obj->u.a.items = fz_calloc(obj->u.a.cap, sizeof(fz_obj*)); + for (i = 0; i < obj->u.a.cap; i++) + obj->u.a.items[i] = NULL; + + return obj; +} + +fz_obj * +fz_copy_array(fz_obj *obj) +{ + fz_obj *new; + int i; + + if (fz_is_indirect(obj) || !fz_is_array(obj)) + fz_warn("assert: not an array (%s)", fz_objkindstr(obj)); + + new = fz_new_array(fz_array_len(obj)); + for (i = 0; i < fz_array_len(obj); i++) + fz_array_push(new, fz_array_get(obj, i)); + + return new; +} + +int +fz_array_len(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (!fz_is_array(obj)) + return 0; + return obj->u.a.len; +} + +fz_obj * +fz_array_get(fz_obj *obj, int i) +{ + obj = fz_resolve_indirect(obj); + + if (!fz_is_array(obj)) + return NULL; + + if (i < 0 || i >= obj->u.a.len) + return NULL; + + return obj->u.a.items[i]; +} + +void +fz_array_put(fz_obj *obj, int i, fz_obj *item) +{ + obj = fz_resolve_indirect(obj); + + if (!fz_is_array(obj)) + fz_warn("assert: not an array (%s)", fz_objkindstr(obj)); + else if (i < 0) + fz_warn("assert: index %d < 0", i); + else if (i >= obj->u.a.len) + fz_warn("assert: index %d > length %d", i, obj->u.a.len); + else + { + if (obj->u.a.items[i]) + fz_drop_obj(obj->u.a.items[i]); + obj->u.a.items[i] = fz_keep_obj(item); + } +} + +void +fz_array_push(fz_obj *obj, fz_obj *item) +{ + obj = fz_resolve_indirect(obj); + + if (!fz_is_array(obj)) + fz_warn("assert: not an array (%s)", fz_objkindstr(obj)); + else + { + if (obj->u.a.len + 1 > obj->u.a.cap) + { + int i; + obj->u.a.cap = (obj->u.a.cap * 3) / 2; + obj->u.a.items = fz_realloc(obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*)); + for (i = obj->u.a.len ; i < obj->u.a.cap; i++) + obj->u.a.items[i] = NULL; + } + obj->u.a.items[obj->u.a.len] = fz_keep_obj(item); + obj->u.a.len++; + } +} + +void +fz_array_insert(fz_obj *obj, fz_obj *item) +{ + obj = fz_resolve_indirect(obj); + + if (!fz_is_array(obj)) + fz_warn("assert: not an array (%s)", fz_objkindstr(obj)); + else + { + if (obj->u.a.len + 1 > obj->u.a.cap) + { + int i; + obj->u.a.cap = (obj->u.a.cap * 3) / 2; + obj->u.a.items = fz_realloc(obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*)); + for (i = obj->u.a.len ; i < obj->u.a.cap; i++) + obj->u.a.items[i] = NULL; + } + memmove(obj->u.a.items + 1, obj->u.a.items, obj->u.a.len * sizeof(fz_obj*)); + obj->u.a.items[0] = fz_keep_obj(item); + obj->u.a.len++; + } +} + +/* dicts may only have names as keys! */ + +static int keyvalcmp(const void *ap, const void *bp) +{ + const struct keyval *a = ap; + const struct keyval *b = bp; + return strcmp(fz_to_name(a->k), fz_to_name(b->k)); +} + +fz_obj * +fz_new_dict(int initialcap) +{ + fz_obj *obj; + int i; + + obj = fz_malloc(sizeof(fz_obj)); + obj->refs = 1; + obj->kind = FZ_DICT; + + obj->u.d.sorted = 1; + obj->u.d.len = 0; + obj->u.d.cap = initialcap > 1 ? initialcap : 10; + + obj->u.d.items = fz_calloc(obj->u.d.cap, sizeof(struct keyval)); + for (i = 0; i < obj->u.d.cap; i++) + { + obj->u.d.items[i].k = NULL; + obj->u.d.items[i].v = NULL; + } + + return obj; +} + +fz_obj * +fz_copy_dict(fz_obj *obj) +{ + fz_obj *new; + int i; + + if (fz_is_indirect(obj) || !fz_is_dict(obj)) + fz_throw("assert: not a dict (%s)", fz_objkindstr(obj)); + + new = fz_new_dict(fz_dict_len(obj)); + for (i = 0; i < fz_dict_len(obj); i++) + fz_dict_put(new, fz_dict_get_key(obj, i), fz_dict_get_val(obj, i)); + + return new; +} + +int +fz_dict_len(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (!fz_is_dict(obj)) + return 0; + return obj->u.d.len; +} + +fz_obj * +fz_dict_get_key(fz_obj *obj, int i) +{ + obj = fz_resolve_indirect(obj); + + if (!fz_is_dict(obj)) + return NULL; + + if (i < 0 || i >= obj->u.d.len) + return NULL; + + return obj->u.d.items[i].k; +} + +fz_obj * +fz_dict_get_val(fz_obj *obj, int i) +{ + obj = fz_resolve_indirect(obj); + + if (!fz_is_dict(obj)) + return NULL; + + if (i < 0 || i >= obj->u.d.len) + return NULL; + + return obj->u.d.items[i].v; +} + +static int +fz_dict_finds(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 = -strcmp(fz_to_name(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 (strcmp(fz_to_name(obj->u.d.items[i].k), key) == 0) + return i; + } + + return -1; +} + +fz_obj * +fz_dict_gets(fz_obj *obj, char *key) +{ + int i; + + obj = fz_resolve_indirect(obj); + + if (!fz_is_dict(obj)) + return NULL; + + i = fz_dict_finds(obj, key); + if (i >= 0) + return obj->u.d.items[i].v; + + return NULL; +} + +fz_obj * +fz_dict_get(fz_obj *obj, fz_obj *key) +{ + if (fz_is_name(key)) + return fz_dict_gets(obj, fz_to_name(key)); + return NULL; +} + +fz_obj * +fz_dict_getsa(fz_obj *obj, char *key, char *abbrev) +{ + fz_obj *v; + v = fz_dict_gets(obj, key); + if (v) + return v; + return fz_dict_gets(obj, abbrev); +} + +void +fz_dict_put(fz_obj *obj, fz_obj *key, fz_obj *val) +{ + char *s; + int i; + + obj = fz_resolve_indirect(obj); + + if (!fz_is_dict(obj)) + { + fz_warn("assert: not a dict (%s)", fz_objkindstr(obj)); + return; + } + + if (fz_is_name(key)) + s = fz_to_name(key); + else + { + fz_warn("assert: key is not a name (%s)", fz_objkindstr(obj)); + return; + } + + if (!val) + { + fz_warn("assert: val does not exist for key (%s)", s); + return; + } + + i = fz_dict_finds(obj, s); + if (i >= 0) + { + fz_drop_obj(obj->u.d.items[i].v); + obj->u.d.items[i].v = fz_keep_obj(val); + return; + } + + if (obj->u.d.len + 1 > obj->u.d.cap) + { + obj->u.d.cap = (obj->u.d.cap * 3) / 2; + obj->u.d.items = fz_realloc(obj->u.d.items, obj->u.d.cap, sizeof(struct keyval)); + for (i = obj->u.d.len; i < obj->u.d.cap; i++) + { + obj->u.d.items[i].k = NULL; + obj->u.d.items[i].v = NULL; + } + } + + /* borked! */ + if (obj->u.d.len) + if (strcmp(fz_to_name(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_keep_obj(key); + obj->u.d.items[obj->u.d.len].v = fz_keep_obj(val); + obj->u.d.len ++; +} + +void +fz_dict_puts(fz_obj *obj, char *key, fz_obj *val) +{ + fz_obj *keyobj = fz_new_name(key); + fz_dict_put(obj, keyobj, val); + fz_drop_obj(keyobj); +} + +void +fz_dict_dels(fz_obj *obj, char *key) +{ + obj = fz_resolve_indirect(obj); + + if (!fz_is_dict(obj)) + fz_warn("assert: not a dict (%s)", fz_objkindstr(obj)); + else + { + int i = fz_dict_finds(obj, key); + if (i >= 0) + { + fz_drop_obj(obj->u.d.items[i].k); + fz_drop_obj(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 --; + } + } +} + +void +fz_dict_del(fz_obj *obj, fz_obj *key) +{ + if (fz_is_name(key)) + fz_dict_dels(obj, fz_to_name(key)); + else + fz_warn("assert: key is not a name (%s)", fz_objkindstr(obj)); +} + +void +fz_sort_dict(fz_obj *obj) +{ + obj = fz_resolve_indirect(obj); + if (!fz_is_dict(obj)) + return; + if (!obj->u.d.sorted) + { + qsort(obj->u.d.items, obj->u.d.len, sizeof(struct keyval), keyvalcmp); + obj->u.d.sorted = 1; + } +} + +static void +fz_free_array(fz_obj *obj) +{ + int i; + + for (i = 0; i < obj->u.a.len; i++) + if (obj->u.a.items[i]) + fz_drop_obj(obj->u.a.items[i]); + + fz_free(obj->u.a.items); + fz_free(obj); +} + +static void +fz_free_dict(fz_obj *obj) +{ + int i; + + for (i = 0; i < obj->u.d.len; i++) { + if (obj->u.d.items[i].k) + fz_drop_obj(obj->u.d.items[i].k); + if (obj->u.d.items[i].v) + fz_drop_obj(obj->u.d.items[i].v); + } + + fz_free(obj->u.d.items); + fz_free(obj); +} + +void +fz_drop_obj(fz_obj *obj) +{ + assert(obj != NULL); + if (--obj->refs == 0) + { + if (obj->kind == FZ_ARRAY) + fz_free_array(obj); + else if (obj->kind == FZ_DICT) + fz_free_dict(obj); + else + fz_free(obj); + } +} |