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




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

    command-7z: 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         | 101 +++++++++++++++++++++++++++++++++++++++-----
 src/fr-command-tar.c        |   6 +--
 4 files changed, 103 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 5a8376e0..e5244241 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", TRUE)
+               if (_g_program_is_available ("7zz", TRUE)
+                   || _g_program_is_available ("7zzs", TRUE)
+                   || _g_program_is_available ("7za", TRUE)
                    || _g_program_is_available ("7zr", TRUE)
                    || _g_program_is_available ("7z", TRUE))
                {
@@ -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", TRUE)) {
+               if (_g_program_is_available ("7zz", TRUE)
+                   || _g_program_is_available ("7zzs", TRUE)
+                   || _g_program_is_available ("7z", TRUE)) {
                        return capabilities;
                }
                if (!_g_program_is_available ("unzip", TRUE)) {
diff --git a/src/fr-command-7z.c b/src/fr-command-7z.c
index fe4573b6..1029d9a3 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,60 @@ 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",
+               NULL
+       };
+       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/Rar.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 +659,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", TRUE)
                            && !_g_program_is_available ("unrar", TRUE)
-                           && (! check_command || g_file_test ("/usr/lib/p7zip/Codecs/Rar.so", 
G_FILE_TEST_EXISTS)))
+                           && has_rar_support (check_command))
                                capabilities |= FR_ARCHIVE_CAN_READ;
                }
                else
@@ -630,7 +711,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 +735,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]