1 /* GepubArchive
2 *
3 * Copyright (C) 2011 Daniel Garcia <danigm@wadobo.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <config.h>
21 #include <libxml/parser.h>
22 #include <libxml/tree.h>
23 #include <archive.h>
24 #include <archive_entry.h>
25
26 #include "gepub-archive.h"
27 #include "gepub-utils.h"
28
29 #define BUFZISE 1024
30
31 struct _GepubArchive {
32 GObject parent;
33
34 struct archive *archive;
35 gchar *path;
36 };
37
38 struct _GepubArchiveClass {
39 GObjectClass parent_class;
40 };
41
G_DEFINE_TYPE(GepubArchive,gepub_archive,G_TYPE_OBJECT)42 G_DEFINE_TYPE (GepubArchive, gepub_archive, G_TYPE_OBJECT)
43
44 static gboolean
45 gepub_archive_open (GepubArchive *archive)
46 {
47 int r;
48
49 archive->archive = archive_read_new ();
50 archive_read_support_format_zip (archive->archive);
51
52 r = archive_read_open_filename (archive->archive, archive->path, 10240);
53
54 if (r != ARCHIVE_OK) {
55 return FALSE;
56 }
57
58 return TRUE;
59 }
60
61 static void
gepub_archive_close(GepubArchive * archive)62 gepub_archive_close (GepubArchive *archive)
63 {
64 if (!archive->archive)
65 return;
66
67 archive_read_free (archive->archive);
68 archive->archive = NULL;
69 }
70
71 static void
gepub_archive_finalize(GObject * object)72 gepub_archive_finalize (GObject *object)
73 {
74 GepubArchive *archive = GEPUB_ARCHIVE (object);
75
76 g_clear_pointer (&archive->path, g_free);
77
78 gepub_archive_close (archive);
79
80 G_OBJECT_CLASS (gepub_archive_parent_class)->finalize (object);
81 }
82
83 static void
gepub_archive_init(GepubArchive * archive)84 gepub_archive_init (GepubArchive *archive)
85 {
86 }
87
88 static void
gepub_archive_class_init(GepubArchiveClass * klass)89 gepub_archive_class_init (GepubArchiveClass *klass)
90 {
91 GObjectClass *object_class = G_OBJECT_CLASS (klass);
92
93 object_class->finalize = gepub_archive_finalize;
94 }
95
96 GepubArchive *
gepub_archive_new(const gchar * path)97 gepub_archive_new (const gchar *path)
98 {
99 GepubArchive *archive;
100
101 archive = GEPUB_ARCHIVE (g_object_new (GEPUB_TYPE_ARCHIVE, NULL));
102 archive->path = g_strdup (path);
103 archive->archive = NULL;
104
105 return archive;
106 }
107
108 /**
109 * gepub_archive_list_files:
110 * @archive: a #GepubArchive
111 *
112 * Returns: (element-type utf8) (transfer full): list of files in the archive
113 */
114 GList *
gepub_archive_list_files(GepubArchive * archive)115 gepub_archive_list_files (GepubArchive *archive)
116 {
117 struct archive_entry *entry;
118 GList *file_list = NULL;
119
120 if (!gepub_archive_open (archive))
121 return NULL;
122 while (archive_read_next_header (archive->archive, &entry) == ARCHIVE_OK) {
123 file_list = g_list_prepend (file_list, g_strdup (archive_entry_pathname (entry)));
124 archive_read_data_skip (archive->archive);
125 }
126 gepub_archive_close (archive);
127
128 return file_list;
129 }
130
131 GBytes *
gepub_archive_read_entry(GepubArchive * archive,const gchar * path)132 gepub_archive_read_entry (GepubArchive *archive,
133 const gchar *path)
134 {
135 struct archive_entry *entry;
136 guchar *buffer;
137 gint size;
138
139 if (!gepub_archive_open (archive))
140 return NULL;
141
142 while (archive_read_next_header (archive->archive, &entry) == ARCHIVE_OK) {
143 if (g_ascii_strcasecmp (path, archive_entry_pathname (entry)) == 0)
144 break;
145 archive_read_data_skip (archive->archive);
146 }
147
148 size = archive_entry_size (entry);
149 buffer = g_malloc0 (size);
150 archive_read_data (archive->archive, buffer, size);
151
152 gepub_archive_close (archive);
153 return g_bytes_new_take (buffer, size);
154 }
155
156 gchar *
gepub_archive_get_root_file(GepubArchive * archive)157 gepub_archive_get_root_file (GepubArchive *archive)
158 {
159 xmlDoc *doc = NULL;
160 xmlNode *root_element = NULL;
161 xmlNode *root_node = NULL;
162 GBytes *bytes;
163 const gchar *buffer;
164 gsize bufsize;
165 gchar *root_file = NULL;
166
167 // root file is in META-INF/container.xml
168 bytes = gepub_archive_read_entry (archive, "META-INF/container.xml");
169 if (!bytes)
170 return NULL;
171
172 buffer = g_bytes_get_data (bytes, &bufsize);
173 doc = xmlRecoverMemory (buffer, bufsize);
174 root_element = xmlDocGetRootElement (doc);
175 root_node = gepub_utils_get_element_by_tag (root_element, "rootfile");
176 root_file = gepub_utils_get_prop (root_node, "full-path");
177
178 xmlFreeDoc (doc);
179 g_bytes_unref (bytes);
180
181 return root_file;
182 }
183