[file-roller/wip/jtojnar/7zip: 1/2] Add support for the official 7-Zip project




commit f5e805fd2bc9de68e1e1f120e8c4ea476a4a9b6c
Author: Jan Tojnar <jtojnar gmail com>
Date:   Mon Jun 20 23:33:47 2022 +0200

    Add support for the official 7-Zip project
    
    Quoting from the project’s README:
    
        Now there are two different ports of 7-Zip for Linux/macOS:
    
        1) p7zip - another port of 7-Zip for Linux, made by an independent developer.
           The latest version of p7zip now is 16.02, and that p7zip 16.02 is outdated now.
    
        2) 7-Zip for Linux/macOS - this package - it's new code with all changes from latest 7-Zip for 
Windows.
    
        These two ports are not identical.
        Note also that some Linux specific things can be implemented better in p7zip than in new 7-Zip for 
Linux.
    
        There are several main executables in 7-Zip and p7zip:
    
            7zz  (7-Zip) - standalone full version of 7-Zip that supports all formats.
    
            7zzs (7-Zip) - standalone full version of 7-Zip that supports all formats (static library 
linking).
    
            7z  (p7zip) - 7-Zip that requires 7z.so shared library, and it supports all formats via 7z.so.
    
            7zr (p7zip) - standalone reduced version of 7-Zip that supports some 7-Zip's formats:
                          7z, xz, lzma and split.
    
            7za (p7zip) - standalone version of 7-Zip that supports some main formats:
                          7z, xz, lzma, zip, bzip2, gzip, tar, cab, ppmd and split.
    
        7zzs is similar to 7zz, but 7zzs was compiled for static library linking,
        so 7zzs does not use external shared library (".so") files.
        You can use 7zzs, if 7zz does not work due to lack of required shared library (".so") files.
    
        The command line syntax for executables from p7zip is similar to 7zz syntax from this package.
    
    This change also renames the package names for PackageKit integration. If a distro wants File-Roller to 
suggest installing `p7zip`, point `7zip` packages listed in packages.match file to it.
    
    Most package repositories that ship 7zz disable the RAR support by default (e.g. Debian, NixOS).

 data/packages.match         |   6 +--
 src/fr-archive-libarchive.c |   8 +++-
 src/fr-command-7z.c         | 100 +++++++++++++++++++++++++++++++++++++++-----
 src/fr-command-tar.c        |   6 +--
 4 files changed, 102 insertions(+), 18 deletions(-)
---
diff --git a/data/packages.match b/data/packages.match
index 68ce591f..80e1099f 100644
--- a/data/packages.match
+++ b/data/packages.match
@@ -1,4 +1,7 @@
 [Package Matches]
+7zip=
+7zip-full=
+7zip-rar=
 arj=
 binutils=
 brotli=
@@ -13,9 +16,6 @@ lzip=
 lzma=
 lzop=
 ncompress=
-p7zip=
-p7zip-full=
-p7zip-rar=
 rar=
 rpm=
 rzip=
