1 | /* |
2 | * << Haru Free PDF Library >> -- hpdf_dict.c |
3 | * |
4 | * URL: http://libharu.org |
5 | * |
6 | * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp> |
7 | * Copyright (c) 2007-2009 Antony Dovgal <tony@daylessday.org> |
8 | * |
9 | * Permission to use, copy, modify, distribute and sell this software |
10 | * and its documentation for any purpose is hereby granted without fee, |
11 | * provided that the above copyright notice appear in all copies and |
12 | * that both that copyright notice and this permission notice appear |
13 | * in supporting documentation. |
14 | * It is provided "as is" without express or implied warranty. |
15 | * |
16 | */ |
17 | |
18 | #include "hpdf_conf.h" |
19 | #include "hpdf_utils.h" |
20 | #include "hpdf_objects.h" |
21 | |
22 | HPDF_DictElement |
23 | GetElement (HPDF_Dict dict, |
24 | const char *key); |
25 | |
26 | /*--------------------------------------------------------------------------*/ |
27 | |
28 | HPDF_Dict |
29 | HPDF_Dict_New (HPDF_MMgr mmgr) |
30 | { |
31 | HPDF_Dict obj; |
32 | |
33 | obj = (HPDF_Dict)HPDF_GetMem (mmgr, sizeof(HPDF_Dict_Rec)); |
34 | if (obj) { |
35 | HPDF_MemSet (obj, 0, sizeof(HPDF_Dict_Rec)); |
36 | obj->header.obj_class = HPDF_OCLASS_DICT; |
37 | obj->mmgr = mmgr; |
38 | obj->error = mmgr->error; |
39 | obj->list = HPDF_List_New (mmgr, HPDF_DEF_ITEMS_PER_BLOCK); |
40 | obj->filter = HPDF_STREAM_FILTER_NONE; |
41 | if (!obj->list) { |
42 | HPDF_FreeMem (mmgr, obj); |
43 | obj = NULL; |
44 | } |
45 | } |
46 | |
47 | return obj; |
48 | } |
49 | |
50 | |
51 | HPDF_Dict |
52 | HPDF_DictStream_New (HPDF_MMgr mmgr, |
53 | HPDF_Xref xref) |
54 | { |
55 | HPDF_Dict obj; |
56 | HPDF_Number length; |
57 | HPDF_STATUS ret = 0; |
58 | |
59 | obj = HPDF_Dict_New (mmgr); |
60 | if (!obj) |
61 | return NULL; |
62 | |
63 | /* only stream object is added to xref automatically */ |
64 | ret += HPDF_Xref_Add (xref, obj); |
65 | if (ret != HPDF_OK) |
66 | return NULL; |
67 | |
68 | length = HPDF_Number_New (mmgr, 0); |
69 | if (!length) |
70 | return NULL; |
71 | |
72 | ret = HPDF_Xref_Add (xref, length); |
73 | if (ret != HPDF_OK) |
74 | return NULL; |
75 | |
76 | ret = HPDF_Dict_Add (obj, "Length" , length); |
77 | if (ret != HPDF_OK) |
78 | return NULL; |
79 | |
80 | obj->stream = HPDF_MemStream_New (mmgr, HPDF_STREAM_BUF_SIZ); |
81 | if (!obj->stream) |
82 | return NULL; |
83 | |
84 | return obj; |
85 | } |
86 | |
87 | |
88 | void |
89 | HPDF_Dict_Free (HPDF_Dict dict) |
90 | { |
91 | HPDF_UINT i; |
92 | |
93 | if (!dict) |
94 | return; |
95 | |
96 | if (dict->free_fn) |
97 | dict->free_fn (dict); |
98 | |
99 | for (i = 0; i < dict->list->count; i++) { |
100 | HPDF_DictElement element = |
101 | (HPDF_DictElement)HPDF_List_ItemAt (dict->list, i); |
102 | |
103 | if (element) { |
104 | HPDF_Obj_Free (dict->mmgr, element->value); |
105 | HPDF_FreeMem (dict->mmgr, element); |
106 | } |
107 | } |
108 | |
109 | if (dict->stream) |
110 | HPDF_Stream_Free (dict->stream); |
111 | |
112 | HPDF_List_Free (dict->list); |
113 | |
114 | dict->header.obj_class = 0; |
115 | |
116 | HPDF_FreeMem (dict->mmgr, dict); |
117 | } |
118 | |
119 | HPDF_STATUS |
120 | HPDF_Dict_Add_FilterParams(HPDF_Dict dict, HPDF_Dict filterParam) |
121 | { |
122 | HPDF_Array paramArray; |
123 | /* prepare params object */ |
124 | paramArray = HPDF_Dict_GetItem (dict, "DecodeParms" , |
125 | HPDF_OCLASS_ARRAY); |
126 | if(paramArray==NULL) { |
127 | paramArray = HPDF_Array_New (dict->mmgr); |
128 | if (!paramArray) |
129 | return HPDF_Error_GetCode (dict->error); |
130 | |
131 | /* add parameters */ |
132 | HPDF_Dict_Add(dict, "DecodeParms" , paramArray); |
133 | } |
134 | HPDF_Array_Add(paramArray, filterParam); |
135 | return HPDF_OK; |
136 | } |
137 | |
138 | |
139 | HPDF_STATUS |
140 | HPDF_Dict_Write (HPDF_Dict dict, |
141 | HPDF_Stream stream, |
142 | HPDF_Encrypt e) |
143 | { |
144 | HPDF_UINT i; |
145 | HPDF_STATUS ret; |
146 | |
147 | ret = HPDF_Stream_WriteStr (stream, "<<\012" ); |
148 | if (ret != HPDF_OK) |
149 | return ret; |
150 | |
151 | if (dict->before_write_fn) { |
152 | if ((ret = dict->before_write_fn (dict)) != HPDF_OK) |
153 | return ret; |
154 | } |
155 | |
156 | /* encrypt-dict must not be encrypted. */ |
157 | if (dict->header.obj_class == (HPDF_OCLASS_DICT | HPDF_OSUBCLASS_ENCRYPT)) |
158 | e = NULL; |
159 | |
160 | if (dict->stream) { |
161 | /* set filter element */ |
162 | if (dict->filter == HPDF_STREAM_FILTER_NONE) |
163 | HPDF_Dict_RemoveElement (dict, "Filter" ); |
164 | else { |
165 | HPDF_Array array = HPDF_Dict_GetItem (dict, "Filter" , |
166 | HPDF_OCLASS_ARRAY); |
167 | |
168 | if (!array) { |
169 | array = HPDF_Array_New (dict->mmgr); |
170 | if (!array) |
171 | return HPDF_Error_GetCode (dict->error); |
172 | |
173 | ret = HPDF_Dict_Add (dict, "Filter" , array); |
174 | if (ret != HPDF_OK) |
175 | return ret; |
176 | } |
177 | |
178 | HPDF_Array_Clear (array); |
179 | |
180 | #ifndef LIBHPDF_HAVE_NOZLIB |
181 | if (dict->filter & HPDF_STREAM_FILTER_FLATE_DECODE) |
182 | HPDF_Array_AddName (array, "FlateDecode" ); |
183 | #endif /* LIBHPDF_HAVE_NOZLIB */ |
184 | |
185 | if (dict->filter & HPDF_STREAM_FILTER_DCT_DECODE) |
186 | HPDF_Array_AddName (array, "DCTDecode" ); |
187 | |
188 | if(dict->filter & HPDF_STREAM_FILTER_CCITT_DECODE) |
189 | HPDF_Array_AddName (array, "CCITTFaxDecode" ); |
190 | |
191 | if(dict->filterParams!=NULL) |
192 | { |
193 | HPDF_Dict_Add_FilterParams(dict, dict->filterParams); |
194 | } |
195 | } |
196 | } |
197 | |
198 | for (i = 0; i < dict->list->count; i++) { |
199 | HPDF_DictElement element = |
200 | (HPDF_DictElement)HPDF_List_ItemAt (dict->list, i); |
201 | HPDF_Obj_Header * = (HPDF_Obj_Header *)(element->value); |
202 | |
203 | if (!element->value) |
204 | return HPDF_SetError (dict->error, HPDF_INVALID_OBJECT, 0); |
205 | |
206 | if (header->obj_id & HPDF_OTYPE_HIDDEN) { |
207 | HPDF_PTRACE((" HPDF_Dict_Write obj=%p skipped obj_id=0x%08X\n" , |
208 | element->value, (HPDF_UINT)header->obj_id)); |
209 | } else { |
210 | ret = HPDF_Stream_WriteEscapeName (stream, element->key); |
211 | if (ret != HPDF_OK) |
212 | return ret; |
213 | |
214 | ret = HPDF_Stream_WriteChar (stream, ' '); |
215 | if (ret != HPDF_OK) |
216 | return ret; |
217 | |
218 | ret = HPDF_Obj_Write (element->value, stream, e); |
219 | if (ret != HPDF_OK) |
220 | return ret; |
221 | |
222 | ret = HPDF_Stream_WriteStr (stream, "\012" ); |
223 | if (ret != HPDF_OK) |
224 | return ret; |
225 | } |
226 | } |
227 | |
228 | if (dict->write_fn) { |
229 | if ((ret = dict->write_fn (dict, stream)) != HPDF_OK) |
230 | return ret; |
231 | } |
232 | |
233 | if ((ret = HPDF_Stream_WriteStr (stream, ">>" )) != HPDF_OK) |
234 | return ret; |
235 | |
236 | if (dict->stream) { |
237 | HPDF_UINT32 strptr; |
238 | HPDF_Number length; |
239 | |
240 | /* get "length" element */ |
241 | length = (HPDF_Number)HPDF_Dict_GetItem (dict, "Length" , |
242 | HPDF_OCLASS_NUMBER); |
243 | if (!length) |
244 | return HPDF_SetError (dict->error, |
245 | HPDF_DICT_STREAM_LENGTH_NOT_FOUND, 0); |
246 | |
247 | /* "length" element must be indirect-object */ |
248 | if (!(length->header.obj_id & HPDF_OTYPE_INDIRECT)) { |
249 | return HPDF_SetError (dict->error, HPDF_DICT_ITEM_UNEXPECTED_TYPE, |
250 | 0); |
251 | } |
252 | |
253 | if ((ret = HPDF_Stream_WriteStr (stream, "\012stream\015\012" )) /* Acrobat 8.15 requires both \r and \n here */ |
254 | != HPDF_OK) |
255 | return ret; |
256 | |
257 | strptr = stream->size; |
258 | |
259 | if (e) |
260 | HPDF_Encrypt_Reset (e); |
261 | |
262 | if ((ret = HPDF_Stream_WriteToStream (dict->stream, stream, |
263 | dict->filter, e)) != HPDF_OK) |
264 | return ret; |
265 | |
266 | HPDF_Number_SetValue (length, stream->size - strptr); |
267 | |
268 | ret = HPDF_Stream_WriteStr (stream, "\012endstream" ); |
269 | } |
270 | |
271 | /* 2006.08.13 add. */ |
272 | if (dict->after_write_fn) { |
273 | if ((ret = dict->after_write_fn (dict)) != HPDF_OK) |
274 | return ret; |
275 | } |
276 | |
277 | return ret; |
278 | } |
279 | |
280 | HPDF_STATUS |
281 | HPDF_Dict_Add (HPDF_Dict dict, |
282 | const char *key, |
283 | void *obj) |
284 | { |
285 | HPDF_Obj_Header *; |
286 | HPDF_STATUS ret = HPDF_OK; |
287 | HPDF_DictElement element; |
288 | |
289 | if (!obj) { |
290 | if (HPDF_Error_GetCode (dict->error) == HPDF_OK) |
291 | return HPDF_SetError (dict->error, HPDF_INVALID_OBJECT, 0); |
292 | else |
293 | return HPDF_INVALID_OBJECT; |
294 | } |
295 | |
296 | header = (HPDF_Obj_Header *)obj; |
297 | |
298 | if (header->obj_id & HPDF_OTYPE_DIRECT) |
299 | return HPDF_SetError (dict->error, HPDF_INVALID_OBJECT, 0); |
300 | |
301 | if (!key) { |
302 | HPDF_Obj_Free (dict->mmgr, obj); |
303 | return HPDF_SetError (dict->error, HPDF_INVALID_OBJECT, 0); |
304 | } |
305 | |
306 | if (dict->list->count >= HPDF_LIMIT_MAX_DICT_ELEMENT) { |
307 | HPDF_PTRACE((" HPDF_Dict_Add exceed limitatin of dict count(%d)\n" , |
308 | HPDF_LIMIT_MAX_DICT_ELEMENT)); |
309 | |
310 | HPDF_Obj_Free (dict->mmgr, obj); |
311 | return HPDF_SetError (dict->error, HPDF_DICT_COUNT_ERR, 0); |
312 | } |
313 | |
314 | /* check whether there is an object which has same name */ |
315 | element = GetElement (dict, key); |
316 | |
317 | if (element) { |
318 | HPDF_Obj_Free (dict->mmgr, element->value); |
319 | element->value = NULL; |
320 | } else { |
321 | element = (HPDF_DictElement)HPDF_GetMem (dict->mmgr, |
322 | sizeof(HPDF_DictElement_Rec)); |
323 | |
324 | if (!element) { |
325 | /* cannot create element object */ |
326 | if (!(header->obj_id & HPDF_OTYPE_INDIRECT)) |
327 | HPDF_Obj_Free (dict->mmgr, obj); |
328 | |
329 | return HPDF_Error_GetCode (dict->error); |
330 | } |
331 | |
332 | HPDF_StrCpy (element->key, key, element->key + |
333 | HPDF_LIMIT_MAX_NAME_LEN + 1); |
334 | element->value = NULL; |
335 | |
336 | ret = HPDF_List_Add (dict->list, element); |
337 | if (ret != HPDF_OK) { |
338 | if (!(header->obj_id & HPDF_OTYPE_INDIRECT)) |
339 | HPDF_Obj_Free (dict->mmgr, obj); |
340 | |
341 | HPDF_FreeMem (dict->mmgr, element); |
342 | |
343 | return HPDF_Error_GetCode (dict->error); |
344 | } |
345 | } |
346 | |
347 | if (header->obj_id & HPDF_OTYPE_INDIRECT) { |
348 | HPDF_Proxy proxy = HPDF_Proxy_New (dict->mmgr, obj); |
349 | |
350 | if (!proxy) |
351 | return HPDF_Error_GetCode (dict->error); |
352 | |
353 | element->value = proxy; |
354 | proxy->header.obj_id |= HPDF_OTYPE_DIRECT; |
355 | } else { |
356 | element->value = obj; |
357 | header->obj_id |= HPDF_OTYPE_DIRECT; |
358 | } |
359 | |
360 | return ret; |
361 | } |
362 | |
363 | |
364 | HPDF_STATUS |
365 | HPDF_Dict_AddName (HPDF_Dict dict, |
366 | const char *key, |
367 | const char *value) |
368 | { |
369 | HPDF_Name name = HPDF_Name_New (dict->mmgr, value); |
370 | if (!name) |
371 | return HPDF_Error_GetCode (dict->error); |
372 | |
373 | return HPDF_Dict_Add (dict, key, name); |
374 | } |
375 | |
376 | |
377 | HPDF_STATUS |
378 | HPDF_Dict_AddNumber (HPDF_Dict dict, |
379 | const char *key, |
380 | HPDF_INT32 value) |
381 | { |
382 | HPDF_Number number = HPDF_Number_New (dict->mmgr, value); |
383 | |
384 | if (!number) |
385 | return HPDF_Error_GetCode (dict->error); |
386 | |
387 | return HPDF_Dict_Add (dict, key, number); |
388 | } |
389 | |
390 | |
391 | HPDF_STATUS |
392 | HPDF_Dict_AddReal (HPDF_Dict dict, |
393 | const char *key, |
394 | HPDF_REAL value) |
395 | { |
396 | HPDF_Real real = HPDF_Real_New (dict->mmgr, value); |
397 | |
398 | if (!real) |
399 | return HPDF_Error_GetCode (dict->error); |
400 | |
401 | return HPDF_Dict_Add (dict, key, real); |
402 | } |
403 | |
404 | |
405 | HPDF_STATUS |
406 | HPDF_Dict_AddBoolean (HPDF_Dict dict, |
407 | const char *key, |
408 | HPDF_BOOL value) |
409 | { |
410 | HPDF_Boolean obj = HPDF_Boolean_New (dict->mmgr, value); |
411 | |
412 | if (!obj) |
413 | return HPDF_Error_GetCode (dict->error); |
414 | |
415 | return HPDF_Dict_Add (dict, key, obj); |
416 | } |
417 | |
418 | |
419 | void* |
420 | HPDF_Dict_GetItem (HPDF_Dict dict, |
421 | const char *key, |
422 | HPDF_UINT16 obj_class) |
423 | { |
424 | HPDF_DictElement element = GetElement (dict, key); |
425 | void *obj; |
426 | |
427 | if (element && HPDF_StrCmp(key, element->key) == 0) { |
428 | HPDF_Obj_Header * = (HPDF_Obj_Header *)element->value; |
429 | |
430 | if (header->obj_class == HPDF_OCLASS_PROXY) { |
431 | HPDF_Proxy p = element->value; |
432 | header = (HPDF_Obj_Header *)p->obj; |
433 | obj = p->obj; |
434 | } else |
435 | obj = element->value; |
436 | |
437 | if ((header->obj_class & HPDF_OCLASS_ANY) != obj_class) { |
438 | HPDF_PTRACE((" HPDF_Dict_GetItem dict=%p key=%s obj_class=0x%08X\n" , |
439 | dict, key, (HPDF_UINT)header->obj_class)); |
440 | HPDF_SetError (dict->error, HPDF_DICT_ITEM_UNEXPECTED_TYPE, 0); |
441 | |
442 | return NULL; |
443 | } |
444 | |
445 | return obj; |
446 | } |
447 | |
448 | return NULL; |
449 | } |
450 | |
451 | |
452 | HPDF_DictElement |
453 | GetElement (HPDF_Dict dict, |
454 | const char *key) |
455 | { |
456 | HPDF_UINT i; |
457 | |
458 | for (i = 0; i < dict->list->count; i++) { |
459 | HPDF_DictElement element = |
460 | (HPDF_DictElement)HPDF_List_ItemAt (dict->list, i); |
461 | |
462 | if (HPDF_StrCmp (key, element->key) == 0) |
463 | return element; |
464 | } |
465 | |
466 | return NULL; |
467 | } |
468 | |
469 | |
470 | HPDF_STATUS |
471 | HPDF_Dict_RemoveElement (HPDF_Dict dict, |
472 | const char *key) |
473 | { |
474 | HPDF_UINT i; |
475 | |
476 | for (i = 0; i < dict->list->count; i++) { |
477 | HPDF_DictElement element = |
478 | (HPDF_DictElement)HPDF_List_ItemAt (dict->list, i); |
479 | |
480 | if (HPDF_StrCmp (key, element->key) == 0) { |
481 | HPDF_List_Remove (dict->list, element); |
482 | |
483 | HPDF_Obj_Free (dict->mmgr, element->value); |
484 | HPDF_FreeMem (dict->mmgr, element); |
485 | |
486 | return HPDF_OK; |
487 | } |
488 | } |
489 | |
490 | return HPDF_DICT_ITEM_NOT_FOUND; |
491 | } |
492 | |
493 | const char* |
494 | HPDF_Dict_GetKeyByObj (HPDF_Dict dict, |
495 | void *obj) |
496 | { |
497 | HPDF_UINT i; |
498 | |
499 | for (i = 0; i < dict->list->count; i++) { |
500 | HPDF_Obj_Header *; |
501 | HPDF_DictElement element = |
502 | (HPDF_DictElement)HPDF_List_ItemAt (dict->list, i); |
503 | |
504 | header = (HPDF_Obj_Header *)(element->value); |
505 | if (header->obj_class == HPDF_OCLASS_PROXY) { |
506 | HPDF_Proxy p = element->value; |
507 | |
508 | if (p->obj == obj) |
509 | return element->key; |
510 | } else { |
511 | if (element->value == obj) |
512 | return element->key; |
513 | } |
514 | } |
515 | |
516 | return NULL; |
517 | } |
518 | |
519 | |