Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2.  
  3. typedef enum fz_objkind_e
  4. {
  5.         FZ_NULL,
  6.         FZ_BOOL,
  7.         FZ_INT,
  8.         FZ_REAL,
  9.         FZ_STRING,
  10.         FZ_NAME,
  11.         FZ_ARRAY,
  12.         FZ_DICT,
  13.         FZ_INDIRECT
  14. } fz_objkind;
  15.  
  16. struct keyval
  17. {
  18.         fz_obj *k;
  19.         fz_obj *v;
  20. };
  21.  
  22. struct fz_obj_s
  23. {
  24.         int refs;
  25.         fz_objkind kind;
  26.         union
  27.         {
  28.                 int b;
  29.                 int i;
  30.                 float f;
  31.                 struct {
  32.                         unsigned short len;
  33.                         char buf[1];
  34.                 } s;
  35.                 char n[1];
  36.                 struct {
  37.                         int len;
  38.                         int cap;
  39.                         fz_obj **items;
  40.                 } a;
  41.                 struct {
  42.                         char sorted;
  43.                         int len;
  44.                         int cap;
  45.                         struct keyval *items;
  46.                 } d;
  47.                 struct {
  48.                         int num;
  49.                         int gen;
  50.                         struct pdf_xref_s *xref;
  51.                 } r;
  52.         } u;
  53. };
  54.  
  55. static fz_obj *fz_resolve_indirect_null(fz_obj *ref)
  56. {
  57.         return ref;
  58. }
  59.  
  60. fz_obj* (*fz_resolve_indirect)(fz_obj*) = fz_resolve_indirect_null;
  61.  
  62. fz_obj *
  63. fz_new_null(void)
  64. {
  65.         fz_obj *obj = fz_malloc(sizeof(fz_obj));
  66.         obj->refs = 1;
  67.         obj->kind = FZ_NULL;
  68.         return obj;
  69. }
  70.  
  71. fz_obj *
  72. fz_new_bool(int b)
  73. {
  74.         fz_obj *obj = fz_malloc(sizeof(fz_obj));
  75.         obj->refs = 1;
  76.         obj->kind = FZ_BOOL;
  77.         obj->u.b = b;
  78.         return obj;
  79. }
  80.  
  81. fz_obj *
  82. fz_new_int(int i)
  83. {
  84.         fz_obj *obj = fz_malloc(sizeof(fz_obj));
  85.         obj->refs = 1;
  86.         obj->kind = FZ_INT;
  87.         obj->u.i = i;
  88.         return obj;
  89. }
  90.  
  91. fz_obj *
  92. fz_new_real(float f)
  93. {
  94.         fz_obj *obj = fz_malloc(sizeof(fz_obj));
  95.         obj->refs = 1;
  96.         obj->kind = FZ_REAL;
  97.         obj->u.f = f;
  98.         return obj;
  99. }
  100.  
  101. fz_obj *
  102. fz_new_string(char *str, int len)
  103. {
  104.         fz_obj *obj = fz_malloc(offsetof(fz_obj, u.s.buf) + len + 1);
  105.         obj->refs = 1;
  106.         obj->kind = FZ_STRING;
  107.         obj->u.s.len = len;
  108.         memcpy(obj->u.s.buf, str, len);
  109.         obj->u.s.buf[len] = '\0';
  110.         return obj;
  111. }
  112.  
  113. fz_obj *
  114. fz_new_name(char *str)
  115. {
  116.         fz_obj *obj = fz_malloc(offsetof(fz_obj, u.n) + strlen(str) + 1);
  117.         obj->refs = 1;
  118.         obj->kind = FZ_NAME;
  119.         strcpy(obj->u.n, str);
  120.         return obj;
  121. }
  122.  
  123. fz_obj *
  124. fz_new_indirect(int num, int gen, void *xref)
  125. {
  126.         fz_obj *obj = fz_malloc(sizeof(fz_obj));
  127.         obj->refs = 1;
  128.         obj->kind = FZ_INDIRECT;
  129.         obj->u.r.num = num;
  130.         obj->u.r.gen = gen;
  131.         obj->u.r.xref = xref;
  132.         return obj;
  133. }
  134.  
  135. fz_obj *
  136. fz_keep_obj(fz_obj *obj)
  137. {
  138.         assert(obj != NULL);
  139.         obj->refs ++;
  140.         return obj;
  141. }
  142.  
  143. int fz_is_indirect(fz_obj *obj)
  144. {
  145.         return obj ? obj->kind == FZ_INDIRECT : 0;
  146. }
  147.  
  148. int fz_is_null(fz_obj *obj)
  149. {
  150.         obj = fz_resolve_indirect(obj);
  151.         return obj ? obj->kind == FZ_NULL : 0;
  152. }
  153.  
  154. int fz_is_bool(fz_obj *obj)
  155. {
  156.         obj = fz_resolve_indirect(obj);
  157.         return obj ? obj->kind == FZ_BOOL : 0;
  158. }
  159.  
  160. int fz_is_int(fz_obj *obj)
  161. {
  162.         obj = fz_resolve_indirect(obj);
  163.         return obj ? obj->kind == FZ_INT : 0;
  164. }
  165.  
  166. int fz_is_real(fz_obj *obj)
  167. {
  168.         obj = fz_resolve_indirect(obj);
  169.         return obj ? obj->kind == FZ_REAL : 0;
  170. }
  171.  
  172. int fz_is_string(fz_obj *obj)
  173. {
  174.         obj = fz_resolve_indirect(obj);
  175.         return obj ? obj->kind == FZ_STRING : 0;
  176. }
  177.  
  178. int fz_is_name(fz_obj *obj)
  179. {
  180.         obj = fz_resolve_indirect(obj);
  181.         return obj ? obj->kind == FZ_NAME : 0;
  182. }
  183.  
  184. int fz_is_array(fz_obj *obj)
  185. {
  186.         obj = fz_resolve_indirect(obj);
  187.         return obj ? obj->kind == FZ_ARRAY : 0;
  188. }
  189.  
  190. int fz_is_dict(fz_obj *obj)
  191. {
  192.         obj = fz_resolve_indirect(obj);
  193.         return obj ? obj->kind == FZ_DICT : 0;
  194. }
  195.  
  196. int fz_to_bool(fz_obj *obj)
  197. {
  198.         obj = fz_resolve_indirect(obj);
  199.         if (fz_is_bool(obj))
  200.                 return obj->u.b;
  201.         return 0;
  202. }
  203.  
  204. int fz_to_int(fz_obj *obj)
  205. {
  206.         obj = fz_resolve_indirect(obj);
  207.         if (fz_is_int(obj))
  208.                 return obj->u.i;
  209.         if (fz_is_real(obj))
  210.                 return obj->u.f;
  211.         return 0;
  212. }
  213.  
  214. float fz_to_real(fz_obj *obj)
  215. {
  216.         obj = fz_resolve_indirect(obj);
  217.         if (fz_is_real(obj))
  218.                 return obj->u.f;
  219.         if (fz_is_int(obj))
  220.                 return obj->u.i;
  221.         return 0;
  222. }
  223.  
  224. char *fz_to_name(fz_obj *obj)
  225. {
  226.         obj = fz_resolve_indirect(obj);
  227.         if (fz_is_name(obj))
  228.                 return obj->u.n;
  229.         return "";
  230. }
  231.  
  232. char *fz_to_str_buf(fz_obj *obj)
  233. {
  234.         obj = fz_resolve_indirect(obj);
  235.         if (fz_is_string(obj))
  236.                 return obj->u.s.buf;
  237.         return "";
  238. }
  239.  
  240. int fz_to_str_len(fz_obj *obj)
  241. {
  242.         obj = fz_resolve_indirect(obj);
  243.         if (fz_is_string(obj))
  244.                 return obj->u.s.len;
  245.         return 0;
  246. }
  247.  
  248. /* for use by pdf_crypt_obj_imp to decrypt AES string in place */
  249. void fz_set_str_len(fz_obj *obj, int newlen)
  250. {
  251.         obj = fz_resolve_indirect(obj);
  252.         if (fz_is_string(obj))
  253.                 if (newlen < obj->u.s.len)
  254.                         obj->u.s.len = newlen;
  255. }
  256.  
  257. int fz_to_num(fz_obj *obj)
  258. {
  259.         if (fz_is_indirect(obj))
  260.                 return obj->u.r.num;
  261.         return 0;
  262. }
  263.  
  264. int fz_to_gen(fz_obj *obj)
  265. {
  266.         if (fz_is_indirect(obj))
  267.                 return obj->u.r.gen;
  268.         return 0;
  269. }
  270.  
  271. void *fz_get_indirect_xref(fz_obj *obj)
  272. {
  273.         if (fz_is_indirect(obj))
  274.                 return obj->u.r.xref;
  275.         return NULL;
  276. }
  277.  
  278. int
  279. fz_objcmp(fz_obj *a, fz_obj *b)
  280. {
  281.         int i;
  282.  
  283.         if (a == b)
  284.                 return 0;
  285.  
  286.         if (!a || !b)
  287.                 return 1;
  288.  
  289.         if (a->kind != b->kind)
  290.                 return 1;
  291.  
  292.         switch (a->kind)
  293.         {
  294.         case FZ_NULL:
  295.                 return 0;
  296.  
  297.         case FZ_BOOL:
  298.                 return a->u.b - b->u.b;
  299.  
  300.         case FZ_INT:
  301.                 return a->u.i - b->u.i;
  302.  
  303.         case FZ_REAL:
  304.                 if (a->u.f < b->u.f)
  305.                         return -1;
  306.                 if (a->u.f > b->u.f)
  307.                         return 1;
  308.                 return 0;
  309.  
  310.         case FZ_STRING:
  311.                 if (a->u.s.len < b->u.s.len)
  312.                 {
  313.                         if (memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len) <= 0)
  314.                                 return -1;
  315.                         return 1;
  316.                 }
  317.                 if (a->u.s.len > b->u.s.len)
  318.                 {
  319.                         if (memcmp(a->u.s.buf, b->u.s.buf, b->u.s.len) >= 0)
  320.                                 return 1;
  321.                         return -1;
  322.                 }
  323.                 return memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len);
  324.  
  325.         case FZ_NAME:
  326.                 return strcmp(a->u.n, b->u.n);
  327.  
  328.         case FZ_INDIRECT:
  329.                 if (a->u.r.num == b->u.r.num)
  330.                         return a->u.r.gen - b->u.r.gen;
  331.                 return a->u.r.num - b->u.r.num;
  332.  
  333.         case FZ_ARRAY:
  334.                 if (a->u.a.len != b->u.a.len)
  335.                         return a->u.a.len - b->u.a.len;
  336.                 for (i = 0; i < a->u.a.len; i++)
  337.                         if (fz_objcmp(a->u.a.items[i], b->u.a.items[i]))
  338.                                 return 1;
  339.                 return 0;
  340.  
  341.         case FZ_DICT:
  342.                 if (a->u.d.len != b->u.d.len)
  343.                         return a->u.d.len - b->u.d.len;
  344.                 for (i = 0; i < a->u.d.len; i++)
  345.                 {
  346.                         if (fz_objcmp(a->u.d.items[i].k, b->u.d.items[i].k))
  347.                                 return 1;
  348.                         if (fz_objcmp(a->u.d.items[i].v, b->u.d.items[i].v))
  349.                                 return 1;
  350.                 }
  351.                 return 0;
  352.  
  353.         }
  354.         return 1;
  355. }
  356.  
  357. static char *
  358. fz_objkindstr(fz_obj *obj)
  359. {
  360.         if (obj == NULL)
  361.                 return "<NULL>";
  362.         switch (obj->kind)
  363.         {
  364.         case FZ_NULL: return "null";
  365.         case FZ_BOOL: return "boolean";
  366.         case FZ_INT: return "integer";
  367.         case FZ_REAL: return "real";
  368.         case FZ_STRING: return "string";
  369.         case FZ_NAME: return "name";
  370.         case FZ_ARRAY: return "array";
  371.         case FZ_DICT: return "dictionary";
  372.         case FZ_INDIRECT: return "reference";
  373.         }
  374.         return "<unknown>";
  375. }
  376.  
  377. fz_obj *
  378. fz_new_array(int initialcap)
  379. {
  380.         fz_obj *obj;
  381.         int i;
  382.  
  383.         obj = fz_malloc(sizeof(fz_obj));
  384.         obj->refs = 1;
  385.         obj->kind = FZ_ARRAY;
  386.  
  387.         obj->u.a.len = 0;
  388.         obj->u.a.cap = initialcap > 1 ? initialcap : 6;
  389.  
  390.         obj->u.a.items = fz_calloc(obj->u.a.cap, sizeof(fz_obj*));
  391.         for (i = 0; i < obj->u.a.cap; i++)
  392.                 obj->u.a.items[i] = NULL;
  393.  
  394.         return obj;
  395. }
  396.  
  397. fz_obj *
  398. fz_copy_array(fz_obj *obj)
  399. {
  400.         fz_obj *new;
  401.         int i;
  402.  
  403.         if (fz_is_indirect(obj) || !fz_is_array(obj))
  404.                 fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
  405.  
  406.         new = fz_new_array(fz_array_len(obj));
  407.         for (i = 0; i < fz_array_len(obj); i++)
  408.                 fz_array_push(new, fz_array_get(obj, i));
  409.  
  410.         return new;
  411. }
  412.  
  413. int
  414. fz_array_len(fz_obj *obj)
  415. {
  416.         obj = fz_resolve_indirect(obj);
  417.         if (!fz_is_array(obj))
  418.                 return 0;
  419.         return obj->u.a.len;
  420. }
  421.  
  422. fz_obj *
  423. fz_array_get(fz_obj *obj, int i)
  424. {
  425.         obj = fz_resolve_indirect(obj);
  426.  
  427.         if (!fz_is_array(obj))
  428.                 return NULL;
  429.  
  430.         if (i < 0 || i >= obj->u.a.len)
  431.                 return NULL;
  432.  
  433.         return obj->u.a.items[i];
  434. }
  435.  
  436. void
  437. fz_array_put(fz_obj *obj, int i, fz_obj *item)
  438. {
  439.         obj = fz_resolve_indirect(obj);
  440.  
  441.         if (!fz_is_array(obj))
  442.                 fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
  443.         else if (i < 0)
  444.                 fz_warn("assert: index %d < 0", i);
  445.         else if (i >= obj->u.a.len)
  446.                 fz_warn("assert: index %d > length %d", i, obj->u.a.len);
  447.         else
  448.         {
  449.                 if (obj->u.a.items[i])
  450.                         fz_drop_obj(obj->u.a.items[i]);
  451.                 obj->u.a.items[i] = fz_keep_obj(item);
  452.         }
  453. }
  454.  
  455. void
  456. fz_array_push(fz_obj *obj, fz_obj *item)
  457. {
  458.         obj = fz_resolve_indirect(obj);
  459.  
  460.         if (!fz_is_array(obj))
  461.                 fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
  462.         else
  463.         {
  464.                 if (obj->u.a.len + 1 > obj->u.a.cap)
  465.                 {
  466.                         int i;
  467.                         obj->u.a.cap = (obj->u.a.cap * 3) / 2;
  468.                         obj->u.a.items = fz_realloc(obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*));
  469.                         for (i = obj->u.a.len ; i < obj->u.a.cap; i++)
  470.                                 obj->u.a.items[i] = NULL;
  471.                 }
  472.                 obj->u.a.items[obj->u.a.len] = fz_keep_obj(item);
  473.                 obj->u.a.len++;
  474.         }
  475. }
  476.  
  477. void
  478. fz_array_insert(fz_obj *obj, fz_obj *item)
  479. {
  480.         obj = fz_resolve_indirect(obj);
  481.  
  482.         if (!fz_is_array(obj))
  483.                 fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
  484.         else
  485.         {
  486.                 if (obj->u.a.len + 1 > obj->u.a.cap)
  487.                 {
  488.                         int i;
  489.                         obj->u.a.cap = (obj->u.a.cap * 3) / 2;
  490.                         obj->u.a.items = fz_realloc(obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*));
  491.                         for (i = obj->u.a.len ; i < obj->u.a.cap; i++)
  492.                                 obj->u.a.items[i] = NULL;
  493.                 }
  494.                 memmove(obj->u.a.items + 1, obj->u.a.items, obj->u.a.len * sizeof(fz_obj*));
  495.                 obj->u.a.items[0] = fz_keep_obj(item);
  496.                 obj->u.a.len++;
  497.         }
  498. }
  499.  
  500. /* dicts may only have names as keys! */
  501.  
  502. static int keyvalcmp(const void *ap, const void *bp)
  503. {
  504.         const struct keyval *a = ap;
  505.         const struct keyval *b = bp;
  506.         return strcmp(fz_to_name(a->k), fz_to_name(b->k));
  507. }
  508.  
  509. fz_obj *
  510. fz_new_dict(int initialcap)
  511. {
  512.         fz_obj *obj;
  513.         int i;
  514.  
  515.         obj = fz_malloc(sizeof(fz_obj));
  516.         obj->refs = 1;
  517.         obj->kind = FZ_DICT;
  518.  
  519.         obj->u.d.sorted = 1;
  520.         obj->u.d.len = 0;
  521.         obj->u.d.cap = initialcap > 1 ? initialcap : 10;
  522.  
  523.         obj->u.d.items = fz_calloc(obj->u.d.cap, sizeof(struct keyval));
  524.         for (i = 0; i < obj->u.d.cap; i++)
  525.         {
  526.                 obj->u.d.items[i].k = NULL;
  527.                 obj->u.d.items[i].v = NULL;
  528.         }
  529.  
  530.         return obj;
  531. }
  532.  
  533. fz_obj *
  534. fz_copy_dict(fz_obj *obj)
  535. {
  536.         fz_obj *new;
  537.         int i;
  538.  
  539.         if (fz_is_indirect(obj) || !fz_is_dict(obj))
  540.                 fz_throw("assert: not a dict (%s)", fz_objkindstr(obj));
  541.  
  542.         new = fz_new_dict(fz_dict_len(obj));
  543.         for (i = 0; i < fz_dict_len(obj); i++)
  544.                 fz_dict_put(new, fz_dict_get_key(obj, i), fz_dict_get_val(obj, i));
  545.  
  546.         return new;
  547. }
  548.  
  549. int
  550. fz_dict_len(fz_obj *obj)
  551. {
  552.         obj = fz_resolve_indirect(obj);
  553.         if (!fz_is_dict(obj))
  554.                 return 0;
  555.         return obj->u.d.len;
  556. }
  557.  
  558. fz_obj *
  559. fz_dict_get_key(fz_obj *obj, int i)
  560. {
  561.         obj = fz_resolve_indirect(obj);
  562.  
  563.         if (!fz_is_dict(obj))
  564.                 return NULL;
  565.  
  566.         if (i < 0 || i >= obj->u.d.len)
  567.                 return NULL;
  568.  
  569.         return obj->u.d.items[i].k;
  570. }
  571.  
  572. fz_obj *
  573. fz_dict_get_val(fz_obj *obj, int i)
  574. {
  575.         obj = fz_resolve_indirect(obj);
  576.  
  577.         if (!fz_is_dict(obj))
  578.                 return NULL;
  579.  
  580.         if (i < 0 || i >= obj->u.d.len)
  581.                 return NULL;
  582.  
  583.         return obj->u.d.items[i].v;
  584. }
  585.  
  586. static int
  587. fz_dict_finds(fz_obj *obj, char *key)
  588. {
  589.         if (obj->u.d.sorted)
  590.         {
  591.                 int l = 0;
  592.                 int r = obj->u.d.len - 1;
  593.                 while (l <= r)
  594.                 {
  595.                         int m = (l + r) >> 1;
  596.                         int c = -strcmp(fz_to_name(obj->u.d.items[m].k), key);
  597.                         if (c < 0)
  598.                                 r = m - 1;
  599.                         else if (c > 0)
  600.                                 l = m + 1;
  601.                         else
  602.                                 return m;
  603.                 }
  604.         }
  605.  
  606.         else
  607.         {
  608.                 int i;
  609.                 for (i = 0; i < obj->u.d.len; i++)
  610.                         if (strcmp(fz_to_name(obj->u.d.items[i].k), key) == 0)
  611.                                 return i;
  612.         }
  613.  
  614.         return -1;
  615. }
  616.  
  617. fz_obj *
  618. fz_dict_gets(fz_obj *obj, char *key)
  619. {
  620.         int i;
  621.  
  622.         obj = fz_resolve_indirect(obj);
  623.  
  624.         if (!fz_is_dict(obj))
  625.                 return NULL;
  626.  
  627.         i = fz_dict_finds(obj, key);
  628.         if (i >= 0)
  629.                 return obj->u.d.items[i].v;
  630.  
  631.         return NULL;
  632. }
  633.  
  634. fz_obj *
  635. fz_dict_get(fz_obj *obj, fz_obj *key)
  636. {
  637.         if (fz_is_name(key))
  638.                 return fz_dict_gets(obj, fz_to_name(key));
  639.         return NULL;
  640. }
  641.  
  642. fz_obj *
  643. fz_dict_getsa(fz_obj *obj, char *key, char *abbrev)
  644. {
  645.         fz_obj *v;
  646.         v = fz_dict_gets(obj, key);
  647.         if (v)
  648.                 return v;
  649.         return fz_dict_gets(obj, abbrev);
  650. }
  651.  
  652. void
  653. fz_dict_put(fz_obj *obj, fz_obj *key, fz_obj *val)
  654. {
  655.         char *s;
  656.         int i;
  657.  
  658.         obj = fz_resolve_indirect(obj);
  659.  
  660.         if (!fz_is_dict(obj))
  661.         {
  662.                 fz_warn("assert: not a dict (%s)", fz_objkindstr(obj));
  663.                 return;
  664.         }
  665.  
  666.         if (fz_is_name(key))
  667.                 s = fz_to_name(key);
  668.         else
  669.         {
  670.                 fz_warn("assert: key is not a name (%s)", fz_objkindstr(obj));
  671.                 return;
  672.         }
  673.  
  674.         if (!val)
  675.         {
  676.                 fz_warn("assert: val does not exist for key (%s)", s);
  677.                 return;
  678.         }
  679.  
  680.         i = fz_dict_finds(obj, s);
  681.         if (i >= 0)
  682.         {
  683.                 fz_drop_obj(obj->u.d.items[i].v);
  684.                 obj->u.d.items[i].v = fz_keep_obj(val);
  685.                 return;
  686.         }
  687.  
  688.         if (obj->u.d.len + 1 > obj->u.d.cap)
  689.         {
  690.                 obj->u.d.cap = (obj->u.d.cap * 3) / 2;
  691.                 obj->u.d.items = fz_realloc(obj->u.d.items, obj->u.d.cap, sizeof(struct keyval));
  692.                 for (i = obj->u.d.len; i < obj->u.d.cap; i++)
  693.                 {
  694.                         obj->u.d.items[i].k = NULL;
  695.                         obj->u.d.items[i].v = NULL;
  696.                 }
  697.         }
  698.  
  699.         /* borked! */
  700.         if (obj->u.d.len)
  701.                 if (strcmp(fz_to_name(obj->u.d.items[obj->u.d.len - 1].k), s) > 0)
  702.                         obj->u.d.sorted = 0;
  703.  
  704.         obj->u.d.items[obj->u.d.len].k = fz_keep_obj(key);
  705.         obj->u.d.items[obj->u.d.len].v = fz_keep_obj(val);
  706.         obj->u.d.len ++;
  707. }
  708.  
  709. void
  710. fz_dict_puts(fz_obj *obj, char *key, fz_obj *val)
  711. {
  712.         fz_obj *keyobj = fz_new_name(key);
  713.         fz_dict_put(obj, keyobj, val);
  714.         fz_drop_obj(keyobj);
  715. }
  716.  
  717. void
  718. fz_dict_dels(fz_obj *obj, char *key)
  719. {
  720.         obj = fz_resolve_indirect(obj);
  721.  
  722.         if (!fz_is_dict(obj))
  723.                 fz_warn("assert: not a dict (%s)", fz_objkindstr(obj));
  724.         else
  725.         {
  726.                 int i = fz_dict_finds(obj, key);
  727.                 if (i >= 0)
  728.                 {
  729.                         fz_drop_obj(obj->u.d.items[i].k);
  730.                         fz_drop_obj(obj->u.d.items[i].v);
  731.                         obj->u.d.sorted = 0;
  732.                         obj->u.d.items[i] = obj->u.d.items[obj->u.d.len-1];
  733.                         obj->u.d.len --;
  734.                 }
  735.         }
  736. }
  737.  
  738. void
  739. fz_dict_del(fz_obj *obj, fz_obj *key)
  740. {
  741.         if (fz_is_name(key))
  742.                 fz_dict_dels(obj, fz_to_name(key));
  743.         else
  744.                 fz_warn("assert: key is not a name (%s)", fz_objkindstr(obj));
  745. }
  746.  
  747. void
  748. fz_sort_dict(fz_obj *obj)
  749. {
  750.         obj = fz_resolve_indirect(obj);
  751.         if (!fz_is_dict(obj))
  752.                 return;
  753.         if (!obj->u.d.sorted)
  754.         {
  755.                 qsort(obj->u.d.items, obj->u.d.len, sizeof(struct keyval), keyvalcmp);
  756.                 obj->u.d.sorted = 1;
  757.         }
  758. }
  759.  
  760. static void
  761. fz_free_array(fz_obj *obj)
  762. {
  763.         int i;
  764.  
  765.         for (i = 0; i < obj->u.a.len; i++)
  766.                 if (obj->u.a.items[i])
  767.                         fz_drop_obj(obj->u.a.items[i]);
  768.  
  769.         fz_free(obj->u.a.items);
  770.         fz_free(obj);
  771. }
  772.  
  773. static void
  774. fz_free_dict(fz_obj *obj)
  775. {
  776.         int i;
  777.  
  778.         for (i = 0; i < obj->u.d.len; i++) {
  779.                 if (obj->u.d.items[i].k)
  780.                         fz_drop_obj(obj->u.d.items[i].k);
  781.                 if (obj->u.d.items[i].v)
  782.                         fz_drop_obj(obj->u.d.items[i].v);
  783.         }
  784.  
  785.         fz_free(obj->u.d.items);
  786.         fz_free(obj);
  787. }
  788.  
  789. void
  790. fz_drop_obj(fz_obj *obj)
  791. {
  792.         assert(obj != NULL);
  793.         if (--obj->refs == 0)
  794.         {
  795.                 if (obj->kind == FZ_ARRAY)
  796.                         fz_free_array(obj);
  797.                 else if (obj->kind == FZ_DICT)
  798.                         fz_free_dict(obj);
  799.                 else
  800.                         fz_free(obj);
  801.         }
  802. }
  803.