diff options
35 files changed, 6211 insertions, 149 deletions
diff --git a/atril-view.h b/atril-view.h index b9261c97..7ed8898a 100644 --- a/atril-view.h +++ b/atril-view.h @@ -26,6 +26,7 @@ #include <libview/ev-document-model.h> #include <libview/ev-print-operation.h> #include <libview/ev-view.h> +#include <libview/ev-web-view.h> #include <libview/ev-view-type-builtins.h> #include <libview/ev-stock-icons.h> diff --git a/backend/Makefile.am b/backend/Makefile.am index ef76c4ee..49bfdf6a 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -6,6 +6,10 @@ if ENABLE_PDF SUBDIRS += pdf endif +if ENABLE_EPUB +SUBDIRS += epub +endif + if ENABLE_PS SUBDIRS += ps endif diff --git a/backend/epub/Makefile.am b/backend/epub/Makefile.am new file mode 100644 index 00000000..31dd455e --- /dev/null +++ b/backend/epub/Makefile.am @@ -0,0 +1,37 @@ +SUBDIRS = minizip + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/libdocument \ + -I$(srcdir)/minizip \ + -DMATELOCALEDIR=\"$(datadir)/locale\" \ + -DATRIL_COMPILATION \ + $(BACKEND_CFLAGS) \ + $(WARN_CXXFLAGS) \ + $(WEBKIT_CFLAGS) \ + $(DISABLE_DEPRECATED) + +backend_LTLIBRARIES = libepubdocument.la + +libepubdocument_la_SOURCES = \ + epub-document.c \ + epub-document.h + +libepubdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS) +libepubdocument_la_LIBADD = \ + $(top_builddir)/libdocument/libatrildocument.la \ + minizip/libminizip.la \ + $(WEBKIT_LIBS) \ + $(BACKEND_LIBS) + + +backend_in_files = epubdocument.atril-backend.in +backend_DATA = $(backend_in_files:.atril-backend.in=.atril-backend) + +EXTRA_DIST = $(backend_in_files) + +CLEANFILES = $(backend_DATA) + +@EV_INTLTOOL_ATRIL_BACKEND_RULE@ + +-include $(top_srcdir)/git.mk diff --git a/backend/epub/epub-document.c b/backend/epub/epub-document.c new file mode 100644 index 00000000..d0dce118 --- /dev/null +++ b/backend/epub/epub-document.c @@ -0,0 +1,1391 @@ +/* this file is part of atril, a mate document viewer + * + * Copyright (C) 2014 Avishkar Gupta + * + * Author: + * Avishkar Gupta <[email protected]> + * + * Atril is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Atril is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "epub-document.h" +#include "ev-file-helpers.h" +#include "unzip.h" +#include "ev-document-thumbnails.h" +#include "ev-document-find.h" +#include "ev-document-links.h" +#include "ev-document-misc.h" +#include <libxml/parser.h> +#include <libxml/xmlmemory.h> +#include <libxml/HTMLparser.h> +#include <config.h> + +#include <glib/gi18n.h> +#include <glib/gstdio.h> + +#include <gtk/gtk.h> + +/*For strcasestr(),strstr()*/ +#include <string.h> + +typedef enum _xmlParseReturnType +{ + XML_ATTRIBUTE, + XML_KEYWORD +}xmlParseReturnType; + +typedef struct _contentListNode { + gchar* key ; + gchar* value ; + gint index ; +}contentListNode; + +typedef struct _linknode { + gchar *pagelink; + gchar *linktext; + guint page; +}linknode; + +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 ; + /* A variable to hold our epubDocument for unzipping*/ + unzFile epubDocument ; + /*The (sub)directory that actually houses the document*/ + gchar* documentdir; + /*Stores the table of contents*/ + GList *index; + /*Document title, for the sidebar links*/ + gchar *docTitle; +}; + +static void epub_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface); +static void epub_document_document_find_iface_init (EvDocumentFindInterface *iface); +static void epub_document_document_links_iface_init (EvDocumentLinksInterface *iface); + +EV_BACKEND_REGISTER_WITH_CODE (EpubDocument, epub_document, + { + EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS, + epub_document_document_thumbnails_iface_init); + EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND, + epub_document_document_find_iface_init); + EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS, + epub_document_document_links_iface_init); + + } ); + +static void +epub_document_thumbnails_get_dimensions (EvDocumentThumbnails *document, + EvRenderContext *rc, + gint *width, + gint *height) +{ + gdouble page_width, page_height; + + page_width = 800; + page_height = 1080; + + *width = MAX ((gint)(page_width * rc->scale + 0.5), 1); + *height = MAX ((gint)(page_height * rc->scale + 0.5), 1); +} + +static GdkPixbuf * +epub_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document, + EvRenderContext *rc, + gboolean border) +{ + cairo_surface_t *webpage; + GdkPixbuf *thumbnailpix = NULL ; + gint width,height; + epub_document_thumbnails_get_dimensions(document,rc,&width,&height); + webpage = ev_document_misc_surface_rotate_and_scale(rc->page->backend_page,width,height,0); + thumbnailpix = ev_document_misc_pixbuf_from_surface(webpage); + return thumbnailpix; +} + +static gboolean +in_tag(const char* found) +{ + const char* bracket = found ; + + /* Since the dump started with the body tag, the '<' will be the first + * character in the haystack. + */ + while (*bracket != '<') { + bracket--; + if (*bracket == '>') { + /*We encounted a close brace before an open*/ + return FALSE ; + } + } + + return TRUE; +} + +static int +get_substr_count(const char * haystack,const char *needle,gboolean case_sensitive) +{ + const char* tmp = haystack ; + char* (*string_compare_function)(const char*,const char*); + int count=0; + if (case_sensitive) { + string_compare_function = strstr ; + } + else { + string_compare_function = strcasestr; + } + + while ((tmp=string_compare_function(tmp,needle))) { + if (!in_tag(tmp)) { + count++; + } + tmp = tmp + strlen(needle); + } + + return count; +} + +static guint +epub_document_check_hits(EvDocumentFind *document_find, + EvPage *page, + const gchar *text, + gboolean case_sensitive) +{ + gchar *filepath = g_filename_from_uri((gchar*)page->backend_page,NULL,NULL); + htmlDocPtr htmldoc = xmlParseFile(filepath); + htmlNodePtr htmltag = xmlDocGetRootElement(htmldoc); + int count=0; + htmlNodePtr bodytag = htmltag->xmlChildrenNode; + + while ( xmlStrcmp(bodytag->name,(xmlChar*)"body") ) { + bodytag = bodytag->next; + } + + xmlBufferPtr bodybuffer = xmlBufferCreate(); + xmlNodeDump(bodybuffer,htmldoc,bodytag,0,1); + + count = get_substr_count((char*)bodybuffer->content,text,case_sensitive); + + xmlBufferFree(bodybuffer); + xmlFreeDoc(htmldoc); + + return count; +} + +static gboolean +epub_document_links_has_document_links(EvDocumentLinks *document_links) +{ + EpubDocument *epub_document = EPUB_DOCUMENT(document_links); + + g_return_if_fail(EPUB_IS_DOCUMENT(epub_document)); + + if (!epub_document->index) + return FALSE; + + return TRUE; +} + + +typedef struct _LinksCBStruct { + GtkTreeModel *model; + GtkTreeIter *parent; +}LinksCBStruct; + +static void +epub_document_make_tree_entry(linknode* ListData,LinksCBStruct* UserData) +{ + GtkTreeIter tree_iter; + EvLink *link = NULL; + gboolean expand; + char *title_markup; + + //These are all children of the document title, and have no chlidren nodes + expand = FALSE; + + EvLinkDest *ev_dest = NULL; + EvLinkAction *ev_action; + + /* We shall use a EV_LINK_DEST_TYPE_PAGE for page links, + * and a EV_LINK_DEST_TYPE_HLINK(custom) for refs on a page of type url#label + * because we need both dest and page label for this. + */ + + if (g_strrstr(ListData->pagelink,"#") == NULL) { + ev_dest = ev_link_dest_new_page(ListData->page); + } + else { + ev_dest = ev_link_dest_new_hlink((gchar*)ListData->pagelink,ListData->page); + } + + ev_action = ev_link_action_new_dest (ev_dest); + + link = ev_link_new((gchar*)ListData->linktext,ev_action); + + gtk_tree_store_append (GTK_TREE_STORE (UserData->model), &tree_iter,(UserData->parent)); + title_markup = g_strdup((gchar*)ListData->linktext); + + gtk_tree_store_set (GTK_TREE_STORE (UserData->model), &tree_iter, + EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup, + EV_DOCUMENT_LINKS_COLUMN_LINK, link, + EV_DOCUMENT_LINKS_COLUMN_EXPAND, expand, + -1); + + g_free (title_markup); + g_object_unref (link); +} + +static GtkTreeModel * +epub_document_links_get_links_model(EvDocumentLinks *document_links) +{ + GtkTreeModel *model = NULL; + + g_return_val_if_fail (EPUB_IS_DOCUMENT (document_links), NULL); + + EpubDocument *epub_document = EPUB_DOCUMENT(document_links); + + model = (GtkTreeModel*) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, + G_TYPE_OBJECT, + G_TYPE_BOOLEAN, + G_TYPE_STRING); + + LinksCBStruct linkStruct; + linkStruct.model = model; + EvLink *link = ev_link_new(epub_document->docTitle, + ev_link_action_new_dest(ev_link_dest_new_page(0))); + GtkTreeIter parent; + + linkStruct.parent = &parent; + + gtk_tree_store_append (GTK_TREE_STORE (model), &parent,NULL); + + gtk_tree_store_set (GTK_TREE_STORE (model), &parent, + EV_DOCUMENT_LINKS_COLUMN_MARKUP, epub_document->docTitle, + EV_DOCUMENT_LINKS_COLUMN_LINK, link, + EV_DOCUMENT_LINKS_COLUMN_EXPAND, TRUE, + -1); + + g_object_unref(link); + + if (epub_document->index) { + g_list_foreach (epub_document->index,(GFunc)epub_document_make_tree_entry,&linkStruct); + } + + return model; +} + +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; +} + +static void +epub_document_document_find_iface_init (EvDocumentFindInterface *iface) +{ + iface->check_for_hits = epub_document_check_hits; +} + +static void +epub_document_document_links_iface_init(EvDocumentLinksInterface *iface) +{ + iface->has_document_links = epub_document_links_has_document_links; + iface->get_links_model = epub_document_links_get_links_model; +} + +static gboolean +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); +} + +/** + * 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 +open_xml_document (const gchar* filename); + +static gboolean +set_xml_root_node (xmlChar* rootname); + +static xmlNodePtr +xml_get_pointer_to_node (xmlChar* parserfor, + xmlChar* attributename, + xmlChar* attributevalue); +static void +xml_parse_children_of_node (xmlNodePtr parent, + xmlChar* parserfor, + xmlChar* attributename, + xmlChar* attributevalue); + +static gboolean +xml_check_attribute_value (xmlNode* node, + xmlChar * attributename, + xmlChar* attributevalue); + +static xmlChar* +xml_get_data_from_node (xmlNodePtr node, + xmlParseReturnType rettype, + xmlChar* attributename); + +static void +xml_free_doc(); + +static void +free_tree_nodes (gpointer data); + +/*Global variables for XML parsing*/ +static xmlDocPtr xmldocument ; +static xmlNodePtr xmlroot ; +static xmlNodePtr xmlretval ; + +/* +**Functions to parse the xml files. +**Open a XML document for reading +*/ +static gboolean +open_xml_document ( const gchar* filename ) +{ + xmldocument = xmlParseFile(filename); + + if ( xmldocument == NULL ) + { + return FALSE ; + } + else + { + return TRUE ; + } +} + +/** + *Check if the root value is same as rootname . + *if supplied rootvalue = NULL ,just set root to rootnode . +**/ +static gboolean +set_xml_root_node(xmlChar* rootname) +{ + xmlroot = xmlDocGetRootElement(xmldocument); + + if (xmlroot == NULL) { + + xmlFreeDoc(xmldocument); + return FALSE; + } + + if ( rootname == NULL ) + { + return TRUE ; + } + + if ( !xmlStrcmp(xmlroot->name,rootname)) + { + return TRUE ; + } + else + { + return FALSE; + } +} + +static xmlNodePtr +xml_get_pointer_to_node(xmlChar* parserfor, + xmlChar* attributename, + xmlChar* attributevalue ) +{ + xmlNodePtr topchild,children ; + + xmlretval = NULL ; + + if ( !xmlStrcmp( xmlroot->name, parserfor) ) + { + return xmlroot ; + } + + topchild = xmlroot->xmlChildrenNode ; + + while ( topchild != NULL ) + { + if ( !xmlStrcmp(topchild->name,parserfor) ) + { + if ( xml_check_attribute_value(topchild,attributename,attributevalue) == TRUE ) + { + xmlretval = topchild; + return xmlretval; + } + else + { + /*No need to parse children node*/ + topchild = topchild->next ; + continue ; + } + } + + xml_parse_children_of_node(topchild , parserfor, attributename, attributevalue) ; + + topchild = topchild->next ; + } + + return xmlretval ; +} + +static void +xml_parse_children_of_node(xmlNodePtr parent, + xmlChar* parserfor, + xmlChar* attributename, + xmlChar* attributevalue ) +{ + xmlNodePtr child = parent->xmlChildrenNode ; + + while ( child != NULL ) + { + if ( !xmlStrcmp(child->name,parserfor)) + { + if ( xml_check_attribute_value(child,attributename,attributevalue) == TRUE ) + { + xmlretval = child; + return ; + } + else + { + /*No need to parse children node*/ + child = child->next ; + continue ; + } + } + + /*return already if we have xmlretval set*/ + if ( xmlretval != NULL ) + { + return ; + } + + xml_parse_children_of_node(child,parserfor,attributename,attributevalue) ; + child = child->next ; + } +} + +static void +xml_free_doc() +{ + xmlFreeDoc(xmldocument); + xmldocument = NULL; +} + +static gboolean +xml_check_attribute_value(xmlNode* node, + xmlChar * attributename, + xmlChar* attributevalue) +{ + xmlChar* attributefromfile ; + if ( attributename == NULL || attributevalue == NULL ) + { + return TRUE ; + } + else if ( !xmlStrcmp(( attributefromfile = xmlGetProp(node,attributename)), + attributevalue) ) + { + xmlFree(attributefromfile); + return TRUE ; + } + xmlFree(attributefromfile); + return FALSE ; +} + +static xmlChar* +xml_get_data_from_node(xmlNodePtr node, + xmlParseReturnType rettype, + xmlChar* attributename) +{ + xmlChar* datastring ; + if ( rettype == XML_ATTRIBUTE ) + datastring= xmlGetProp(node,attributename); + else + datastring= xmlNodeListGetString(xmldocument,node->xmlChildrenNode, 1); + + return datastring; +} + +static gboolean +check_mime_type(const gchar* uri,GError** error) +{ + GError * err = NULL ; + const gchar* mimeFromFile = ev_file_get_mime_type(uri,FALSE,&err); + + gchar* mimetypes[] = {"application/epub+zip","application/x-booki+zip"}; + int typecount = 2; + if ( !mimeFromFile ) + { + if (err) { + g_propagate_error (error, err); + } + else { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("Unknown MIME Type")); + } + return FALSE; + } + else + { + int i=0; + for (i=0; i < typecount ;i++) { + if ( g_strcmp0(mimeFromFile, mimetypes[i]) == 0 ) { + return TRUE; + } + } + + /*We didn't find a match*/ + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("Not an ePub document")); + + return FALSE; + } +} + +static gboolean +extract_one_file(EpubDocument* epub_document,GError ** error) +{ + GFile * outfile ; + gsize writesize = 0; + GString * gfilepath ; + unz_file_info64 info ; + gchar* directory; + GString* dir_create; + GFileOutputStream * outstream ; + gpointer currentfilename = g_malloc0(512); + gpointer buffer = g_malloc0(512); + gchar* createdirnametemp = NULL ; + gchar* createdirname = NULL; + 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); + unzCloseCurrentFile (epub_document->epubDocument) ; + g_string_free(gfilepath,TRUE); + g_free(currentfilename); + g_free(buffer); + return TRUE; + } + else if (directory != NULL && *directory != '\0' ) { + gchar* createdir = currentfilename; + /*Since a substring can't be longer than the parent string, allocating space equal to the parent's size should suffice*/ + createdirname = g_malloc0(strlen(currentfilename)); + /* Add the name of the directory and subdiectories,if any to a buffer and then create it */ + createdirnametemp = createdirname; + while ( createdir != directory ) { + (*createdirnametemp) = (*createdir); + createdirnametemp++; + createdir++; + } + (*createdirnametemp) = '\0'; + dir_create = g_string_new(epub_document->tmp_archive_dir); + g_string_append_printf(dir_create,"/%s",createdirname); + g_mkdir_with_parents(dir_create->str,0777); + g_string_free(dir_create,TRUE); + } + + 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); + if ( createdirname != NULL) { + g_free(createdirname); + } + return TRUE; +} + +static gboolean +extract_epub_from_container (const gchar* uri, + EpubDocument *epub_document, + GError ** error) +{ + GError* err = NULL ; + GString * temporary_sub_directory ; + epub_document->archivename = g_filename_from_uri(uri,NULL,error); + gchar* epubfilename ; + if ( !epub_document->archivename ) + { + if (err) { + g_propagate_error (error, err); + } + else { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not retrieve filename")); + } + return FALSE ; + } + + epubfilename = g_strrstr(epub_document->archivename,"/"); + if ( *epubfilename == '/' ) + epubfilename++ ; + + temporary_sub_directory = g_string_new( epubfilename ); + g_string_append(temporary_sub_directory,"XXXXXX") ; + + epub_document->tmp_archive_dir = ev_mkdtemp(temporary_sub_directory->str,error) ; + + if (!epub_document->tmp_archive_dir) { + return FALSE ; + } + + g_string_free(temporary_sub_directory,TRUE); + + epub_document->epubDocument = unzOpen64(epub_document->archivename); + + if ( epub_document->epubDocument == NULL ) + { + if (err) { + g_propagate_error (error, err); + } + else { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not open archive")); + } + return FALSE ; + } + if ( unzGoToFirstFile(epub_document->epubDocument) != UNZ_OK ) + { + if (err) { + g_propagate_error (error, err); + } + else { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not extract archive")); + } + return FALSE ; + } + while ( TRUE ) + { + if ( extract_one_file(epub_document,&err) == FALSE ) + { + if (err) { + g_propagate_error (error, err); + } + else { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not extract archive")); + } + return FALSE; + } + + if ( unzGoToNextFile(epub_document->epubDocument) == UNZ_END_OF_LIST_OF_FILE ) + break ; + } + + unzClose(epub_document->epubDocument); + return TRUE ; +} + +static gchar* +get_uri_to_content(const gchar* uri,GError ** error,EpubDocument *epub_document) +{ + gchar* tmp_archive_dir = epub_document->tmp_archive_dir; + GError * err = NULL ; + gchar* containerpath = g_filename_from_uri(uri,NULL,&err); + GString* absolutepath ; + gchar* content_uri ; + xmlNodePtr rootfileNode ; + xmlChar* relativepath; + gchar* directorybuffer = g_malloc0(sizeof(gchar*)*100); + + if ( !containerpath ) + { + if (err) { + g_propagate_error (error,err); + } + else { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not retrieve container file")); + } + return NULL ; + } + + if ( open_xml_document(containerpath) == FALSE ) + { + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not open container file")); + + return NULL ; + } + + if ( set_xml_root_node((xmlChar*)"container") == FALSE) { + + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("container file is corrupt")); + return NULL ; + } + + if ( (rootfileNode = xml_get_pointer_to_node((xmlChar*)"rootfile",(xmlChar*)"media-type",(xmlChar*)"application/oebps-package+xml")) == NULL) + { + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("epub file is invalid or corrput")); + return NULL ; + } + + relativepath = xml_get_data_from_node(rootfileNode,XML_ATTRIBUTE,(xmlChar*)"full-path") ; + if ( relativepath == NULL ) + { + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("epub file is corrupt,no container")); + return NULL ; + } + absolutepath = g_string_new(tmp_archive_dir); + gchar* documentfolder = g_strrstr((gchar*)relativepath,"/"); + if (documentfolder != NULL) { + gchar* copybuffer = (gchar*)relativepath ; + gchar* writer = directorybuffer; + + while(copybuffer != documentfolder) { + (*writer) = (*copybuffer); + writer++;copybuffer++; + } + *writer = '\0'; + GString *documentdir = g_string_new(tmp_archive_dir); + g_string_append_printf(documentdir,"/%s",directorybuffer); + epub_document->documentdir = g_strdup(documentdir->str); + + g_string_free(documentdir,TRUE); + } + else + { + epub_document->documentdir = g_strdup(tmp_archive_dir); + } + + g_string_append_printf(absolutepath,"/%s",relativepath); + content_uri = g_filename_to_uri(absolutepath->str,NULL,&err); + if ( !content_uri ) { + if (err) { + g_propagate_error (error,err); + } + else { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not retrieve container file")); + } + return NULL ; + } + g_string_free(absolutepath,TRUE); + g_free(directorybuffer); + xml_free_doc(); + return content_uri ; +} + +static gboolean +link_present_on_page(const gchar* link,const gchar *page_uri) +{ + if (g_strrstr(link, page_uri)) { + return TRUE; + } + else { + return FALSE; + } +} + +static GList* +setup_document_content_list(const gchar* content_uri, GError** error,gchar *documentdir,GList *docindex) +{ + GList* newlist = NULL ; + GError * err = NULL ; + gint indexcounter= 1; + xmlNodePtr manifest,spine,itemrefptr,itemptr ; + gboolean errorflag = FALSE; + GList *indexcopy = docindex,*indexcopyiter = docindex; + gchar* relativepath ; + GString* absolutepath = g_string_new(NULL); + + if ( open_xml_document(content_uri) == FALSE ) + { + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("could not parse content manifest")); + + return FALSE ; + } + if ( set_xml_root_node((xmlChar*)"package") == FALSE) { + + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("content file is invalid")); + return FALSE ; + } + + if ( ( spine = xml_get_pointer_to_node((xmlChar*)"spine",NULL,NULL) )== NULL ) + { + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("epub file has no spine")); + return FALSE ; + } + + if ( ( manifest = xml_get_pointer_to_node((xmlChar*)"manifest",NULL,NULL) )== NULL ) + { + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("epub file has no manifest")); + return FALSE ; + } + + xmlretval = NULL ; + + /*Get first instance of itemref from the spine*/ + xml_parse_children_of_node(spine,(xmlChar*)"itemref",NULL,NULL); + + if ( xmlretval != NULL ) + itemrefptr = xmlretval ; + else + { + errorflag=TRUE; + } + /*Parse the spine for remaining itemrefs*/ + do + { + indexcopyiter = indexcopy ; + /*for the first time that we enter the loop, if errorflag is set we break*/ + if ( errorflag ) + { + break; + } + if ( xmlStrcmp(itemrefptr->name,(xmlChar*)"itemref") == 0) + { + contentListNode* newnode = g_malloc0(sizeof(newnode)); + newnode->key = (gchar*)xml_get_data_from_node(itemrefptr,XML_ATTRIBUTE,(xmlChar*)"idref"); + if ( newnode->key == NULL ) + { + errorflag =TRUE; + break; + } + xmlretval=NULL ; + xml_parse_children_of_node(manifest,(xmlChar*)"item",(xmlChar*)"id",(xmlChar*)newnode->key); + + if ( xmlretval != NULL ) + { + itemptr = xmlretval ; + } + else + { + errorflag=TRUE; + break; + } + relativepath = (gchar*)xml_get_data_from_node(itemptr,XML_ATTRIBUTE,(xmlChar*)"href"); + g_string_assign(absolutepath,documentdir); + g_string_append_printf(absolutepath,"/%s",relativepath); + newnode->value = g_filename_to_uri(absolutepath->str,NULL,&err); + if ( newnode->value == NULL ) + { + errorflag =TRUE; + break; + } + + newnode->index = indexcounter++ ; + + /* NOTE:Because the TOC is not always in a sorted manner, we need to check all remaining pages every time. + */ + while (indexcopyiter != NULL) { + linknode *linkdata = indexcopyiter->data; + + if (link_present_on_page(linkdata->pagelink,newnode->value)) { + linkdata->page = newnode->index - 1; + indexcopy = indexcopy->next; + } + indexcopyiter = indexcopyiter->next; + } + + newlist = g_list_prepend(newlist,newnode); + } + itemrefptr = itemrefptr->next ; + } + while ( itemrefptr != NULL ); + + if ( errorflag ) + { + if ( err ) + { + g_propagate_error(error,err); + } + else + { + g_set_error_literal(error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("Could not set up document tree for loading, some files missing")); + } + /*free any nodes that were set up and return empty*/ + g_string_free(absolutepath,TRUE); + g_list_free_full(newlist,(GDestroyNotify)free_tree_nodes); + return NULL ; + } + newlist = g_list_reverse(newlist); + g_string_free(absolutepath,TRUE); + xml_free_doc(); + return newlist ; + +} + +/* Callback function to free the contentlist.*/ +static void +free_tree_nodes(gpointer data) +{ + contentListNode* dataptr = data ; + g_free(dataptr->value); + g_free(dataptr->key); + g_free(dataptr); +} + +static void +free_link_nodes(gpointer data) +{ + linknode* dataptr = data ; + g_free(dataptr->pagelink); + g_free(dataptr->linktext); + g_free(dataptr); +} + +static gchar* +get_toc_file_name(gchar *containeruri) +{ + gchar *containerfilename = g_filename_from_uri(containeruri,NULL,NULL); + + open_xml_document(containerfilename); + + set_xml_root_node(NULL); + + xmlNodePtr manifest = xml_get_pointer_to_node((xmlChar*)"manifest",NULL,NULL); + xmlNodePtr spine = xml_get_pointer_to_node((xmlChar*)"spine",NULL,NULL); + + xmlChar *ncx = xml_get_data_from_node(spine,XML_ATTRIBUTE,(xmlChar*)"toc"); + xmlretval = NULL; + xml_parse_children_of_node(manifest,(xmlChar*)"item",(xmlChar*)"id",ncx); + + gchar* tocfilename = (gchar*)xml_get_data_from_node(xmlretval,XML_ATTRIBUTE,(xmlChar*)"href"); + xml_free_doc(); + + return tocfilename; +} + +static GList* +setup_document_index(EpubDocument *epub_document,gchar *containeruri) +{ + GString *tocpath = g_string_new(epub_document->documentdir); + gchar *tocfilename = get_toc_file_name(containeruri); + GList *index = NULL; + g_string_append_printf (tocpath,"/%s",tocfilename); + GString *pagelink; + open_xml_document(tocpath->str); + g_string_free(tocpath,TRUE); + set_xml_root_node((xmlChar*)"ncx"); + + xmlNodePtr docTitle = xml_get_pointer_to_node((xmlChar*)"docTitle",NULL,NULL); + xmlretval = NULL; + xml_parse_children_of_node(docTitle,(xmlChar*)"text",NULL,NULL); + + while (epub_document->docTitle == NULL && xmlretval != NULL) { + epub_document->docTitle = (gchar*)xml_get_data_from_node(xmlretval,XML_KEYWORD,NULL); + xmlretval = xmlretval->next; + } + xmlNodePtr navMap = xml_get_pointer_to_node((xmlChar*)"navMap",NULL,NULL); + xmlretval = NULL; + xml_parse_children_of_node(navMap,(xmlChar*)"navPoint",NULL,NULL); + + xmlNodePtr navPoint = xmlretval; + + do { + + if ( !xmlStrcmp(navPoint->name,(xmlChar*)"navPoint")) { + xmlretval = NULL; + xml_parse_children_of_node(navPoint,(xmlChar*)"navLabel",NULL,NULL); + xmlNodePtr navLabel = xmlretval; + xmlretval = NULL; + gchar *fragment=NULL,*end=NULL; + GString *uri = NULL; + + xml_parse_children_of_node(navLabel,(xmlChar*)"text",NULL,NULL); + linknode *newnode = g_new0(linknode,1); + newnode->linktext = NULL; + while (newnode->linktext == NULL) { + newnode->linktext = (gchar*)xml_get_data_from_node(xmlretval,XML_KEYWORD,NULL); + xmlretval = xmlretval->next; + } + xmlretval = NULL; + xml_parse_children_of_node(navPoint,(xmlChar*)"content",NULL,NULL); + pagelink = g_string_new(epub_document->documentdir); + newnode->pagelink = (gchar*)xml_get_data_from_node(xmlretval,XML_ATTRIBUTE,(xmlChar*)"src"); + g_string_append_printf(pagelink,"/%s",newnode->pagelink); + xmlFree(newnode->pagelink); + + if ((end = g_strrstr(pagelink->str,"#")) != NULL) { + fragment = g_strdup(g_strrstr(pagelink->str,"#")); + *end = '\0'; + } + uri = g_string_new(g_filename_to_uri(pagelink->str,NULL,NULL)); + g_string_free(pagelink,TRUE); + + if (fragment) { + g_string_append(uri,fragment); + } + + newnode->pagelink = g_strdup(uri->str); + g_string_free(uri,TRUE); + index = g_list_prepend(index,newnode); + } + + navPoint = navPoint->next; + + } while(navPoint != NULL); + + xml_free_doc(); + + return g_list_reverse(index); +} + +static EvDocumentInfo* +epub_document_get_info(EvDocument *document) +{ + EpubDocument *epub_document = EPUB_DOCUMENT(document); + GError *error = NULL ; + gchar* infofile ; + xmlNodePtr metanode ; + GString* buffer ; + gchar* archive_dir = epub_document->tmp_archive_dir; + GString* containerpath = g_string_new(epub_document->tmp_archive_dir); + g_string_append_printf(containerpath,"/META-INF/container.xml"); + gchar* containeruri = g_filename_to_uri(containerpath->str,NULL,&error); + if ( error ) + { + return NULL ; + } + gchar* uri = get_uri_to_content (containeruri,&error,epub_document); + if ( error ) + { + return NULL ; + } + EvDocumentInfo* epubinfo = g_new0 (EvDocumentInfo, 1); + + epubinfo->fields_mask = EV_DOCUMENT_INFO_TITLE | + EV_DOCUMENT_INFO_FORMAT | + EV_DOCUMENT_INFO_AUTHOR | + EV_DOCUMENT_INFO_SUBJECT | + EV_DOCUMENT_INFO_KEYWORDS | + EV_DOCUMENT_INFO_LAYOUT | + EV_DOCUMENT_INFO_CREATOR | + EV_DOCUMENT_INFO_LINEARIZED | + EV_DOCUMENT_INFO_PERMISSIONS | + EV_DOCUMENT_INFO_N_PAGES ; + + infofile = g_filename_from_uri(uri,NULL,&error); + if ( error ) + return epubinfo; + + open_xml_document(infofile); + + set_xml_root_node((xmlChar*)"package"); + + metanode = xml_get_pointer_to_node((xmlChar*)"title",NULL,NULL); + if ( metanode == NULL ) + epubinfo->title = NULL ; + else + epubinfo->title = (char*)xml_get_data_from_node(metanode,XML_KEYWORD,NULL); + + metanode = xml_get_pointer_to_node((xmlChar*)"creator",NULL,NULL); + if ( metanode == NULL ) + epubinfo->author = g_strdup("unknown"); + else + epubinfo->author = (char*)xml_get_data_from_node(metanode,XML_KEYWORD,NULL); + + metanode = xml_get_pointer_to_node((xmlChar*)"subject",NULL,NULL); + if ( metanode == NULL ) + epubinfo->subject = g_strdup("unknown"); + else + epubinfo->subject = (char*)xml_get_data_from_node(metanode,XML_KEYWORD,NULL); + + buffer = g_string_new((gchar*)xml_get_data_from_node (xmlroot,XML_ATTRIBUTE,(xmlChar*)"version")); + g_string_prepend(buffer,"epub "); + epubinfo->format = g_strdup(buffer->str); + + /*FIXME: Add more of these as you write the corresponding modules*/ + + epubinfo->layout = EV_DOCUMENT_LAYOUT_SINGLE_PAGE; + + metanode = xml_get_pointer_to_node((xmlChar*)"publisher",NULL,NULL); + if ( metanode == NULL ) + epubinfo->creator = g_strdup("unknown"); + else + epubinfo->creator = (char*)xml_get_data_from_node(metanode,XML_KEYWORD,NULL); + + /* number of pages */ + epubinfo->n_pages = epub_document_get_n_pages(document); + + /*Copying*/ + epubinfo->permissions = EV_DOCUMENT_PERMISSIONS_OK_TO_COPY; + /*TODO : Add a function to get date*/ + g_free(uri); + g_string_free(containerpath,TRUE); + g_string_free(buffer,TRUE); + + if (xmldocument) + xml_free_doc(); + return epubinfo ; +} + +static EvPage* +epub_document_get_page(EvDocument *document, + gint index) +{ + EpubDocument *epub_document = EPUB_DOCUMENT(document); + EvPage* page = ev_page_new(index); + contentListNode *listptr = g_list_nth_data (epub_document->contentList,index); + page->backend_page = g_strdup(listptr->value); + return page ; +} + + +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; + } + + extract_epub_from_container (uri,epub_document,&err); + + if ( err ) + { + 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); + + if ( contentOpfUri == NULL ) + { + g_propagate_error(error,err); + return FALSE; + } + + epub_document->index = setup_document_index(epub_document,contentOpfUri); + + epub_document->contentList = setup_document_content_list (contentOpfUri,&err,epub_document->documentdir,epub_document->index); + + if ( epub_document->contentList == NULL ) + { + g_propagate_error(error,err); + return FALSE; + } + + return TRUE ; +} + +static void +epub_document_init (EpubDocument *epub_document) +{ + epub_document->archivename = NULL ; + epub_document->tmp_archive_dir = NULL ; + epub_document->contentList = NULL ; + epub_document->documentdir = NULL; + epub_document->index = NULL; + epub_document->docTitle = NULL; +} + +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); + } + + if ( epub_document->contentList ) { + g_list_free_full(epub_document->contentList,(GDestroyNotify)free_tree_nodes); + epub_document->contentList = NULL; + } + + if (epub_document->index) { + g_list_free_full(epub_document->index,(GDestroyNotify)free_link_nodes); + epub_document->index = NULL; + } + + if ( epub_document->tmp_archive_dir) { + g_free (epub_document->tmp_archive_dir); + epub_document->tmp_archive_dir = NULL; + } + + if (epub_document->docTitle) { + g_free(epub_document->docTitle); + epub_document->docTitle = NULL; + } + if ( epub_document->archivename) { + g_free (epub_document->archivename); + epub_document->archivename = NULL; + } + if ( epub_document->documentdir) { + g_free (epub_document->documentdir); + epub_document->documentdir = NULL; + } + 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_info = epub_document_get_info; + ev_document_class->get_page = epub_document_get_page; +}
\ No newline at end of file diff --git a/backend/epub/epub-document.h b/backend/epub/epub-document.h new file mode 100644 index 00000000..b1120ec7 --- /dev/null +++ b/backend/epub/epub-document.h @@ -0,0 +1,21 @@ +#ifndef __EPUB_DOCUMENT_H__ +#define __EPUB_DOCUMENT_H__ + +#define _GNU_SOURCE +#include "ev-document.h" + +G_BEGIN_DECLS + +#define EPUB_TYPE_DOCUMENT (epub_document_get_type ()) +#define EPUB_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPUB_TYPE_DOCUMENT, EpubDocument)) +#define EPUB_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPUB_TYPE_DOCUMENT)) + +typedef struct _EpubDocument EpubDocument; + +GType epub_document_get_type (void) G_GNUC_CONST; + +G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module); + +G_END_DECLS + +#endif /* __EPUB_DOCUMENT_H__ */ diff --git a/backend/epub/epubdocument.atril-backend.in b/backend/epub/epubdocument.atril-backend.in new file mode 100644 index 00000000..ef7767eb --- /dev/null +++ b/backend/epub/epubdocument.atril-backend.in @@ -0,0 +1,4 @@ +[Atril Backend] +Module=epubdocument +_TypeDescription=epub Documents +MimeType=application/epub+zip; diff --git a/backend/epub/minizip/Makefile.am b/backend/epub/minizip/Makefile.am new file mode 100644 index 00000000..315fada0 --- /dev/null +++ b/backend/epub/minizip/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = \ + $(WARN_CFLAGS) \ + $(ZLIB_CFLAGS) + +noinst_LTLIBRARIES = libminizip.la + +libminizip_la_SOURCES = \ + unzip.c \ + ioapi.c + +libminizip_la_LIBADD = \ + $(ZLIB_LIBS) + +-include $(top_srcdir)/git.mk diff --git a/backend/epub/minizip/ioapi.c b/backend/epub/minizip/ioapi.c new file mode 100644 index 00000000..7f5c191b --- /dev/null +++ b/backend/epub/minizip/ioapi.c @@ -0,0 +1,247 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(__APPLE__) || defined(IOAPI_NO_64) +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == MAXU32) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = FOPEN_FUNC((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = FTELLO_FUNC((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/backend/epub/minizip/ioapi.h b/backend/epub/minizip/ioapi.h new file mode 100644 index 00000000..8dcbdb06 --- /dev/null +++ b/backend/epub/minizip/ioapi.h @@ -0,0 +1,208 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif + +#endif + +#include <stdio.h> +#include <stdlib.h> +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include <stdint.h> + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/backend/epub/minizip/unzip.c b/backend/epub/minizip/unzip.c new file mode 100644 index 00000000..90935043 --- /dev/null +++ b/backend/epub/minizip/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include <stddef.h> +# include <string.h> +# include <stdlib.h> +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include <errno.h> +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1<c2) + return -1; + if (c1>c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackRead<uMaxBack) + { + uLong uReadSize; + ZPOS64_T uReadPos ; + int i; + if (uBackRead+BUFREADCOMMENT>uMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackRead<uMaxBack) + { + uLong uReadSize; + ZPOS64_T uReadPos; + int i; + if (uBackRead+BUFREADCOMMENT>uMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pos<us.offset_central_dir+us.size_central_dir) && + (err==UNZ_OK)) + err=UNZ_BADZIPFILE; + + if (err!=UNZ_OK) + { + ZCLOSE64(us.z_filefunc, us.filestream); + return NULL; + } + + us.byte_before_the_zipfile = central_pos - + (us.offset_central_dir+us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + us.encrypted = 0; + + + s=(unz64_s*)ALLOC(sizeof(unz64_s)); + if( s != NULL) + { + *s=us; + unzGoToFirstFile((unzFile)s); + } + return (unzFile)s; +} + + +extern unzFile ZEXPORT unzOpen2 (const char *path, + zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0); + } + else + return unzOpenInternal(path, NULL, 0); +} + +extern unzFile ZEXPORT unzOpen2_64 (const void *path, + zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1); + } + else + return unzOpenInternal(path, NULL, 1); +} + +extern unzFile ZEXPORT unzOpen (const char *path) +{ + return unzOpenInternal(path, NULL, 0); +} + +extern unzFile ZEXPORT unzOpen64 (const void *path) +{ + return unzOpenInternal(path, NULL, 1); +} + +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzClose (unzFile file) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + if (s->pfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename<fileNameBufferSize) + { + *(szFileName+file_info.size_filename)='\0'; + uSizeRead = file_info.size_filename; + } + else + uSizeRead = fileNameBufferSize; + + if ((file_info.size_filename>0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extra<extraFieldBufferSize) + uSizeRead = file_info.size_file_extra; + else + uSizeRead = extraFieldBufferSize; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == MAXU32) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_comment<commentBufferSize) + { + *(szComment+file_info.size_file_comment)='\0'; + uSizeRead = file_info.size_file_comment; + } + else + uSizeRead = commentBufferSize; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if ((err==UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://[email protected]) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressed<uReadThis) + uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;i<uReadThis;i++) + pfile_in_zip_read_info->read_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;i<uDoCopy;i++) + *(pfile_in_zip_read_info->stream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/backend/epub/minizip/unzip.h b/backend/epub/minizip/unzip.h new file mode 100644 index 00000000..2104e391 --- /dev/null +++ b/backend/epub/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/configure.ac b/configure.ac index 13203bbf..fc297187 100644 --- a/configure.ac +++ b/configure.ac @@ -53,14 +53,14 @@ AM_MAINTAINER_MODE([enable]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -AM_PROG_LIBTOOL + AC_ISC_POSIX AC_PROG_CC AM_PROG_CC_C_O AC_PROG_CXX AC_STDC_HEADERS - +AM_PROG_LIBTOOL AC_PROG_SED AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal]) AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums]) @@ -688,6 +688,44 @@ AM_CONDITIONAL(ENABLE_XPS, test x$enable_xps = xyes) dnl ================== End of XPS checks =================================================== + +dnl ================== EPUB checks =================================================== + +AC_ARG_ENABLE(epub, + [AS_HELP_STRING([--enable-epub], + [Compile with support for epub documents.])], + [enable_epub=$enableval], + [enable_epub=yes]) + +if test "x$enable_epub" = "xyes"; then + WEBKIT_REQUIRED=2.4.2 + case "$with_gtk" in + 2.0) + PKG_CHECK_MODULES(WEBKIT, webkit-1.0 >= $WEBKIT_REQUIRED libxml-2.0 >= $LIBXML_REQUIRED zlib,enable_epub=yes,enable_epub=no) + ;; + 3.0) + PKG_CHECK_MODULES(WEBKIT, webkit2gtk-3.0 >= $WEBKIT_REQUIRED libxml-2.0 >= $LIBXML_REQUIRED zlib,enable_epub=yes,enable_epub=no) + ;; + esac + if test "x$enable_epub" = "xyes"; then + AC_DEFINE([ENABLE_EPUB], [1], [Enable support for ePub documents.]) + else + enable_epub="no" + AC_MSG_WARN(["ePub support is disabled since webkit-1.0( version >= $WEBKIT_REQUIRED ) is needed"]) + case "$with_gtk" in + 2.0) + AC_MSG_WARN(["ePub support is disabled since webkit-1.0( version >= $WEBKIT_REQUIRED ) is needed"]) + ;; + 3.0)AC_MSG_WARN(["ePub support is disabled since webkit2gtk-3.0( version >= $WEBKIT_REQUIRED ) is needed"]) + ;; + esac + fi +fi + +AM_CONDITIONAL(ENABLE_EPUB, test x$enable_epub = xyes) + +dnl ================== End of EPUB checks =================================================== + dnl =================== Mime types list ==================================================== if test "x$enable_pdf" = "xyes" ; then @@ -714,6 +752,10 @@ fi if test "x$enable_xps" = "xyes"; then ATRIL_MIME_TYPES="${ATRIL_MIME_TYPES}application/oxps;application/vnd.ms-xpsdocument;" fi +if test "x$enable_epub" = "xyes"; then + ATRIL_MIME_TYPES="${ATRIL_MIME_TYPES}application/epub+zip" +fi + AC_SUBST(ATRIL_MIME_TYPES) AC_CHECK_FUNC(localtime_r, AC_DEFINE(HAVE_LOCALTIME_R, 1, [Defines if localtime_r is available on your system])) @@ -766,6 +808,8 @@ backend/comics/Makefile backend/djvu/Makefile backend/dvi/Makefile backend/dvi/mdvi-lib/Makefile +backend/epub/Makefile +backend/epub/minizip/Makefile backend/pdf/Makefile backend/pixbuf/Makefile backend/ps/Makefile @@ -854,4 +898,5 @@ Configure summary: Pixbuf Backend.....: $enable_pixbuf Comics Backend.....: $enable_comics XPS Backend........: $enable_xps + ePub Backend.......: $enable_epub " diff --git a/help/reference/shell/Makefile.am b/help/reference/shell/Makefile.am index a78201d7..40ece8fc 100644 --- a/help/reference/shell/Makefile.am +++ b/help/reference/shell/Makefile.am @@ -106,6 +106,7 @@ GTKDOC_CFLAGS = \ -DATRIL_COMPILATION \ $(SHELL_CFLAGS) \ $(WARN_CFLAGS) \ + $(WEBKIT_CFLAGS) \ $(DISABLE_DEPRECATED) \ $(GTK_PRINT_CFLAGS) @@ -126,6 +127,7 @@ GTKDOC_LIBS = \ $(top_builddir)/libmisc/libevmisc.la \ $(SHELL_LIBS) \ $(GTK_PRINT_LIBS) \ + $(WEBKIT_LIBS) \ $(filter-out $(FILTER_OUT),$(wildcard $(top_builddir)/shell/*.o)) # This includes the standard gtk-doc make rules, copied by gtkdocize. diff --git a/libdocument/ev-document-find.c b/libdocument/ev-document-find.c index 0b5fac01..92dfffe5 100644 --- a/libdocument/ev-document-find.c +++ b/libdocument/ev-document-find.c @@ -40,3 +40,12 @@ ev_document_find_find_text (EvDocumentFind *document_find, return iface->find_text (document_find, page, text, case_sensitive); } +guint +ev_document_find_check_for_hits(EvDocumentFind *document_find, + EvPage *page, + const gchar *text, + gboolean case_sensitive) +{ + EvDocumentFindInterface *iface = EV_DOCUMENT_FIND_GET_IFACE (document_find); + return iface->check_for_hits (document_find, page, text, case_sensitive); +}
\ No newline at end of file diff --git a/libdocument/ev-document-find.h b/libdocument/ev-document-find.h index 7fcf49c7..2b6ba68b 100644 --- a/libdocument/ev-document-find.h +++ b/libdocument/ev-document-find.h @@ -52,6 +52,11 @@ struct _EvDocumentFindInterface EvPage *page, const gchar *text, gboolean case_sensitive); + + guint (* check_for_hits) (EvDocumentFind *document_find, + EvPage *page, + const gchar *text, + gboolean case_sensitive); }; GType ev_document_find_get_type (void) G_GNUC_CONST; @@ -60,6 +65,10 @@ GList *ev_document_find_find_text (EvDocumentFind *document_find, const gchar *text, gboolean case_sensitive); +guint ev_document_find_check_for_hits (EvDocumentFind *document_find, + EvPage *page, + const gchar *text, + gboolean case_sensitive); G_END_DECLS #endif /* EV_DOCUMENT_FIND_H */ diff --git a/libdocument/ev-document-thumbnails.c b/libdocument/ev-document-thumbnails.c index 9482e09e..65248683 100644 --- a/libdocument/ev-document-thumbnails.c +++ b/libdocument/ev-document-thumbnails.c @@ -59,5 +59,4 @@ ev_document_thumbnails_get_dimensions (EvDocumentThumbnails *document, iface = EV_DOCUMENT_THUMBNAILS_GET_IFACE (document); iface->get_dimensions (document, rc, width, height); -} - +}
\ No newline at end of file diff --git a/libdocument/ev-document-thumbnails.h b/libdocument/ev-document-thumbnails.h index 1a7cb9fd..5f425ef0 100644 --- a/libdocument/ev-document-thumbnails.h +++ b/libdocument/ev-document-thumbnails.h @@ -26,7 +26,7 @@ #define EV_DOCUMENT_THUMBNAILS_H #include <gdk-pixbuf/gdk-pixbuf.h> - +#include <gtk/gtk.h> #include "ev-render-context.h" G_BEGIN_DECLS @@ -52,6 +52,7 @@ struct _EvDocumentThumbnailsInterface { EvRenderContext *rc, gint *width, gint *height); + }; GType ev_document_thumbnails_get_type (void) G_GNUC_CONST; @@ -63,7 +64,6 @@ void ev_document_thumbnails_get_dimensions (EvDocumentThumbnails *document EvRenderContext *rc, gint *width, gint *height); - G_END_DECLS #endif /* EV_DOCUMENT_THUMBNAILS_H */ diff --git a/libdocument/ev-document.c b/libdocument/ev-document.c index 19d51d9b..a242bdf6 100644 --- a/libdocument/ev-document.c +++ b/libdocument/ev-document.c @@ -26,6 +26,7 @@ #include "ev-document.h" #include "synctex_parser.h" +#include "ev-file-helpers.h" #define EV_DOCUMENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EV_TYPE_DOCUMENT, EvDocumentPrivate)) @@ -141,6 +142,8 @@ ev_document_init (EvDocument *document) /* Assume all pages are the same size until proven otherwise */ document->priv->uniform = TRUE; + /* Assume that the document is not a web document*/ + document->iswebdocument = FALSE ; } static void @@ -237,6 +240,14 @@ ev_document_load (EvDocument *document, gboolean retval; GError *err = NULL; + /* + * Hardcoding a check for ePub documents, cause it needs a web document DOM + * and webkit, support for any other web document types can be added similarly. + */ + + if ( !g_strcmp0 (ev_file_get_mime_type(uri,TRUE,&err),"application/epub+zip") ) + document->iswebdocument=TRUE ; + retval = klass->load (document, uri, &err); if (!retval) { if (err) { @@ -258,18 +269,34 @@ ev_document_load (EvDocument *document, /* Cache some info about the document to avoid * going to the backends since it requires locks */ + priv->uri = g_strdup (uri); - priv->n_pages = _ev_document_get_n_pages (document); + priv->n_pages = _ev_document_get_n_pages (document); + for (i = 0; i < priv->n_pages; i++) { + + /* + * Since there is no sense of paging in an ePub,it makes no sense to have pages sizes. + * We are however geeneralising the scenario by considering epub as a type of web document. + * FIXME: Labels, or bookmarks though, can be done. + */ + EvPage *page = ev_document_get_page (document, i); gdouble page_width = 0; gdouble page_height = 0; EvPageSize *page_size; gchar *page_label; - - _ev_document_get_page_size (document, page, &page_width, &page_height); - + + if ( document->iswebdocument == FALSE ) { + _ev_document_get_page_size (document, page, &page_width, &page_height); + } + else { + //Fixed page sized to resolve the X-windowing system error. + page_width = 800; + page_height= 600; + } + if (i == 0) { priv->uniform_width = page_width; priv->uniform_height = page_height; @@ -277,14 +304,21 @@ ev_document_load (EvDocument *document, priv->max_height = priv->uniform_height; priv->min_width = priv->uniform_width; priv->min_height = priv->uniform_height; + if (document->iswebdocument == TRUE ) { + priv->page_sizes = g_new0 (EvPageSize, 1); + priv->page_sizes->width = priv->uniform_width; + priv->page_sizes->height = priv->uniform_height; + priv->uniform = TRUE ; + break; + } } else if (priv->uniform && (priv->uniform_width != page_width || priv->uniform_height != page_height)) { /* It's a different page size. Backfill the array. */ int j; - + priv->page_sizes = g_new0 (EvPageSize, priv->n_pages); - + for (j = 0; j < i; j++) { page_size = &(priv->page_sizes[j]); page_size->width = priv->uniform_width; @@ -511,15 +545,21 @@ ev_document_get_page_size (EvDocument *document, { g_return_if_fail (EV_IS_DOCUMENT (document)); g_return_if_fail (page_index >= 0 || page_index < document->priv->n_pages); - - if (width) - *width = document->priv->uniform ? - document->priv->uniform_width : - document->priv->page_sizes[page_index].width; - if (height) - *height = document->priv->uniform ? - document->priv->uniform_height : - document->priv->page_sizes[page_index].height; + if (document->iswebdocument == TRUE ) { + if (width) + *width = document->priv->uniform_width; + if (height) + *height = document->priv->uniform_height; + } else { + if (width) + *width = document->priv->uniform ? + document->priv->uniform_width : + document->priv->page_sizes[page_index].width; + if (height) + *height = document->priv->uniform ? + document->priv->uniform_height : + document->priv->page_sizes[page_index].height; + } } static gchar * diff --git a/libdocument/ev-document.h b/libdocument/ev-document.h index d10d261a..24e31912 100644 --- a/libdocument/ev-document.h +++ b/libdocument/ev-document.h @@ -85,6 +85,11 @@ struct _EvDocument GObject base; EvDocumentPrivate *priv; + /* + * Since we can only access the members of this structure from the window frontend, + * we need a flag to detemine whether to replace the atril-view with a web-view. + */ + gboolean iswebdocument; }; struct _EvDocumentClass diff --git a/libdocument/ev-link-dest.c b/libdocument/ev-link-dest.c index 62f2cd47..b9ea0dfd 100644 --- a/libdocument/ev-link-dest.c +++ b/libdocument/ev-link-dest.c @@ -509,3 +509,13 @@ ev_link_dest_new_page_label (const gchar *page_label) "type", EV_LINK_DEST_TYPE_PAGE_LABEL, NULL)); } + +EvLinkDest * +ev_link_dest_new_hlink(const gchar* hlink,gint page) +{ + return EV_LINK_DEST(g_object_new(EV_TYPE_LINK_DEST, + "named",hlink, + "page",page, + "type", EV_LINK_DEST_TYPE_HLINK, + NULL)); +}
\ No newline at end of file diff --git a/libdocument/ev-link-dest.h b/libdocument/ev-link-dest.h index a0e2539f..dd1f10a1 100644 --- a/libdocument/ev-link-dest.h +++ b/libdocument/ev-link-dest.h @@ -49,6 +49,7 @@ typedef enum { EV_LINK_DEST_TYPE_FITR, EV_LINK_DEST_TYPE_NAMED, EV_LINK_DEST_TYPE_PAGE_LABEL, + EV_LINK_DEST_TYPE_HLINK, EV_LINK_DEST_TYPE_UNKNOWN } EvLinkDestType; @@ -89,6 +90,7 @@ EvLinkDest *ev_link_dest_new_fitr (gint page, gdouble top); EvLinkDest *ev_link_dest_new_named (const gchar *named_dest); EvLinkDest *ev_link_dest_new_page_label (const gchar *page_label); +EvLinkDest *ev_link_dest_new_hlink (const gchar* hlink,gint page); G_END_DECLS diff --git a/libview/Makefile.am b/libview/Makefile.am index 7dd0a950..96e80ea3 100644 --- a/libview/Makefile.am +++ b/libview/Makefile.am @@ -19,6 +19,7 @@ INST_H_SRC_FILES = \ ev-print-operation.h \ ev-stock-icons.h \ ev-view.h \ + ev-web-view.h \ ev-view-presentation.h INST_H_FILES = \ @@ -41,6 +42,7 @@ libatrilview_la_SOURCES = \ ev-timeline.c \ ev-transition-animation.c \ ev-view.c \ + ev-web-view.c \ ev-view-accessible.c \ ev-view-marshal.c \ ev-view-cursor.c \ @@ -63,6 +65,7 @@ libatrilview_la_CFLAGS = \ $(LIBVIEW_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED) \ + $(WEBKIT_CFLAGS) \ $(AM_CFLAGS) libatrilview_la_LDFLAGS = \ @@ -73,7 +76,8 @@ libatrilview_la_LDFLAGS = \ libatrilview_la_LIBADD = \ $(top_builddir)/libdocument/libatrildocument.la \ - $(LIBVIEW_LIBS) + $(LIBVIEW_LIBS) \ + $(WEBKIT_LIBS) BUILT_SOURCES = \ ev-view-marshal.h \ diff --git a/libview/ev-document-model.c b/libview/ev-document-model.c index 403df466..dbf0477f 100644 --- a/libview/ev-document-model.c +++ b/libview/ev-document-model.c @@ -109,7 +109,12 @@ ev_document_model_set_property (GObject *object, ev_document_model_set_rotation (model, g_value_get_int (value)); break; case PROP_INVERTED_COLORS: - ev_document_model_set_inverted_colors (model, g_value_get_boolean (value)); + if ( model->document->iswebdocument == TRUE ) { + atril_web_document_set_inverted_colors(model,g_value_get_boolean(value)); + } + else { + ev_document_model_set_inverted_colors (model, g_value_get_boolean (value)); + } break; case PROP_SCALE: ev_document_model_set_scale (model, g_value_get_double (value)); @@ -490,6 +495,15 @@ ev_document_model_set_inverted_colors (EvDocumentModel *model, g_object_notify (G_OBJECT (model), "inverted-colors"); } +void +atril_web_document_set_inverted_colors (EvDocumentModel *model, + gboolean inverted_colors) +{ + //TODO + model->inverted_colors = FALSE; + g_object_notify (G_OBJECT (model), "inverted-colors"); +} + gboolean ev_document_model_get_inverted_colors (EvDocumentModel *model) { diff --git a/libview/ev-document-model.h b/libview/ev-document-model.h index b8bea62c..f9d175c0 100644 --- a/libview/ev-document-model.h +++ b/libview/ev-document-model.h @@ -69,7 +69,9 @@ EvSizingMode ev_document_model_get_sizing_mode (EvDocumentModel *model); void ev_document_model_set_rotation (EvDocumentModel *model, gint rotation); gint ev_document_model_get_rotation (EvDocumentModel *model); -void ev_document_model_set_inverted_colors (EvDocumentModel *model, +void ev_document_model_set_inverted_colors (EvDocumentModel *model, + gboolean inverted_colors); +void atril_web_document_set_inverted_colors(EvDocumentModel *model, gboolean inverted_colors); gboolean ev_document_model_get_inverted_colors (EvDocumentModel *model); void ev_document_model_set_continuous (EvDocumentModel *model, diff --git a/libview/ev-jobs.c b/libview/ev-jobs.c index d8d3043d..c4324a1c 100644 --- a/libview/ev-jobs.c +++ b/libview/ev-jobs.c @@ -24,6 +24,7 @@ #include "ev-document-thumbnails.h" #include "ev-document-links.h" #include "ev-document-images.h" +#include "ev-job-scheduler.h" #include "ev-document-forms.h" #include "ev-file-exporter.h" #include "ev-document-factory.h" @@ -39,6 +40,14 @@ #include "ev-document-text.h" #include "ev-debug.h" +#include <gtk/gtk.h> +#ifdef ENABLE_EPUB +#if GTK_CHECK_VERSION(3, 0, 0) +#include <webkit2/webkit2.h> +#else +#include <webkit/webkit.h> +#endif +#endif #include <errno.h> #include <glib/gstdio.h> #include <glib/gi18n-lib.h> @@ -87,6 +96,9 @@ enum { FIND_LAST_SIGNAL }; +static GtkWidget* webview; +static GtkWidget* offscreenwindow; + static guint job_signals[LAST_SIGNAL] = { 0 }; static guint job_fonts_signals[FONTS_LAST_SIGNAL] = { 0 }; static guint job_find_signals[FIND_LAST_SIGNAL] = { 0 }; @@ -211,7 +223,7 @@ ev_job_run (EvJob *job) { EvJobClass *class = EV_JOB_GET_CLASS (job); - return class->run (job); + return class-> run (job); } void @@ -568,6 +580,24 @@ ev_job_render_run (EvJob *job) ev_document_fc_mutex_lock (); ev_page = ev_document_get_page (job->document, job_render->page); + + if ( job->document->iswebdocument == TRUE ) + { + return TRUE; + + if (g_cancellable_is_cancelled (job->cancellable)) { + ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); + g_object_unref (rc); + + return FALSE; + } + + ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); + ev_job_succeeded (job); + return FALSE; + } rc = ev_render_context_new (ev_page, job_render->rotation, job_render->scale); g_object_unref (ev_page); @@ -740,7 +770,7 @@ ev_job_page_data_new (EvDocument *document, static void ev_job_thumbnail_init (EvJobThumbnail *job) { - EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; } static void @@ -760,28 +790,139 @@ ev_job_thumbnail_dispose (GObject *object) (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object); } +#if !GTK_CHECK_VERSION(3, 0, 0) +static void +web_thumbnail_get_screenshot_cb(WebKitWebView *webview, + WebKitWebFrame *webframe, + EvJobThumbnail *job_thumb) +{ + if (webkit_web_view_get_load_status(webview) != WEBKIT_LOAD_FINISHED) { + return; + } + EvPage *page = ev_document_get_page (EV_JOB(job_thumb)->document, job_thumb->page); + job_thumb->surface = webkit_web_view_get_snapshot (WEBKIT_WEB_VIEW(webview)); + EvRenderContext *rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + EvPage *screenshotpage; + screenshotpage = ev_page_new(job_thumb->page); + screenshotpage->backend_page = (EvBackendPage)job_thumb->surface; + screenshotpage->backend_destroy_func = (EvBackendPageDestroyFunc)cairo_surface_destroy ; + ev_render_context_set_page(rc,screenshotpage); + + job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB(job_thumb)->document), + rc, TRUE); + g_object_unref(screenshotpage); + g_object_unref(rc); + + ev_document_doc_mutex_unlock(); + ev_job_succeeded(EV_JOB(job_thumb)); +} +#else + +static void +snapshot_callback(WebKitWebView *webview, + GAsyncResult *results, + EvJobThumbnail *job_thumb) +{ + EvPage *page = ev_document_get_page (EV_JOB(job_thumb)->document, job_thumb->page); + job_thumb->surface = webkit_web_view_get_snapshot_finish (webview, + results, + NULL); + EvRenderContext *rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + EvPage *screenshotpage; + screenshotpage = ev_page_new(job_thumb->page); + screenshotpage->backend_page = (EvBackendPage)job_thumb->surface; + screenshotpage->backend_destroy_func = (EvBackendPageDestroyFunc)cairo_surface_destroy ; + ev_render_context_set_page(rc,screenshotpage); + + job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB(job_thumb)->document), + rc, TRUE); + g_object_unref(screenshotpage); + g_object_unref(rc); + + ev_document_doc_mutex_unlock(); + ev_job_succeeded(EV_JOB(job_thumb)); +} + +static void +web_thumbnail_get_screenshot_cb (WebKitWebView *webview, + WebKitLoadEvent event, + EvJobThumbnail *job_thumb) +{ + if (event != WEBKIT_LOAD_FINISHED) { + return; + } + + webkit_web_view_get_snapshot (webview, + WEBKIT_SNAPSHOT_REGION_VISIBLE, + WEBKIT_SNAPSHOT_OPTIONS_NONE, + NULL, + (GAsyncReadyCallback)snapshot_callback, + g_object_ref(job_thumb)); +} +#endif + static gboolean ev_job_thumbnail_run (EvJob *job) { EvJobThumbnail *job_thumb = EV_JOB_THUMBNAIL (job); EvRenderContext *rc; EvPage *page; - ev_debug_message (DEBUG_JOBS, "%d (%p)", job_thumb->page, job); ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); - - ev_document_doc_mutex_lock (); + + if (job->document->iswebdocument) { + /* Do not block the main loop */ + if (!ev_document_doc_mutex_trylock ()) + return TRUE; + } + else { + ev_document_doc_mutex_lock (); + } page = ev_document_get_page (job->document, job_thumb->page); - rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + if (job->document->iswebdocument == TRUE ) { + rc = ev_render_context_new (page, 0, job_thumb->scale); + } + else { + rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + } g_object_unref (page); - job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document), - rc, TRUE); - g_object_unref (rc); - ev_document_doc_mutex_unlock (); + if (job->document->iswebdocument == TRUE) { + if (!webview) { + webview = webkit_web_view_new(); + } + + if (!offscreenwindow) { + offscreenwindow = gtk_offscreen_window_new(); + + gtk_container_add(GTK_CONTAINER(offscreenwindow),GTK_WIDGET(webview)); + + gtk_window_set_default_size (GTK_WINDOW(offscreenwindow),800,1080); + + gtk_widget_show_all(offscreenwindow); + } + + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)rc->page->backend_page); +#if !GTK_CHECK_VERSION (3, 0, 0) + g_signal_connect(WEBKIT_WEB_VIEW(webview),"notify::load-status", + G_CALLBACK(web_thumbnail_get_screenshot_cb), + g_object_ref(job_thumb)); +#else + g_signal_connect(WEBKIT_WEB_VIEW(webview),"load-changed", + G_CALLBACK(web_thumbnail_get_screenshot_cb), + g_object_ref(job_thumb)); - ev_job_succeeded (job); +#endif + } + else { + job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document), + rc, TRUE); + ev_document_doc_mutex_unlock (); + + ev_job_succeeded (job); + } + g_object_unref (rc); return FALSE; } @@ -1185,6 +1326,10 @@ ev_job_find_dispose (GObject *object) g_free (job->pages); job->pages = NULL; } + + if (job->results) { + g_free(job->results); + } (* G_OBJECT_CLASS (ev_job_find_parent_class)->dispose) (object); } @@ -1196,7 +1341,6 @@ ev_job_find_run (EvJob *job) EvDocumentFind *find = EV_DOCUMENT_FIND (job->document); EvPage *ev_page; GList *matches; - ev_debug_message (DEBUG_JOBS, NULL); /* Do not block the main loop */ @@ -1210,16 +1354,30 @@ ev_job_find_run (EvJob *job) #endif ev_page = ev_document_get_page (job->document, job_find->current_page); - matches = ev_document_find_find_text (find, ev_page, job_find->text, - job_find->case_sensitive); + + if (job->document->iswebdocument) { + job_find->results[job_find->current_page] = ev_document_find_check_for_hits(find, ev_page, job_find->text, + job_find->case_sensitive); + }else { + matches = ev_document_find_find_text (find, ev_page, job_find->text, + job_find->case_sensitive); + } + g_object_unref (ev_page); ev_document_doc_mutex_unlock (); - if (!job_find->has_results) + if (!job_find->has_results && !job->document->iswebdocument) { job_find->has_results = (matches != NULL); + } + else if (!job_find->has_results && job->document->iswebdocument){ + job_find->has_results = (job_find->results[job_find->current_page] > 0); + } + + if (job->document->iswebdocument == FALSE) { + job_find->pages[job_find->current_page] = matches; + } - job_find->pages[job_find->current_page] = matches; g_signal_emit (job_find, job_find_signals[FIND_UPDATED], 0, job_find->current_page); job_find->current_page = (job_find->current_page + 1) % job_find->n_pages; @@ -1269,7 +1427,13 @@ ev_job_find_new (EvDocument *document, job->start_page = start_page; job->current_page = start_page; job->n_pages = n_pages; - job->pages = g_new0 (GList *, n_pages); + + if (document->iswebdocument) { + job->results = g_malloc0 (sizeof(guint) *n_pages); + } + else { + job->pages = g_new0 (GList *, n_pages); + } job->text = g_strdup (text); job->case_sensitive = case_sensitive; job->has_results = FALSE; @@ -1281,7 +1445,12 @@ gint ev_job_find_get_n_results (EvJobFind *job, gint page) { - return g_list_length (job->pages[page]); + if (EV_JOB(job)->document->iswebdocument) { + return job->results[page]; + } + else { + return g_list_length (job->pages[page]); + } } gdouble diff --git a/libview/ev-jobs.h b/libview/ev-jobs.h index e6ae4552..fdc23bae 100644 --- a/libview/ev-jobs.h +++ b/libview/ev-jobs.h @@ -45,6 +45,9 @@ typedef struct _EvJobPageDataClass EvJobPageDataClass; typedef struct _EvJobThumbnail EvJobThumbnail; typedef struct _EvJobThumbnailClass EvJobThumbnailClass; +typedef struct _EvJobWebThumbnail EvJobWebThumbnail; +typedef struct _EvJobWebThumbnailClass EvJobWebThumbnailClass; + typedef struct _EvJobLinks EvJobLinks; typedef struct _EvJobLinksClass EvJobLinksClass; @@ -111,6 +114,11 @@ typedef struct _EvJobPrintClass EvJobPrintClass; #define EV_JOB_THUMBNAIL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnailClass)) #define EV_IS_JOB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_THUMBNAIL)) +#define EV_TYPE_JOB_WEB_THUMBNAIL (ev_job_web_thumbnail_get_type()) +#define EV_JOB_WEB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_WEB_THUMBNAIL, EvJobWebThumbnail)) +#define EV_JOB_WEB_THUMBNAIL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_WEB_THUMBNAIL, EvJobWebThumbnailClass)) +#define EV_IS_JOB_WEB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_WEB_THUMBNAIL)) + #define EV_TYPE_JOB_FONTS (ev_job_fonts_get_type()) #define EV_JOB_FONTS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_FONTS, EvJobFonts)) #define EV_JOB_FONTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_FONTS, EvJobFontsClass)) @@ -281,11 +289,10 @@ struct _EvJobPageDataClass struct _EvJobThumbnail { EvJob parent; - gint page; gint rotation; gdouble scale; - + cairo_surface_t *surface; GdkPixbuf *thumbnail; }; @@ -343,6 +350,7 @@ struct _EvJobFind gint current_page; gint n_pages; GList **pages; + guint *results; gchar *text; gboolean case_sensitive; gboolean has_results; @@ -450,6 +458,7 @@ EvJob *ev_job_thumbnail_new (EvDocument *document, gint page, gint rotation, gdouble scale); + /* EvJobFonts */ GType ev_job_fonts_get_type (void) G_GNUC_CONST; EvJob *ev_job_fonts_new (EvDocument *document); diff --git a/libview/ev-view.c b/libview/ev-view.c index 7bb56cae..ec378758 100644..100755 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -6568,3 +6568,41 @@ ev_view_previous_page (EvView *view) } } +/** + * ev_view_disconnect_handlers + * @view: #EvView instance + * + * Disconnect all signal handlers from the model, to ensure error free operation of the webview, + * we have an equivalent function for the webview. + */ +void +ev_view_disconnect_handlers(EvView *view) +{ + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_rotation_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_inverted_colors_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_sizing_mode_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_scale_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_continuous_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_dual_page_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_fullscreen_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_page_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_document_changed_cb), + view); +}
\ No newline at end of file diff --git a/libview/ev-view.h b/libview/ev-view.h index 402b9895..0a9e1718 100644..100755 --- a/libview/ev-view.h +++ b/libview/ev-view.h @@ -110,6 +110,8 @@ void ev_view_begin_add_annotation (EvView *view, EvAnnotationType annot_type); void ev_view_cancel_add_annotation (EvView *view); +/*For epub*/ +void ev_view_disconnect_handlers (EvView *view); G_END_DECLS #endif /* __EV_VIEW_H__ */ diff --git a/libview/ev-web-view.c b/libview/ev-web-view.c new file mode 100644 index 00000000..b1fe3b08 --- /dev/null +++ b/libview/ev-web-view.c @@ -0,0 +1,874 @@ +/* this file is part of atril, a mate document viewer + * + * Copyright (C) 2014 Avishkar Gupta + * Based on ev-view.c, also a part of atril, a mate document viewer. + * + * Atril is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Atril is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> +#include <gtk/gtk.h> +#include <stdlib.h> + +#if GTK_CHECK_VERSION (3, 0, 0) +#include <webkit2/webkit2.h> +#else +#include <webkit/webkit.h> +#endif + +#include "ev-web-view.h" +#include "ev-document-model.h" +#include "ev-jobs.h" + +#define EV_WEB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_WEB_VIEW, EvWebViewClass)) +#define EV_IS_WEB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_WEB_VIEW)) +#define EV_WEB_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_WEB_VIEW, EvWebViewClass)) + + typedef enum { + EV_WEB_VIEW_FIND_NEXT, + EV_WEB_VIEW_FIND_PREV + } EvWebViewFindDirection; + +typedef struct _SearchParams { + gboolean case_sensitive; + gchar* search_string; + EvWebViewFindDirection direction; + gboolean search_jump; + gint on_result; + guint *results; +}SearchParams; + +struct _EvWebView +{ + WebKitWebView web_view; + EvDocument *document; + EvDocumentModel *model; + gint current_page; + gboolean inverted_colors ; + gboolean fullscreen; + SearchParams *search; +#if GTK_CHECK_VERSION (3, 0, 0) + WebKitFindController *findcontroller; + WebKitFindOptions findoptions; + gdouble zoom_level; +#endif + gchar *hlink; +}; + +struct _EvWebViewClass +{ + WebKitWebViewClass base_class; +}; + +/*** Callbacks ***/ +static void ev_web_view_change_page (EvWebView *webview, + gint new_page); + +static void ev_web_view_page_changed_cb (EvDocumentModel *model, + gint old_page, + gint new_page, + EvWebView *webview); +/*** GObject ***/ +static void ev_web_view_dispose (GObject *object); + +static void ev_web_view_finalize (GObject *object); +static void ev_web_view_class_init (EvWebViewClass *klass); +static void ev_web_view_init (EvWebView *webview); + +G_DEFINE_TYPE (EvWebView, ev_web_view, WEBKIT_TYPE_WEB_VIEW) + +static void +web_view_update_range_and_current_page (EvWebView *webview) +{ + g_return_if_fail(EV_IS_WEB_VIEW(webview)); + + if (ev_document_get_n_pages (webview->document) <= 0) + return; + + ev_document_model_set_page(webview->model, 0); + webview->current_page = 0; + EvPage *webpage = ev_document_get_page(webview->document,0); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); +} + +static void +ev_web_view_dispose (GObject *object) +{ + EvWebView *webview = EV_WEB_VIEW (object); + + if (webview->document) { + g_object_unref(webview->document); + webview->document = NULL ; + } + + if (webview->model) { + g_object_unref(webview->model); + webview->model = NULL; + } + + if (webview->hlink) { + g_free(webview->hlink); + webview->hlink = NULL; + } + + if (webview->search) { + g_free(webview->search); + webview->search = NULL; + } + + G_OBJECT_CLASS (ev_web_view_parent_class)->dispose (object); +} + +static void +ev_web_view_class_init (EvWebViewClass *klass) +{ + G_OBJECT_CLASS(klass)->finalize = ev_web_view_finalize; + G_OBJECT_CLASS(klass)->dispose = ev_web_view_dispose; +} + +static void +ev_web_view_init (EvWebView *webview) +{ + gtk_widget_set_can_focus (GTK_WIDGET (webview), TRUE); + + gtk_widget_set_has_window (GTK_WIDGET (webview), TRUE); + + webview->current_page = 0; + + webview->search = g_new0(SearchParams, 1); + webview->search->search_string = NULL; + + webview->search->on_result = -1 ; + webview->search->results = NULL; + webview->search->search_jump = TRUE ; + + webview->fullscreen = FALSE; + + webview->hlink = NULL; +} + +static void +ev_web_view_finalize (GObject *object) +{ + G_OBJECT_CLASS(ev_web_view_parent_class)->finalize(object); +} + +/*** Callbacks ***/ + +static void +ev_web_view_change_page (EvWebView *webview, + gint new_page) +{ + g_return_if_fail(EV_IS_WEB_VIEW(webview)); + + EvDocumentClass *klass = EV_DOCUMENT_GET_CLASS(webview->document); + + webview->current_page = new_page; + ev_document_model_set_page(webview->model,new_page); +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_finish(webview->findcontroller); +#else + webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(webview)); +#endif + if (webview->hlink) { + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webview->hlink); + g_free(webview->hlink); + webview->hlink = NULL; + } + else { + EvPage *page = klass->get_page(webview->document,new_page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)page->backend_page); + } +} + +static void +ev_web_view_page_changed_cb (EvDocumentModel *model, + gint old_page, + gint new_page, + EvWebView *webview) +{ + if (!webview->document) + return; + + if (webview->current_page != new_page) { + ev_web_view_change_page (webview, new_page); + } else { + webkit_web_view_reload (WEBKIT_WEB_VIEW(webview)); + } +} + +GtkWidget* +ev_web_view_new (void) +{ + GtkWidget *webview; + + webview = g_object_new (EV_TYPE_WEB_VIEW, NULL); + + #if GTK_CHECK_VERSION (3, 0, 0) + EV_WEB_VIEW(webview)->findcontroller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW(webview)); + EV_WEB_VIEW(webview)->findoptions = webkit_find_controller_get_options (EV_WEB_VIEW(webview)->findcontroller); + + EV_WEB_VIEW(webview)->zoom_level = 1.0; + + EV_WEB_VIEW(webview)->findoptions |= WEBKIT_FIND_OPTIONS_NONE; + #endif + + return webview; +} + +static void +ev_web_view_document_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvWebView *webview) +{ + g_return_if_fail(EV_IS_WEB_VIEW(webview)); + + EvDocument *document = ev_document_model_get_document (model); + + if (document != webview->document) { + + if (webview->document ) + g_object_unref(webview->document); + + webview->document = document ; + + if(webview->document) { + g_object_ref(webview->document); + } + + gint current_page = ev_document_model_get_page(model); + + ev_web_view_change_page (webview, current_page); + + } +} + +static void +ev_web_view_inverted_colors_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvWebView *webview) +{ + guint inverted_colors = ev_document_model_get_inverted_colors (model); + inverted_colors = !inverted_colors; + /*TODO*/ +} + +static void +ev_web_view_fullscreen_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvWebView *webview) +{ + gboolean fullscreen = ev_document_model_get_fullscreen (model); + + webview->fullscreen = fullscreen; +#if GTK_CHECK_VERSION (3, 0, 0) + WebKitWindowProperties *window_properties = + webkit_web_view_get_window_properties (WEBKIT_WEB_VIEW(webview)); + + webkit_window_properties_get_fullscreen(window_properties); + /*TODO*/ +#else + webkit_web_view_set_view_mode(WEBKIT_WEB_VIEW(webview), WEBKIT_WEB_VIEW_VIEW_MODE_FULLSCREEN); +#endif +} +void +ev_web_view_set_model (EvWebView *webview, + EvDocumentModel *model) +{ + g_return_if_fail (EV_IS_WEB_VIEW (webview)); + g_return_if_fail (EV_IS_DOCUMENT_MODEL (model)); + + if (model == webview->model) + return; + + if (webview->model) { + g_signal_handlers_disconnect_by_func (webview->model, + ev_web_view_document_changed_cb, + webview); + g_signal_handlers_disconnect_by_func (webview->model, + ev_web_view_page_changed_cb, + webview); + g_object_unref (webview->model); + } + webview->model = g_object_ref (model); + + /* Initialize webview from model */ + webview->fullscreen = ev_document_model_get_fullscreen (webview->model); + webview->document = ev_document_model_get_document(webview->model); + webview->inverted_colors = ev_document_model_get_inverted_colors(webview->model); + ev_web_view_document_changed_cb (webview->model, NULL, webview); + + g_signal_connect (webview->model, "notify::document", + G_CALLBACK (ev_web_view_document_changed_cb), + webview); + g_signal_connect (webview->model, "notify::inverted-colors", + G_CALLBACK (ev_web_view_inverted_colors_changed_cb), + webview); + g_signal_connect (webview->model,"page-changed", + G_CALLBACK(ev_web_view_page_changed_cb), + webview); +} + +void +ev_web_view_reload_page (EvWebView *webview, + gint page) +{ + webkit_web_view_reload (WEBKIT_WEB_VIEW(webview)); +} + +void +ev_web_view_reload (EvWebView *webview) +{ + web_view_update_range_and_current_page (webview); +} + + +gboolean +ev_web_view_next_page (EvWebView *webview) +{ + int page, n_pages; + + g_return_val_if_fail (EV_IS_WEB_VIEW (webview), FALSE); + + if (!webview->document) + return FALSE; + + page = ev_document_model_get_page (webview->model); + n_pages = ev_document_get_n_pages (webview->document); + + page = page + 1; + + if (page < n_pages) { + ev_document_model_set_page (webview->model, page); + EvPage *webpage = ev_document_get_page(webview->document,page); + webview->current_page = page ; + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else if (page == n_pages) { + ev_document_model_set_page (webview->model, page - 1); + EvPage *webpage = ev_document_get_page(webview->document,page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else { + return FALSE; + } +} + +gboolean +ev_web_view_previous_page (EvWebView *webview) +{ + int page; + + g_return_val_if_fail (EV_IS_WEB_VIEW (webview), FALSE); + + if (!webview->document) + return FALSE; + + page = ev_document_model_get_page (webview->model); + + page = page - 1 ; + + if (page >= 0) { + ev_document_model_set_page (webview->model, page); + EvPage *webpage = ev_document_get_page(webview->document,page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else if (page == -1) { + ev_document_model_set_page (webview->model, 0); + EvPage *webpage = ev_document_get_page(webview->document,page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else { + return FALSE; + } +} + +void +ev_web_view_handle_link(EvWebView *webview,EvLink *link) +{ + EvLinkAction *action = NULL; + EvLinkDest *dest = NULL; + EvLinkDestType dest_type ; + action = ev_link_get_action(link); + + if (action == NULL) + return; + + dest = ev_link_action_get_dest(action); + + if (dest == NULL) + return; + + dest_type = ev_link_dest_get_dest_type(dest); + + switch(dest_type) { + case EV_LINK_DEST_TYPE_PAGE: { + ev_document_model_set_page(webview->model,ev_link_dest_get_page(dest)); + break; + } + + case EV_LINK_DEST_TYPE_PAGE_LABEL: { + const gchar *text = ev_link_dest_get_page_label (dest); + gint page = atoi(text); + + if (page <= ev_document_get_n_pages(webview->document) && page > 0) { + ev_document_model_set_page(webview->model,page-1); + } + break; + } + case EV_LINK_DEST_TYPE_HLINK: { + const gchar *uri = ev_link_dest_get_named_dest(dest); + ev_document_model_set_page(webview->model,ev_link_dest_get_page(dest)); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),uri); + break; + + default:return; + } + } +} +/* Searching */ + +#if !GTK_CHECK_VERSION (3, 0, 0) +static void +jump_to_find_result_on_page(EvWebView *webview, + EvWebViewFindDirection direction) +{ + gboolean forward,wrap; + + if (direction == EV_WEB_VIEW_FIND_NEXT) { + forward = TRUE; + wrap = FALSE; + } + else { + forward = FALSE; + wrap = FALSE; + } + + if (webview->search->search_jump) { + wrap = TRUE; + } + webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview), + webview->search->search_string, + webview->search->case_sensitive, + forward, + wrap); + + webview->search->search_jump = FALSE; +} +#endif + +#if GTK_CHECK_VERSION (3, 0, 0) +static void +results_counted_cb(WebKitFindController *findcontroller, + guint match_count, + EvWebView *webview) +{ + if (match_count > 0 && webview->search->on_result < match_count) { + webkit_find_controller_search(findcontroller, + webview->search->search_string, + webview->findoptions, + match_count); + webview->search->search_jump = FALSE; + } +} +#endif +/* + * Jump to find results once we have changed the page in the webview. + */ +#if GTK_CHECK_VERSION (3, 0, 0) +static void +jump_to_find_results(EvWebView *webview, + WebKitLoadEvent load_event, + gpointer data) +#else +static void +jump_to_find_results(EvWebView *webview, + GParamSpec *pspec, + gpointer data) +#endif +{ + #if !GTK_CHECK_VERSION (3, 0, 0) + gint n_results; + gboolean forward ; + gboolean wrap ; + + if (webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(webview)) != WEBKIT_LOAD_FINISHED) { + return; + } +#else + if ( load_event != WEBKIT_LOAD_FINISHED) { + return; + } +#endif + if (!webview->search->search_string) { + return; + } + +#if GTK_CHECK_VERSION (3, 0, 0) + if (webview->search->direction == EV_WEB_VIEW_FIND_NEXT) { + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_BACKWARDS; + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_WRAP_AROUND; + } + else { + webview->findoptions |= WEBKIT_FIND_OPTIONS_BACKWARDS; + webview->findoptions |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + } + + webkit_find_controller_count_matches (webview->findcontroller, + webview->search->search_string, + webview->findoptions, + G_MAXUINT); +#else + n_results = webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW(webview), + webview->search->search_string, + webview->search->case_sensitive, + 0); + + ev_web_view_find_set_highlight_search(webview,TRUE); + + if (webview->search->direction == EV_WEB_VIEW_FIND_NEXT) { + forward = TRUE ; + wrap = FALSE; + } + else { + forward = FALSE; + wrap = TRUE ; + } + + if (n_results > 0 && webview->search->on_result < n_results) { + webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview), + webview->search->search_string, + webview->search->case_sensitive, + forward, + wrap); + + webview->search->search_jump = FALSE; + } +#endif + webview->search->search_jump = FALSE; +} + +static gint +ev_web_view_find_get_n_results (EvWebView *webview, gint page) +{ + return webview->search->results[page]; +} + +/** + * jump_to_find_page + * @webview: #EvWebView instance + * @direction: Direction to look + * @shift: Shift from current page + * + * Jumps to the first page that has occurences of searched word. + * Uses a direction where to look and a shift from current page. +**/ +static void +jump_to_find_page (EvWebView *webview, EvWebViewFindDirection direction, gint shift) +{ + int n_pages, i; + + n_pages = ev_document_get_n_pages (webview->document); + + for (i = 0; i < n_pages; i++) { + int page; + + if (direction == EV_WEB_VIEW_FIND_NEXT) + page = webview->current_page + i; + else + page = webview->current_page - i; + page += shift; + + if (page >= n_pages) { + page = page - n_pages; + } else if (page < 0) + page = page + n_pages; + + if (page == webview->current_page && ev_web_view_find_get_n_results(webview,page) > 0) { +#if !GTK_CHECK_VERSION (3, 0, 0) + jump_to_find_result_on_page(webview,EV_WEB_VIEW_FIND_NEXT); +#else + if (direction == EV_WEB_VIEW_FIND_PREV) { + webview->findoptions |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + webview->findoptions |= WEBKIT_FIND_OPTIONS_BACKWARDS; + } + else { + if (webview->search->search_jump) + webview->findoptions |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + else + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_WRAP_AROUND; + + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_BACKWARDS; + } + + webkit_find_controller_search (webview->findcontroller, + webview->search->search_string, + webview->findoptions, + /*Highlight all the results.*/ + G_MAXUINT); + webview->search->search_jump = FALSE; +#endif + break; + } + + if (ev_web_view_find_get_n_results (webview, page) > 0) { + webview->search->direction = direction; +#if !GTK_CHECK_VERSION (3, 0, 0) + webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(webview)); +#else + webkit_find_controller_search_finish(webview->findcontroller); +#endif + ev_document_model_set_page (webview->model, page); + break; + } + } +} + +void +ev_web_view_find_changed (EvWebView *webview, guint *results, gchar *text,gboolean case_sensitive) +{ + webview->search->results = results; + webview->search->on_result = 0; + webview->search->search_string = g_strdup(text); + webview->search->case_sensitive = case_sensitive; + if (webview->search->search_jump == TRUE) { +#if GTK_CHECK_VERSION (3, 0, 0) + if (!case_sensitive) { + webview->findoptions |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + } + else { + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + } +#endif + jump_to_find_page (webview, EV_WEB_VIEW_FIND_NEXT, 0); + } +} + +void +ev_web_view_find_next (EvWebView *webview) +{ + gint n_results; + + n_results = ev_web_view_find_get_n_results (webview, webview->current_page); + webview->search->on_result++; + + if (webview->search->on_result >= n_results) { + webview->search->on_result = 0; + jump_to_find_page (webview, EV_WEB_VIEW_FIND_NEXT, 1); + } + else { +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_next(webview->findcontroller); +#else + jump_to_find_result_on_page (webview, EV_WEB_VIEW_FIND_NEXT); +#endif + } +} + +void +ev_web_view_find_previous (EvWebView *webview) +{ + webview->search->on_result--; + + if (webview->search->on_result < 0) { + jump_to_find_page (webview, EV_WEB_VIEW_FIND_PREV, -1); + webview->search->on_result = MAX (0, ev_web_view_find_get_n_results (webview, webview->current_page) - 1); + } else { +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_previous(webview->findcontroller); +#else + jump_to_find_result_on_page (webview,EV_WEB_VIEW_FIND_PREV); +#endif + } +} + +void +ev_web_view_find_search_changed (EvWebView *webview) +{ + /* search string has changed, focus on new search result */ +#if !GTK_CHECK_VERSION(3, 0, 0) + webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webview)); +#endif + if (webview->search->search_string) { + g_free(webview->search->search_string); + webview->search->search_string = NULL; + } +#if GTK_CHECK_VERSION(3, 0, 0) + webkit_find_controller_search_finish(webview->findcontroller); +#endif + + webview->search->search_jump = TRUE; +} + +#if !GTK_CHECK_VERSION (3, 0, 0) +void +ev_web_view_find_set_highlight_search (EvWebView *webview, gboolean value) +{ + webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW(webview),value); +} +#endif + +void +ev_web_view_find_cancel (EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_finish (webview->findcontroller); +#else + webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webview)); + ev_web_view_find_set_highlight_search(webview,FALSE); +#endif +} + + + +void +ev_web_view_set_handler(EvWebView *webview,gboolean visible) +{ + if (visible) { + g_signal_connect(webview, +#if GTK_CHECK_VERSION (3, 0, 0) + "load-changed", +#else + "notify::load-status", +#endif + G_CALLBACK(jump_to_find_results), + NULL); +#if GTK_CHECK_VERSION (3, 0, 0) + g_signal_connect(webview->findcontroller, + "counted-matches", + G_CALLBACK(results_counted_cb), + webview); +#endif + } + else { + g_signal_handlers_disconnect_by_func(webview, + jump_to_find_results, + NULL); +#if GTK_CHECK_VERSION (3, 0, 0) + g_signal_handlers_disconnect_by_func(webview, + results_counted_cb, + NULL); +#endif + } +} + +/* Selection and copying*/ +#if !GTK_CHECK_VERSION (3, 0, 0) +gboolean +ev_web_view_get_has_selection(EvWebView *webview) +{ + return webkit_web_view_has_selection(WEBKIT_WEB_VIEW(webview)); +} +#endif + +void +ev_web_view_select_all(EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_web_view_execute_editing_command(WEBKIT_WEB_VIEW(webview), + WEBKIT_EDITING_COMMAND_SELECT_ALL); +#else + webkit_web_view_select_all(WEBKIT_WEB_VIEW(webview)); +#endif +} + +#if GTK_CHECK_VERSION (3, 0, 0) +static void +copy_text_cb(WebKitWebView *webview, + GAsyncResult *res, + gpointer data) +{ + gboolean okay_to_copy = webkit_web_view_can_execute_editing_command_finish (WEBKIT_WEB_VIEW(webview), + res, + NULL); + + if (okay_to_copy) { + webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW(webview), + WEBKIT_EDITING_COMMAND_COPY); + } +} +#endif + +void +ev_web_view_copy(EvWebView *webview) +{ +#if !GTK_CHECK_VERSION (3, 0, 0) + /* If for some reason we don't have a selection any longer,best to be safe */ + if (ev_web_view_get_has_selection(webview) == FALSE) + return; + if (webkit_web_view_can_copy_clipboard(WEBKIT_WEB_VIEW(webview))) { + webkit_web_view_copy_clipboard(WEBKIT_WEB_VIEW(webview)); + } +#else + webkit_web_view_can_execute_editing_command(WEBKIT_WEB_VIEW(webview), + WEBKIT_EDITING_COMMAND_COPY, + NULL, + (GAsyncReadyCallback)copy_text_cb, + NULL); + +#endif + +} + +/*Zoom control*/ +gboolean +ev_web_view_zoom_in(EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(webview), + (webview->zoom_level+= 0.1)); +#else + webkit_web_view_zoom_in(WEBKIT_WEB_VIEW(webview)); +#endif + return TRUE; +} + +gboolean +ev_web_view_zoom_out(EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + if (webview->zoom_level == 1) + return FALSE; + + webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(webview), + (webview->zoom_level -= 0.1)); +#else + webkit_web_view_zoom_out(WEBKIT_WEB_VIEW(webview)); +#endif + return TRUE; +} + +/** + * ev_web_view_disconnect_handlers + * @webview : #EvWebView instance + * + * This function call will disconnect all model signal handlers from the webview, to ensure smooth operation of the Atril-view. + * Equivalent to function ev_view_disconnect_handlers in ev-view.c + */ +void +ev_web_view_disconnect_handlers(EvWebView *webview) +{ + g_signal_handlers_disconnect_by_func(webview->model, + ev_web_view_document_changed_cb, + webview); + g_signal_handlers_disconnect_by_func(webview->model, + ev_web_view_inverted_colors_changed_cb, + webview); + g_signal_handlers_disconnect_by_func(webview->model, + ev_web_view_page_changed_cb, + webview); +}
\ No newline at end of file diff --git a/libview/ev-web-view.h b/libview/ev-web-view.h new file mode 100644 index 00000000..74b7eb6b --- /dev/null +++ b/libview/ev-web-view.h @@ -0,0 +1,89 @@ +/* this file is part of atril, a mate document viewer + * + * Copyright (C) 2014 Avishkar Gupta + * Based on ev-view.h, also a part of atril, a mate document viewer + * + * Atril is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Atril is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#if !defined (__EV_ATRIL_VIEW_H_INSIDE__) && !defined (ATRIL_COMPILATION) +#error "Only <atril-web_view.h> can be included directly." +#endif + +#ifndef __EV_WEB_VIEW_H__ +#define __EV_WEB_VIEW_H__ + +#include <gtk/gtk.h> + +#include <atril-document.h> +#include "ev-jobs.h" +#include "ev-document-model.h" +#include <glib-object.h> +G_BEGIN_DECLS + + +typedef struct _EvWebView EvWebView; +typedef struct _EvWebViewClass EvWebViewClass; + +#define EV_TYPE_WEB_VIEW (ev_web_view_get_type ()) +#define EV_WEB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_WEB_VIEW, EvWebView)) +#define EV_IS_WEB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_WEB_VIEW)) + +GType ev_web_view_get_type (void) G_GNUC_CONST; + +GtkWidget* ev_web_view_new (void); + +void ev_web_view_set_model (EvWebView *webview, + EvDocumentModel *model); + +void ev_web_view_reload (EvWebView *webview); + +void ev_web_view_reload_page (EvWebView *webview, + gint page); + +/* Navigation */ +gboolean ev_web_view_next_page (EvWebView *webview); +gboolean ev_web_view_previous_page (EvWebView *webview); + +/* Sidebar links */ +void ev_web_view_handle_link (EvWebView *webview, EvLink* link); + +/* Searching */ +void ev_web_view_find_next (EvWebView *webview); +void ev_web_view_find_previous (EvWebView *webview); + +void ev_web_view_find_changed (EvWebView *webview, + guint *results, + gchar *text, + gboolean case_sensitive); + +void ev_web_view_find_search_changed (EvWebView *webview); +void ev_web_view_find_cancel (EvWebView *webview); +void ev_web_view_find_set_highlight_search (EvWebView *webview,gboolean visible); +void ev_web_view_set_handler (EvWebView *webview,gboolean visible); +/* Selection */ +gboolean ev_web_view_get_has_selection (EvWebView *webview); +void ev_web_view_select_all (EvWebView *webview); +void ev_web_view_copy (EvWebView *webview); + +/* Zoom control */ +gboolean ev_web_view_zoom_in (EvWebView *webview); +gboolean ev_web_view_zoom_out (EvWebView *webview); + +/*For safe replacement by an EvView*/ +void ev_web_view_disconnect_handlers (EvWebView *webview); +G_END_DECLS + +#endif /* __EV_WEB_VIEW_H__ */ diff --git a/previewer/Makefile.am b/previewer/Makefile.am index 756446c4..5ac0d110 100644 --- a/previewer/Makefile.am +++ b/previewer/Makefile.am @@ -21,7 +21,8 @@ atril_previewer_CFLAGS = \ $(PREVIEWER_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED) \ - $(AM_CFLAGS) + $(AM_CFLAGS) \ + $(WEBKIT_CFLAGS) atril_previewer_LDFLAGS = $(AM_LDFLAGS) @@ -33,7 +34,8 @@ atril_previewer_LDADD = \ $(top_builddir)/libdocument/libatrildocument.la \ $(top_builddir)/libview/libatrilview.la \ $(top_builddir)/libmisc/libevmisc.la \ - $(PREVIEWER_LIBS) + $(PREVIEWER_LIBS) \ + $(WEBKIT_LIBS) EXTRA_DIST = $(man_MANS) diff --git a/shell/Makefile.am b/shell/Makefile.am index cd123aad..aff9fde0 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -20,6 +20,7 @@ AM_CPPFLAGS= \ -DATRIL_COMPILATION \ $(SHELL_CFLAGS) \ $(WARN_CFLAGS) \ + $(WEBKIT_CFLAGS) \ $(DISABLE_DEPRECATED) bin_PROGRAMS=atril @@ -109,7 +110,8 @@ atril_LDADD= \ $(top_builddir)/libdocument/libatrildocument.la \ $(top_builddir)/libview/libatrilview.la \ $(top_builddir)/libmisc/libevmisc.la \ - $(SHELL_LIBS) + $(SHELL_LIBS) \ + $(WEBKIT_LIBS) if PLATFORM_WIN32 atril_LDADD += atril-icon.o diff --git a/shell/ev-convert-metadata.c b/shell/ev-convert-metadata.c index 5664253b..72431dd5 100644 --- a/shell/ev-convert-metadata.c +++ b/shell/ev-convert-metadata.c @@ -26,7 +26,7 @@ #include <glib/gi18n.h> #include <string.h> #include <libxml/tree.h> - +#include <X11/Xlib.h> #define EV_METADATA_NAMESPACE "metadata::atril" typedef struct { @@ -294,7 +294,7 @@ main (gint argc, gchar **argv) g_printerr ("%s\n", "Usage: atril-convert-metadata FILE"); return 1; } - + XInitThreads(); gtk_init (&argc, &argv); if (!convert_metadata_file (argv[1])) diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c index ec03d998..a6102355 100644 --- a/shell/ev-sidebar-thumbnails.c +++ b/shell/ev-sidebar-thumbnails.c @@ -68,7 +68,6 @@ struct _EvSidebarThumbnailsPrivate { EvDocument *document; EvDocumentModel *model; EvThumbsSizeCache *size_cache; - gint n_pages, pages_done; int rotation; @@ -136,8 +135,14 @@ ev_thumbnails_size_cache_new (EvDocument *document) page = ev_document_get_page (document, i); - ev_document_get_page_size (document, i, &page_width, &page_height); - + if (document->iswebdocument == FALSE ) { + ev_document_get_page_size (document, i, &page_width, &page_height); + } + else { + /* Hardcoding these values to a large enough dimesnsion so as to achieve max content without loss in visibility*/ + page_width = 800; + page_height = 1080; + } if (!rc) { rc = ev_render_context_new (page, 0, (gdouble)THUMBNAIL_WIDTH / page_width); } else { @@ -368,6 +373,7 @@ clear_range (EvSidebarThumbnails *sidebar_thumbnails, result && start_page <= end_page; result = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store), &iter), start_page ++) { EvJobThumbnail *job; + GdkPixbuf *loading_icon = NULL; gint width, height; @@ -409,9 +415,12 @@ get_scale_for_page (EvSidebarThumbnails *sidebar_thumbnails, { EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv; gdouble width; - - ev_document_get_page_size (priv->document, page, &width, NULL); - + if (priv->document->iswebdocument == TRUE ) { + /* Hardcoded for epub documents*/ + width = 800; + } else { + ev_document_get_page_size (priv->document, page, &width, NULL); + } return (gdouble)THUMBNAIL_WIDTH / width; } @@ -444,6 +453,11 @@ add_range (EvSidebarThumbnails *sidebar_thumbnails, job = ev_job_thumbnail_new (priv->document, page, priv->rotation, get_scale_for_page (sidebar_thumbnails, page)); + + if (priv->document->iswebdocument) { + ev_job_set_run_mode(job, EV_JOB_RUN_MAIN_LOOP); + } + ev_job_scheduler_push_job (EV_JOB (job), EV_JOB_PRIORITY_HIGH); g_object_set_data_full (G_OBJECT (job), "tree_iter", diff --git a/shell/ev-window.c b/shell/ev-window.c index d3a8181d..c1e389b3 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -88,6 +88,7 @@ #include "ev-utils.h" #include "ev-keyring.h" #include "ev-view.h" +#include "ev-web-view.h" #include "ev-view-presentation.h" #include "ev-view-type-builtins.h" #include "ev-window.h" @@ -142,7 +143,9 @@ struct _EvWindowPrivate { GtkWidget *sidebar_attachments; GtkWidget *sidebar_layers; GtkWidget *sidebar_annots; - +#ifdef ENABLE_EPUB + GtkWidget *webview; +#endif /* Settings */ GSettings *settings; GSettings *default_settings; @@ -406,7 +409,9 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) if (has_document && EV_IS_SELECTION (document)) { can_get_text = TRUE; } - + else if (has_document && document->iswebdocument) { + can_get_text = TRUE; + } if (has_pages && EV_IS_DOCUMENT_FIND (document)) { can_find = TRUE; } @@ -445,18 +450,21 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) ev_window_set_action_sensitive (ev_window, "EditSelectAll", has_pages && can_get_text); ev_window_set_action_sensitive (ev_window, "EditFind", can_find); ev_window_set_action_sensitive (ev_window, "Slash", can_find); - ev_window_set_action_sensitive (ev_window, "EditRotateLeft", has_pages); - ev_window_set_action_sensitive (ev_window, "EditRotateRight", has_pages); + ev_window_set_action_sensitive (ev_window, "EditRotateLeft", has_pages && !(document->iswebdocument)); + ev_window_set_action_sensitive (ev_window, "EditRotateRight", has_pages && !(document->iswebdocument)); /* View menu */ - ev_window_set_action_sensitive (ev_window, "ViewContinuous", has_pages); - ev_window_set_action_sensitive (ev_window, "ViewDual", has_pages); - ev_window_set_action_sensitive (ev_window, "ViewBestFit", has_pages); - ev_window_set_action_sensitive (ev_window, "ViewPageWidth", has_pages); + /*If it has pages it is a document, so our check for a webdocument won't lead to a crash. We need to switch these view modes off since more than one + *webview is hard to manage, and would lead to unexpected behaviour in case the number of webviews gets too large. + */ + ev_window_set_action_sensitive (ev_window, "ViewContinuous", has_pages && !(document->iswebdocument)); + ev_window_set_action_sensitive (ev_window, "ViewDual", has_pages && !(document->iswebdocument)); + ev_window_set_action_sensitive (ev_window, "ViewBestFit", has_pages && !(document->iswebdocument)); + ev_window_set_action_sensitive (ev_window, "ViewPageWidth", has_pages && !(document->iswebdocument)); ev_window_set_action_sensitive (ev_window, "ViewReload", has_pages); - ev_window_set_action_sensitive (ev_window, "ViewAutoscroll", has_pages); + ev_window_set_action_sensitive (ev_window, "ViewAutoscroll", has_pages && !(document->iswebdocument)); ev_window_set_action_sensitive (ev_window, "ViewInvertedColors", has_pages); - ev_window_set_action_sensitive (ev_window, "ViewExpandWindow", has_pages); + ev_window_set_action_sensitive (ev_window, "ViewExpandWindow", has_pages && !(document->iswebdocument)); /* Toolbar-specific actions: */ ev_window_set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages); @@ -469,7 +477,9 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) static void ev_window_update_actions (EvWindow *ev_window) { - EvView *view = EV_VIEW (ev_window->priv->view); + EvWebView *webview = NULL; + EvView *view = NULL; + int n_pages = 0, page = -1; gboolean has_pages = FALSE; gboolean presentation_mode; @@ -482,12 +492,36 @@ ev_window_update_actions (EvWindow *ev_window) has_pages = n_pages > 0; } + if (ev_window->priv->document && ev_window->priv->document->iswebdocument == TRUE ) { + webview = EV_WEB_VIEW(ev_window->priv->webview); + } else { + view = EV_VIEW (ev_window->priv->view); + } + can_find_in_page = (ev_window->priv->find_job && ev_job_find_has_results (EV_JOB_FIND (ev_window->priv->find_job))); - - ev_window_set_action_sensitive (ev_window, "EditCopy", - has_pages && - ev_view_get_has_selection (view)); + if (view) { + ev_window_set_action_sensitive (ev_window, "EditCopy", + has_pages && + ev_view_get_has_selection (view)); + } +#if GTK_CHECK_VERSION (3, 0, 0) + else if (webview) { + /* + * The webkit2 function for this is an asynchronous call, + * so our only option is to set this to always on, and we'll take care of whether we can copy + * or not when this command is actually given. + */ + ev_window_set_action_sensitive (ev_window,"EditCopy", + has_pages); + } +#else + else if(webview) { + ev_window_set_action_sensitive (ev_window, "EditCopy", + has_pages && + ev_web_view_get_has_selection (webview)); + } +#endif ev_window_set_action_sensitive (ev_window, "EditFindNext", has_pages && can_find_in_page); ev_window_set_action_sensitive (ev_window, "EditFindPrevious", @@ -497,15 +531,16 @@ ev_window_update_actions (EvWindow *ev_window) presentation_mode = EV_WINDOW_IS_PRESENTATION (ev_window); - ev_window_set_action_sensitive (ev_window, "ViewZoomIn", - has_pages && - ev_view_can_zoom_in (view) && - !presentation_mode); - ev_window_set_action_sensitive (ev_window, "ViewZoomOut", - has_pages && - ev_view_can_zoom_out (view) && - !presentation_mode); - + if (ev_window->priv->document && ev_window->priv->document->iswebdocument == FALSE ) { + ev_window_set_action_sensitive (ev_window, "ViewZoomIn", + has_pages && + ev_view_can_zoom_in (view) && + !presentation_mode); + ev_window_set_action_sensitive (ev_window, "ViewZoomOut", + has_pages && + ev_view_can_zoom_out (view) && + !presentation_mode); + } /* Go menu */ if (has_pages) { ev_window_set_action_sensitive (ev_window, "GoPreviousPage", page > 0); @@ -660,8 +695,10 @@ update_sizing_buttons (EvWindow *window) ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), EPHY_ZOOM_BEST_FIT); } else if (page_width) { - ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), - EPHY_ZOOM_FIT_WIDTH); + if (!window->priv->document || (window->priv->document && !window->priv->document->iswebdocument)) { + ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), + EPHY_ZOOM_FIT_WIDTH); + } } } @@ -904,6 +941,15 @@ view_selection_changed_cb (EvView *view, ev_window_set_action_sensitive (window, "EditCopy", ev_view_get_has_selection (view)); } +#if !GTK_CHECK_VERSION (3, 0, 0) +static void +web_view_selection_changed_cb(EvWebView *webview, + EvWindow *window) +{ + ev_window_set_action_sensitive (window,"EditCopy", + ev_web_view_get_has_selection(webview)); +} +#endif static void ev_window_page_changed_cb (EvWindow *ev_window, @@ -987,6 +1033,12 @@ static void update_document_mode (EvWindow *window, EvDocumentMode mode) { if (mode == EV_DOCUMENT_MODE_PRESENTATION) { + if (window->priv->document) { + if (window->priv->document->iswebdocument) { + ev_window_warning_message(window,_("Cannot enter presentation mode with ePub documents use fullscreen mode instead.")); + return; + } + } ev_window_run_presentation (window); } else if (mode == EV_DOCUMENT_MODE_FULL_SCREEN) { @@ -1278,7 +1330,12 @@ setup_view_from_metadata (EvWindow *window) /* Presentation */ if (ev_metadata_get_boolean (window->priv->metadata, "presentation", &presentation)) { if (presentation) { - ev_window_run_presentation (window); + if (window->priv->document->iswebdocument == TRUE ) { + return; + } + else { + ev_window_run_presentation (window); + } } } } @@ -1333,6 +1390,10 @@ ev_window_refresh_window_thumbnail (EvWindow *ev_window) rotation = ev_document_model_get_rotation (ev_window->priv->model); ev_window->priv->thumbnail_job = ev_job_thumbnail_new (document, 0, rotation, scale); + + if (document->iswebdocument) { + ev_job_set_run_mode(EV_JOB(ev_window->priv->thumbnail_job), EV_JOB_RUN_MAIN_LOOP); + } g_signal_connect (ev_window->priv->thumbnail_job, "finished", G_CALLBACK (ev_window_set_icon_from_thumbnail), ev_window); @@ -1363,10 +1424,10 @@ ev_window_setup_document (EvWindow *ev_window) GtkAction *action; ev_window->priv->setup_document_idle = 0; - ev_window_refresh_window_thumbnail (ev_window); - + ev_window_set_page_mode (ev_window, PAGE_MODE_DOCUMENT); + ev_window_title_set_document (ev_window->priv->title, document); ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri); @@ -1403,12 +1464,15 @@ ev_window_setup_document (EvWindow *ev_window) info = ev_document_get_info (document); update_document_mode (ev_window, info->mode); - - if (EV_WINDOW_IS_PRESENTATION (ev_window)) + /*FIXME*/ + if (EV_WINDOW_IS_PRESENTATION (ev_window) && document->iswebdocument == FALSE) gtk_widget_grab_focus (ev_window->priv->presentation_view); - else - gtk_widget_grab_focus (ev_window->priv->view); - + else { + if ( document->iswebdocument == FALSE ) + gtk_widget_grab_focus (ev_window->priv->view); + else + gtk_widget_grab_focus (ev_window->priv->webview); + } return FALSE; } @@ -1429,15 +1493,40 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document) if (ev_document_get_n_pages (document) <= 0) { ev_window_warning_message (ev_window, "%s", _("The document contains no pages")); - } else if (!ev_document_check_dimensions (document)) { + } else if (!ev_document_check_dimensions (document) && document->iswebdocument == FALSE) { ev_window_warning_message (ev_window, "%s", _("The document contains only empty pages")); } - - if (EV_WINDOW_IS_PRESENTATION (ev_window)) { +#ifdef ENABLE_EPUB + GtkWidget *parent= gtk_widget_get_parent(ev_window->priv->webview); + if (document->iswebdocument == TRUE && + parent == NULL ) + { + /*We have encountered a web document, replace the atril view with a web view, if the web view is not already loaded.*/ + gtk_container_remove (GTK_CONTAINER(ev_window->priv->scrolled_window), + ev_window->priv->view); + ev_view_disconnect_handlers(EV_VIEW(ev_window->priv->view)); + g_object_unref(ev_window->priv->view); + ev_window->priv->view = NULL; + gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window), + ev_window->priv->webview); + gtk_widget_show(ev_window->priv->webview); + } + else { + /*Since the document is not a webdocument might as well get rid of the webview now*/ + ev_web_view_disconnect_handlers(EV_WEB_VIEW(ev_window->priv->webview)); + g_object_ref_sink(ev_window->priv->webview); + g_object_unref(ev_window->priv->webview); + } +#endif + if (EV_WINDOW_IS_PRESENTATION (ev_window) && document->iswebdocument == FALSE) { gtk_widget_destroy (ev_window->priv->presentation_view); ev_window->priv->presentation_view = NULL; ev_window_run_presentation (ev_window); + } else if ( EV_WINDOW_IS_PRESENTATION (ev_window) && document->iswebdocument == TRUE ) + { + ev_window_warning_message (ev_window, "%s", + _("Presentation mode is not supported for ePub documents.")); } if (ev_window->priv->setup_document_idle > 0) @@ -1505,6 +1594,9 @@ static void ev_window_handle_link (EvWindow *ev_window, EvLinkDest *dest) { + if (ev_window->priv->document->iswebdocument == FALSE ) { + return; + } if (dest) { EvLink *link; EvLinkAction *link_action; @@ -1535,9 +1627,8 @@ ev_window_load_job_cb (EvJob *job, g_assert (job_load->uri); ev_view_set_loading (EV_VIEW (ev_window->priv->view), FALSE); - /* Success! */ - if (!ev_job_is_failed (job)) { + if (!ev_job_is_failed (job)) { ev_document_model_set_document (ev_window->priv->model, document); #ifdef ENABLE_DBUS @@ -1799,6 +1890,8 @@ static void ev_window_load_remote_failed (EvWindow *ev_window, GError *error) { + if ( !ev_window->priv->view ) return; + ev_view_set_loading (EV_VIEW (ev_window->priv->view), FALSE); ev_window->priv->in_reload = FALSE; ev_window_error_message (ev_window, error, @@ -2054,9 +2147,6 @@ ev_window_open_document (EvWindow *ev_window, EvWindowRunMode mode, const gchar *search_string) { - if (document == ev_window->priv->document) - return; - ev_window_close_dialogs (ev_window); ev_window_clear_load_job (ev_window); ev_window_clear_local_uri (ev_window); @@ -2078,7 +2168,7 @@ ev_window_open_document (EvWindow *ev_window, setup_document_from_metadata (ev_window); setup_view_from_metadata (ev_window); - if (dest) { + if (dest && document->iswebdocument == FALSE) { EvLink *link; EvLinkAction *link_action; @@ -2272,13 +2362,10 @@ ev_window_reload_document (EvWindow *ev_window, EvLinkDest *dest) { gint page; - - ev_window_clear_reload_job (ev_window); ev_window->priv->in_reload = TRUE; page = ev_document_model_get_page (ev_window->priv->model); - if (ev_window->priv->dest) g_object_unref (ev_window->priv->dest); ev_window->priv->dest = dest ? g_object_ref (dest) : NULL; @@ -3605,12 +3692,18 @@ ev_window_cmd_focus_page_selector (GtkAction *act, EvWindow *window) static void ev_window_cmd_scroll_forward (GtkAction *action, EvWindow *window) { + /*If the webview is occupying the window*/ + if ( window->priv->document->iswebdocument == TRUE) return ; + ev_view_scroll (EV_VIEW (window->priv->view), GTK_SCROLL_PAGE_FORWARD, FALSE); } static void ev_window_cmd_scroll_backward (GtkAction *action, EvWindow *window) { + /*If the webview is occupying the window*/ + if ( window->priv->document->iswebdocument == TRUE ) return ; + ev_view_scroll (EV_VIEW (window->priv->view), GTK_SCROLL_PAGE_BACKWARD, FALSE); } @@ -3673,8 +3766,10 @@ ev_window_cmd_edit_select_all (GtkAction *action, EvWindow *ev_window) */ if (ev_window->priv->chrome & EV_CHROME_FINDBAR) { egg_find_bar_grab_focus(ev_window->priv->find_bar); - } else { + } else if (ev_window->priv->document->iswebdocument == FALSE ) { ev_view_select_all (EV_VIEW (ev_window->priv->view)); + } else { + ev_web_view_select_all(EV_WEB_VIEW(ev_window->priv->webview)); } } @@ -3701,7 +3796,11 @@ ev_window_cmd_edit_find_next (GtkAction *action, EvWindow *ev_window) update_chrome_flag (ev_window, EV_CHROME_FINDBAR, TRUE); update_chrome_visibility (ev_window); gtk_widget_grab_focus (ev_window->priv->find_bar); - ev_view_find_next (EV_VIEW (ev_window->priv->view)); + if (ev_window->priv->document->iswebdocument == FALSE) { + ev_view_find_next (EV_VIEW (ev_window->priv->view)); + } else { + ev_web_view_find_next(EV_WEB_VIEW(ev_window->priv->webview)); + } } static void @@ -3712,15 +3811,23 @@ ev_window_cmd_edit_find_previous (GtkAction *action, EvWindow *ev_window) update_chrome_flag (ev_window, EV_CHROME_FINDBAR, TRUE); update_chrome_visibility (ev_window); gtk_widget_grab_focus (ev_window->priv->find_bar); - ev_view_find_previous (EV_VIEW (ev_window->priv->view)); + if (ev_window->priv->document->iswebdocument == FALSE) { + ev_view_find_previous (EV_VIEW (ev_window->priv->view)); + } else { + ev_web_view_find_previous(EV_WEB_VIEW(ev_window->priv->webview)); + } } static void ev_window_cmd_edit_copy (GtkAction *action, EvWindow *ev_window) { g_return_if_fail (EV_IS_WINDOW (ev_window)); - - ev_view_copy (EV_VIEW (ev_window->priv->view)); + + if (ev_window->priv->document->iswebdocument) { + ev_web_view_copy(EV_WEB_VIEW(ev_window->priv->webview)); + } else { + ev_view_copy (EV_VIEW (ev_window->priv->view)); + } } static void @@ -3832,8 +3939,12 @@ ev_window_run_fullscreen (EvWindow *window) if (fullscreen_window) gtk_window_fullscreen (GTK_WINDOW (window)); - gtk_widget_grab_focus (window->priv->view); - + if (window->priv->view) { + gtk_widget_grab_focus (window->priv->view); + } + else { + gtk_widget_grab_focus(window->priv->webview); + } if (window->priv->metadata && !ev_window_is_empty (window)) ev_metadata_set_boolean (window->priv->metadata, "fullscreen", TRUE); } @@ -3903,7 +4014,11 @@ ev_window_run_presentation (EvWindow *window) if (EV_WINDOW_IS_PRESENTATION (window)) return; - + + if (window->priv->document->iswebdocument) { + ev_window_warning_message(window,_("Presentation mode is not supported for ePub documents")); + return; + } if (ev_document_model_get_fullscreen (window->priv->model)) { ev_window_stop_fullscreen (window, FALSE); fullscreen_window = FALSE; @@ -3961,9 +4076,13 @@ ev_window_stop_presentation (EvWindow *window, update_chrome_visibility (window); if (unfullscreen_window) gtk_window_unfullscreen (GTK_WINDOW (window)); - - gtk_widget_grab_focus (window->priv->view); - + + if (window->priv->view) { + gtk_widget_grab_focus (window->priv->view); + } else { + gtk_widget_grab_focus (window->priv->webview); + } + ev_application_screensaver_enable (EV_APP); if (window->priv->metadata && !ev_window_is_empty (window)) @@ -4099,7 +4218,12 @@ ev_window_set_page_mode (EvWindow *window, switch (page_mode) { case PAGE_MODE_DOCUMENT: - child = window->priv->view; + if ( window->priv->document && window->priv->document->iswebdocument == FALSE ) { + child = window->priv->view; + } + else { + child=window->priv->webview; + } break; case PAGE_MODE_PASSWORD: child = window->priv->password_view; @@ -4241,7 +4365,12 @@ ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window) g_return_if_fail (EV_IS_WINDOW (ev_window)); ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE); - ev_view_zoom_in (EV_VIEW (ev_window->priv->view)); + if (ev_window->priv->document->iswebdocument) { + ev_web_view_zoom_in(EV_WEB_VIEW(ev_window->priv->webview)); + } + else { + ev_view_zoom_in (EV_VIEW (ev_window->priv->view)); + } } static void @@ -4250,15 +4379,24 @@ ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window) g_return_if_fail (EV_IS_WINDOW (ev_window)); ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE); - ev_view_zoom_out (EV_VIEW (ev_window->priv->view)); + + if ( ev_window->priv->document->iswebdocument) { + ev_web_view_zoom_out(EV_WEB_VIEW(ev_window->priv->webview)); + } + else { + ev_view_zoom_out (EV_VIEW (ev_window->priv->view)); + } } static void ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window) { g_return_if_fail (EV_IS_WINDOW (ev_window)); - - ev_view_previous_page (EV_VIEW (ev_window->priv->view)); + if ( ev_window->priv->document->iswebdocument == TRUE ) { + ev_web_view_previous_page(EV_WEB_VIEW(ev_window->priv->webview)); + } else { + ev_view_previous_page (EV_VIEW (ev_window->priv->view)); + } } static void @@ -4266,7 +4404,11 @@ ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window) { g_return_if_fail (EV_IS_WINDOW (ev_window)); - ev_view_next_page (EV_VIEW (ev_window->priv->view)); + if ( ev_window->priv->document->iswebdocument == TRUE ) { + ev_web_view_next_page(EV_WEB_VIEW(ev_window->priv->webview)); + } else { + ev_view_next_page (EV_VIEW (ev_window->priv->view)); + } } static void @@ -4332,7 +4474,12 @@ ev_window_cmd_view_expand_window (GtkAction *action, EvWindow *ev_window) static void ev_window_cmd_view_autoscroll (GtkAction *action, EvWindow *ev_window) { - ev_view_autoscroll_start (EV_VIEW (ev_window->priv->view)); + EvDocument* document = ev_window->priv->document; + if (document->iswebdocument == TRUE ) { + return ; + }else { + ev_view_autoscroll_start (EV_VIEW (ev_window->priv->view)); + } } #define EV_HELP "help:atril" @@ -4370,13 +4517,18 @@ ev_window_cmd_escape (GtkAction *action, EvWindow *window) { GtkWidget *widget; - ev_view_autoscroll_stop (EV_VIEW (window->priv->view)); + if (!window->priv->document->iswebdocument && window->priv->view) + ev_view_autoscroll_stop (EV_VIEW (window->priv->view)); widget = gtk_window_get_focus (GTK_WINDOW (window)); if (widget && gtk_widget_get_ancestor (widget, EGG_TYPE_FIND_BAR)) { update_chrome_flag (window, EV_CHROME_FINDBAR, FALSE); update_chrome_visibility (window); - gtk_widget_grab_focus (window->priv->view); + + if (window->priv->view) + gtk_widget_grab_focus (window->priv->view); + else + gtk_widget_grab_focus (window->priv->webview); } else { gboolean fullscreen; @@ -4388,7 +4540,10 @@ ev_window_cmd_escape (GtkAction *action, EvWindow *window) ev_window_stop_presentation (window, TRUE); gtk_widget_grab_focus (window->priv->view); } else { - gtk_widget_grab_focus (window->priv->view); + if (window->priv->view) + gtk_widget_grab_focus (window->priv->view); + else + gtk_widget_grab_focus (window->priv->webview); } if (fullscreen && EV_WINDOW_IS_PRESENTATION (window)) @@ -4585,6 +4740,7 @@ ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window) "Perberos <[email protected]>", "Stefano Karapetsas <[email protected]>", "Steve Zesch <[email protected]>", + "Avishkar Gupta <[email protected]>", NULL }; @@ -4707,6 +4863,8 @@ view_menu_link_popup (EvWindow *ev_window, gboolean show_external = FALSE; gboolean show_internal = FALSE; GtkAction *action; + + if ( ev_window->priv->document->iswebdocument == TRUE ) return ; if (ev_window->priv->link) g_object_unref (ev_window->priv->link); @@ -4759,7 +4917,8 @@ view_menu_image_popup (EvWindow *ev_window, { GtkAction *action; gboolean show_image = FALSE; - + + if (ev_window->priv->document->iswebdocument == TRUE ) return ; if (ev_window->priv->image) g_object_unref (ev_window->priv->image); @@ -4785,7 +4944,7 @@ view_menu_annot_popup (EvWindow *ev_window, { GtkAction *action; gboolean show_annot = FALSE; - + if (ev_window->priv->document->iswebdocument == TRUE ) return ; if (ev_window->priv->annot) g_object_unref (ev_window->priv->annot); ev_window->priv->annot = (annot) ? g_object_ref (annot) : NULL; @@ -4934,10 +5093,15 @@ ev_window_find_job_updated_cb (EvJobFind *job, EvWindow *ev_window) { ev_window_update_actions (ev_window); - - ev_view_find_changed (EV_VIEW (ev_window->priv->view), - ev_job_find_get_results (job), - page); + if (ev_window->priv->document->iswebdocument == TRUE ) { + ev_web_view_find_changed(EV_WEB_VIEW(ev_window->priv->webview), + job->results,job->text, job->case_sensitive); + } + else { + ev_view_find_changed (EV_VIEW (ev_window->priv->view), + ev_job_find_get_results (job), + page); + } ev_window_update_find_status_message (ev_window); } @@ -4963,21 +5127,34 @@ static void find_bar_previous_cb (EggFindBar *find_bar, EvWindow *ev_window) { - ev_view_find_previous (EV_VIEW (ev_window->priv->view)); + if (ev_window->priv->document->iswebdocument == TRUE ) { + ev_web_view_find_previous(EV_WEB_VIEW(ev_window->priv->webview)); + }else { + ev_view_find_previous (EV_VIEW (ev_window->priv->view)); + } } static void find_bar_next_cb (EggFindBar *find_bar, EvWindow *ev_window) { - ev_view_find_next (EV_VIEW (ev_window->priv->view)); + if (ev_window->priv->document->iswebdocument == TRUE ) { + ev_web_view_find_next(EV_WEB_VIEW(ev_window->priv->webview)); + } else { + ev_view_find_next (EV_VIEW (ev_window->priv->view)); + } } static void find_bar_close_cb (EggFindBar *find_bar, EvWindow *ev_window) { - ev_view_find_cancel (EV_VIEW (ev_window->priv->view)); + if (ev_window->priv->document->iswebdocument == TRUE ) { + ev_web_view_find_cancel(EV_WEB_VIEW(ev_window->priv->webview)); + } + else { + ev_view_find_cancel (EV_VIEW (ev_window->priv->view)); + } ev_window_clear_find_job (ev_window); update_chrome_flag (ev_window, EV_CHROME_FINDBAR, FALSE); update_chrome_visibility (ev_window); @@ -4998,8 +5175,11 @@ find_bar_search_changed_cb (EggFindBar *find_bar, case_sensitive = egg_find_bar_get_case_sensitive (find_bar); search_string = egg_find_bar_get_search_string (find_bar); - ev_view_find_search_changed (EV_VIEW (ev_window->priv->view)); - + if (ev_window->priv->document->iswebdocument) { + ev_web_view_find_search_changed(EV_WEB_VIEW(ev_window->priv->webview)); + } else { + ev_view_find_search_changed (EV_VIEW (ev_window->priv->view)); + } ev_window_clear_find_job (ev_window); if (search_string && search_string[0]) { @@ -5008,6 +5188,7 @@ find_bar_search_changed_cb (EggFindBar *find_bar, ev_document_get_n_pages (ev_window->priv->document), search_string, case_sensitive); + g_signal_connect (ev_window->priv->find_job, "finished", G_CALLBACK (ev_window_find_job_finished_cb), ev_window); @@ -5019,7 +5200,9 @@ find_bar_search_changed_cb (EggFindBar *find_bar, ev_window_update_actions (ev_window); egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar), NULL); - gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view)); + if (ev_window->priv->document->iswebdocument == FALSE) { + gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view)); + } } } @@ -5029,13 +5212,23 @@ find_bar_visibility_changed_cb (EggFindBar *find_bar, EvWindow *ev_window) { gboolean visible; - visible = gtk_widget_get_visible (GTK_WIDGET (find_bar)); if (ev_window->priv->document && EV_IS_DOCUMENT_FIND (ev_window->priv->document)) { - ev_view_find_set_highlight_search (EV_VIEW (ev_window->priv->view), visible); - ev_view_find_search_changed (EV_VIEW (ev_window->priv->view)); + + if (!ev_window->priv->document->iswebdocument) { + ev_view_find_set_highlight_search (EV_VIEW (ev_window->priv->view), visible); + ev_view_find_search_changed (EV_VIEW (ev_window->priv->view)); + } + else { +#if !GTK_CHECK_VERSION(3, 0, 0) + ev_web_view_find_set_highlight_search(EV_WEB_VIEW(ev_window->priv->webview),visible); +#endif + ev_web_view_find_search_changed(EV_WEB_VIEW(ev_window->priv->webview)); + ev_web_view_set_handler(EV_WEB_VIEW(ev_window->priv->webview),visible); + } + ev_window_update_actions (ev_window); if (visible) @@ -5050,6 +5243,7 @@ find_bar_scroll (EggFindBar *find_bar, GtkScrollType scroll, EvWindow *ev_window) { + if (ev_window->priv->document->iswebdocument == TRUE ) return ; ev_view_scroll (EV_VIEW (ev_window->priv->view), scroll, FALSE); } @@ -5296,7 +5490,7 @@ ev_window_dispose (GObject *object) } if (priv->view) { - g_object_unref (priv->view); + g_object_unref (priv->view); priv->view = NULL; } @@ -5422,13 +5616,13 @@ ev_window_key_press_event (GtkWidget *widget, * It's needed to be able to type in * annot popups windows */ - if (priv->view) { + if ( priv->view) { g_object_ref (priv->view); if (gtk_widget_is_sensitive (priv->view)) handled = gtk_widget_event (priv->view, (GdkEvent*) event); g_object_unref (priv->view); } - + if (!handled && !EV_WINDOW_IS_PRESENTATION (ev_window)) { guint modifier = event->state & gtk_accelerator_get_default_mod_mask (); @@ -5689,19 +5883,35 @@ static const GtkActionEntry attachment_popup_entries [] = { static void sidebar_links_link_activated_cb (EvSidebarLinks *sidebar_links, EvLink *link, EvWindow *window) { - ev_view_handle_link (EV_VIEW (window->priv->view), link); + if (window->priv->document->iswebdocument == FALSE ) { + ev_view_handle_link (EV_VIEW (window->priv->view), link); + } + else { + ev_web_view_handle_link(EV_WEB_VIEW(window->priv->webview), link); + } } static void activate_link_cb (EvPageAction *page_action, EvLink *link, EvWindow *window) { - ev_view_handle_link (EV_VIEW (window->priv->view), link); - gtk_widget_grab_focus (window->priv->view); + if (window->priv->view) { + ev_view_handle_link (EV_VIEW (window->priv->view), link); + gtk_widget_grab_focus (window->priv->view); + } + else { + ev_web_view_handle_link (EV_WEB_VIEW (window->priv->webview), link); + gtk_widget_grab_focus (window->priv->webview); + } } static void navigation_action_activate_link_cb (EvNavigationAction *action, EvLink *link, EvWindow *window) { + if (window->priv->document->iswebdocument == TRUE ) { + ev_web_view_handle_link(EV_WEB_VIEW(window->priv->webview),link); + gtk_widget_grab_focus (window->priv->webview); + return; + } ev_view_handle_link (EV_VIEW (window->priv->view), link); gtk_widget_grab_focus (window->priv->view); @@ -5711,7 +5921,13 @@ static void sidebar_layers_visibility_changed (EvSidebarLayers *layers, EvWindow *window) { - ev_view_reload (EV_VIEW (window->priv->view)); + if (window->priv->document->iswebdocument == FALSE ) { + ev_view_reload (EV_VIEW (window->priv->view)); + } + else + { + ev_web_view_reload(EV_WEB_VIEW(window->priv->webview)); + } } static void @@ -5719,6 +5935,7 @@ sidebar_annots_annot_activated_cb (EvSidebarAnnotations *sidebar_annots, EvMapping *annot_mapping, EvWindow *window) { + if (window->priv->document->iswebdocument == TRUE ) return; ev_view_focus_annotation (EV_VIEW (window->priv->view), annot_mapping); } @@ -5727,6 +5944,7 @@ sidebar_annots_begin_annot_add (EvSidebarAnnotations *sidebar_annots, EvAnnotationType annot_type, EvWindow *window) { + if (window->priv->document->iswebdocument == TRUE ) return; ev_view_begin_add_annotation (EV_VIEW (window->priv->view), annot_type); } @@ -5743,6 +5961,7 @@ static void sidebar_annots_annot_add_cancelled (EvSidebarAnnotations *sidebar_annots, EvWindow *window) { + if (window->priv->document->iswebdocument == TRUE ) return; ev_view_cancel_add_annotation (EV_VIEW (window->priv->view)); } @@ -6146,6 +6365,7 @@ view_external_link_cb (EvView *view, EvLinkAction *action, EvWindow *window) static void ev_view_popup_cmd_open_link (GtkAction *action, EvWindow *window) { + if (window->priv->document->iswebdocument == TRUE ) return; ev_view_handle_link (EV_VIEW (window->priv->view), window->priv->link); } @@ -6170,7 +6390,7 @@ static void ev_view_popup_cmd_copy_link_address (GtkAction *action, EvWindow *window) { EvLinkAction *ev_action; - + if (window->priv->document->iswebdocument == TRUE ) return; ev_action = ev_link_get_action (window->priv->link); if (!ev_action) return; @@ -6345,6 +6565,8 @@ static void ev_view_popup_cmd_annot_properties (GtkAction *action, EvWindow *window) { + if (window->priv->document->iswebdocument == TRUE ) return; + const gchar *author; GdkColor color; gdouble opacity; @@ -6730,8 +6952,9 @@ method_call_cb (GDBusConnection *connection, GDBusMethodInvocation *invocation, gpointer user_data) { - EvWindow *window = EV_WINDOW (user_data); - + EvWindow *window = EV_WINDOW (user_data); + if (window->priv->document->iswebdocument == TRUE ) return; + if (g_strcmp0 (method_name, "SyncView") != 0) return; @@ -7025,6 +7248,16 @@ ev_window_init (EvWindow *ev_window) gtk_widget_show (ev_window->priv->view_box); ev_window->priv->view = ev_view_new (); + +#ifdef ENABLE_EPUB /*The webview, we won't add it now but it will replace the atril-view if a web(epub) document is encountered.*/ + ev_window->priv->webview = ev_web_view_new(); + ev_web_view_set_model(EV_WEB_VIEW(ev_window->priv->webview),ev_window->priv->model); +#if !GTK_CHECK_VERSION (3, 0, 0) + g_signal_connect_object (ev_window->priv->webview,"selection-changed", + G_CALLBACK(web_view_selection_changed_cb), + ev_window, 0); +#endif +#endif ev_view_set_page_cache_size (EV_VIEW (ev_window->priv->view), PAGE_CACHE_SIZE); ev_view_set_model (EV_VIEW (ev_window->priv->view), ev_window->priv->model); @@ -7071,9 +7304,9 @@ ev_window_init (EvWindow *ev_window) /* We own a ref on these widgets, as we can swap them in and out */ g_object_ref (ev_window->priv->view); g_object_ref (ev_window->priv->password_view); - + gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window), - ev_window->priv->view); + ev_window->priv->view); /* Connect to model signals */ g_signal_connect_swapped (ev_window->priv->model, |