summaryrefslogtreecommitdiff
path: root/backend/epub/epub-document.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/epub/epub-document.c')
-rw-r--r--backend/epub/epub-document.c503
1 files changed, 374 insertions, 129 deletions
diff --git a/backend/epub/epub-document.c b/backend/epub/epub-document.c
index 826ccf74..39c114e3 100644
--- a/backend/epub/epub-document.c
+++ b/backend/epub/epub-document.c
@@ -1,6 +1,7 @@
#include "ev-file-helpers.h"
#include "epub-document.h"
#include "unzip.h"
+#include "ev-document-thumbnails.h"
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
@@ -10,38 +11,194 @@
#include <glib/gi18n.h>
#include <glib/gstdio.h>
-/* A variable to hold the path where we extact our ePub */
-static gchar* tmp_dir = NULL;
-/* A variable to hold our epubDocument , for unzip purposes */
-static unzFile epubDocument ;
+#include <webkit/webkit.h>
+#include <gtk/gtk.h>
typedef enum _xmlParseReturnType
{
- xmlattribute = 0,
- xmlkeyword = 1
-
+ XML_ATTRIBUTE,
+ XML_KEYWORD
}xmlParseReturnType;
-struct _DocumentTreeNode {
+typedef struct _contentListNode {
gchar* key ;
gchar* value ;
+}contentListNode;
+
+typedef struct _EpubDocumentClass EpubDocumentClass;
+
+struct _EpubDocumentClass
+{
+ EvDocumentClass parent_class;
+};
+
+struct _EpubDocument
+{
+ EvDocument parent_instance;
+ /*Stores the path to the source archive*/
+ gchar* archivename ;
+ /*Stores the path of the directory where we unzipped the epub*/
+ gchar* tmp_archive_dir ;
+ /*Stores the contentlist in a sorted manner*/
+ GList* contentList ;
+ /*uri of the current page being displayed in the webview*/
+ gchar* currentpageuri ;
+ /* A variable to hold our epubDocument for unzipping*/
+ unzFile epubDocument ;
};
-typedef struct _DocumentTreeNode DocumentTreeNode;
+static void epub_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
+
+EV_BACKEND_REGISTER_WITH_CODE (EpubDocument, epub_document,
+ {
+ EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
+ epub_document_document_thumbnails_iface_init);
+ } );
+
+static GdkPixbuf *
+epub_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
+ EvRenderContext *rc,
+ gboolean border)
+{
+ GdkPixbuf *thumbnail;
+ return thumbnail;
+}
+
+static void
+epub_document_get_page_size (EvDocument *document,
+ EvPage *page,
+ double *width,
+ double *height)
+{
+}
+
+static void
+epub_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
+ EvRenderContext *rc,
+ gint *width,
+ gint *height)
+{
+ gdouble page_width, page_height;
+
+ epub_document_get_page_size (EV_DOCUMENT (document), rc->page,
+ &page_width, &page_height);
+
+ if (rc->rotation == 90 || rc->rotation == 270) {
+ *width = (gint) (page_height * rc->scale);
+ *height = (gint) (page_width * rc->scale);
+ } else {
+ *width = (gint) (page_width * rc->scale);
+ *height = (gint) (page_height * rc->scale);
+ }
+}
+
+static void
+epub_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
+{
+ iface->get_thumbnail = epub_document_thumbnails_get_thumbnail;
+ iface->get_dimensions = epub_document_thumbnails_get_dimensions;
+}
-/*Prototypes for some future functions*/
static gboolean
-extract_one_file (GError ** error);
+epub_document_save (EvDocument *document,
+ const char *uri,
+ GError **error)
+{
+ EpubDocument *epub_document = EPUB_DOCUMENT (document);
+
+ return ev_xfer_uri_simple (epub_document->archivename, uri, error);
+}
+
+static int
+epub_document_get_n_pages (EvDocument *document)
+{
+ EpubDocument *epub_document = EPUB_DOCUMENT (document);
+
+ if (epub_document-> contentList == NULL)
+ return 0;
+
+ return g_list_length(epub_document->contentList);
+}
+
+static void
+render_cb_function(GtkWidget *web_view,
+ GParamSpec *specification,
+ cairo_surface_t **surface)
+{
+ WebKitLoadStatus status = webkit_web_view_get_load_status (WEBKIT_WEB_VIEW(web_view));
+
+ if ( status == WEBKIT_LOAD_FINISHED )
+ {
+ *(surface) = webkit_web_view_get_snapshot (WEBKIT_WEB_VIEW(web_view));
+ }
+}
+static void
+epub_webkit_render(cairo_surface_t **surface,EpubDocument *epub_document,
+ const char* uri)
+{
+ GtkWidget *offscreen_window = gtk_offscreen_window_new ();
+ gtk_window_set_default_size(GTK_WINDOW(offscreen_window),800,600);
+ GtkWidget* web_view = webkit_web_view_new ();
+ GtkWidget* scroll_view = gtk_scrolled_window_new (NULL,NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scroll_view),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),epub_document->currentpageuri);
+ gtk_container_add(GTK_CONTAINER(scroll_view),web_view);
+ gtk_container_add(GTK_CONTAINER(offscreen_window),scroll_view);
+ g_signal_connect(WEBKIT_WEB_VIEW(web_view),"notify::load-status",G_CALLBACK(render_cb_function),surface);
+ gtk_widget_show_all (offscreen_window);
+ g_object_unref(web_view);
+ g_object_unref(scroll_view);
+ g_object_unref(offscreen_window);
+}
+
+static cairo_surface_t *
+epub_document_render (EvDocument *document)
+{
+ cairo_surface_t *surface;
+ EpubDocument *epub_document = EPUB_DOCUMENT(document);
+ epub_webkit_render(&surface,epub_document,epub_document->currentpageuri);
+ return surface;
+}
+
+/**
+ * epub_remove_temporary_dir : Removes a directory recursively.
+ * This function is same as comics_remove_temporary_dir
+ * Returns:
+ * 0 if it was successfully deleted,
+ * -1 if an error occurred
+ */
+static int
+epub_remove_temporary_dir (gchar *path_name)
+{
+ GDir *content_dir;
+ const gchar *filename;
+ gchar *filename_with_path;
+
+ if (g_file_test (path_name, G_FILE_TEST_IS_DIR)) {
+ content_dir = g_dir_open (path_name, 0, NULL);
+ filename = g_dir_read_name (content_dir);
+ while (filename) {
+ filename_with_path =
+ g_build_filename (path_name,
+ filename, NULL);
+ epub_remove_temporary_dir (filename_with_path);
+ g_free (filename_with_path);
+ filename = g_dir_read_name (content_dir);
+ }
+ g_dir_close (content_dir);
+ }
+ /* Note from g_remove() documentation: on Windows, it is in general not
+ * possible to remove a file that is open to some process, or mapped
+ * into memory.*/
+ return (g_remove (path_name));
+}
+
static gboolean
check_mime_type (const gchar* uri,
GError** error);
static gboolean
-extract_epub_from_container (const gchar* uri,
- GError ** error);
-
-static gboolean
open_xml_document (const gchar* filename);
static gboolean
@@ -73,14 +230,10 @@ xml_free_doc();
static void
free_tree_nodes (gpointer data);
-static GList*
-setup_document_tree (const gchar* content_uri,
- GError** error);
-
/*Global variables for XML parsing*/
static xmlDocPtr xmldocument ;
static xmlNodePtr xmlroot ;
-static xmlNodePtr retval ;
+static xmlNodePtr xmlretval ;
/*
**Functions to parse the xml files.
@@ -138,7 +291,7 @@ xml_get_pointer_to_node(xmlChar* parserfor,
{
xmlNodePtr topchild,children ;
- retval = NULL ;
+ xmlretval = NULL ;
if ( !xmlStrcmp( xmlroot->name, parserfor) )
{
@@ -153,8 +306,8 @@ xml_get_pointer_to_node(xmlChar* parserfor,
{
if ( xml_check_attribute_value(topchild,attributename,attributevalue) == TRUE )
{
- retval = topchild;
- return retval;
+ xmlretval = topchild;
+ return xmlretval;
}
else
{
@@ -169,7 +322,7 @@ xml_get_pointer_to_node(xmlChar* parserfor,
topchild = topchild->next ;
}
- return retval ;
+ return xmlretval ;
}
static void
@@ -186,7 +339,7 @@ xml_parse_children_of_node(xmlNodePtr parent,
{
if ( xml_check_attribute_value(child,attributename,attributevalue) == TRUE )
{
- retval = child;
+ xmlretval = child;
return ;
}
else
@@ -197,8 +350,8 @@ xml_parse_children_of_node(xmlNodePtr parent,
}
}
- /*return already if we have retval set*/
- if ( retval != NULL )
+ /*return already if we have xmlretval set*/
+ if ( xmlretval != NULL )
{
return ;
}
@@ -235,10 +388,12 @@ xml_check_attribute_value(xmlNode* node,
}
static xmlChar*
-xml_get_data_from_node(xmlNodePtr node,xmlParseReturnType rettype,xmlChar* attributename)
+xml_get_data_from_node(xmlNodePtr node,
+ xmlParseReturnType rettype,
+ xmlChar* attributename)
{
xmlChar* datastring ;
- if ( rettype == xmlattribute )
+ if ( rettype == XML_ATTRIBUTE )
datastring= xmlGetProp(node,attributename);
else
datastring= xmlNodeListGetString(xmldocument,node->xmlChildrenNode, 1);
@@ -280,14 +435,70 @@ check_mime_type(const gchar* uri,GError** error)
}
}
+static gboolean
+extract_one_file(EpubDocument* epub_document,GError ** error)
+{
+ GFile * outfile ;
+ gsize writesize = 0;
+ GString * gfilepath ;
+ unz_file_info64 info ;
+ gchar* directory;
+ GFileOutputStream * outstream ;
+ gpointer currentfilename = g_malloc0(512);
+ gpointer buffer = g_malloc0(512);
+
+ if ( unzOpenCurrentFile(epub_document->epubDocument) != UNZ_OK )
+ {
+ return FALSE ;
+ }
+
+ unzGetCurrentFileInfo64(epub_document->epubDocument,&info,currentfilename,512,NULL,0,NULL,0) ;
+ directory = g_strrstr(currentfilename,"/") ;
+
+ if ( directory != NULL )
+ directory++;
+
+ gfilepath = g_string_new(epub_document->tmp_archive_dir) ;
+ g_string_append_printf(gfilepath,"/%s",(gchar*)currentfilename);
+
+ /*if we encounter a directory, make a directory inside our temporary folder.*/
+ if (directory != NULL && *directory == '\0')
+ {
+ g_mkdir(gfilepath->str,0777);
+ }
+ else
+ {
+ outfile = g_file_new_for_path(gfilepath->str);
+ outstream = g_file_create(outfile,G_FILE_CREATE_PRIVATE,NULL,error);
+ while ( (writesize = unzReadCurrentFile(epub_document->epubDocument,buffer,512) ) != 0 )
+ {
+ if ( g_output_stream_write((GOutputStream*)outstream,buffer,writesize,NULL,error) == -1 )
+ {
+ return FALSE ;
+ }
+ }
+ g_output_stream_close((GOutputStream*)outstream,NULL,error);
+ g_object_unref(outfile) ;
+ g_object_unref(outstream) ;
+ }
+
+ unzCloseCurrentFile (epub_document->epubDocument) ;
+ g_string_free(gfilepath,TRUE);
+ g_free(currentfilename);
+ g_free(buffer);
+
+}
+
static gboolean
-extract_epub_from_container (const gchar* uri, GError ** error)
+extract_epub_from_container (const gchar* uri,
+ EpubDocument *epub_document,
+ GError ** error)
{
GError* err = NULL ;
GString * temporary_sub_directory ;
- gchar* archivename = g_filename_from_uri(uri,NULL,error);
-
- if ( !archivename )
+ epub_document->archivename = g_filename_from_uri(uri,NULL,error);
+ gchar* epubfilename ;
+ if ( !epub_document->archivename )
{
if (err) {
g_propagate_error (error, err);
@@ -301,24 +512,24 @@ extract_epub_from_container (const gchar* uri, GError ** error)
return FALSE ;
}
- tmp_dir = g_strrstr(archivename,"/");
- if ( *tmp_dir == '/' )
- tmp_dir++ ;
+ epubfilename = g_strrstr(epub_document->archivename,"/");
+ if ( *epubfilename == '/' )
+ epubfilename++ ;
- temporary_sub_directory = g_string_new( tmp_dir );
+ temporary_sub_directory = g_string_new( epubfilename );
g_string_append(temporary_sub_directory,"XXXXXX") ;
- tmp_dir = ev_mkdtemp(temporary_sub_directory->str,error) ;
+ epub_document->tmp_archive_dir = ev_mkdtemp(temporary_sub_directory->str,error) ;
- if (!tmp_dir) {
+ if (!epub_document->tmp_archive_dir) {
return FALSE ;
}
g_string_free(temporary_sub_directory,TRUE);
- epubDocument = unzOpen64(archivename);
+ epub_document->epubDocument = unzOpen64(epub_document->archivename);
- if ( epubDocument == NULL )
+ if ( epub_document->epubDocument == NULL )
{
if (err) {
g_propagate_error (error, err);
@@ -331,7 +542,7 @@ extract_epub_from_container (const gchar* uri, GError ** error)
}
return FALSE ;
}
- if ( unzGoToFirstFile(epubDocument) != UNZ_OK )
+ if ( unzGoToFirstFile(epub_document->epubDocument) != UNZ_OK )
{
if (err) {
g_propagate_error (error, err);
@@ -346,7 +557,7 @@ extract_epub_from_container (const gchar* uri, GError ** error)
}
while ( TRUE )
{
- if ( extract_one_file(&err) == FALSE )
+ if ( extract_one_file(epub_document,&err) == FALSE )
{
if (err) {
g_propagate_error (error, err);
@@ -357,77 +568,20 @@ extract_epub_from_container (const gchar* uri, GError ** error)
EV_DOCUMENT_ERROR_INVALID,
_("could not extract archive"));
}
+ return FALSE;
}
- if ( unzGoToNextFile(epubDocument) == UNZ_END_OF_LIST_OF_FILE )
+ if ( unzGoToNextFile(epub_document->epubDocument) == UNZ_END_OF_LIST_OF_FILE )
break ;
}
- unzClose(epubDocument);
-
- if ( err != NULL )
- g_error_free(err);
-
- g_free(archivename);
-
+ unzClose(epub_document->epubDocument);
return TRUE ;
}
-static gboolean
-extract_one_file(GError ** error)
-{
- GFile * outfile ;
- gsize writesize = 0;
- GString * gfilepath ;
- unz_file_info64 info ;
- gchar* directory;
- GFileOutputStream * outstream ;
- gpointer currentfilename = g_malloc0(512);
- gpointer buffer = g_malloc0(512);
-
- if ( unzOpenCurrentFile(epubDocument) != UNZ_OK )
- {
- return FALSE ;
- }
-
- unzGetCurrentFileInfo64(epubDocument,&info,currentfilename,512,NULL,0,NULL,0) ;
- directory = g_strrstr(currentfilename,"/") ;
-
- if ( directory != NULL )
- directory++;
-
- gfilepath = g_string_new(tmp_dir) ;
- g_string_append_printf(gfilepath,"/%s",(gchar*)currentfilename);
-
- /*if we encounter a directory, make a directory inside our temporary folder.*/
- if (directory != NULL && *directory == '\0')
- {
- g_mkdir(gfilepath->str,0777);
- }
- else
- {
- outfile = g_file_new_for_path(gfilepath->str);
- outstream = g_file_create(outfile,G_FILE_CREATE_PRIVATE,NULL,error);
- while ( (writesize = unzReadCurrentFile(epubDocument,buffer,512) ) != 0 )
- {
- if ( g_output_stream_write((GOutputStream*)outstream,buffer,writesize,NULL,error) == -1 )
- {
- return FALSE ;
- }
- }
- g_output_stream_close((GOutputStream*)outstream,NULL,error);
- g_object_unref(outfile) ;
- g_object_unref(outstream) ;
- }
- unzCloseCurrentFile (epubDocument) ;
- g_string_free(gfilepath,TRUE);
- g_free(currentfilename);
- g_free(buffer);
-
-}
-
-static gchar* get_uri_to_content(const gchar* uri,GError ** error)
+static gchar*
+get_uri_to_content(const gchar* uri,GError ** error,gchar* tmp_archive_dir)
{
GError * err = NULL ;
gchar* containerpath = g_filename_from_uri(uri,NULL,&err);
@@ -477,9 +631,8 @@ static gchar* get_uri_to_content(const gchar* uri,GError ** error)
return NULL ;
}
- relativepath = xml_get_data_from_node(rootfileNode,xmlattribute,(xmlChar*)"full-path") ;
-
- if ( relativepath == NULL )
+ relativepath = xml_get_data_from_node(rootfileNode,XML_ATTRIBUTE,(xmlChar*)"full-path") ;
+ if ( relativepath == NULL )
{
g_set_error_literal(error,
EV_DOCUMENT_ERROR,
@@ -487,7 +640,7 @@ static gchar* get_uri_to_content(const gchar* uri,GError ** error)
_("epub file is corrupt,no container"));
return NULL ;
}
- g_string_printf(absolutepath,"%s/%s",tmp_dir,relativepath);
+ g_string_printf(absolutepath,"%s/%s",tmp_archive_dir,relativepath);
content_uri = g_filename_to_uri(absolutepath->str,NULL,&err);
if ( !content_uri ) {
@@ -508,18 +661,18 @@ static gchar* get_uri_to_content(const gchar* uri,GError ** error)
}
static GList*
-setup_document_tree(const gchar* content_uri, GError** error)
+setup_document_content_list(const gchar* content_uri, GError** error,gchar *tmp_archive_dir)
{
GList* newlist = NULL ;
GError * err = NULL ;
- gchar* contentOpf="/home/rootavish/Downloads/zlib/progit/content.opf";
+
xmlNodePtr manifest,spine,itemrefptr,itemptr ;
gboolean errorflag = FALSE;
gchar* relativepath ;
GString* absolutepath = g_string_new(NULL);
- if ( open_xml_document(contentOpf) == FALSE )
+ if ( open_xml_document(content_uri) == FALSE )
{
g_set_error_literal(error,
EV_DOCUMENT_ERROR,
@@ -555,13 +708,13 @@ setup_document_tree(const gchar* content_uri, GError** error)
return FALSE ;
}
- retval = NULL ;
+ xmlretval = NULL ;
/*Get first instance of itemref from the spine*/
xml_parse_children_of_node(spine,"itemref",NULL,NULL);
- if ( retval != NULL )
- itemrefptr = retval ;
+ if ( xmlretval != NULL )
+ itemrefptr = xmlretval ;
else
{
errorflag=TRUE;
@@ -574,31 +727,29 @@ setup_document_tree(const gchar* content_uri, GError** error)
{
break;
}
- if ( xmlStrcmp(itemrefptr->name,"itemref") == 0)
+ if ( xmlStrcmp(itemrefptr->name,(xmlChar*)"itemref") == 0)
{
- DocumentTreeNode* newnode = g_malloc0(sizeof(newnode));
- newnode->key = xml_get_data_from_node(itemrefptr,xmlattribute,(xmlChar*)"idref");
-
- if ( newnode->key == NULL )
+ contentListNode* newnode = g_malloc0(sizeof(newnode));
+ newnode->key = xml_get_data_from_node(itemrefptr,XML_ATTRIBUTE,(xmlChar*)"idref");
+ if ( newnode->key == NULL )
{
errorflag =TRUE;
break;
}
- retval=NULL ;
- xml_parse_children_of_node(manifest,"item","id",newnode->key);
+ xmlretval=NULL ;
+ xml_parse_children_of_node(manifest,(xmlChar*)"item",(xmlChar*)"id",(xmlChar*)newnode->key);
- if ( retval != NULL )
+ if ( xmlretval != NULL )
{
- itemptr = retval ;
+ itemptr = xmlretval ;
}
else
{
errorflag=TRUE;
break;
}
- relativepath = xml_get_data_from_node(itemptr,xmlattribute,(xmlChar*)"href");
-
- g_string_assign(absolutepath,tmp_dir);
+ relativepath = xml_get_data_from_node(itemptr,XML_ATTRIBUTE,(xmlChar*)"href");
+ g_string_assign(absolutepath,tmp_archive_dir);
g_string_append_printf(absolutepath,"/%s",relativepath);
newnode->value = g_filename_to_uri(absolutepath->str,NULL,&err);
if ( newnode->value == NULL )
@@ -636,11 +787,105 @@ setup_document_tree(const gchar* content_uri, GError** error)
}
+/* Callback function to free the contentlist.*/
static void
free_tree_nodes(gpointer data)
{
- DocumentTreeNode* dataptr = data ;
+ contentListNode* dataptr = data ;
g_free(dataptr->value);
g_free(dataptr->key);
g_free(dataptr);
-} \ No newline at end of file
+}
+
+static void
+epub_document_init (EpubDocument *epub_document)
+{
+ epub_document->archivename = NULL ;
+ epub_document->tmp_archive_dir = NULL ;
+ epub_document->contentList = NULL ;
+ epub_document->currentpageuri = NULL;
+}
+
+static gboolean
+epub_document_load (EvDocument* document,
+ const char* uri,
+ GError** error)
+{
+ EpubDocument *epub_document = EPUB_DOCUMENT(document);
+ GError* err = NULL ;
+ gchar* containeruri ;
+ GString *containerpath ;
+ gchar* contentOpfUri ;
+ if ( check_mime_type (uri,&err) == FALSE )
+ {
+ /*Error would've been set by the function*/
+ g_propagate_error(error,err);
+ return FALSE;
+ }
+
+ /*FIXME : can this be different, ever?*/
+ containerpath = g_string_new(epub_document->tmp_archive_dir);
+ g_string_append_printf(containerpath,"/META-INF/container.xml");
+ containeruri = g_filename_to_uri(containerpath->str,NULL,&err);
+
+ if ( err )
+ {
+ g_propagate_error(error,err);
+ return FALSE;
+ }
+ contentOpfUri = get_uri_to_content (containeruri,&err,epub_document->tmp_archive_dir);
+
+ if ( contentOpfUri == NULL )
+ {
+ g_propagate_error(error,err);
+ return FALSE;
+ }
+
+ epub_document->contentList = setup_document_content_list (contentOpfUri,&err,epub_document->tmp_archive_dir);
+
+ if ( epub_document->contentList == NULL )
+ {
+ g_propagate_error(error,err);
+ return FALSE;
+ }
+
+ return TRUE ;
+}
+
+static void
+epub_document_finalize (GObject *object)
+{
+ EpubDocument *epub_document = EPUB_DOCUMENT (object);
+
+ if (epub_document->epubDocument != NULL) {
+ if (epub_remove_temporary_dir (epub_document->tmp_archive_dir) == -1)
+ g_warning (_("There was an error deleting ā€œ%sā€."),
+ epub_document->tmp_archive_dir);
+ g_free (epub_document->tmp_archive_dir);
+ }
+
+ if ( epub_document->contentList ) {
+ g_list_free_full(epub_document->contentList,(GDestroyNotify)free_tree_nodes);
+ }
+
+ g_free (epub_document->tmp_archive_dir);
+ g_free (epub_document->currentpageuri);
+ g_free (epub_document->archivename);
+
+ G_OBJECT_CLASS (epub_document_parent_class)->finalize (object);
+}
+
+static void
+epub_document_class_init (EpubDocumentClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
+
+ gobject_class->finalize = epub_document_finalize;
+
+ ev_document_class->load = epub_document_load;
+ ev_document_class->save = epub_document_save;
+ ev_document_class->get_n_pages = epub_document_get_n_pages;
+ ev_document_class->get_page_size = epub_document_get_page_size;
+ ev_document_class->render = epub_document_render;
+}