2 #include "fitz-stream.h"
4 /* keep either names or strings in the dict. don't mix & match. */
6 static int keyvalcmp(const void *ap
, const void *bp
)
8 const fz_keyval
*a
= ap
;
9 const fz_keyval
*b
= bp
;
11 return strcmp(fz_toname(a
->k
), fz_toname(b
->k
));
12 if (fz_isstring(a
->k
))
13 return strcmp(fz_tostrbuf(a
->k
), fz_tostrbuf(b
->k
));
17 static inline int keystrcmp(fz_obj
*key
, char *s
)
20 return strcmp(fz_toname(key
), s
);
22 return strcmp(fz_tostrbuf(key
), s
);
27 fz_newdict(fz_obj
**op
, int initialcap
)
32 obj
= *op
= fz_malloc(sizeof (fz_obj
));
33 if (!obj
) return fz_outofmem
;
40 obj
->u
.d
.cap
= initialcap
> 0 ? initialcap
: 10;
42 obj
->u
.d
.items
= fz_malloc(sizeof(fz_keyval
) * obj
->u
.d
.cap
);
43 if (!obj
->u
.d
.items
) { fz_free(obj
); return fz_outofmem
; }
45 for (i
= 0; i
< obj
->u
.d
.cap
; i
++) {
46 obj
->u
.d
.items
[i
].k
= nil
;
47 obj
->u
.d
.items
[i
].v
= nil
;
54 fz_copydict(fz_obj
**op
, fz_obj
*obj
)
61 return fz_throw("typecheck in copydict");
63 error
= fz_newdict(&new, obj
->u
.d
.cap
);
64 if (error
) return error
;
67 for (i
= 0; i
< fz_dictlen(obj
); i
++) {
68 error
= fz_dictput(new, fz_dictgetkey(obj
, i
), fz_dictgetval(obj
, i
));
69 if (error
) { fz_dropobj(new); return error
; }
76 fz_deepcopydict(fz_obj
**op
, fz_obj
*obj
)
84 return fz_throw("typecheck in deepcopydict");
86 error
= fz_newdict(&new, obj
->u
.d
.cap
);
87 if (error
) return error
;
90 for (i
= 0; i
< fz_dictlen(obj
); i
++)
92 val
= fz_dictgetval(obj
, i
);
94 if (fz_isarray(val
)) {
95 error
= fz_deepcopyarray(&val
, val
);
96 if (error
) { fz_dropobj(new); return error
; }
97 error
= fz_dictput(new, fz_dictgetkey(obj
, i
), val
);
98 if (error
) { fz_dropobj(val
); fz_dropobj(new); return error
; }
102 else if (fz_isdict(val
)) {
103 error
= fz_deepcopydict(&val
, val
);
104 if (error
) { fz_dropobj(new); return error
; }
105 error
= fz_dictput(new, fz_dictgetkey(obj
, i
), val
);
106 if (error
) { fz_dropobj(val
); fz_dropobj(new); return error
; }
111 error
= fz_dictput(new, fz_dictgetkey(obj
, i
), val
);
112 if (error
) { fz_dropobj(new); return error
; }
120 growdict(fz_obj
*obj
)
126 newcap
= obj
->u
.d
.cap
* 2;
128 newitems
= fz_realloc(obj
->u
.d
.items
, sizeof(fz_keyval
) * newcap
);
129 if (!newitems
) return fz_outofmem
;
131 obj
->u
.d
.items
= newitems
;
132 for (i
= obj
->u
.d
.cap
; i
< newcap
; i
++) {
133 obj
->u
.d
.items
[i
].k
= nil
;
134 obj
->u
.d
.items
[i
].v
= nil
;
136 obj
->u
.d
.cap
= newcap
;
142 fz_dictlen(fz_obj
*obj
)
150 fz_dictgetkey(fz_obj
*obj
, int i
)
155 if (i
< 0 || i
>= obj
->u
.d
.len
)
158 return obj
->u
.d
.items
[i
].k
;
162 fz_dictgetval(fz_obj
*obj
, int i
)
167 if (i
< 0 || i
>= obj
->u
.d
.len
)
170 return obj
->u
.d
.items
[i
].v
;
173 static inline int dictfinds(fz_obj
*obj
, char *key
)
178 int r
= obj
->u
.d
.len
- 1;
181 int m
= (l
+ r
) >> 1;
182 int c
= -keystrcmp(obj
->u
.d
.items
[m
].k
, key
);
195 for (i
= 0; i
< obj
->u
.d
.len
; i
++)
196 if (keystrcmp(obj
->u
.d
.items
[i
].k
, key
) == 0)
204 fz_dictgets(fz_obj
*obj
, char *key
)
211 i
= dictfinds(obj
, key
);
213 return obj
->u
.d
.items
[i
].v
;
219 fz_dictget(fz_obj
*obj
, fz_obj
*key
)
222 return fz_dictgets(obj
, fz_toname(key
));
223 if (fz_isstring(key
))
224 return fz_dictgets(obj
, fz_tostrbuf(key
));
229 fz_dictgetsa(fz_obj
*obj
, char *key
, char *abbrev
)
232 v
= fz_dictgets(obj
, key
);
235 return fz_dictgets(obj
, abbrev
);
239 fz_dictput(fz_obj
*obj
, fz_obj
*key
, fz_obj
*val
)
246 return fz_throw("typecheck in dictput");
250 else if (fz_isstring(key
))
251 s
= fz_tostrbuf(key
);
253 return fz_throw("typecheck in dictput");
255 i
= dictfinds(obj
, s
);
258 fz_dropobj(obj
->u
.d
.items
[i
].v
);
259 obj
->u
.d
.items
[i
].v
= fz_keepobj(val
);
263 if (obj
->u
.d
.len
+ 1 > obj
->u
.d
.cap
)
265 error
= growdict(obj
);
272 if (keystrcmp(obj
->u
.d
.items
[obj
->u
.d
.len
- 1].k
, s
) > 0)
275 obj
->u
.d
.items
[obj
->u
.d
.len
].k
= fz_keepobj(key
);
276 obj
->u
.d
.items
[obj
->u
.d
.len
].v
= fz_keepobj(val
);
283 fz_dictputs(fz_obj
*obj
, char *key
, fz_obj
*val
)
287 error
= fz_newname(&keyobj
, key
);
288 if (error
) return error
;
289 error
= fz_dictput(obj
, keyobj
, val
);
295 fz_dictdels(fz_obj
*obj
, char *key
)
300 return fz_throw("typecheck in dictdel");
302 i
= dictfinds(obj
, key
);
305 fz_dropobj(obj
->u
.d
.items
[i
].k
);
306 fz_dropobj(obj
->u
.d
.items
[i
].v
);
308 obj
->u
.d
.items
[i
] = obj
->u
.d
.items
[obj
->u
.d
.len
-1];
316 fz_dictdel(fz_obj
*obj
, fz_obj
*key
)
319 return fz_dictdels(obj
, fz_toname(key
));
320 else if (fz_isstring(key
))
321 return fz_dictdels(obj
, fz_tostrbuf(key
));
323 return fz_throw("typecheck in dictdel");
327 fz_dropdict(fz_obj
*obj
)
334 for (i
= 0; i
< obj
->u
.d
.len
; i
++) {
335 if (obj
->u
.d
.items
[i
].k
)
336 fz_dropobj(obj
->u
.d
.items
[i
].k
);
337 if (obj
->u
.d
.items
[i
].v
)
338 fz_dropobj(obj
->u
.d
.items
[i
].v
);
341 fz_free(obj
->u
.d
.items
);
346 fz_sortdict(fz_obj
*obj
)
350 if (!obj
->u
.d
.sorted
)
352 qsort(obj
->u
.d
.items
, obj
->u
.d
.len
, sizeof(fz_keyval
), keyvalcmp
);