diff --git a/src/fr-archive-libarchive.c b/src/fr-archive-libarchive.c
index bc601c07..e7b0cfe1 100644
--- a/src/fr-archive-libarchive.c
+++ b/src/fr-archive-libarchive.c
@@ -116,7 +116,9 @@ fr_archive_libarchive_get_capabilities (FrArchive  *archive,
 
        /* give priority to 7z* for 7z archives. */
        if (strcmp (mime_type, "application/x-7z-compressed") == 0) {
-               if (_g_program_is_available ("7za", check_command)
+               if (_g_program_is_available ("7zz", check_command)
+                   || _g_program_is_available ("7zzs", check_command)
+                   || _g_program_is_available ("7za", check_command)
                    || _g_program_is_available ("7zr", check_command)
                    || _g_program_is_available ("7z", check_command))
                {
@@ -135,7 +137,9 @@ fr_archive_libarchive_get_capabilities (FrArchive  *archive,
        if ((strcmp (mime_type, "application/zip") == 0)
            || (strcmp (mime_type, "application/x-cbz") == 0))
        {
-               if (_g_program_is_available ("7z", check_command)) {
+               if (_g_program_is_available ("7zz", check_command)
+                   || _g_program_is_available ("7zzs", check_command)
+                   || _g_program_is_available ("7z", check_command)) {
                        return capabilities;
                }
                if (!_g_program_is_available ("unzip", check_command)) {
diff --git a/src/fr-command-7z.c b/src/fr-command-7z.c
index fe76d1ea..d1ec1527 100644
--- a/src/fr-command-7z.c
+++ b/src/fr-command-7z.c
@@ -179,7 +179,15 @@ list__process_line (char     *line,
 static void
 fr_command_7z_begin_command (FrCommand *comm)
 {
-       if (_g_program_is_in_path ("7z"))
+       // Modern 7-Zip by the original author.
+       // Statically linked from a binary distribution, almost guaranteed to work.
+       if (_g_program_is_in_path ("7zzs"))
+               fr_process_begin_command (comm->process, "7zzs");
+       // Dynamically linked from either binary or source distribution.
+       else if (_g_program_is_in_path ("7zz"))
+               fr_process_begin_command (comm->process, "7zz");
+       // Legacy p7zip project.
+       else if (_g_program_is_in_path ("7z"))
                fr_process_begin_command (comm->process, "7z");
        else if (_g_program_is_in_path ("7za"))
                fr_process_begin_command (comm->process, "7za");
@@ -589,6 +597,59 @@ fr_command_7z_get_mime_types (FrArchive *archive)
 }
 
 
+static gboolean
+check_info_subcommand_for_codec_support (char *program_name, char *codec_name) {
+       if (! _g_program_is_in_path (program_name)) {
+               return FALSE;
+       }
+
+       g_autofree gchar **standard_output = NULL;
+
+       gchar* argv[] = {
+               program_name,
+               "i"
+       };
+       if (!g_spawn_sync (
+               /* working_directory = */ NULL,
+               argv,
+               /* envp = */ NULL,
+               G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
+               /* child_setup = */ NULL,
+               /* user_data = */ NULL,
+               standard_output,
+               /* standard_error = */ NULL,
+               /* wait_status = */ NULL,
+               /* error = */ NULL
+       )) {
+               return FALSE;
+       }
+
+       gchar *codecs = g_strrstr(*standard_output, "Codecs:");
+
+       if (codecs == NULL) {
+               return FALSE;
+       }
+
+       gchar *codec_found = g_strrstr(codecs, codec_name);
+
+       return codec_found != NULL;
+}
+
+
+static gboolean
+has_rar_support (gboolean check_command)
+{
+       /*
+        * Some 7-Zip distributions store RAR codec as a separate shared library and we can detect that.
+        * Most commonly, however, the programs link the codec statically so the only way to find out is to 
query them.
+        */
+       return !check_command
+              || g_file_test ("/usr/lib/p7zip/Codecs/Rar29.so", G_FILE_TEST_EXISTS)
+              || check_info_subcommand_for_codec_support ("7zzs", "Rar3")
+              || check_info_subcommand_for_codec_support ("7zz", "Rar3");
+}
+
+
 static FrArchiveCap
 fr_command_7z_get_capabilities (FrArchive  *archive,
                                const char *mime_type,
@@ -597,27 +658,46 @@ fr_command_7z_get_capabilities (FrArchive  *archive,
        FrArchiveCap capabilities;
 
        capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
-       if (! _g_program_is_available ("7za", check_command) && ! _g_program_is_available ("7zr", 
check_command) && ! _g_program_is_available ("7z", check_command))
+       /*
+        * We support two sets of program names:
+        * - 7z/7za/7zr from the no longer maintained p7zip project
+        * - 7zz/7zzs from the 7-Zip project by the original author
+        * Their CLI is mostly compatible.
+        */
+
+       // Support full range of formats (except possibly rar).
+       gboolean available_7zip = _g_program_is_available ("7zzs", check_command) || _g_program_is_available 
("7zz", check_command);
+       gboolean available_p7zip_full = _g_program_is_available ("7z", check_command);
+       gboolean available_formats_full = available_7zip || available_p7zip_full;
+       // Supports 7z, xz, lzma, zip, bzip2, gzip, tar, cab, ppmd and split.
+       gboolean available_p7zip_partial = _g_program_is_available ("7za", check_command);
+       // Supports 7z, xz, lzma and split.
+       gboolean available_p7zip_reduced = _g_program_is_available ("7zr", check_command);
+
+       if (! available_7zip
+           && ! available_p7zip_full
+           && ! available_p7zip_partial
+           && ! available_p7zip_reduced)
                return capabilities;
 
        if (_g_mime_type_matches (mime_type, "application/x-7z-compressed")) {
                capabilities |= FR_ARCHIVE_CAN_READ_WRITE | FR_ARCHIVE_CAN_CREATE_VOLUMES;
-               if (_g_program_is_available ("7z", check_command))
+               if (available_formats_full)
                        capabilities |= FR_ARCHIVE_CAN_ENCRYPT | FR_ARCHIVE_CAN_ENCRYPT_HEADER;
        }
        else if (_g_mime_type_matches (mime_type, "application/x-7z-compressed-tar")) {
                capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
-               if (_g_program_is_available ("7z", check_command))
+               if (available_formats_full)
                        capabilities |= FR_ARCHIVE_CAN_ENCRYPT | FR_ARCHIVE_CAN_ENCRYPT_HEADER;
        }
-       else if (_g_program_is_available ("7z", check_command)) {
+       else if (available_formats_full) {
                if (_g_mime_type_matches (mime_type, "application/x-rar")
                    || _g_mime_type_matches (mime_type, "application/x-cbr"))
                {
                        /* give priority to rar and unrar that supports RAR files better. */
                        if (!_g_program_is_available ("rar", check_command)
                            && !_g_program_is_available ("unrar", check_command)
-                           && (! check_command || g_file_test ("/usr/lib/p7zip/Codecs/Rar29.so", 
G_FILE_TEST_EXISTS)))
+                           && has_rar_support (check_command))
                                capabilities |= FR_ARCHIVE_CAN_READ;
                }
                else
@@ -630,7 +710,7 @@ fr_command_7z_get_capabilities (FrArchive  *archive,
                        capabilities |= FR_ARCHIVE_CAN_WRITE | FR_ARCHIVE_CAN_ENCRYPT;
                }
        }
-       else if (_g_program_is_available ("7za", check_command)) {
+       else if (available_p7zip_partial) {
                if (_g_mime_type_matches (mime_type, "application/vnd.ms-cab-compressed")
                    || _g_mime_type_matches (mime_type, "application/zip"))
                {
@@ -654,11 +734,11 @@ fr_command_7z_get_packages (FrArchive  *archive,
                            const char *mime_type)
 {
        if (_g_mime_type_matches (mime_type, "application/x-rar"))
-               return PACKAGES ("p7zip,p7zip-rar");
+               return PACKAGES ("7zip,7zip-rar");
        else if (_g_mime_type_matches (mime_type, "application/zip") || _g_mime_type_matches (mime_type, 
"application/vnd.ms-cab-compressed"))
-               return PACKAGES ("p7zip,p7zip-full");
+               return PACKAGES ("7zip,7zip-full");
        else
-               return PACKAGES ("p7zip");
+               return PACKAGES ("7zip");
 }
 
 
diff --git a/src/fr-command-tar.c b/src/fr-command-tar.c
index 3c620772..22eab489 100644
--- a/src/fr-command-tar.c
+++ b/src/fr-command-tar.c
@@ -1241,7 +1241,7 @@ fr_command_tar_get_capabilities (FrArchive  *archive,
                        capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
        }
        else if (_g_mime_type_matches (mime_type, "application/x-7z-compressed-tar")) {
-               char *try_command[3] = { "7za", "7zr", "7z" };
+               char *try_command[5] = { "7zzs", "7zz", "7za", "7zr", "7z" };
                int   i;
 
                for (i = 0; i < G_N_ELEMENTS (try_command); i++) {
@@ -1273,7 +1273,7 @@ fr_command_tar_set_mime_type (FrArchive  *archive,
        FR_ARCHIVE_CLASS (fr_command_tar_parent_class)->set_mime_type (archive, mime_type);
 
        if (_g_mime_type_matches (mime_type, "application/x-7z-compressed-tar")) {
-               char *try_command[3] = { "7za", "7zr", "7z" };
+               char *try_command[5] = { "7zzs", "7zz", "7za", "7zr", "7z" };
                int   i;
 
                for (i = 0; i < G_N_ELEMENTS (try_command); i++) {
@@ -1313,7 +1313,7 @@ fr_command_tar_get_packages (FrArchive  *archive,
        else if (_g_mime_type_matches (mime_type, "application/x-tzo"))
                return PACKAGES ("tar,lzop");
        else if (_g_mime_type_matches (mime_type, "application/x-7z-compressed-tar"))
-               return PACKAGES ("tar,p7zip");
+               return PACKAGES ("tar,7zip");
        else if (_g_mime_type_matches (mime_type, "application/x-rzip-compressed-tar"))
                return PACKAGES ("tar,rzip");
        else if (_g_mime_type_matches (mime_type, "application/x-zstd-compressed-tar"))


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]