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 | |
27 | static HPDF_STATUS |
28 | AddChild (HPDF_Outline parent, |
29 | HPDF_Outline item); |
30 | |
31 | |
32 | static HPDF_STATUS |
33 | BeforeWrite (HPDF_Dict obj); |
34 | |
35 | |
36 | static HPDF_UINT |
37 | CountChild (HPDF_Outline outline); |
38 | |
39 | |
40 | |
41 | /*----------------------------------------------------------------------------*/ |
42 | /*----- HPDF_Outline ---------------------------------------------------------*/ |
43 | |
44 | HPDF_Outline |
45 | HPDF_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 | |
81 | HPDF_Outline |
82 | HPDF_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 | |
133 | static HPDF_STATUS |
134 | AddChild (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 | |
163 | HPDF_BOOL |
164 | HPDF_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 | |
178 | HPDF_Outline |
179 | HPDF_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 | |
188 | HPDF_Outline |
189 | HPDF_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 | |
197 | HPDF_Outline |
198 | HPDF_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 | |
206 | HPDF_Outline |
207 | HPDF_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 | |
215 | HPDF_Outline |
216 | HPDF_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 | |
225 | static HPDF_STATUS |
226 | BeforeWrite (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 | |
250 | static HPDF_UINT |
251 | CountChild (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 | |
271 | HPDF_BOOL |
272 | HPDF_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 | |
286 | HPDF_EXPORT(HPDF_STATUS) |
287 | HPDF_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 | |
308 | HPDF_EXPORT(HPDF_STATUS) |
309 | HPDF_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 | |