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
22HPDF_DictElement
23GetElement (HPDF_Dict dict,
24 const char *key);
25
26/*--------------------------------------------------------------------------*/
27
28HPDF_Dict
29HPDF_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
51HPDF_Dict
52HPDF_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
88void
89HPDF_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
119HPDF_STATUS
120HPDF_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
139HPDF_STATUS
140HPDF_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 *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
280HPDF_STATUS
281HPDF_Dict_Add (HPDF_Dict dict,
282 const char *key,
283 void *obj)
284{
285 HPDF_Obj_Header *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
364HPDF_STATUS
365HPDF_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
377HPDF_STATUS
378HPDF_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
391HPDF_STATUS
392HPDF_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
405HPDF_STATUS
406HPDF_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
419void*
420HPDF_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 *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
452HPDF_DictElement
453GetElement (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
470HPDF_STATUS
471HPDF_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
493const char*
494HPDF_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 *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