1 /* GepubDoc
2 *
3 * Copyright (C) 2011 Daniel Garcia <danigm@wadobo.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <config.h>
21 #include <libxml/tree.h>
22 #include <libxml/HTMLparser.h>
23 #include <string.h>
24
25 #include "gepub-utils.h"
26 #include "gepub-doc.h"
27 #include "gepub-archive.h"
28 #include "gepub-text-chunk.h"
29
30
31 static GQuark
gepub_error_quark(void)32 gepub_error_quark (void)
33 {
34 static GQuark q = 0;
35 if (q == 0)
36 q = g_quark_from_string ("gepub-quark");
37 return q;
38 }
39
40 /**
41 * GepubDocError:
42 * @GEPUB_ERROR_INVALID: Invalid file
43 *
44 * Common errors that may be reported by GepubDoc.
45 */
46 typedef enum {
47 GEPUB_ERROR_INVALID = 0, /*< nick=Invalid >*/
48 } GepubDocError;
49
50
51
52 static void gepub_doc_fill_resources (GepubDoc *doc);
53 static void gepub_doc_fill_spine (GepubDoc *doc);
54 static void gepub_doc_initable_iface_init (GInitableIface *iface);
55
56 struct _GepubDoc {
57 GObject parent;
58
59 GepubArchive *archive;
60 GBytes *content;
61 gchar *content_base;
62 gchar *path;
63 GHashTable *resources;
64
65 GList *spine;
66 GList *chapter;
67 };
68
69 struct _GepubDocClass {
70 GObjectClass parent_class;
71 };
72
73 enum {
74 PROP_0,
75 PROP_PATH,
76 PROP_CHAPTER,
77 NUM_PROPS
78 };
79
80 static GParamSpec *properties[NUM_PROPS] = { NULL, };
81
G_DEFINE_TYPE_WITH_CODE(GepubDoc,gepub_doc,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,gepub_doc_initable_iface_init))82 G_DEFINE_TYPE_WITH_CODE (GepubDoc, gepub_doc, G_TYPE_OBJECT,
83 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gepub_doc_initable_iface_init))
84
85 static void
86 gepub_resource_free (GepubResource *res)
87 {
88 g_free (res->mime);
89 g_free (res->uri);
90 g_free (res);
91 }
92
93 static void
gepub_doc_finalize(GObject * object)94 gepub_doc_finalize (GObject *object)
95 {
96 GepubDoc *doc = GEPUB_DOC (object);
97
98 g_clear_object (&doc->archive);
99 g_clear_pointer (&doc->content, g_bytes_unref);
100 g_clear_pointer (&doc->path, g_free);
101 g_clear_pointer (&doc->resources, g_hash_table_destroy);
102
103 if (doc->spine) {
104 g_list_foreach (doc->spine, (GFunc)g_free, NULL);
105 g_clear_pointer (&doc->spine, g_list_free);
106 }
107
108 G_OBJECT_CLASS (gepub_doc_parent_class)->finalize (object);
109 }
110
111 static void
gepub_doc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)112 gepub_doc_set_property (GObject *object,
113 guint prop_id,
114 const GValue *value,
115 GParamSpec *pspec)
116 {
117 GepubDoc *doc = GEPUB_DOC (object);
118
119 switch (prop_id) {
120 case PROP_PATH:
121 doc->path = g_value_dup_string (value);
122 break;
123 case PROP_CHAPTER:
124 gepub_doc_set_chapter (doc, g_value_get_int (value));
125 break;
126 default:
127 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
128 break;
129 }
130 }
131
132 static void
gepub_doc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)133 gepub_doc_get_property (GObject *object,
134 guint prop_id,
135 GValue *value,
136 GParamSpec *pspec)
137 {
138 GepubDoc *doc = GEPUB_DOC (object);
139
140 switch (prop_id) {
141 case PROP_PATH:
142 g_value_set_string (value, doc->path);
143 break;
144 case PROP_CHAPTER:
145 g_value_set_int (value, gepub_doc_get_chapter (doc));
146 break;
147 default:
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149 break;
150 }
151 }
152
153 static void
gepub_doc_init(GepubDoc * doc)154 gepub_doc_init (GepubDoc *doc)
155 {
156 /* doc resources hashtable:
157 * id : (mime, path)
158 */
159 doc->resources = g_hash_table_new_full (g_str_hash,
160 g_str_equal,
161 (GDestroyNotify)g_free,
162 (GDestroyNotify)gepub_resource_free);
163 }
164
165 static void
gepub_doc_class_init(GepubDocClass * klass)166 gepub_doc_class_init (GepubDocClass *klass)
167 {
168 GObjectClass *object_class = G_OBJECT_CLASS (klass);
169
170 object_class->finalize = gepub_doc_finalize;
171 object_class->set_property = gepub_doc_set_property;
172 object_class->get_property = gepub_doc_get_property;
173
174 properties[PROP_PATH] =
175 g_param_spec_string ("path",
176 "Path",
177 "Path to the EPUB document",
178 NULL,
179 G_PARAM_READWRITE |
180 G_PARAM_CONSTRUCT_ONLY |
181 G_PARAM_STATIC_STRINGS);
182 properties[PROP_CHAPTER] =
183 g_param_spec_int ("chapter",
184 "Current chapter",
185 "The current chapter index",
186 -1, G_MAXINT, 0,
187 G_PARAM_READWRITE |
188 G_PARAM_STATIC_STRINGS);
189
190 g_object_class_install_properties (object_class, NUM_PROPS, properties);
191 }
192
193 static gboolean
gepub_doc_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)194 gepub_doc_initable_init (GInitable *initable,
195 GCancellable *cancellable,
196 GError **error)
197 {
198 GepubDoc *doc = GEPUB_DOC (initable);
199 gchar *file;
200 gint i = 0, len;
201
202 g_assert (doc->path != NULL);
203
204 doc->archive = gepub_archive_new (doc->path);
205 file = gepub_archive_get_root_file (doc->archive);
206 if (!file) {
207 if (error != NULL) {
208 g_set_error (error, gepub_error_quark (), GEPUB_ERROR_INVALID,
209 "Invalid epub file: %s", doc->path);
210 }
211 return FALSE;
212 }
213 doc->content = gepub_archive_read_entry (doc->archive, file);
214 if (!doc->content) {
215 if (error != NULL) {
216 g_set_error (error, gepub_error_quark (), GEPUB_ERROR_INVALID,
217 "Invalid epub file: %s", doc->path);
218 }
219 return FALSE;
220 }
221
222 len = strlen (file);
223 doc->content_base = g_strdup ("");
224 for (i=0; i<len; i++) {
225 if (file[i] == '/') {
226 g_free (doc->content_base);
227 doc->content_base = g_strndup (file, i+1);
228 break;
229 }
230 }
231
232 gepub_doc_fill_resources (doc);
233 gepub_doc_fill_spine (doc);
234
235 g_free (file);
236
237 return TRUE;
238 }
239
240 static void
gepub_doc_initable_iface_init(GInitableIface * iface)241 gepub_doc_initable_iface_init (GInitableIface *iface)
242 {
243 iface->init = gepub_doc_initable_init;
244 }
245
246 /**
247 * gepub_doc_new:
248 * @path: the epub doc path
249 * @error: (nullable): Error
250 *
251 * Returns: (transfer full): the new GepubDoc created
252 */
253 GepubDoc *
gepub_doc_new(const gchar * path,GError ** error)254 gepub_doc_new (const gchar *path, GError **error)
255 {
256 return g_initable_new (GEPUB_TYPE_DOC,
257 NULL, error,
258 "path", path,
259 NULL);
260 }
261
262 static void
gepub_doc_fill_resources(GepubDoc * doc)263 gepub_doc_fill_resources (GepubDoc *doc)
264 {
265 xmlDoc *xdoc = NULL;
266 xmlNode *root_element = NULL;
267 xmlNode *mnode = NULL;
268 xmlNode *item = NULL;
269 gchar *id, *tmpuri, *uri;
270 GepubResource *res;
271 const char *data;
272 gsize size;
273
274 data = g_bytes_get_data (doc->content, &size);
275 xdoc = xmlRecoverMemory (data, size);
276 root_element = xmlDocGetRootElement (xdoc);
277 mnode = gepub_utils_get_element_by_tag (root_element, "manifest");
278
279 item = mnode->children;
280 while (item) {
281 if (item->type != XML_ELEMENT_NODE ) {
282 item = item->next;
283 continue;
284 }
285
286 id = gepub_utils_get_prop (item, "id");
287 tmpuri = gepub_utils_get_prop (item, "href");
288 uri = g_strdup_printf ("%s%s", doc->content_base, tmpuri);
289 g_free (tmpuri);
290
291 res = g_malloc (sizeof (GepubResource));
292 res->mime = gepub_utils_get_prop (item, "media-type");
293 res->uri = uri;
294 g_hash_table_insert (doc->resources, id, res);
295 item = item->next;
296 }
297
298 xmlFreeDoc (xdoc);
299 }
300
301 static void
gepub_doc_fill_spine(GepubDoc * doc)302 gepub_doc_fill_spine (GepubDoc *doc)
303 {
304 xmlDoc *xdoc = NULL;
305 xmlNode *root_element = NULL;
306 xmlNode *snode = NULL;
307 xmlNode *item = NULL;
308 gchar *id;
309 const char *data;
310 gsize size;
311 GList *spine = NULL;
312
313 data = g_bytes_get_data (doc->content, &size);
314 xdoc = xmlRecoverMemory (data, size);
315 root_element = xmlDocGetRootElement (xdoc);
316 snode = gepub_utils_get_element_by_tag (root_element, "spine");
317
318 item = snode->children;
319 while (item) {
320 if (item->type != XML_ELEMENT_NODE ) {
321 item = item->next;
322 continue;
323 }
324
325 id = gepub_utils_get_prop (item, "idref");
326
327 spine = g_list_prepend (spine, id);
328 item = item->next;
329 }
330
331 doc->spine = g_list_reverse (spine);
332 doc->chapter = doc->spine;
333
334 xmlFreeDoc (xdoc);
335 }
336
337 /**
338 * gepub_doc_get_content:
339 * @doc: a #GepubDoc
340 *
341 * Returns: (transfer none): the document content
342 */
343 GBytes *
gepub_doc_get_content(GepubDoc * doc)344 gepub_doc_get_content (GepubDoc *doc)
345 {
346 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
347
348 return doc->content;
349 }
350
351 /**
352 * gepub_doc_get_metadata:
353 * @doc: a #GepubDoc
354 * @mdata: a metadata name string, GEPUB_META_TITLE for example
355 *
356 * Returns: (transfer full): metadata string
357 */
358 gchar *
gepub_doc_get_metadata(GepubDoc * doc,const gchar * mdata)359 gepub_doc_get_metadata (GepubDoc *doc, const gchar *mdata)
360 {
361 xmlDoc *xdoc = NULL;
362 xmlNode *root_element = NULL;
363 xmlNode *mnode = NULL;
364 xmlNode *mdata_node = NULL;
365 gchar *ret;
366 xmlChar *text;
367 const char *data;
368 gsize size;
369
370 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
371 g_return_val_if_fail (mdata != NULL, NULL);
372
373 data = g_bytes_get_data (doc->content, &size);
374 xdoc = xmlRecoverMemory (data, size);
375 root_element = xmlDocGetRootElement (xdoc);
376 mnode = gepub_utils_get_element_by_tag (root_element, "metadata");
377 mdata_node = gepub_utils_get_element_by_tag (mnode, mdata);
378
379 text = xmlNodeGetContent (mdata_node);
380 ret = g_strdup ((const char *) text);
381 xmlFree (text);
382
383 xmlFreeDoc (xdoc);
384
385 return ret;
386 }
387
388 /**
389 * gepub_doc_get_resources:
390 * @doc: a #GepubDoc
391 *
392 * Returns: (element-type utf8 Gepub.Resource) (transfer none): doc resource table
393 */
394 GHashTable *
gepub_doc_get_resources(GepubDoc * doc)395 gepub_doc_get_resources (GepubDoc *doc)
396 {
397 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
398
399 return doc->resources;
400 }
401
402 /**
403 * gepub_doc_get_resource_by_id:
404 * @doc: a #GepubDoc
405 * @id: the resource id
406 *
407 * Returns: (transfer full): the resource content
408 */
409 GBytes *
gepub_doc_get_resource_by_id(GepubDoc * doc,const gchar * id)410 gepub_doc_get_resource_by_id (GepubDoc *doc, const gchar *id)
411 {
412 GepubResource *gres;
413
414 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
415 g_return_val_if_fail (id != NULL, NULL);
416
417 gres = g_hash_table_lookup (doc->resources, id);
418 if (!gres) {
419 // not found
420 return NULL;
421 }
422
423 return gepub_archive_read_entry (doc->archive, gres->uri);
424 }
425
426 /**
427 * gepub_doc_get_resource:
428 * @doc: a #GepubDoc
429 * @path: the resource path
430 *
431 * Returns: (transfer full): the resource content
432 */
433 GBytes *
gepub_doc_get_resource(GepubDoc * doc,const gchar * path)434 gepub_doc_get_resource (GepubDoc *doc, const gchar *path)
435 {
436 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
437 g_return_val_if_fail (path != NULL, NULL);
438
439 return gepub_archive_read_entry (doc->archive, path);
440 }
441
442 /**
443 * gepub_doc_get_resource_mime_by_id:
444 * @doc: a #GepubDoc
445 * @id: the resource id
446 *
447 * Returns: (transfer full): the resource content
448 */
449 gchar *
gepub_doc_get_resource_mime_by_id(GepubDoc * doc,const gchar * id)450 gepub_doc_get_resource_mime_by_id (GepubDoc *doc, const gchar *id)
451 {
452 GepubResource *gres;
453
454 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
455 g_return_val_if_fail (id != NULL, NULL);
456
457 gres = g_hash_table_lookup (doc->resources, id);
458 if (!gres) {
459 // not found
460 return NULL;
461 }
462
463 return g_strdup (gres->mime);
464 }
465
466 /**
467 * gepub_doc_get_resource_mime:
468 * @doc: a #GepubDoc
469 * @path: the resource path
470 *
471 * Returns: (transfer full): the resource mime
472 */
473 gchar *
gepub_doc_get_resource_mime(GepubDoc * doc,const gchar * path)474 gepub_doc_get_resource_mime (GepubDoc *doc, const gchar *path)
475 {
476 GepubResource *gres;
477 GList *keys;
478
479 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
480 g_return_val_if_fail (path != NULL, NULL);
481
482 keys = g_hash_table_get_keys (doc->resources);
483
484 while (keys) {
485 gres = ((GepubResource*)g_hash_table_lookup (doc->resources, keys->data));
486 if (!strcmp (gres->uri, path))
487 break;
488 keys = keys->next;
489 }
490
491 if (keys)
492 return g_strdup (gres->mime);
493 else
494 return NULL;
495 }
496
497 /**
498 * gepub_doc_get_current_mime:
499 * @doc: a #GepubDoc
500 *
501 * Returns: (transfer full): the current resource mime
502 */
503 gchar *
gepub_doc_get_current_mime(GepubDoc * doc)504 gepub_doc_get_current_mime (GepubDoc *doc)
505 {
506 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
507 g_return_val_if_fail (doc->chapter != NULL, NULL);
508
509 return gepub_doc_get_resource_mime_by_id (doc, doc->chapter->data);
510 }
511
512 /**
513 * gepub_doc_get_current:
514 * @doc: a #GepubDoc
515 *
516 * Returns: (transfer full): the current chapter data
517 */
518 GBytes *
gepub_doc_get_current(GepubDoc * doc)519 gepub_doc_get_current (GepubDoc *doc)
520 {
521 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
522 g_return_val_if_fail (doc->chapter != NULL, NULL);
523
524 return gepub_doc_get_resource_by_id (doc, doc->chapter->data);
525 }
526
527 /**
528 * gepub_doc_get_current_with_epub_uris:
529 * @doc: a #GepubDoc
530 *
531 * Returns: (transfer full): the current chapter
532 * data, with resource uris renamed so they have the epub:/// prefix and all
533 * are relative to the root file
534 */
535 GBytes *
gepub_doc_get_current_with_epub_uris(GepubDoc * doc)536 gepub_doc_get_current_with_epub_uris (GepubDoc *doc)
537 {
538 GBytes *content, *replaced;
539 gchar *path, *base;
540
541 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
542
543 content = gepub_doc_get_current (doc);
544 path = gepub_doc_get_current_path (doc);
545 // getting the basepath of the current xhtml loaded
546 base = g_path_get_dirname (path);
547
548 replaced = gepub_utils_replace_resources (content, base);
549
550 g_free (path);
551 g_bytes_unref (content);
552
553 return replaced;
554 }
555
556 /**
557 * gepub_doc_get_text:
558 * @doc: a #GepubDoc
559 *
560 * Returns: (element-type Gepub.TextChunk) (transfer full): the list of text in the current chapter.
561 */
562 GList *
gepub_doc_get_text(GepubDoc * doc)563 gepub_doc_get_text (GepubDoc *doc)
564 {
565 xmlDoc *xdoc = NULL;
566 xmlNode *root_element = NULL;
567 GBytes *current;
568 const gchar *data;
569 gsize size;
570
571 GList *texts = NULL;
572
573 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
574
575 current = gepub_doc_get_current (doc);
576 if (!current) {
577 return NULL;
578 }
579 data = g_bytes_get_data (current, &size);
580 xdoc = htmlReadMemory (data, size, "", NULL, HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
581 root_element = xmlDocGetRootElement (xdoc);
582 texts = gepub_utils_get_text_elements (root_element);
583
584 g_bytes_unref (current);
585 xmlFreeDoc (xdoc);
586
587 return texts;
588 }
589
590 /**
591 * gepub_doc_get_text_by_id:
592 * @doc: a #GepubDoc
593 * @id: the resource id
594 *
595 * Returns: (element-type Gepub.TextChunk) (transfer full): the list of text in the current chapter.
596 */
597 GList *
gepub_doc_get_text_by_id(GepubDoc * doc,const gchar * id)598 gepub_doc_get_text_by_id (GepubDoc *doc, const gchar *id)
599 {
600 xmlDoc *xdoc = NULL;
601 xmlNode *root_element = NULL;
602 gsize size;
603 const gchar *res;
604 GBytes *contents;
605
606 GList *texts = NULL;
607
608 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
609 g_return_val_if_fail (id != NULL, NULL);
610
611 contents = gepub_doc_get_resource_by_id (doc, id);
612 if (!contents) {
613 return NULL;
614 }
615
616 res = g_bytes_get_data (contents, &size);
617 xdoc = htmlReadMemory (res, size, "", NULL, HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
618 root_element = xmlDocGetRootElement (xdoc);
619 texts = gepub_utils_get_text_elements (root_element);
620
621 g_bytes_unref (contents);
622 xmlFreeDoc (xdoc);
623
624 return texts;
625 }
626
627 static gboolean
gepub_doc_set_chapter_internal(GepubDoc * doc,GList * chapter)628 gepub_doc_set_chapter_internal (GepubDoc *doc,
629 GList *chapter)
630 {
631 if (!chapter || doc->chapter == chapter)
632 return FALSE;
633
634 doc->chapter = chapter;
635 g_object_notify_by_pspec (G_OBJECT (doc), properties[PROP_CHAPTER]);
636
637 return TRUE;
638 }
639
640 /**
641 * gepub_doc_go_next:
642 * @doc: a #GepubDoc
643 *
644 * Returns: TRUE on success, FALSE if there's no next chapter
645 */
646 gboolean
gepub_doc_go_next(GepubDoc * doc)647 gepub_doc_go_next (GepubDoc *doc)
648 {
649 g_return_val_if_fail (GEPUB_IS_DOC (doc), FALSE);
650 g_return_val_if_fail (doc->chapter != NULL, FALSE);
651
652 return gepub_doc_set_chapter_internal (doc, doc->chapter->next);
653 }
654
655 /**
656 * gepub_doc_go_prev:
657 * @doc: a #GepubDoc
658 *
659 * Returns: TRUE on success, FALSE if there's no previous chapter
660 */
661 gboolean
gepub_doc_go_prev(GepubDoc * doc)662 gepub_doc_go_prev (GepubDoc *doc)
663 {
664 g_return_val_if_fail (GEPUB_IS_DOC (doc), FALSE);
665 g_return_val_if_fail (doc->chapter != NULL, FALSE);
666
667 return gepub_doc_set_chapter_internal (doc, doc->chapter->prev);
668 }
669
670 /**
671 * gepub_doc_get_n_chapters:
672 * @doc: a #GepubDoc
673 *
674 * Returns: the number of chapters in the document
675 */
676 int
gepub_doc_get_n_chapters(GepubDoc * doc)677 gepub_doc_get_n_chapters (GepubDoc *doc)
678 {
679 g_return_val_if_fail (GEPUB_IS_DOC (doc), 0);
680
681 return g_list_length (doc->spine);
682 }
683
684 /**
685 * gepub_doc_get_chapter:
686 * @doc: a #GepubDoc
687 *
688 * Returns: the current chapter index, starting from 0
689 */
690 int
gepub_doc_get_chapter(GepubDoc * doc)691 gepub_doc_get_chapter (GepubDoc *doc)
692 {
693 g_return_val_if_fail (GEPUB_IS_DOC (doc), 0);
694 g_return_val_if_fail (doc->spine != NULL, 0);
695 g_return_val_if_fail (doc->chapter != NULL, 0);
696
697 return g_list_position (doc->spine, doc->chapter);
698 }
699
700 /**
701 * gepub_doc_set_chapter:
702 * @doc: a #GepubDoc
703 * @index: the index of the new chapter
704 *
705 * Sets the document current chapter to @index.
706 */
707 void
gepub_doc_set_chapter(GepubDoc * doc,gint index)708 gepub_doc_set_chapter (GepubDoc *doc,
709 gint index)
710 {
711 GList *chapter;
712
713 g_return_if_fail (GEPUB_IS_DOC (doc));
714
715 g_return_if_fail (index >= 0 && index <= gepub_doc_get_n_chapters (doc));
716
717 chapter = g_list_nth (doc->spine, index);
718 gepub_doc_set_chapter_internal (doc, chapter);
719 }
720
721 /**
722 * gepub_doc_get_cover:
723 * @doc: a #GepubDoc
724 *
725 * Returns: (transfer full): cover file path to retrieve with
726 * gepub_doc_get_resource
727 */
728 gchar *
gepub_doc_get_cover(GepubDoc * doc)729 gepub_doc_get_cover (GepubDoc *doc)
730 {
731 xmlDoc *xdoc = NULL;
732 xmlNode *root_element = NULL;
733 xmlNode *mnode = NULL;
734 gchar *ret;
735 const char *data;
736 gsize size;
737
738 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
739 g_return_val_if_fail (doc->content != NULL, NULL);
740
741 data = g_bytes_get_data (doc->content, &size);
742 xdoc = xmlRecoverMemory (data, size);
743 root_element = xmlDocGetRootElement (xdoc);
744 mnode = gepub_utils_get_element_by_attr (root_element, "name", "cover");
745 ret = gepub_utils_get_prop (mnode, "content");
746
747 xmlFreeDoc (xdoc);
748
749 return ret;
750 }
751
752 /**
753 * gepub_doc_get_resource_path:
754 * @doc: a #GepubDoc
755 * @id: the resource id
756 *
757 * Returns: (transfer full): the resource path
758 */
759 gchar *
gepub_doc_get_resource_path(GepubDoc * doc,const gchar * id)760 gepub_doc_get_resource_path (GepubDoc *doc, const gchar *id)
761 {
762 GepubResource *gres;
763
764 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
765 g_return_val_if_fail (id != NULL, NULL);
766
767 gres = g_hash_table_lookup (doc->resources, id);
768 if (!gres) {
769 // not found
770 return NULL;
771 }
772
773 return g_strdup (gres->uri);
774 }
775
776 /**
777 * gepub_doc_get_current_path:
778 * @doc: a #GepubDoc
779 *
780 * Returns: (transfer full): the current resource path
781 */
782 gchar *
gepub_doc_get_current_path(GepubDoc * doc)783 gepub_doc_get_current_path (GepubDoc *doc)
784 {
785 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
786 g_return_val_if_fail (doc->chapter != NULL, NULL);
787
788 return gepub_doc_get_resource_path (doc, doc->chapter->data);
789 }
790
791 /**
792 * gepub_doc_get_current_id:
793 * @doc: a #GepubDoc
794 *
795
796 * Returns: (transfer none): the current resource id
797 */
798 const gchar *
gepub_doc_get_current_id(GepubDoc * doc)799 gepub_doc_get_current_id (GepubDoc *doc)
800 {
801 g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
802 g_return_val_if_fail (doc->chapter != NULL, NULL);
803
804 return doc->chapter->data;
805 }
806