/src/ebook-tools-0.2.2/src/libepub/opf.c
Line | Count | Source |
1 | | #include "epublib.h" |
2 | | |
3 | 1.73k | struct opf *_opf_parse(struct epub *epub, char *opfStr) { |
4 | 1.73k | struct opf *opf; |
5 | 1.73k | xmlTextReaderPtr reader; |
6 | 1.73k | int ret; |
7 | | |
8 | 1.73k | _epub_print_debug(epub, DEBUG_INFO, "building opf struct"); |
9 | | |
10 | 1.73k | opf = malloc(sizeof(struct opf)); |
11 | 1.73k | if (!opf) { |
12 | 0 | _epub_err_set_oom(&epub->error); |
13 | 0 | return NULL; |
14 | 0 | } |
15 | 1.73k | memset(opf, 0, sizeof(struct opf)); |
16 | 1.73k | opf->epub = epub; |
17 | | |
18 | 1.73k | reader = xmlReaderForMemory(opfStr, strlen(opfStr), |
19 | 1.73k | "OPF", NULL, 0); |
20 | 1.73k | if (reader != NULL) { |
21 | 1.73k | ret = xmlTextReaderRead(reader); |
22 | 10.9k | while (ret == 1) { |
23 | 9.17k | const xmlChar *name = xmlTextReaderConstLocalName(reader); |
24 | 9.17k | if (xmlStrcmp(name, (xmlChar *)"metadata") == 0) |
25 | 1.18k | _opf_parse_metadata(opf, reader); |
26 | 7.98k | else |
27 | 7.98k | if (xmlStrcmp(name, (xmlChar *)"manifest") == 0) |
28 | 564 | _opf_parse_manifest(opf, reader); |
29 | 7.41k | else |
30 | 7.41k | if (xmlStrcmp(name, (xmlChar *)"spine") == 0) |
31 | 571 | _opf_parse_spine(opf, reader); |
32 | 6.84k | else |
33 | 6.84k | if (xmlStrcmp(name, (xmlChar *)"guide") == 0) |
34 | 530 | _opf_parse_guide(opf, reader); |
35 | 6.31k | else |
36 | 6.31k | if (xmlStrcmp(name, (xmlChar *)"tours") == 0) |
37 | 0 | _opf_parse_tours(opf, reader); |
38 | | |
39 | 9.17k | ret = xmlTextReaderRead(reader); |
40 | 9.17k | } |
41 | | |
42 | 1.73k | xmlFreeTextReader(reader); |
43 | 1.73k | if (ret != 0) { |
44 | 1.21k | _epub_print_debug(opf->epub, DEBUG_ERROR, "failed to parse OPF"); |
45 | 1.21k | return NULL; |
46 | 1.21k | } else if(!opf->spine) { |
47 | 3 | _epub_print_debug(opf->epub, DEBUG_ERROR, "Ilegal OPF no spine found"); |
48 | 3 | return NULL; |
49 | 3 | } |
50 | 1.73k | } else { |
51 | 0 | _epub_print_debug(opf->epub, DEBUG_ERROR, "unable to open OPF"); |
52 | 0 | return NULL; |
53 | 0 | } |
54 | | |
55 | 516 | return opf; |
56 | 1.73k | } |
57 | | |
58 | | xmlChar *_get_possible_namespace(xmlTextReaderPtr reader, |
59 | | const xmlChar * localName, |
60 | | const xmlChar * namespace) |
61 | 4.70k | { |
62 | 4.70k | xmlChar *tmp, *ns; |
63 | 4.70k | ns = xmlTextReaderLookupNamespace(reader, namespace); |
64 | 4.70k | tmp = xmlTextReaderGetAttributeNs(reader, localName, ns); |
65 | | |
66 | 4.70k | if (ns) |
67 | 4.41k | free(ns); |
68 | | |
69 | 4.70k | if (! tmp) |
70 | 1.76k | return xmlTextReaderGetAttribute(reader, localName); |
71 | | |
72 | 2.94k | return tmp; |
73 | 4.70k | } |
74 | | |
75 | 1.18k | void _opf_init_metadata(struct opf *opf) { |
76 | 1.18k | struct metadata *meta = malloc(sizeof(struct metadata)); |
77 | | |
78 | 1.18k | meta->id = NewListAlloc(LIST, NULL, NULL, NULL); |
79 | 1.18k | meta->title = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
80 | 1.18k | meta->creator = NewListAlloc(LIST, NULL, NULL, NULL); |
81 | 1.18k | meta->contrib = NewListAlloc(LIST, NULL, NULL, NULL); |
82 | 1.18k | meta->subject = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
83 | 1.18k | meta->publisher = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
84 | 1.18k | meta->description = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
85 | 1.18k | meta->date = NewListAlloc(LIST, NULL, NULL, NULL); |
86 | 1.18k | meta->type = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
87 | 1.18k | meta->format = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
88 | 1.18k | meta->source = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
89 | 1.18k | meta->lang = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
90 | 1.18k | meta->relation = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
91 | 1.18k | meta->coverage = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
92 | 1.18k | meta->rights = NewListAlloc(LIST, NULL, NULL, (NodeCompareFunc)StringCompare); |
93 | 1.18k | meta->meta = NewListAlloc(LIST, NULL, NULL, NULL); |
94 | | |
95 | 1.18k | opf->metadata = meta; |
96 | 1.18k | } |
97 | | |
98 | 508 | void _opf_free_metadata(struct metadata *meta) { |
99 | 508 | FreeList(meta->id, (ListFreeFunc)_list_free_id); |
100 | 508 | FreeList(meta->title, free); |
101 | 508 | FreeList(meta->creator, (ListFreeFunc)_list_free_creator); |
102 | 508 | FreeList(meta->contrib, (ListFreeFunc)_list_free_creator); |
103 | 508 | FreeList(meta->subject, free); |
104 | 508 | FreeList(meta->publisher, free); |
105 | 508 | FreeList(meta->description, free); |
106 | 508 | FreeList(meta->date, (ListFreeFunc)_list_free_date); |
107 | 508 | FreeList(meta->type, free); |
108 | 508 | FreeList(meta->format, free); |
109 | 508 | FreeList(meta->source, free); |
110 | 508 | FreeList(meta->lang, free); |
111 | 508 | FreeList(meta->relation, free); |
112 | 508 | FreeList(meta->coverage, free); |
113 | 508 | FreeList(meta->rights, free); |
114 | 508 | FreeList(meta->meta, (ListFreeFunc)_list_free_meta); |
115 | 508 | free(meta); |
116 | 508 | } |
117 | | |
118 | 1.18k | void _opf_parse_metadata(struct opf *opf, xmlTextReaderPtr reader) { |
119 | 1.18k | int ret; |
120 | 1.18k | struct metadata *meta; |
121 | 1.18k | const xmlChar *local; |
122 | 1.18k | xmlChar *string; |
123 | | |
124 | 1.18k | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing metadata"); |
125 | | |
126 | | // must have title, identifier and language |
127 | 1.18k | _opf_init_metadata(opf); |
128 | 1.18k | meta = opf->metadata; |
129 | | |
130 | 1.18k | ret = xmlTextReaderRead(reader); |
131 | 62.1k | while (ret == 1 && |
132 | 61.6k | xmlStrcasecmp(xmlTextReaderConstLocalName(reader),(xmlChar *)"metadata")) { |
133 | | |
134 | | // ignore non starting tags |
135 | 60.9k | if (xmlTextReaderNodeType(reader) != 1) { |
136 | 44.4k | ret = xmlTextReaderRead(reader); |
137 | 44.4k | continue; |
138 | 44.4k | } |
139 | | |
140 | 16.5k | local = xmlTextReaderConstLocalName(reader); |
141 | 16.5k | string = (xmlChar *)xmlTextReaderReadString(reader); |
142 | | |
143 | 16.5k | if (xmlStrcasecmp(local, (xmlChar *)"identifier") == 0) { |
144 | 666 | struct id *new = malloc(sizeof(struct id)); |
145 | 666 | new->string = string; |
146 | 666 | new->scheme = _get_possible_namespace(reader, (xmlChar *)"scheme", |
147 | 666 | (xmlChar *)"opf"); |
148 | 666 | new->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
149 | | |
150 | 666 | AddNode(meta->id, NewListNode(meta->id, new)); |
151 | 666 | _epub_print_debug(opf->epub, DEBUG_INFO, "identifier %s(%s) is: %s", |
152 | 666 | new->id, new->scheme, new->string); |
153 | 15.8k | } else if (xmlStrcasecmp(local, (xmlChar *)"title") == 0) { |
154 | 838 | AddNode(meta->title, NewListNode(meta->title, string)); |
155 | 838 | _epub_print_debug(opf->epub, DEBUG_INFO, "title is %s", string); |
156 | | |
157 | 15.0k | } else if (xmlStrcasecmp(local, (xmlChar *)"creator") == 0) { |
158 | 926 | struct creator *new = malloc(sizeof(struct creator)); |
159 | 926 | new->name = string; |
160 | 926 | new->fileAs = |
161 | 926 | _get_possible_namespace(reader, (xmlChar *)"file-as", |
162 | 926 | (xmlChar *)"opf"); |
163 | 926 | new->role = |
164 | 926 | _get_possible_namespace(reader, (xmlChar *)"role", |
165 | 926 | (xmlChar *)"opf"); |
166 | 926 | AddNode(meta->creator, NewListNode(meta->creator, new)); |
167 | 926 | _epub_print_debug(opf->epub, DEBUG_INFO, "creator - %s: %s (%s)", |
168 | 926 | new->role, new->name, new->fileAs); |
169 | | |
170 | 14.0k | } else if (xmlStrcasecmp(local, (xmlChar *)"contributor") == 0) { |
171 | 652 | struct creator *new = malloc(sizeof(struct creator)); |
172 | 652 | new->name = string; |
173 | 652 | new->fileAs = |
174 | 652 | _get_possible_namespace(reader, (xmlChar *)"file-as", |
175 | 652 | (xmlChar *)"opf"); |
176 | 652 | new->role = |
177 | 652 | _get_possible_namespace(reader, (xmlChar *)"role", |
178 | 652 | (xmlChar *)"opf"); |
179 | 652 | AddNode(meta->contrib, NewListNode(meta->contrib, new)); |
180 | 652 | _epub_print_debug(opf->epub, DEBUG_INFO, "contributor - %s: %s (%s)", |
181 | 652 | new->role, new->name, new->fileAs); |
182 | | |
183 | 13.4k | } else if (xmlStrcasecmp(local, (xmlChar *)"meta") == 0) { |
184 | 2.42k | struct meta *new = malloc(sizeof(struct meta)); |
185 | 2.42k | new->name = xmlTextReaderGetAttribute(reader, (xmlChar *)"name"); |
186 | 2.42k | new->content = xmlTextReaderGetAttribute(reader, (xmlChar *)"content"); |
187 | | |
188 | 2.42k | AddNode(meta->meta, NewListNode(meta->meta, new)); |
189 | 2.42k | if (string) |
190 | 0 | free(string); |
191 | 2.42k | _epub_print_debug(opf->epub, DEBUG_INFO, "meta is %s: %s", |
192 | 2.42k | new->name, new->content); |
193 | 11.0k | } else if (xmlStrcasecmp(local, (xmlChar *)"date") == 0) { |
194 | 885 | struct date *new = malloc(sizeof(struct date)); |
195 | 885 | new->date = string; |
196 | 885 | new->event = _get_possible_namespace(reader, (xmlChar *)"event", |
197 | 885 | (xmlChar *)"opf"); |
198 | 885 | AddNode(meta->date, NewListNode(meta->date, new)); |
199 | 885 | _epub_print_debug(opf->epub, DEBUG_INFO, "date of %s: %s", |
200 | 885 | new->event, new->date); |
201 | | |
202 | 10.1k | } else if (xmlStrcasecmp(local, (xmlChar *)"subject") == 0) { |
203 | 741 | AddNode(meta->subject, NewListNode(meta->subject, string)); |
204 | 741 | _epub_print_debug(opf->epub, DEBUG_INFO, "subject is %s", string); |
205 | | |
206 | 9.39k | } else if (xmlStrcasecmp(local, (xmlChar *)"publisher") == 0) { |
207 | 804 | AddNode(meta->publisher, NewListNode(meta->publisher, string)); |
208 | 804 | _epub_print_debug(opf->epub, DEBUG_INFO, "publisher is %s", string); |
209 | | |
210 | 8.58k | } else if (xmlStrcasecmp(local, (xmlChar *)"description") == 0) { |
211 | 1.05k | AddNode(meta->description, NewListNode(meta->description, string)); |
212 | 1.05k | _epub_print_debug(opf->epub, DEBUG_INFO, "description is %s", string); |
213 | | |
214 | 7.53k | } else if (xmlStrcasecmp(local, (xmlChar *)"type") == 0) { |
215 | 892 | AddNode(meta->type, NewListNode(meta->type, string)); |
216 | 892 | _epub_print_debug(opf->epub, DEBUG_INFO, "type is %s", string); |
217 | | |
218 | 6.64k | } else if (xmlStrcasecmp(local, (xmlChar *)"format") == 0) { |
219 | 889 | AddNode(meta->format, NewListNode(meta->format, string)); |
220 | 889 | _epub_print_debug(opf->epub, DEBUG_INFO, "format is %s", string); |
221 | | |
222 | 5.75k | } else if (xmlStrcasecmp(local, (xmlChar *)"source") == 0) { |
223 | 1.06k | AddNode(meta->source, NewListNode(meta->source, string)); |
224 | 1.06k | _epub_print_debug(opf->epub, DEBUG_INFO, "source is %s", string); |
225 | | |
226 | 4.68k | } else if (xmlStrcasecmp(local, (xmlChar *)"language") == 0) { |
227 | 812 | AddNode(meta->lang, NewListNode(meta->lang, string)); |
228 | 812 | _epub_print_debug(opf->epub, DEBUG_INFO, "language is %s", string); |
229 | | |
230 | 3.87k | } else if (xmlStrcasecmp(local, (xmlChar *)"relation") == 0) { |
231 | 893 | AddNode(meta->relation, NewListNode(meta->relation, string)); |
232 | 893 | _epub_print_debug(opf->epub, DEBUG_INFO, "relation is %s", string); |
233 | | |
234 | 2.98k | } else if (xmlStrcasecmp(local, (xmlChar *)"coverage") == 0) { |
235 | 663 | AddNode(meta->coverage, NewListNode(meta->coverage, string)); |
236 | 663 | _epub_print_debug(opf->epub, DEBUG_INFO, "coverage is %s", string); |
237 | 2.32k | } else if (xmlStrcasecmp(local, (xmlChar *)"rights") == 0) { |
238 | 1.00k | AddNode(meta->rights, NewListNode(meta->rights, string)); |
239 | 1.00k | _epub_print_debug(opf->epub, DEBUG_INFO, "rights is %s", string); |
240 | 1.32k | } else if (string) { |
241 | 1.21k | if (xmlStrcasecmp(local, (xmlChar *)"dc-metadata") != 0 && |
242 | 1.21k | xmlStrcasecmp(local, (xmlChar *)"x-metadata") != 0) |
243 | 1.21k | _epub_print_debug(opf->epub, DEBUG_INFO, |
244 | 1.21k | "unsupported local %s: %s", local, string); |
245 | 1.21k | free(string); |
246 | 1.21k | } |
247 | | |
248 | 16.5k | ret = xmlTextReaderRead(reader); |
249 | 16.5k | } |
250 | 1.18k | } |
251 | | |
252 | 167 | struct toc *_opf_init_toc() { |
253 | | |
254 | 167 | struct toc *toc = malloc(sizeof(struct toc)); |
255 | 167 | memset(toc, 0, sizeof(struct toc)); |
256 | | |
257 | 167 | toc->playOrder = NewListAlloc(LIST, NULL, NULL, |
258 | 167 | (NodeCompareFunc)_list_cmp_toc_by_playorder); |
259 | | |
260 | 167 | return toc; |
261 | 167 | } |
262 | | |
263 | 64 | struct tocCategory *_opf_init_toc_category() { |
264 | 64 | struct tocCategory *tc = malloc(sizeof(struct tocCategory)); |
265 | 64 | memset(tc, 0, sizeof(struct tocCategory)); |
266 | | |
267 | 64 | tc->info = NewListAlloc(LIST, NULL, NULL, NULL); //tocLabel |
268 | 64 | tc->label = NewListAlloc(LIST, NULL, NULL, NULL); //tocLabel |
269 | 64 | tc->items = NewListAlloc(LIST, NULL, NULL, NULL); //tocItem |
270 | | |
271 | 64 | return tc; |
272 | 64 | } |
273 | | |
274 | 51 | void _opf_free_toc_category(struct tocCategory *tc) { |
275 | 51 | if (tc->id) |
276 | 0 | free(tc->id); |
277 | 51 | if (tc->class) |
278 | 0 | free(tc->class); |
279 | | |
280 | 51 | FreeList(tc->info, (ListFreeFunc)_list_free_toc_label); |
281 | 51 | FreeList(tc->label, (ListFreeFunc)_list_free_toc_label); |
282 | 51 | FreeList(tc->items, (ListFreeFunc)_list_free_toc_item); |
283 | | |
284 | 51 | free(tc); |
285 | 51 | } |
286 | | |
287 | 139 | void _opf_free_toc(struct toc *toc) { |
288 | | |
289 | 139 | if (toc->navMap) |
290 | 51 | _opf_free_toc_category(toc->navMap); |
291 | 139 | if (toc->navList) |
292 | 0 | _opf_free_toc_category(toc->navList); |
293 | 139 | if (toc->pageList) |
294 | 0 | _opf_free_toc_category(toc->pageList); |
295 | | |
296 | | // all items are already free, lets free only the struct |
297 | 139 | FreeList(toc->playOrder, NULL); |
298 | | |
299 | 139 | free(toc); |
300 | | |
301 | 139 | } |
302 | | |
303 | | // Parse a navLabel or navInfo returns NULL on failure and the label on success |
304 | 15 | struct tocLabel *_opf_parse_navlabel(struct opf *opf, xmlTextReaderPtr reader) { |
305 | 15 | int ret; |
306 | | |
307 | 15 | struct tocLabel *new = malloc(sizeof(struct tocLabel)); |
308 | 15 | memset(new, 0, sizeof(struct tocLabel)); |
309 | | |
310 | 15 | new->lang = xmlTextReaderGetAttribute(reader, (xmlChar *)"lang"); |
311 | 15 | new->dir = xmlTextReaderGetAttribute(reader, (xmlChar *)"dir"); |
312 | | |
313 | 15 | ret = xmlTextReaderRead(reader); |
314 | 87 | while (ret == 1 && |
315 | 84 | xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navLabel") && |
316 | 72 | xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navInfo")) { |
317 | 72 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"text") && |
318 | 30 | xmlTextReaderNodeType(reader) == 1) { |
319 | 15 | new->text = (xmlChar *)xmlTextReaderReadString(reader); |
320 | 15 | } |
321 | 72 | ret = xmlTextReaderRead(reader); |
322 | 72 | } |
323 | | |
324 | 15 | if (ret != 1) { |
325 | 3 | free(new); |
326 | 3 | return NULL; |
327 | 3 | } |
328 | 12 | _epub_print_debug(opf->epub, DEBUG_INFO, |
329 | 12 | "parsing label/info %s(%s/%s)", |
330 | 12 | new->text, new->lang, new->dir); |
331 | 12 | return new; |
332 | 15 | } |
333 | | |
334 | 29 | struct tocItem *_opf_init_toc_item(int depth) { |
335 | 29 | struct tocItem *item = malloc(sizeof(struct tocItem)); |
336 | 29 | memset(item, 0, sizeof(struct tocItem)); |
337 | | |
338 | 29 | item->depth = depth; |
339 | 29 | item->playOrder = -1; |
340 | 29 | item->value = -1; |
341 | | |
342 | 29 | return item; |
343 | 29 | } |
344 | | |
345 | 29 | int _get_attribute_as_positive_int(xmlTextReaderPtr reader, const xmlChar *name) { |
346 | 29 | xmlChar *str = xmlTextReaderGetAttribute(reader, name); |
347 | 29 | int ret = -1; |
348 | | |
349 | 29 | if (str) { |
350 | 20 | ret = atoi((char *)str); |
351 | 20 | free(str); |
352 | 20 | } |
353 | | |
354 | 29 | return ret; |
355 | 29 | } |
356 | | |
357 | 64 | void _opf_parse_navmap(struct opf *opf, xmlTextReaderPtr reader) { |
358 | 64 | int ret; |
359 | 64 | int depth = 0; |
360 | | |
361 | 64 | struct tocCategory *tc = _opf_init_toc_category(); |
362 | 64 | struct tocItem *item = NULL; |
363 | | |
364 | 64 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing nav map"); |
365 | | |
366 | 64 | tc->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
367 | | |
368 | 64 | ret = xmlTextReaderRead(reader); |
369 | 222 | while (ret == 1 && |
370 | 168 | xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navMap")) { |
371 | | |
372 | 158 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navPoint")) { |
373 | 41 | if (xmlTextReaderNodeType(reader) == 1) { |
374 | | |
375 | 29 | if (item) { |
376 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, |
377 | 0 | "adding nav point item->%s %s (d:%d,p:%d)", |
378 | 0 | item->id, item->src, item->depth, item->playOrder); |
379 | 0 | AddNode(tc->items, NewListNode(tc->items, item)); |
380 | 0 | AddNode(opf->toc->playOrder, NewListNode(opf->toc->playOrder, item)); |
381 | 0 | item = NULL; |
382 | 0 | } |
383 | | |
384 | 29 | depth++; |
385 | 29 | item = _opf_init_toc_item(depth); |
386 | 29 | item->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
387 | 29 | item->class = xmlTextReaderGetAttribute(reader, (xmlChar *)"class"); |
388 | | |
389 | 29 | item->playOrder = _get_attribute_as_positive_int(reader, (xmlChar *)"playOrder"); |
390 | 29 | if (item->playOrder == -1) { |
391 | 9 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
392 | 9 | "- missing play order in nav point element"); |
393 | 9 | } |
394 | | |
395 | 29 | } else if (xmlTextReaderNodeType(reader) == 15) { |
396 | 12 | if (item) { |
397 | 12 | _epub_print_debug(opf->epub, DEBUG_INFO, |
398 | 12 | "adding nav point item->%s %s (d:%d,p:%d)", |
399 | 12 | item->id, item->src, item->depth, item->playOrder); |
400 | 12 | AddNode(tc->items, NewListNode(tc->items, item)); |
401 | 12 | AddNode(opf->toc->playOrder, NewListNode(opf->toc->playOrder, item)); |
402 | 12 | item = NULL; |
403 | 12 | } |
404 | 12 | depth--; |
405 | 12 | } |
406 | 41 | } |
407 | | |
408 | | // ignore non starting tags |
409 | 158 | if (xmlTextReaderNodeType(reader) != 1) { |
410 | 96 | ret = xmlTextReaderRead(reader); |
411 | 96 | continue; |
412 | 96 | } |
413 | | |
414 | 62 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navLabel")) { |
415 | 15 | if (item) { |
416 | 15 | if (! item->label) |
417 | 15 | item->label = NewListAlloc(LIST, NULL, NULL, NULL); //tocLabel |
418 | 15 | AddNode(item->label, NewListNode(item->label, |
419 | 15 | _opf_parse_navlabel(opf, reader))); |
420 | 15 | } else { // Not inside navpoint |
421 | 0 | AddNode(tc->label, NewListNode(tc->label, |
422 | 0 | _opf_parse_navlabel(opf, reader))); |
423 | 0 | } |
424 | 47 | } else if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navInfo")) { |
425 | 0 | AddNode(tc->info, NewListNode(tc->info, |
426 | 0 | _opf_parse_navlabel(opf, reader))); |
427 | 0 | if (item) |
428 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
429 | 0 | "nav info inside nav point element"); |
430 | 0 | } else |
431 | 47 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"content")) { |
432 | 10 | if (item) |
433 | 10 | item->src = xmlTextReaderGetAttribute(reader, (xmlChar *)"src"); |
434 | 0 | else |
435 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
436 | 0 | "content not inside nav point element"); |
437 | 10 | } |
438 | | |
439 | 62 | ret = xmlTextReaderRead(reader); |
440 | 62 | } |
441 | | |
442 | 64 | opf->toc->navMap = tc; |
443 | 64 | _epub_print_debug(opf->epub, DEBUG_INFO, "finished parsing nav map"); |
444 | 64 | } |
445 | | |
446 | 0 | void _opf_parse_navlist(struct opf *opf, xmlTextReaderPtr reader) { |
447 | 0 | int ret; |
448 | |
|
449 | 0 | struct tocCategory *tc = _opf_init_toc_category(); |
450 | 0 | struct tocItem *item = NULL; |
451 | |
|
452 | 0 | tc->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
453 | 0 | tc->class = xmlTextReaderGetAttribute(reader, (xmlChar *)"class"); |
454 | | |
455 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing nav list"); |
456 | |
|
457 | 0 | ret = xmlTextReaderRead(reader); |
458 | 0 | while (ret == 1 && |
459 | 0 | xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navList")) { |
460 | |
|
461 | 0 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navTarget")) { |
462 | 0 | if (xmlTextReaderNodeType(reader) == 1) { |
463 | 0 | item = _opf_init_toc_item(1); |
464 | 0 | item->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
465 | 0 | item->class = xmlTextReaderGetAttribute(reader, (xmlChar *)"class"); |
466 | | |
467 | 0 | item->playOrder = _get_attribute_as_positive_int(reader, (xmlChar *)"playOrder"); |
468 | 0 | if (item->playOrder == -1) { |
469 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
470 | 0 | "- missing play order in nav target element"); |
471 | 0 | } |
472 | 0 | item->value = _get_attribute_as_positive_int(reader, (xmlChar *)"value"); |
473 | 0 | } else if (xmlTextReaderNodeType(reader) == 15) { |
474 | 0 | if (item) { |
475 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, |
476 | 0 | "adding nav target item->%s %s (d:%d,p:%d)", |
477 | 0 | item->id, item->src, item->depth, item->playOrder); |
478 | 0 | AddNode(tc->items, NewListNode(tc->items, item)); |
479 | 0 | AddNode(opf->toc->playOrder, NewListNode(opf->toc->playOrder, item)); |
480 | 0 | item = NULL; |
481 | 0 | } else { |
482 | 0 | _epub_print_debug(opf->epub, DEBUG_ERROR, "empty item in nav list"); |
483 | 0 | } |
484 | 0 | } |
485 | 0 | } |
486 | | |
487 | | |
488 | | // ignore non starting tags |
489 | 0 | if (xmlTextReaderNodeType(reader) != 1) { |
490 | 0 | ret = xmlTextReaderRead(reader); |
491 | 0 | continue; |
492 | 0 | } |
493 | 0 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navLabel")) { |
494 | 0 | if (item) { |
495 | 0 | if (! item->label) |
496 | 0 | item->label = NewListAlloc(LIST, NULL, NULL, NULL); //tocLabel |
497 | 0 | AddNode(item->label, NewListNode(item->label, |
498 | 0 | _opf_parse_navlabel(opf, reader))); |
499 | 0 | } else { // Not inside navpoint |
500 | 0 | AddNode(tc->label, NewListNode(tc->label, |
501 | 0 | _opf_parse_navlabel(opf, reader))); |
502 | 0 | } |
503 | 0 | } else if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navInfo")) { |
504 | 0 | AddNode(tc->info, NewListNode(tc->info, |
505 | 0 | _opf_parse_navlabel(opf, reader))); |
506 | 0 | if (item) |
507 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
508 | 0 | "nav info inside nav target element"); |
509 | 0 | } else |
510 | 0 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"content")) { |
511 | 0 | if (item) |
512 | 0 | item->src = xmlTextReaderGetAttribute(reader, (xmlChar *)"src"); |
513 | 0 | else |
514 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
515 | 0 | "content not inside nav target element"); |
516 | 0 | } |
517 | |
|
518 | 0 | ret = xmlTextReaderRead(reader); |
519 | 0 | } |
520 | | |
521 | 0 | opf->toc->navList = tc; |
522 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, "finished parsing nav list"); |
523 | | |
524 | 0 | } |
525 | | |
526 | 0 | void _opf_parse_pagelist(struct opf *opf, xmlTextReaderPtr reader) { |
527 | 0 | int ret; |
528 | 0 | struct tocCategory *tc = _opf_init_toc_category(); |
529 | 0 | struct tocItem *item = NULL; |
530 | | |
531 | 0 | tc->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
532 | 0 | tc->class = xmlTextReaderGetAttribute(reader, (xmlChar *)"class"); |
533 | | |
534 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing page list"); |
535 | | |
536 | 0 | ret = xmlTextReaderRead(reader); |
537 | 0 | while (ret == 1 && |
538 | 0 | xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"pageList")) { |
539 | 0 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"pageTarget")) { |
540 | 0 | if (xmlTextReaderNodeType(reader) == 1) { |
541 | 0 | item = _opf_init_toc_item(1); |
542 | 0 | item->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
543 | 0 | item->class = xmlTextReaderGetAttribute(reader, (xmlChar *)"class"); |
544 | 0 | item->type = xmlTextReaderGetAttribute(reader, (xmlChar *)"type"); |
545 | | |
546 | 0 | item->playOrder = _get_attribute_as_positive_int(reader, (xmlChar *)"playOrder"); |
547 | 0 | if (item->playOrder == -1) { |
548 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
549 | 0 | "- missing play order in page target element"); |
550 | 0 | } |
551 | 0 | item->value = _get_attribute_as_positive_int(reader, (xmlChar *)"value"); |
552 | 0 | } else if (xmlTextReaderNodeType(reader) == 15) { |
553 | 0 | if (item) { |
554 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, |
555 | 0 | "adding page target item->%s %s (d:%d,p:%d)", |
556 | 0 | item->id, item->src, item->depth, item->playOrder); |
557 | 0 | AddNode(tc->items, NewListNode(tc->items, item)); |
558 | 0 | AddNode(opf->toc->playOrder, NewListNode(opf->toc->playOrder, item)); |
559 | 0 | item = NULL; |
560 | 0 | } else { |
561 | 0 | _epub_print_debug(opf->epub, DEBUG_ERROR, "empty item in nav list"); |
562 | 0 | } |
563 | 0 | } |
564 | 0 | } |
565 | | |
566 | | // ignore non starting tags |
567 | 0 | if (xmlTextReaderNodeType(reader) != 1) { |
568 | 0 | ret = xmlTextReaderRead(reader); |
569 | 0 | continue; |
570 | 0 | } |
571 | | |
572 | 0 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navLabel")) { |
573 | 0 | if (item) { |
574 | 0 | if (! item->label) |
575 | 0 | item->label = NewListAlloc(LIST, NULL, NULL, NULL); //tocLabel |
576 | 0 | AddNode(item->label, NewListNode(item->label, |
577 | 0 | _opf_parse_navlabel(opf, reader))); |
578 | 0 | } else { // Not inside navpoint |
579 | 0 | AddNode(tc->label, NewListNode(tc->label, |
580 | 0 | _opf_parse_navlabel(opf, reader))); |
581 | 0 | } |
582 | 0 | } else if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"navInfo")) { |
583 | 0 | AddNode(tc->info, NewListNode(tc->info, |
584 | 0 | _opf_parse_navlabel(opf, reader))); |
585 | 0 | if (item) |
586 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
587 | 0 | "nav info inside page target element"); |
588 | 0 | } else |
589 | 0 | if (! xmlStrcasecmp(xmlTextReaderConstName(reader),(xmlChar *)"content")) { |
590 | 0 | if (item) |
591 | 0 | item->src = xmlTextReaderGetAttribute(reader, (xmlChar *)"src"); |
592 | 0 | else |
593 | 0 | _epub_print_debug(opf->epub, DEBUG_WARNING, |
594 | 0 | "content not inside nav target element"); |
595 | 0 | } |
596 | |
|
597 | 0 | ret = xmlTextReaderRead(reader); |
598 | 0 | } |
599 | | |
600 | 0 | opf->toc->navList = tc; |
601 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, "finished parsing page list"); |
602 | | |
603 | 0 | } |
604 | | |
605 | 167 | void _opf_parse_toc(struct opf *opf, char *tocStr, int size) { |
606 | | |
607 | 167 | xmlTextReaderPtr reader; |
608 | 167 | int ret; |
609 | | |
610 | 167 | _epub_print_debug(opf->epub, DEBUG_INFO, "building toc"); |
611 | | |
612 | 167 | opf->toc = _opf_init_toc(); |
613 | | |
614 | 167 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing toc"); |
615 | | |
616 | 167 | reader = xmlReaderForMemory(tocStr, size, "TOC", NULL, 0); |
617 | | |
618 | 167 | if (reader != NULL) { |
619 | 167 | ret = xmlTextReaderRead(reader); |
620 | | |
621 | 2.03k | while (ret == 1) { |
622 | | |
623 | 1.87k | const xmlChar *name = xmlTextReaderConstName(reader); |
624 | 1.87k | if (xmlStrcasecmp(name, (xmlChar *)"navList") == 0) |
625 | 0 | _opf_parse_navlist(opf, reader); |
626 | 1.87k | else |
627 | 1.87k | if (xmlStrcasecmp(name, (xmlChar *)"navMap") == 0) |
628 | 64 | _opf_parse_navmap(opf, reader); |
629 | 1.80k | else |
630 | 1.80k | if (xmlStrcasecmp(name, (xmlChar *)"pageList") == 0) |
631 | 0 | _opf_parse_pagelist(opf, reader); |
632 | | |
633 | 1.87k | ret = xmlTextReaderRead(reader); |
634 | 1.87k | } |
635 | | |
636 | 167 | xmlFreeTextReader(reader); |
637 | 167 | if (ret != 0) { |
638 | 157 | _epub_print_debug(opf->epub, DEBUG_ERROR, "failed to parse toc"); |
639 | 157 | } |
640 | 167 | } else { |
641 | 0 | _epub_print_debug(opf->epub, DEBUG_ERROR, "unable to open toc reader"); |
642 | 0 | } |
643 | | |
644 | 167 | SortList(opf->toc->playOrder); |
645 | 167 | _epub_print_debug(opf->epub, DEBUG_INFO, "finished parsing toc"); |
646 | 167 | } |
647 | | |
648 | 571 | void _opf_parse_spine(struct opf *opf, xmlTextReaderPtr reader) { |
649 | 571 | int ret; |
650 | 571 | xmlChar *linear; |
651 | | |
652 | 571 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing spine"); |
653 | | |
654 | 571 | opf->spine = NewListAlloc(LIST, NULL, NULL, NULL); |
655 | 571 | opf->tocName = xmlTextReaderGetAttribute(reader, (xmlChar *)"toc"); |
656 | | |
657 | 571 | if (opf->tocName) { |
658 | 541 | char *tocStr = NULL; |
659 | 541 | struct manifest *item; |
660 | 541 | int size; |
661 | | |
662 | 541 | _epub_print_debug(opf->epub, DEBUG_INFO, "toc is %s", opf->tocName); |
663 | | |
664 | 541 | item = _opf_manifest_get_by_id(opf, opf->tocName); |
665 | 541 | if (item != NULL) { |
666 | 476 | size = _ocf_get_data_file(opf->epub->ocf, (char *)item->href, &tocStr); |
667 | | |
668 | 476 | if (size <= 0) { |
669 | 309 | _epub_print_debug(opf->epub, DEBUG_ERROR, "Faulty toc file %s", |
670 | 309 | opf->tocName); |
671 | 309 | } else { |
672 | 167 | _opf_parse_toc(opf, tocStr, size); |
673 | 167 | free(tocStr); |
674 | 167 | } |
675 | 476 | } else { |
676 | 65 | _epub_print_debug(opf->epub, DEBUG_ERROR, "Toc not in manifest (-) %s", |
677 | 65 | opf->tocName); |
678 | 65 | } |
679 | 541 | } else { |
680 | 30 | _epub_print_debug(opf->epub, DEBUG_WARNING, "toc not found (-)"); |
681 | 30 | opf->toc = NULL; |
682 | 30 | } |
683 | | |
684 | | |
685 | 571 | ret = xmlTextReaderRead(reader); |
686 | 3.31k | while (ret == 1 && |
687 | 3.29k | xmlStrcasecmp(xmlTextReaderConstLocalName(reader), (xmlChar *)"spine")) { |
688 | 2.74k | struct spine *item; |
689 | | |
690 | | // ignore non starting tags |
691 | 2.74k | if (xmlTextReaderNodeType(reader) != 1) { |
692 | 1.64k | ret = xmlTextReaderRead(reader); |
693 | 1.64k | continue; |
694 | 1.64k | } |
695 | | |
696 | 1.10k | item = malloc(sizeof(struct spine)); |
697 | 1.10k | memset(item, 0, sizeof(struct spine)); |
698 | | |
699 | 1.10k | item->idref = xmlTextReaderGetAttribute(reader, (xmlChar *)"idref"); |
700 | 1.10k | linear = xmlTextReaderGetAttribute(reader, (xmlChar *)"linear"); |
701 | 1.10k | if (linear && xmlStrcasecmp(linear, (xmlChar *)"no") == 0) { |
702 | 0 | item->linear = 0; |
703 | 1.10k | } else { |
704 | 1.10k | item->linear = 1; |
705 | 1.10k | opf->linearCount++; |
706 | 1.10k | } |
707 | | |
708 | 1.10k | if(linear) |
709 | 0 | free(linear); |
710 | | |
711 | 1.10k | AddNode(opf->spine, NewListNode(opf->spine, item)); |
712 | | |
713 | | // decide what to do with non linear items |
714 | 1.10k | _epub_print_debug(opf->epub, DEBUG_INFO, "found item %s", item->idref); |
715 | | |
716 | 1.10k | ret = xmlTextReaderRead(reader); |
717 | 1.10k | } |
718 | 571 | } |
719 | | |
720 | 564 | void _opf_parse_manifest(struct opf *opf, xmlTextReaderPtr reader) { |
721 | 564 | int ret; |
722 | | |
723 | 564 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing manifest"); |
724 | | |
725 | 564 | opf->manifest = NewListAlloc(LIST, NULL, NULL, |
726 | 564 | (NodeCompareFunc)_list_cmp_manifest_by_id ); |
727 | | |
728 | 564 | ret = xmlTextReaderRead(reader); |
729 | | |
730 | 7.35k | while (ret == 1 && |
731 | 7.29k | xmlStrcasecmp(xmlTextReaderConstLocalName(reader),(xmlChar *)"manifest")) { |
732 | 6.78k | struct manifest *item; |
733 | | |
734 | | // ignore non starting tags |
735 | 6.78k | if (xmlTextReaderNodeType(reader) != 1) { |
736 | 3.64k | ret = xmlTextReaderRead(reader); |
737 | 3.64k | continue; |
738 | 3.64k | } |
739 | | |
740 | 3.14k | item = malloc(sizeof(struct manifest)); |
741 | | |
742 | 3.14k | item->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
743 | 3.14k | item->href = xmlTextReaderGetAttribute(reader, (xmlChar *)"href"); |
744 | 3.14k | item->type = xmlTextReaderGetAttribute(reader, (xmlChar *)"media-type"); |
745 | 3.14k | item->fallback = xmlTextReaderGetAttribute(reader, (xmlChar *)"fallback"); |
746 | 3.14k | item->fbStyle = |
747 | 3.14k | xmlTextReaderGetAttribute(reader, (xmlChar *)"fallback-style"); |
748 | 3.14k | item->nspace = |
749 | 3.14k | xmlTextReaderGetAttribute(reader, (xmlChar *)"required-namespace"); |
750 | 3.14k | item->modules = |
751 | 3.14k | xmlTextReaderGetAttribute(reader, (xmlChar *)"required-modules"); |
752 | | |
753 | 3.14k | _epub_print_debug(opf->epub, DEBUG_INFO, |
754 | 3.14k | "manifest item %s href %s media-type %s", |
755 | 3.14k | item->id, item->href, item->type); |
756 | | |
757 | 3.14k | AddNode(opf->manifest, NewListNode(opf->manifest, item)); |
758 | | |
759 | 3.14k | ret = xmlTextReaderRead(reader); |
760 | 3.14k | } |
761 | 564 | } |
762 | | |
763 | 2.00k | struct manifest *_opf_manifest_get_by_id(struct opf *opf, xmlChar* id) { |
764 | 2.00k | struct manifest data; |
765 | 2.00k | data.id = id; |
766 | | |
767 | 2.00k | return FindNode(opf->manifest, &data); |
768 | | |
769 | 2.00k | } |
770 | | |
771 | 530 | void _opf_parse_guide(struct opf *opf, xmlTextReaderPtr reader) { |
772 | 530 | int ret; |
773 | 530 | struct guide *item; |
774 | | |
775 | 530 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing guides"); |
776 | | |
777 | 530 | opf->guide = NewListAlloc(LIST, NULL, NULL, NULL); |
778 | | |
779 | 530 | ret = xmlTextReaderRead(reader); |
780 | 3.62k | while (ret == 1 && |
781 | 3.09k | xmlStrcasecmp(xmlTextReaderConstLocalName(reader),(xmlChar *)"guides")) { |
782 | | |
783 | | // ignore non starting tags |
784 | 3.09k | if (xmlTextReaderNodeType(reader) != 1) { |
785 | 2.57k | ret = xmlTextReaderRead(reader); |
786 | 2.57k | continue; |
787 | 2.57k | } |
788 | | |
789 | 521 | item = malloc(sizeof(struct guide)); |
790 | 521 | item->type = xmlTextReaderGetAttribute(reader, (xmlChar *)"type"); |
791 | 521 | item->title = xmlTextReaderGetAttribute(reader, (xmlChar *)"title"); |
792 | 521 | item->href = xmlTextReaderGetAttribute(reader, (xmlChar *)"href"); |
793 | | |
794 | 521 | _epub_print_debug(opf->epub, DEBUG_INFO, |
795 | 521 | "guide item: %s href: %s type: %s", |
796 | 521 | item->title, item->href, item->type); |
797 | 521 | AddNode(opf->guide, NewListNode(opf->guide, item)); |
798 | 521 | ret = xmlTextReaderRead(reader); |
799 | 521 | } |
800 | 530 | } |
801 | | |
802 | 0 | listPtr _opf_parse_tour(struct opf *opf, xmlTextReaderPtr reader) { |
803 | 0 | int ret; |
804 | 0 | listPtr tour = NewListAlloc(LIST, NULL, NULL, NULL); |
805 | 0 | struct site *item; |
806 | |
|
807 | 0 | ret = xmlTextReaderRead(reader); |
808 | | |
809 | 0 | while (ret == 1 && |
810 | 0 | xmlStrcasecmp(xmlTextReaderConstLocalName(reader),(xmlChar *)"tour")) { |
811 | | |
812 | | // ignore non starting tags |
813 | 0 | if (xmlTextReaderNodeType(reader) != 1) { |
814 | 0 | ret = xmlTextReaderRead(reader); |
815 | 0 | continue; |
816 | 0 | } |
817 | | |
818 | 0 | item = malloc(sizeof(struct site)); |
819 | 0 | item->title = xmlTextReaderGetAttribute(reader, (xmlChar *)"title"); |
820 | 0 | item->href = xmlTextReaderGetAttribute(reader, (xmlChar *)"href"); |
821 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, |
822 | 0 | "site: %s href: %s", |
823 | 0 | item->title, item->href); |
824 | 0 | AddNode(tour, NewListNode(tour, item)); |
825 | |
|
826 | 0 | ret = xmlTextReaderRead(reader); |
827 | 0 | } |
828 | |
|
829 | 0 | return tour; |
830 | 0 | } |
831 | | |
832 | 0 | void _opf_parse_tours(struct opf *opf, xmlTextReaderPtr reader) { |
833 | 0 | int ret; |
834 | 0 | struct tour *item; |
835 | |
|
836 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, "parsing tours"); |
837 | |
|
838 | 0 | opf->tours = NewListAlloc(LIST, NULL, NULL, NULL); |
839 | |
|
840 | 0 | ret = xmlTextReaderRead(reader); |
841 | | |
842 | 0 | while (ret == 1 && |
843 | 0 | xmlStrcasecmp(xmlTextReaderConstLocalName(reader), (xmlChar *)"tours")) { |
844 | | |
845 | | // ignore non starting tags |
846 | 0 | if (xmlTextReaderNodeType(reader) != 1) { |
847 | 0 | ret = xmlTextReaderRead(reader); |
848 | 0 | continue; |
849 | 0 | } |
850 | | |
851 | 0 | item = malloc(sizeof(struct tour)); |
852 | | |
853 | 0 | item->title = xmlTextReaderGetAttribute(reader, (xmlChar *)"title"); |
854 | 0 | item->id = xmlTextReaderGetAttribute(reader, (xmlChar *)"id"); |
855 | 0 | _epub_print_debug(opf->epub, DEBUG_INFO, |
856 | 0 | "tour: %s id: %s", |
857 | 0 | item->title, item->id); |
858 | 0 | item->sites = _opf_parse_tour(opf, reader); |
859 | 0 | AddNode(opf->tours, NewListNode(opf->tours, item)); |
860 | |
|
861 | 0 | ret = xmlTextReaderRead(reader); |
862 | 0 | } |
863 | 0 | } |
864 | | |
865 | 63 | xmlChar *_opf_label_get_by_lang(struct opf *opf, listPtr label, char *lang) { |
866 | 63 | struct tocLabel data, *tmp; |
867 | 63 | data.lang = (xmlChar *)lang; |
868 | 63 | label->compare = (NodeCompareFunc)_list_cmp_label_by_lang; |
869 | 63 | tmp = FindNode(label, &data); |
870 | 63 | return (tmp?tmp->text:NULL); |
871 | | |
872 | 63 | } |
873 | | |
874 | 63 | xmlChar *_opf_label_get_by_doc_lang(struct opf *opf, listPtr label) { |
875 | 63 | opf->metadata->lang->Current = opf->metadata->lang->Head; |
876 | 63 | return _opf_label_get_by_lang(opf, label, |
877 | 63 | (char *)GetNode(opf->metadata->lang)); |
878 | 63 | } |
879 | | |
880 | 0 | void _opf_dump(struct opf *opf) { |
881 | 0 | printf("Title(s):\n "); |
882 | 0 | DumpList(opf->metadata->title, (ListDumpFunc)_list_dump_string); |
883 | 0 | printf("Creator(s):\n "); |
884 | 0 | DumpList(opf->metadata->creator, (ListDumpFunc)_list_dump_creator); |
885 | 0 | printf("Identifier(s):\n "); |
886 | 0 | DumpList(opf->metadata->id, (ListDumpFunc)_list_dump_id); |
887 | 0 | printf("Reading order:\n "); |
888 | 0 | DumpList(opf->spine, (ListDumpFunc)_list_dump_spine); |
889 | 0 | printf("\n"); |
890 | 0 | if (opf->guide) { |
891 | 0 | printf("Guide:\n"); |
892 | 0 | DumpList(opf->guide, (ListDumpFunc)_list_dump_guide); |
893 | 0 | } |
894 | 0 | if (opf->tours) |
895 | 0 | DumpList(opf->tours, (ListDumpFunc)_list_dump_tour); |
896 | 0 | if (opf->metadata->meta->Size != 0) { |
897 | 0 | printf("Extra local metadata:\n"); |
898 | 0 | DumpList(opf->metadata->meta, (ListDumpFunc)_list_dump_meta); |
899 | 0 | } |
900 | 0 | } |
901 | | |
902 | 516 | void _opf_close(struct opf *opf) { |
903 | 516 | if (opf->metadata) |
904 | 508 | _opf_free_metadata(opf->metadata); |
905 | 516 | if (opf->toc) |
906 | 139 | _opf_free_toc(opf->toc); |
907 | 516 | if (opf->spine) |
908 | 516 | FreeList(opf->spine, (ListFreeFunc)_list_free_spine); |
909 | 516 | if (opf->tocName) |
910 | 490 | free(opf->tocName); |
911 | 516 | if (opf->manifest) |
912 | 459 | FreeList(opf->manifest, (ListFreeFunc)_list_free_manifest); |
913 | 516 | if (opf->guide) |
914 | 503 | FreeList(opf->guide, (ListFreeFunc)_list_free_guide); |
915 | 516 | if (opf->tours) |
916 | 0 | FreeList(opf->tours, (ListFreeFunc)_list_free_tours); |
917 | 516 | free(opf); |
918 | 516 | } |