Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-archive.c
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  * Copyright (C) 2017, Bastien Nocera <hadess@hadess.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 #include "ev-archive.h"
22 
23 #include <archive.h>
24 #include <archive_entry.h>
25 #include <unarr/unarr.h>
26 #include <gio/gio.h>
27 
28 #define BUFFER_SIZE (64 * 1024)
29 
30 struct _EvArchive {
31  GObject parent_instance;
33 
34  /* libarchive */
35  struct archive *libar;
36  struct archive_entry *libar_entry;
37 
38  /* unarr */
41 };
42 
43 G_DEFINE_TYPE(EvArchive, ev_archive, G_TYPE_OBJECT);
44 
45 static void
46 ev_archive_finalize (GObject *object)
47 {
48  EvArchive *archive = EV_ARCHIVE (object);
49 
50  switch (archive->type) {
52  g_clear_pointer (&archive->unarr, ar_close_archive);
53  g_clear_pointer (&archive->unarr_stream, ar_close);
54  break;
56  case EV_ARCHIVE_TYPE_7Z:
58  g_clear_pointer (&archive->libar, archive_free);
59  break;
60  default:
61  break;
62  }
63 
64  G_OBJECT_CLASS (ev_archive_parent_class)->finalize (object);
65 }
66 
67 static void
68 ev_archive_class_init (EvArchiveClass *klass)
69 {
70  GObjectClass *object_class = (GObjectClass *) klass;
71 
72  object_class->finalize = ev_archive_finalize;
73 }
74 
75 EvArchive *
77 {
78  return g_object_new (EV_TYPE_ARCHIVE, NULL);
79 }
80 
81 static void
82 libarchive_set_archive_type (EvArchive *archive,
83  EvArchiveType archive_type)
84 {
85  archive->type = archive_type;
86  archive->libar = archive_read_new ();
87 
88  if (archive_type == EV_ARCHIVE_TYPE_ZIP)
89  archive_read_support_format_zip (archive->libar);
90  else if (archive_type == EV_ARCHIVE_TYPE_7Z)
91  archive_read_support_format_7zip (archive->libar);
92  else if (archive_type == EV_ARCHIVE_TYPE_TAR)
93  archive_read_support_format_tar (archive->libar);
94 }
95 
97 ev_archive_get_archive_type (EvArchive *archive)
98 {
99  g_return_val_if_fail (EV_IS_ARCHIVE (archive), EV_ARCHIVE_TYPE_NONE);
100 
101  return archive->type;
102 }
103 
104 gboolean
105 ev_archive_set_archive_type (EvArchive *archive,
106  EvArchiveType archive_type)
107 {
108  g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
109  g_return_val_if_fail (archive->type == EV_ARCHIVE_TYPE_NONE, FALSE);
110 
111  switch (archive_type) {
112  case EV_ARCHIVE_TYPE_RAR:
113  archive->type = archive_type;
114  break;
115  case EV_ARCHIVE_TYPE_ZIP:
116  case EV_ARCHIVE_TYPE_7Z:
117  case EV_ARCHIVE_TYPE_TAR:
118  libarchive_set_archive_type (archive, archive_type);
119  break;
120  default:
121  g_assert_not_reached ();
122  }
123 
124  return TRUE;
125 }
126 
127 gboolean
128 ev_archive_open_filename (EvArchive *archive,
129  const char *path,
130  GError **error)
131 {
132  int r;
133 
134  g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
135  g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
136  g_return_val_if_fail (path != NULL, FALSE);
137 
138  switch (archive->type) {
140  g_assert_not_reached ();
141  case EV_ARCHIVE_TYPE_RAR:
142  archive->unarr_stream = ar_open_file (path);
143  if (archive->unarr_stream == NULL) {
144  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
145  "Error opening archive");
146  return FALSE;
147  }
148  archive->unarr = ar_open_rar_archive (archive->unarr_stream);
149  if (archive->unarr == NULL) {
150  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
151  "Error opening RAR archive");
152  return FALSE;
153  }
154  return TRUE;
155  case EV_ARCHIVE_TYPE_ZIP:
156  case EV_ARCHIVE_TYPE_7Z:
157  case EV_ARCHIVE_TYPE_TAR:
158  r = archive_read_open_filename (archive->libar, path, BUFFER_SIZE);
159  if (r != ARCHIVE_OK) {
160  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
161  "Error opening archive: %s", archive_error_string (archive->libar));
162  return FALSE;
163  }
164  return TRUE;
165  }
166 
167  return FALSE;
168 }
169 
170 static gboolean
171 libarchive_read_next_header (EvArchive *archive,
172  GError **error)
173 {
174  while (1) {
175  int r;
176 
177  r = archive_read_next_header (archive->libar, &archive->libar_entry);
178  if (r != ARCHIVE_OK) {
179  if (r != ARCHIVE_EOF)
180  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
181  "Error reading archive: %s", archive_error_string (archive->libar));
182  return FALSE;
183  }
184 
185  if (archive_entry_filetype (archive->libar_entry) != AE_IFREG) {
186  g_debug ("Skipping '%s' as it's not a regular file",
187  archive_entry_pathname (archive->libar_entry));
188  continue;
189  }
190 
191  g_debug ("At header for file '%s'", archive_entry_pathname (archive->libar_entry));
192 
193  break;
194  }
195 
196  return TRUE;
197 }
198 
199 gboolean
200 ev_archive_read_next_header (EvArchive *archive,
201  GError **error)
202 {
203  g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
204  g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
205 
206  switch (archive->type) {
208  g_assert_not_reached ();
209  case EV_ARCHIVE_TYPE_RAR:
210  return ar_parse_entry (archive->unarr);
211  case EV_ARCHIVE_TYPE_ZIP:
212  case EV_ARCHIVE_TYPE_7Z:
213  case EV_ARCHIVE_TYPE_TAR:
214  return libarchive_read_next_header (archive, error);
215  }
216 
217  return FALSE;
218 }
219 
220 const char *
221 ev_archive_get_entry_pathname (EvArchive *archive)
222 {
223  g_return_val_if_fail (EV_IS_ARCHIVE (archive), NULL);
224  g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, NULL);
225 
226  switch (archive->type) {
228  g_assert_not_reached ();
229  case EV_ARCHIVE_TYPE_RAR:
230  g_return_val_if_fail (archive->unarr != NULL, NULL);
231  return ar_entry_get_name (archive->unarr);
232  case EV_ARCHIVE_TYPE_ZIP:
233  case EV_ARCHIVE_TYPE_7Z:
234  case EV_ARCHIVE_TYPE_TAR:
235  g_return_val_if_fail (archive->libar_entry != NULL, NULL);
236  return archive_entry_pathname (archive->libar_entry);
237  }
238 
239  return NULL;
240 }
241 
242 gint64
243 ev_archive_get_entry_size (EvArchive *archive)
244 {
245  g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
246  g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
247 
248  switch (archive->type) {
249  case EV_ARCHIVE_TYPE_RAR:
250  g_return_val_if_fail (archive->unarr != NULL, -1);
251  return ar_entry_get_size (archive->unarr);
253  g_assert_not_reached ();
254  case EV_ARCHIVE_TYPE_ZIP:
255  case EV_ARCHIVE_TYPE_7Z:
256  case EV_ARCHIVE_TYPE_TAR:
257  g_return_val_if_fail (archive->libar_entry != NULL, -1);
258  return archive_entry_size (archive->libar_entry);
259  }
260 
261  return -1;
262 }
263 
264 gssize
265 ev_archive_read_data (EvArchive *archive,
266  void *buf,
267  gsize count,
268  GError **error)
269 {
270  gssize r = -1;
271 
272  g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
273  g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
274 
275  switch (archive->type) {
276  case EV_ARCHIVE_TYPE_RAR:
277  g_return_val_if_fail (archive->unarr != NULL, -1);
278  if (!ar_entry_uncompress (archive->unarr, buf, count)) {
279  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
280  "Failed to decompress RAR data");
281  return -1;
282  }
283  r = count;
284  break;
286  g_assert_not_reached ();
287  case EV_ARCHIVE_TYPE_ZIP:
288  case EV_ARCHIVE_TYPE_7Z:
289  case EV_ARCHIVE_TYPE_TAR:
290  g_return_val_if_fail (archive->libar_entry != NULL, -1);
291  r = archive_read_data (archive->libar, buf, count);
292  if (r < 0) {
293  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
294  "Failed to decompress data: %s", archive_error_string (archive->libar));
295  }
296  break;
297  }
298 
299  return r;
300 }
301 
302 void
303 ev_archive_reset (EvArchive *archive)
304 {
305  g_return_if_fail (EV_IS_ARCHIVE (archive));
306  g_return_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE);
307 
308  switch (archive->type) {
309  case EV_ARCHIVE_TYPE_RAR:
310  g_clear_pointer (&archive->unarr, ar_close_archive);
311  g_clear_pointer (&archive->unarr_stream, ar_close);
312  break;
313  case EV_ARCHIVE_TYPE_ZIP:
314  case EV_ARCHIVE_TYPE_7Z:
315  case EV_ARCHIVE_TYPE_TAR:
316  g_clear_pointer (&archive->libar, archive_free);
317  libarchive_set_archive_type (archive, archive->type);
318  break;
319  default:
320  g_assert_not_reached ();
321  }
322 }
323 
324 static void
325 ev_archive_init (EvArchive *archive)
326 {
327 }