diff options
Diffstat (limited to 'backend/epub/epub-document.c')
-rw-r--r-- | backend/epub/epub-document.c | 503 |
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; +} |