1 /* vim: set sw=2 ts=2 sts=2 et: */
2 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /*
4 * autoar-format-filter.c
5 * Functions related to archive formats and filters
6 *
7 * Copyright (C) 2013 Ting-Wei Lan
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this program; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 *
24 */
25
26 #include "config.h"
27
28 #include "autoar-format-filter.h"
29
30 #include <archive.h>
31 #include <gio/gio.h>
32 #include <glib.h>
33
34 /**
35 * SECTION:autoar-format-filter
36 * @Short_description: Utilities for handling archive formats and filters
37 * @Title: autoar-format-filter
38 * @Include: gnome-autoar/autoar.h
39 *
40 * autoar-format-filter is a collection of functions providing information
41 * of archive formats and filters.
42 **/
43
44 typedef struct _AutoarFormatDescription AutoarFormatDescription;
45 typedef struct _AutoarFilterDescription AutoarFilterDescription;
46
47 struct _AutoarFormatDescription
48 {
49 AutoarFormat format;
50 int libarchive_format;
51 char *extension;
52 char *keyword;
53 char *mime_type;
54 char *description;
55 AutoarFormatFunc libarchive_read;
56 AutoarFormatFunc libarchive_write;
57 };
58
59 struct _AutoarFilterDescription
60 {
61 AutoarFilter filter;
62 int libarchive_filter;
63 char *extension;
64 char *keyword;
65 char *mime_type;
66 char *description;
67 AutoarFilterFunc libarchive_read;
68 AutoarFilterFunc libarchive_write;
69 };
70
71 static AutoarFormatDescription autoar_format_description[] = {
72 { AUTOAR_FORMAT_ZIP, ARCHIVE_FORMAT_ZIP, "zip", "zip",
73 "application/zip", "Zip archive",
74 archive_read_support_format_zip,
75 archive_write_set_format_zip },
76
77 { AUTOAR_FORMAT_TAR, ARCHIVE_FORMAT_TAR_PAX_RESTRICTED, "tar", "tar",
78 "application/x-tar", "Tar archive (restricted pax)",
79 archive_read_support_format_tar,
80 archive_write_set_format_pax_restricted },
81
82 { AUTOAR_FORMAT_CPIO, ARCHIVE_FORMAT_CPIO_POSIX, "cpio", "cpio",
83 "application/x-cpio", "CPIO archive",
84 archive_read_support_format_cpio,
85 archive_write_set_format_cpio },
86
87 { AUTOAR_FORMAT_7ZIP, ARCHIVE_FORMAT_7ZIP, "7z", "7z-compressed",
88 "application/x-7z-compressed", "7-zip archive",
89 archive_read_support_format_7zip,
90 archive_write_set_format_7zip },
91
92 { AUTOAR_FORMAT_AR_BSD, ARCHIVE_FORMAT_AR_BSD, "a", "ar",
93 "application/x-ar", "AR archive (BSD)",
94 archive_read_support_format_ar,
95 archive_write_set_format_ar_bsd },
96
97 { AUTOAR_FORMAT_AR_SVR4, ARCHIVE_FORMAT_AR_GNU, "a", "ar",
98 "application/x-ar", "AR archive (SVR4)",
99 archive_read_support_format_ar,
100 archive_write_set_format_ar_svr4 },
101
102 { AUTOAR_FORMAT_CPIO_NEWC, ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, "cpio", "sv4cpio",
103 "application/x-sv4cpio", "SV4 CPIO archive",
104 archive_read_support_format_cpio,
105 archive_write_set_format_cpio_newc },
106
107 { AUTOAR_FORMAT_GNUTAR, ARCHIVE_FORMAT_TAR_GNUTAR, "tar", "tar",
108 "application/x-tar", "Tar archive (GNU tar)",
109 archive_read_support_format_gnutar,
110 archive_write_set_format_gnutar },
111
112 { AUTOAR_FORMAT_ISO9660, ARCHIVE_FORMAT_ISO9660, "iso", "cd-image",
113 "application/x-cd-image", "Raw CD Image",
114 archive_read_support_format_iso9660,
115 archive_write_set_format_iso9660 },
116
117 { AUTOAR_FORMAT_PAX, ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, "tar", "tar",
118 "application/x-tar", "Tar archive (pax)",
119 archive_read_support_format_tar,
120 archive_write_set_format_pax },
121
122 { AUTOAR_FORMAT_USTAR, ARCHIVE_FORMAT_TAR_USTAR, "tar", "tar",
123 "application/x-tar", "Tar archive (ustar)",
124 archive_read_support_format_tar,
125 archive_write_set_format_ustar },
126
127 { AUTOAR_FORMAT_XAR, ARCHIVE_FORMAT_XAR, "xar", "xar",
128 "application/x-xar", "Xar archive",
129 archive_read_support_format_xar,
130 archive_write_set_format_xar }
131 };
132
133 static AutoarFilterDescription autoar_filter_description[] = {
134 { AUTOAR_FILTER_NONE, ARCHIVE_FILTER_NONE, "", "",
135 "", "None",
136 archive_read_support_filter_none,
137 archive_write_add_filter_none },
138
139 { AUTOAR_FILTER_COMPRESS, ARCHIVE_FILTER_COMPRESS, "Z", "compress",
140 "application/x-compress", "UNIX-compressed",
141 archive_read_support_filter_compress,
142 archive_write_add_filter_compress },
143
144 { AUTOAR_FILTER_GZIP, ARCHIVE_FILTER_GZIP, "gz", "gzip",
145 "application/gzip", "Gzip",
146 archive_read_support_filter_gzip,
147 archive_write_add_filter_gzip },
148
149 { AUTOAR_FILTER_BZIP2, ARCHIVE_FILTER_BZIP2, "bz2", "bzip",
150 "application/x-bzip", "Bzip2",
151 archive_read_support_filter_bzip2,
152 archive_write_add_filter_bzip2 },
153
154 { AUTOAR_FILTER_XZ, ARCHIVE_FILTER_XZ, "xz", "xz",
155 "application/x-xz", "XZ",
156 archive_read_support_filter_xz,
157 archive_write_add_filter_xz },
158
159 { AUTOAR_FILTER_LZMA, ARCHIVE_FILTER_LZMA, "lzma", "lzma",
160 "application/x-lzma", "LZMA",
161 archive_read_support_filter_lzma,
162 archive_write_add_filter_lzma },
163
164 { AUTOAR_FILTER_LZIP, ARCHIVE_FILTER_LZIP, "lz", "lzip",
165 "application/x-lzip", "Lzip",
166 archive_read_support_filter_lzip,
167 archive_write_add_filter_lzip },
168
169 { AUTOAR_FILTER_LZOP, ARCHIVE_FILTER_LZOP, "lzo", "lzop",
170 "application/x-lzop", "LZO",
171 archive_read_support_filter_lzop,
172 archive_write_add_filter_lzop },
173
174 { AUTOAR_FILTER_GRZIP, ARCHIVE_FILTER_GRZIP, "grz", "grzip",
175 "application/x-grzip", "GRZip",
176 archive_read_support_filter_grzip,
177 archive_write_add_filter_grzip },
178
179 { AUTOAR_FILTER_LRZIP, ARCHIVE_FILTER_LRZIP, "lrz", "lrzip",
180 "application/x-lrzip", "Long Range ZIP (lrzip)",
181 archive_read_support_filter_lrzip,
182 archive_write_add_filter_lrzip }
183 };
184
185 /**
186 * autoar_format_last:
187 *
188 * Gets the maximal allowed values of #AutoarFormat
189 *
190 * Returns: maximal allowed values of #AutoarFormat
191 **/
192 int
autoar_format_last(void)193 autoar_format_last (void)
194 {
195 return AUTOAR_FORMAT_LAST;
196 }
197
198 /**
199 * autoar_format_is_valid:
200 * @format: an #AutoarFormat
201 *
202 * Checks whether an #AutoarFormat is valid.
203 *
204 * Returns: %TRUE if the value of @format is valid
205 **/
206 gboolean
autoar_format_is_valid(AutoarFormat format)207 autoar_format_is_valid (AutoarFormat format)
208 {
209 return (format > 0 && format < AUTOAR_FORMAT_LAST);
210 }
211
212 /**
213 * autoar_format_get_mime_type:
214 * @format: an #AutoarFormat
215 *
216 * Gets the MIME type of the format from the internal static data.
217 *
218 * Returns: (transfer none): an MIME type
219 **/
220 const char*
autoar_format_get_mime_type(AutoarFormat format)221 autoar_format_get_mime_type (AutoarFormat format)
222 {
223 g_return_val_if_fail (autoar_format_is_valid (format) , NULL);
224 return autoar_format_description[format - 1].mime_type;
225 }
226
227 /**
228 * autoar_format_get_extension:
229 * @format: an #AutoarFormat
230 *
231 * Gets the file name extension of the format from the internal static data.
232 *
233 * Returns: (transfer none): a file name extension
234 **/
235 const char*
autoar_format_get_extension(AutoarFormat format)236 autoar_format_get_extension (AutoarFormat format)
237 {
238 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
239 return autoar_format_description[format - 1].extension;
240 }
241
242 /**
243 * autoar_format_get_description:
244 * @format: an #AutoarFormat
245 *
246 * Gets description of the format from the internal static data.
247 *
248 * Returns: (transfer none): description about the format
249 **/
250 const char*
autoar_format_get_description(AutoarFormat format)251 autoar_format_get_description (AutoarFormat format)
252 {
253 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
254 return autoar_format_description[format - 1].description;
255 }
256
257 /**
258 * autoar_format_get_format_libarchive:
259 * @format: an #AutoarFormat
260 *
261 * Gets the format code used by libarchive. You can use the return value
262 * as the argument for archive_read_support_format_by_code() and
263 * archive_write_set_format(). However, some format cannot be set using
264 * these two functions because of problems inside libarchive. Use
265 * autoar_format_get_libarchive_read() and
266 * autoar_format_get_libarchive_write() to get the function pointer
267 * is the more reliable way to set format on the archive object.
268 *
269 * Returns: an integer
270 **/
271 int
autoar_format_get_format_libarchive(AutoarFormat format)272 autoar_format_get_format_libarchive (AutoarFormat format)
273 {
274 g_return_val_if_fail (autoar_format_is_valid (format), -1);
275 return autoar_format_description[format - 1].libarchive_format;
276 }
277
278 /**
279 * autoar_format_get_description_libarchive:
280 * @format: an #AutoarFormat
281 *
282 * Gets description of the format from libarchive. This function creates
283 * and destroys an archive object in order to get the description string.
284 *
285 * Returns: (transfer full): description about the format. Free the returned
286 * string with g_free().
287 **/
288 gchar*
autoar_format_get_description_libarchive(AutoarFormat format)289 autoar_format_get_description_libarchive (AutoarFormat format)
290 {
291 struct archive* a;
292 gchar *str;
293
294 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
295
296 a = archive_write_new ();
297 archive_write_set_format (a, autoar_format_description[format - 1].libarchive_format);
298 str = g_strdup (archive_format_name (a));
299 archive_write_free (a);
300
301 return str;
302 }
303
304 /**
305 * autoar_format_get_libarchive_read: (skip)
306 * @format: an #AutoarFormat
307 *
308 * Gets the function used to set format on the object returned by
309 * archive_read_new().
310 *
311 * Returns: function pointer to the setter function provided by libarchive
312 **/
313 AutoarFormatFunc
autoar_format_get_libarchive_read(AutoarFormat format)314 autoar_format_get_libarchive_read (AutoarFormat format)
315 {
316 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
317 return autoar_format_description[format - 1].libarchive_read;
318 }
319
320 /**
321 * autoar_format_get_libarchive_write: (skip)
322 * @format: an #AutoarFormat
323 *
324 * Gets the function used to set format on the object returned by
325 * archive_write_new().
326 *
327 * Returns: function pointer to the setter function provided by libarchive
328 **/
329 AutoarFormatFunc
autoar_format_get_libarchive_write(AutoarFormat format)330 autoar_format_get_libarchive_write (AutoarFormat format)
331 {
332 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
333 return autoar_format_description[format - 1].libarchive_write;
334 }
335
336 /**
337 * autoar_filter_last:
338 *
339 * Gets the maximal allowed values of #AutoarFilter
340 *
341 * Returns: maximal allowed values of #AutoarFilter
342 **/
343 int
autoar_filter_last(void)344 autoar_filter_last (void)
345 {
346 return AUTOAR_FILTER_LAST;
347 }
348
349 /**
350 * autoar_filter_is_valid:
351 * @filter: an #AutoarFilter
352 *
353 * Checks whether an #AutoarFilter is valid.
354 *
355 * Returns: %TRUE if the value of @filter is valid
356 **/
357 gboolean
autoar_filter_is_valid(AutoarFilter filter)358 autoar_filter_is_valid (AutoarFilter filter)
359 {
360 return (filter > 0 && filter < AUTOAR_FILTER_LAST);
361 }
362
363 /**
364 * autoar_filter_get_mime_type:
365 * @filter: an #AutoarFilter
366 *
367 * Gets the MIME type of the filter from the internal static data.
368 *
369 * Returns: (transfer none): an MIME type
370 **/
371 const char*
autoar_filter_get_mime_type(AutoarFilter filter)372 autoar_filter_get_mime_type (AutoarFilter filter)
373 {
374 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
375 return autoar_filter_description[filter - 1].mime_type;
376 }
377
378 /**
379 * autoar_filter_get_extension:
380 * @filter: an #AutoarFilter
381 *
382 * Gets the file name extension of the filter from the internal static data.
383 *
384 * Returns: (transfer none): a file name extension
385 **/
386 const char*
autoar_filter_get_extension(AutoarFilter filter)387 autoar_filter_get_extension (AutoarFilter filter)
388 {
389 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
390 return autoar_filter_description[filter - 1].extension;
391 }
392
393 /**
394 * autoar_filter_get_description:
395 * @filter: an #AutoarFilter
396 *
397 * Gets description of the filter from the internal static data.
398 *
399 * Returns: (transfer none): description about the filter
400 **/
401 const char*
autoar_filter_get_description(AutoarFilter filter)402 autoar_filter_get_description (AutoarFilter filter)
403 {
404 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
405 return autoar_filter_description[filter - 1].description;
406 }
407
408 /**
409 * autoar_filter_get_filter_libarchive:
410 * @filter: an #AutoarFilter
411 *
412 * Gets the filter code used by libarchive. You can use the return value
413 * as the argument for archive_write_add_filter().
414 *
415 * Returns: an integer
416 **/
417 int
autoar_filter_get_filter_libarchive(AutoarFilter filter)418 autoar_filter_get_filter_libarchive (AutoarFilter filter)
419 {
420 g_return_val_if_fail (autoar_filter_is_valid (filter), -1);
421 return autoar_filter_description[filter - 1].libarchive_filter;
422 }
423
424 /**
425 * autoar_filter_get_description_libarchive:
426 * @filter: an #AutoarFilter
427 *
428 * Gets description of the filter from libarchive. This function creates
429 * and destroys an archive object in order to get the description string.
430 *
431 * Returns: (transfer full): description about the filter. Free the returned
432 * string with g_free().
433 **/
434 gchar*
autoar_filter_get_description_libarchive(AutoarFilter filter)435 autoar_filter_get_description_libarchive (AutoarFilter filter)
436 {
437 struct archive *a;
438 gchar *str;
439
440 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
441
442 a = archive_write_new ();
443 archive_write_add_filter (a, autoar_filter_description[filter - 1].libarchive_filter);
444 str = g_strdup (archive_filter_name (a, 0));
445 archive_write_free (a);
446
447 return str;
448 }
449
450 /**
451 * autoar_filter_get_libarchive_read: (skip)
452 * @filter: an #AutoarFilter
453 *
454 * Gets the function used to add filter on the object returned by
455 * archive_read_new().
456 *
457 * Returns: function pointer to the setter function provided by libarchive
458 **/
459 AutoarFilterFunc
autoar_filter_get_libarchive_read(AutoarFilter filter)460 autoar_filter_get_libarchive_read (AutoarFilter filter)
461 {
462 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
463 return autoar_filter_description[filter - 1].libarchive_read;
464 }
465
466 /**
467 * autoar_filter_get_libarchive_write: (skip)
468 * @filter: an #AutoarFilter
469 *
470 * Gets the function used to add filter on the object returned by
471 * archive_write_new().
472 *
473 * Returns: function pointer to the setter function provided by libarchive
474 **/
475 AutoarFilterFunc
autoar_filter_get_libarchive_write(AutoarFilter filter)476 autoar_filter_get_libarchive_write (AutoarFilter filter)
477 {
478 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
479 return autoar_filter_description[filter - 1].libarchive_write;
480 }
481
482 /**
483 * autoar_format_filter_get_mime_type:
484 * @format: an #AutoarFormat
485 * @filter: an #AutoarFilter
486 *
487 * Gets the MIME type for an archive @format compressed by
488 * @filter. This function always succeed, but it is not guaranteed
489 * that the returned MIME type exists and can be recognized by applications.
490 * Some combination of format and filter seldom exists in application,
491 * so this function can only generate the string based on some
492 * non-standard rules.
493 *
494 * Returns: (transfer full): an MIME type. Free the returned
495 * string with g_free().
496 **/
497 gchar*
autoar_format_filter_get_mime_type(AutoarFormat format,AutoarFilter filter)498 autoar_format_filter_get_mime_type (AutoarFormat format,
499 AutoarFilter filter)
500 {
501 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
502 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
503
504 switch (filter) {
505 case AUTOAR_FILTER_NONE:
506 return g_strdup (autoar_format_description[format - 1].mime_type);
507 case AUTOAR_FILTER_COMPRESS:
508 return g_strconcat ("application/x-",
509 autoar_format_description[format - 1].keyword,
510 "z", NULL);
511 case AUTOAR_FILTER_GZIP:
512 return g_strconcat ("application/x-compressed-",
513 autoar_format_description[format - 1].keyword,
514 NULL);
515 default:
516 return g_strconcat ("application/x-",
517 autoar_filter_description[filter - 1].keyword,
518 "-compressed-",
519 autoar_format_description[format - 1].keyword,
520 NULL);
521 }
522 }
523
524 /**
525 * autoar_format_filter_get_extension:
526 * @format: an #AutoarFormat
527 * @filter: an #AutoarFilter
528 *
529 * Gets the file name extension for an archive @format compressed by
530 * @filter. The first character of the returned string is always '.'
531 *
532 * Returns: (transfer full): a file name extension. Free the returned string
533 * with g_free().
534 **/
535 gchar*
autoar_format_filter_get_extension(AutoarFormat format,AutoarFilter filter)536 autoar_format_filter_get_extension (AutoarFormat format,
537 AutoarFilter filter)
538 {
539 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
540 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
541
542 return g_strconcat (".",
543 autoar_format_description[format - 1].extension,
544 autoar_filter_description[filter - 1].extension[0] ? "." : "",
545 autoar_filter_description[filter - 1].extension,
546 NULL);
547 }
548
549 /**
550 * autoar_format_filter_get_description:
551 * @format: an #AutoarFormat
552 * @filter: an #AutoarFilter
553 *
554 * Gets the description for an archive @format compressed by
555 * @filter using #GContentType and autoar_format_filter_get_mime_type().
556 *
557 * Returns: (transfer full): description about the archive. Free the returned
558 * string with g_free().
559 **/
560 gchar*
autoar_format_filter_get_description(AutoarFormat format,AutoarFilter filter)561 autoar_format_filter_get_description (AutoarFormat format,
562 AutoarFilter filter)
563 {
564 gchar *mime_type;
565 gchar *description;
566
567 g_return_val_if_fail (autoar_format_is_valid (format), NULL);
568 g_return_val_if_fail (autoar_filter_is_valid (filter), NULL);
569
570 mime_type = autoar_format_filter_get_mime_type (format, filter);
571 description = g_content_type_get_description (mime_type);
572 g_free (mime_type);
573
574 return description;
575 }
576