1/*
2 * << Haru Free PDF Library >> -- hpdf_outline.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_destination.h"
21#include "hpdf.h"
22
23#define HPDF_OUTLINE_CLOSED 0
24#define HPDF_OUTLINE_OPENED 1
25
26
27static HPDF_STATUS
28AddChild (HPDF_Outline parent,
29 HPDF_Outline item);
30
31
32static HPDF_STATUS
33BeforeWrite (HPDF_Dict obj);
34
35
36static HPDF_UINT
37CountChild (HPDF_Outline outline);
38
39
40
41/*----------------------------------------------------------------------------*/
42/*----- HPDF_Outline ---------------------------------------------------------*/
43
44HPDF_Outline
45HPDF_OutlineRoot_New (HPDF_MMgr mmgr,
46 HPDF_Xref xref)
47{
48 HPDF_Outline outline;
49 HPDF_STATUS ret = HPDF_OK;
50 HPDF_Number open_flg;
51
52 HPDF_PTRACE((" HPDF_OutlineRoot_New\n"));
53
54 outline = HPDF_Dict_New (mmgr);
55 if (!outline)
56 return NULL;
57
58 outline->before_write_fn = BeforeWrite;
59
60 if (HPDF_Xref_Add (xref, outline) != HPDF_OK)
61 return NULL;
62
63 open_flg = HPDF_Number_New (mmgr, HPDF_OUTLINE_OPENED);
64 if (!open_flg)
65 return NULL;
66
67 open_flg->header.obj_id |= HPDF_OTYPE_HIDDEN;
68
69 ret += HPDF_Dict_Add (outline, "_OPENED", open_flg);
70 ret += HPDF_Dict_AddName (outline, "Type", "Outlines");
71
72 if (ret != HPDF_OK)
73 return NULL;
74
75 outline->header.obj_class |= HPDF_OSUBCLASS_OUTLINE;
76
77 return outline;
78}
79
80
81HPDF_Outline
82HPDF_Outline_New (HPDF_MMgr mmgr,
83 HPDF_Outline parent,
84 const char *title,
85 HPDF_Encoder encoder,
86 HPDF_Xref xref)
87{
88 HPDF_Outline outline;
89 HPDF_String s;
90 HPDF_STATUS ret = HPDF_OK;
91 HPDF_Number open_flg;
92
93 HPDF_PTRACE((" HPDF_Outline_New\n"));
94
95 if (!mmgr || !parent || !xref)
96 return NULL;
97
98 outline = HPDF_Dict_New (mmgr);
99 if (!outline)
100 return NULL;
101
102 outline->before_write_fn = BeforeWrite;
103
104 if (HPDF_Xref_Add (xref, outline) != HPDF_OK)
105 return NULL;
106
107 s = HPDF_String_New (mmgr, title, encoder);
108 if (!s)
109 return NULL;
110 else
111 ret += HPDF_Dict_Add (outline, "Title", s);
112
113 open_flg = HPDF_Number_New (mmgr, HPDF_OUTLINE_OPENED);
114 if (!open_flg)
115 return NULL;
116
117 open_flg->header.obj_id |= HPDF_OTYPE_HIDDEN;
118 ret += HPDF_Dict_Add (outline, "_OPENED", open_flg);
119
120 ret += HPDF_Dict_AddName (outline, "Type", "Outlines");
121 ret += AddChild (parent, outline);
122
123 if (ret != HPDF_OK)
124 return NULL;
125
126 outline->header.obj_class |= HPDF_OSUBCLASS_OUTLINE;
127
128 return outline;
129}
130
131
132
133static HPDF_STATUS
134AddChild (HPDF_Outline parent,
135 HPDF_Outline item)
136{
137 HPDF_Outline first = (HPDF_Outline)HPDF_Dict_GetItem (parent, "First",
138 HPDF_OCLASS_DICT);
139 HPDF_Outline last = (HPDF_Outline)HPDF_Dict_GetItem (parent, "Last",
140 HPDF_OCLASS_DICT);
141 HPDF_STATUS ret = 0;
142
143 HPDF_PTRACE((" AddChild\n"));
144
145 if (!first)
146 ret += HPDF_Dict_Add (parent, "First", item);
147
148 if (last) {
149 ret += HPDF_Dict_Add (last, "Next", item);
150 ret += HPDF_Dict_Add (item, "Prev", last);
151 }
152
153 ret += HPDF_Dict_Add (parent, "Last", item);
154 ret += HPDF_Dict_Add (item, "Parent", parent);
155
156 if (ret != HPDF_OK)
157 return HPDF_Error_GetCode (item->error);
158
159 return HPDF_OK;
160}
161
162
163HPDF_BOOL
164HPDF_Outline_GetOpened (HPDF_Outline outline)
165{
166 HPDF_Number n = (HPDF_Number)HPDF_Dict_GetItem (outline, "_OPENED",
167 HPDF_OCLASS_NUMBER);
168
169 HPDF_PTRACE((" HPDF_Outline_GetOpened\n"));
170
171 if (!n)
172 return HPDF_FALSE;
173
174 return (HPDF_BOOL)n->value;
175}
176
177
178HPDF_Outline
179HPDF_Outline_GetFirst (HPDF_Outline outline)
180{
181 HPDF_PTRACE((" HPDF_Outline_GetFirst\n"));
182
183 return (HPDF_Outline)HPDF_Dict_GetItem (outline, "First",
184 HPDF_OCLASS_DICT);
185}
186
187
188HPDF_Outline
189HPDF_Outline_GetLast (HPDF_Outline outline)
190{
191 HPDF_PTRACE((" HPDF_Outline_GetLast\n"));
192
193 return (HPDF_Outline)HPDF_Dict_GetItem (outline, "Last", HPDF_OCLASS_DICT);
194}
195
196
197HPDF_Outline
198HPDF_Outline_GetPrev (HPDF_Outline outline)
199{
200 HPDF_PTRACE((" HPDF_Outline_GetPrev\n"));
201
202 return (HPDF_Outline)HPDF_Dict_GetItem (outline, "Prev", HPDF_OCLASS_DICT);
203}
204
205
206HPDF_Outline
207HPDF_Outline_GetNext (HPDF_Outline outline)
208{
209 HPDF_PTRACE((" HPDF_Outline_GetNext\n"));
210
211 return (HPDF_Outline)HPDF_Dict_GetItem (outline, "Next", HPDF_OCLASS_DICT);
212}
213
214
215HPDF_Outline
216HPDF_Outline_GetParent (HPDF_Outline outline)
217{
218 HPDF_PTRACE((" HPDF_Outline_GetParent\n"));
219
220 return (HPDF_Outline)HPDF_Dict_GetItem (outline, "Parent",
221 HPDF_OCLASS_DICT);
222}
223
224
225static HPDF_STATUS
226BeforeWrite (HPDF_Dict obj)
227{
228 HPDF_Number n = (HPDF_Number)HPDF_Dict_GetItem (obj, "Count",
229 HPDF_OCLASS_NUMBER);
230 HPDF_UINT count = CountChild ((HPDF_Outline)obj);
231
232 HPDF_PTRACE((" BeforeWrite\n"));
233
234 if (count == 0 && n)
235 return HPDF_Dict_RemoveElement (obj, "Count");
236
237 if (!HPDF_Outline_GetOpened ((HPDF_Outline)obj))
238 count = count * -1;
239
240 if (n)
241 n->value = count;
242 else
243 if (count)
244 return HPDF_Dict_AddNumber (obj, "Count", count);
245
246 return HPDF_OK;
247}
248
249
250static HPDF_UINT
251CountChild (HPDF_Outline outline)
252{
253 HPDF_Outline child = HPDF_Outline_GetFirst (outline);
254 HPDF_UINT count = 0;
255
256 HPDF_PTRACE((" CountChild\n"));
257
258 while (child) {
259 count++;
260
261 if (HPDF_Outline_GetOpened (child))
262 count += CountChild (child);
263
264 child = HPDF_Outline_GetNext (child);
265 }
266
267 return count;
268}
269
270
271HPDF_BOOL
272HPDF_Outline_Validate (HPDF_Outline outline)
273{
274 if (!outline)
275 return HPDF_FALSE;
276
277 HPDF_PTRACE((" HPDF_Outline_Validate\n"));
278
279 if (outline->header.obj_class !=
280 (HPDF_OSUBCLASS_OUTLINE | HPDF_OCLASS_DICT))
281 return HPDF_FALSE;
282
283 return HPDF_TRUE;
284}
285
286HPDF_EXPORT(HPDF_STATUS)
287HPDF_Outline_SetDestination (HPDF_Outline outline,
288 HPDF_Destination dst)
289{
290 HPDF_PTRACE((" HPDF_Outline_SetDestination\n"));
291
292 if (!HPDF_Outline_Validate (outline))
293 return HPDF_INVALID_OUTLINE;
294
295 if (!HPDF_Destination_Validate (dst))
296 return HPDF_RaiseError (outline->error, HPDF_INVALID_DESTINATION, 0);
297
298 if (dst == NULL)
299 return HPDF_Dict_RemoveElement (outline, "Dest");
300
301 if (HPDF_Dict_Add (outline, "Dest", dst) != HPDF_OK)
302 return HPDF_CheckError (outline->error);
303
304 return HPDF_OK;
305}
306
307
308HPDF_EXPORT(HPDF_STATUS)
309HPDF_Outline_SetOpened (HPDF_Outline outline,
310 HPDF_BOOL opened)
311{
312 HPDF_Number n;
313
314 if (!HPDF_Outline_Validate (outline))
315 return HPDF_INVALID_OUTLINE;
316
317 n = (HPDF_Number)HPDF_Dict_GetItem (outline, "_OPENED",
318 HPDF_OCLASS_NUMBER);
319
320 HPDF_PTRACE((" HPDF_Outline_SetOpened\n"));
321
322 if (!n) {
323 n = HPDF_Number_New (outline->mmgr, (HPDF_INT)opened);
324 if (!n || HPDF_Dict_Add (outline, "_OPENED", n) != HPDF_OK)
325 return HPDF_CheckError (outline->error);
326 } else
327 n->value = (HPDF_INT)opened;
328
329 return HPDF_OK;
330}
331