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