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, | 
