[libgepub] Add TOC parse to GepubDoc
- From: Daniel Garcia Moreno <danigm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgepub] Add TOC parse to GepubDoc
- Date: Fri, 21 Sep 2018 09:02:28 +0000 (UTC)
commit 8680a463dcd3a50cbb94000f2a3b99699c6a792f
Author: Daniel GarcĂa Moreno <danigm wadobo com>
Date: Fri Sep 21 11:00:09 2018 +0200
Add TOC parse to GepubDoc
The new `gepub_doc_get_toc` function returns a GList of GepubNavPoint
with the `toc.ncx` information. There you can find the epub index.
I've added a test function to the gepub-test that shows this
information.
Fix #6
libgepub/gepub-doc.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++
libgepub/gepub-doc.h | 9 ++++
tests/test-gepub.c | 16 +++++++
3 files changed, 143 insertions(+)
---
diff --git a/libgepub/gepub-doc.c b/libgepub/gepub-doc.c
index 9d3219f..ea8dbba 100644
--- a/libgepub/gepub-doc.c
+++ b/libgepub/gepub-doc.c
@@ -51,7 +51,9 @@ typedef enum {
static void gepub_doc_fill_resources (GepubDoc *doc);
static void gepub_doc_fill_spine (GepubDoc *doc);
+static void gepub_doc_fill_toc (GepubDoc *doc, gchar *toc_id);
static void gepub_doc_initable_iface_init (GInitableIface *iface);
+static gint navpoint_compare (GepubNavPoint *a, GepubNavPoint *b);
struct _GepubDoc {
GObject parent;
@@ -64,6 +66,7 @@ struct _GepubDoc {
GList *spine;
GList *chapter;
+ GList *toc;
};
struct _GepubDocClass {
@@ -103,6 +106,8 @@ gepub_doc_finalize (GObject *object)
if (doc->spine) {
g_list_foreach (doc->spine, (GFunc)g_free, NULL);
g_clear_pointer (&doc->spine, g_list_free);
+ g_list_foreach (doc->toc, (GFunc)g_free, NULL);
+ g_clear_pointer (&doc->toc, g_list_free);
}
G_OBJECT_CLASS (gepub_doc_parent_class)->finalize (object);
@@ -309,12 +314,19 @@ gepub_doc_fill_spine (GepubDoc *doc)
const char *data;
gsize size;
GList *spine = NULL;
+ gchar *toc = NULL;
data = g_bytes_get_data (doc->content, &size);
xdoc = xmlRecoverMemory (data, size);
root_element = xmlDocGetRootElement (xdoc);
snode = gepub_utils_get_element_by_tag (root_element, "spine");
+ toc = gepub_utils_get_prop (snode, "toc");
+ if (toc) {
+ gepub_doc_fill_toc (doc, toc);
+ g_free (toc);
+ }
+
item = snode->children;
while (item) {
if (item->type != XML_ELEMENT_NODE ) {
@@ -334,6 +346,97 @@ gepub_doc_fill_spine (GepubDoc *doc)
xmlFreeDoc (xdoc);
}
+static gint
+navpoint_compare (GepubNavPoint *a, GepubNavPoint *b)
+{
+ return a->playorder - b->playorder;
+}
+
+
+static void
+gepub_doc_fill_toc (GepubDoc *doc, gchar *toc_id)
+{
+ xmlDoc *xdoc = NULL;
+ xmlNode *root_element = NULL;
+ xmlNode *mapnode = NULL;
+ xmlNode *item = NULL;
+ const char *data;
+ gsize size;
+ GList *toc = NULL;
+ GBytes *toc_data = NULL;
+
+ doc->toc = toc;
+
+ toc_data = gepub_doc_get_resource_by_id (doc, toc_id);
+ if (!toc_data) {
+ return;
+ }
+
+ data = g_bytes_get_data (toc_data, &size);
+ xdoc = xmlRecoverMemory (data, size);
+ root_element = xmlDocGetRootElement (xdoc);
+ mapnode = gepub_utils_get_element_by_tag (root_element, "navMap");
+
+ // TODO: get docTitle
+ // TODO: parse metadata (dtb:totalPageCount, dtb:depth, dtb:maxPageNumber)
+
+ item = mapnode->children;
+ while (item) {
+ GepubNavPoint *navpoint = NULL;
+ gchar *order;
+ xmlNode *navchilds = NULL;
+
+ if (item->type != XML_ELEMENT_NODE ||
+ g_strcmp0 ((const gchar *)item->name, "navPoint")) {
+ item = item->next;
+ continue;
+ }
+
+ navpoint = g_malloc0 (sizeof (GepubNavPoint));
+
+ order = gepub_utils_get_prop (item, "playOrder");
+ if (order) {
+ g_ascii_string_to_unsigned (order, 10, 0, INT_MAX,
+ &navpoint->playorder, NULL);
+ g_free (order);
+ }
+
+ // parsing navPoint->navLabel->text and navPoint->content
+ navchilds = item->children;
+ while (navchilds) {
+ if (item->type != XML_ELEMENT_NODE) {
+ navchilds = navchilds->next;
+ continue;
+ }
+
+ if (!g_strcmp0 ((const gchar *)navchilds->name, "content")) {
+ gchar *uri, *tmpuri;
+ tmpuri = gepub_utils_get_prop (navchilds, "src");
+ uri = g_strdup_printf ("%s%s", doc->content_base, tmpuri);
+ navpoint->content = uri;
+ g_free (tmpuri);
+ }
+
+ if (!g_strcmp0 ((const gchar *)navchilds->name, "navLabel")) {
+ xmlNode *text = gepub_utils_get_element_by_tag (navchilds, "text");
+ if (text->children && text->children->type == XML_TEXT_NODE) {
+ navpoint->label = g_strdup ((gchar *)text->children->content);
+ }
+ }
+
+ navchilds = navchilds->next;
+ }
+
+ toc = g_list_prepend (toc, navpoint);
+ item = item->next;
+ }
+
+ doc->toc = g_list_sort (toc, (GCompareFunc) navpoint_compare);
+
+ xmlFreeDoc (xdoc);
+ g_bytes_unref (toc_data);
+}
+
/**
* gepub_doc_get_content:
* @doc: a #GepubDoc
@@ -803,3 +906,18 @@ gepub_doc_get_current_id (GepubDoc *doc)
return doc->chapter->data;
}
+
+/**
+ * gepub_doc_get_toc:
+ * @doc: a #GepubDoc
+ *
+
+ * Returns: (element-type Gepub.NavPoint) (transfer none): the navigation list in order
+ */
+GList *
+gepub_doc_get_toc (GepubDoc *doc)
+{
+ g_return_val_if_fail (GEPUB_IS_DOC (doc), NULL);
+ return doc->toc;
+}
+
diff --git a/libgepub/gepub-doc.h b/libgepub/gepub-doc.h
index 01b8f8c..4290d92 100644
--- a/libgepub/gepub-doc.h
+++ b/libgepub/gepub-doc.h
@@ -40,7 +40,14 @@ struct _GepubResource {
gchar *uri;
};
+struct _GepubNavPoint {
+ gchar *label;
+ gchar *content;
+ guint64 playorder;
+};
+
typedef struct _GepubResource GepubResource;
+typedef struct _GepubNavPoint GepubNavPoint;
GType gepub_doc_get_type (void) G_GNUC_CONST;
@@ -69,6 +76,8 @@ gint gepub_doc_get_chapter (GepubDoc *doc);
void gepub_doc_set_chapter (GepubDoc *doc,
gint index);
+GList *gepub_doc_get_toc (GepubDoc *doc);
+
G_END_DECLS
/**
diff --git a/tests/test-gepub.c b/tests/test-gepub.c
index 1d6c0d8..afdf714 100644
--- a/tests/test-gepub.c
+++ b/tests/test-gepub.c
@@ -273,6 +273,21 @@ test_doc_spine (const char *path)
g_object_unref (G_OBJECT (doc));
}
+static void
+test_doc_toc (const char *path)
+{
+ GepubDoc *doc = gepub_doc_new (path, NULL);
+
+ GList *nav = gepub_doc_get_toc (doc);
+ while (nav && nav->data) {
+ GepubNavPoint *point = (GepubNavPoint*)nav->data;
+ PTEST ("%02d: %s -> %s\n", (gint)point->playorder, point->label, point->content);
+ nav = nav->next;
+ }
+
+ g_object_unref (G_OBJECT (doc));
+}
+
static void
destroy_cb (GtkWidget *window,
GtkWidget *view)
@@ -435,6 +450,7 @@ main (int argc, char **argv)
TEST(test_doc_name, argv[1])
TEST(test_doc_resources, argv[1])
TEST(test_doc_spine, argv[1])
+ TEST(test_doc_toc, argv[1])
// Freeing the mallocs :P
if (buf2) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]