commit 17ef504d8b63a864cd7d1ef7d4400027f4ec78db
Author: Maximiliano Curia <maxy@debian.org>
Date:   Thu Feb 27 11:25:38 2014 +0100

    Use libarchive for zip files.

Index: ark/plugins/clizipplugin/CMakeLists.txt
===================================================================
--- ark.orig/plugins/clizipplugin/CMakeLists.txt	2014-11-11 18:14:09.303817277 +0100
+++ ark/plugins/clizipplugin/CMakeLists.txt	2014-11-11 18:14:09.299817438 +0100
@@ -1,6 +1,6 @@
 ########### next target ###############
 
-set(SUPPORTED_CLIZIP_MIMETYPES "application/x-java-archive;application/zip;")
+set(SUPPORTED_CLIZIP_MIMETYPES "application/x-java-archive;")
 
 set(kerfuffle_clizip_SRCS cliplugin.cpp)
 
Index: ark/plugins/libarchive/CMakeLists.txt
===================================================================
--- ark.orig/plugins/libarchive/CMakeLists.txt	2014-11-11 18:14:09.303817277 +0100
+++ ark/plugins/libarchive/CMakeLists.txt	2014-11-11 18:14:09.299817438 +0100
@@ -2,7 +2,7 @@
 
 ########### next target ###############
 set(SUPPORTED_LIBARCHIVE_READONLY_MIMETYPES "application/x-deb;application/x-cd-image;application/x-bcpio;application/x-cpio;application/x-cpio-compressed;application/x-sv4cpio;application/x-sv4crc;")
-set(SUPPORTED_LIBARCHIVE_READWRITE_MIMETYPES "application/x-tar;application/x-compressed-tar;application/x-bzip-compressed-tar;application/x-tarz;application/x-xz-compressed-tar;application/x-lzma-compressed-tar;")
+set(SUPPORTED_LIBARCHIVE_READWRITE_MIMETYPES "application/x-tar;application/x-compressed-tar;application/x-bzip-compressed-tar;application/x-tarz;application/x-xz-compressed-tar;application/x-lzma-compressed-tar;application/zip;")
 if(HAVE_LIBARCHIVE_RPM_SUPPORT)
   set(SUPPORTED_LIBARCHIVE_READONLY_MIMETYPES "${SUPPORTED_LIBARCHIVE_READONLY_MIMETYPES}application/x-rpm;application/x-source-rpm;")
 endif(HAVE_LIBARCHIVE_RPM_SUPPORT)
Index: ark/plugins/libarchive/libarchivehandler.cpp
===================================================================
--- ark.orig/plugins/libarchive/libarchivehandler.cpp	2014-11-11 18:14:09.303817277 +0100
+++ ark/plugins/libarchive/libarchivehandler.cpp	2014-11-12 12:21:34.649576669 +0100
@@ -50,7 +50,7 @@
     static inline void cleanup(struct archive *a)
     {
         if (a) {
-            archive_read_finish(a);
+            archive_read_free(a);
         }
     }
 };
@@ -60,7 +60,7 @@
     static inline void cleanup(struct archive *a)
     {
         if (a) {
-            archive_write_finish(a);
+            archive_write_free(a);
         }
     }
 };
@@ -91,7 +91,7 @@
         return false;
     }
 
-    if (archive_read_support_compression_all(arch_reader.data()) != ARCHIVE_OK) {
+    if (archive_read_support_filter_all(arch_reader.data()) != ARCHIVE_OK) {
         return false;
     }
 
@@ -109,7 +109,7 @@
     m_extractedFilesSize = 0;
 
     struct archive_entry *aentry;
-    int result;
+    int result = ARCHIVE_OK;
 
     while (!m_abortOperation && (result = archive_read_next_header(arch_reader.data(), &aentry)) == ARCHIVE_OK) {
         if (!m_emitNoEntries) {
@@ -157,7 +157,7 @@
         return false;
     }
 
-    if (archive_read_support_compression_all(arch.data()) != ARCHIVE_OK) {
+    if (archive_read_support_filter_all(arch.data()) != ARCHIVE_OK) {
         return false;
     }
 
@@ -210,7 +210,7 @@
         // retry with renamed entry, fire an overwrite query again
         // if the new entry also exists
     retry:
-        const bool entryIsDir = S_ISDIR(archive_entry_mode(entry));
+        const bool entryIsDir = (archive_entry_filetype(entry) == AE_IFDIR);
 
         //we skip directories if not preserving paths
         if (!preservePaths && entryIsDir) {
@@ -337,8 +337,9 @@
 bool LibArchiveInterface::addFiles(const QStringList& files, const CompressionOptions& options)
 {
     const bool creatingNewFile = !QFileInfo(filename()).exists();
-    const QString tempFilename = filename() + QLatin1String( ".arkWriting" );
-    const QString globalWorkDir = options.value(QLatin1String( "GlobalWorkDir" )).toString();
+    const QString tempFilename = filename() + QLatin1String(".arkWriting");
+    const QString globalWorkDir =
+        options.value(QLatin1String("GlobalWorkDir")).toString();
 
     if (!globalWorkDir.isEmpty()) {
         kDebug() << "GlobalWorkDir is set, changing dir to " << globalWorkDir;
@@ -356,7 +357,7 @@
             return false;
         }
 
-        if (archive_read_support_compression_all(arch_reader.data()) != ARCHIVE_OK) {
+        if (archive_read_support_filter_all(arch_reader.data()) != ARCHIVE_OK) {
             return false;
         }
 
@@ -364,7 +365,10 @@
             return false;
         }
 
-        if (archive_read_open_filename(arch_reader.data(), QFile::encodeName(filename()), 10240) != ARCHIVE_OK) {
+        if (ARCHIVE_OK != archive_read_open_filename(
+                    arch_reader.data(),
+                    QFile::encodeName(filename()),
+                    10240)) {
             emit error(i18n("The source file could not be read."));
             return false;
         }
@@ -376,76 +380,98 @@
         return false;
     }
 
-    //pax_restricted is the libarchive default, let's go with that.
-    archive_write_set_format_pax_restricted(arch_writer.data());
-
-    int ret;
+    int ret = ARCHIVE_OK;
     if (creatingNewFile) {
+        // Format
+        if (filename().right(4).toUpper() == QLatin1String( ".ZIP" )) {
+            kDebug() << "Detected zip format for new file";
+            ret = archive_write_set_format_zip(arch_writer.data());
+        } else {
+            //pax_restricted is the libarchive default, let's go with that.
+            ret = archive_write_set_format_pax_restricted(arch_writer.data());
+        }
+        // Filter
         if (filename().right(2).toUpper() == QLatin1String( "GZ" )) {
             kDebug() << "Detected gzip compression for new file";
-            ret = archive_write_set_compression_gzip(arch_writer.data());
+            ret = archive_write_add_filter_gzip(arch_writer.data());
         } else if (filename().right(3).toUpper() == QLatin1String( "BZ2" )) {
             kDebug() << "Detected bzip2 compression for new file";
-            ret = archive_write_set_compression_bzip2(arch_writer.data());
+            ret = archive_write_add_filter_bzip2(arch_writer.data());
 #ifdef HAVE_LIBARCHIVE_XZ_SUPPORT
         } else if (filename().right(2).toUpper() == QLatin1String( "XZ" )) {
             kDebug() << "Detected xz compression for new file";
-            ret = archive_write_set_compression_xz(arch_writer.data());
+            ret = archive_write_add_filter_xz(arch_writer.data());
 #endif
 #ifdef HAVE_LIBARCHIVE_LZMA_SUPPORT
         } else if (filename().right(4).toUpper() == QLatin1String( "LZMA" )) {
             kDebug() << "Detected lzma compression for new file";
-            ret = archive_write_set_compression_lzma(arch_writer.data());
+            ret = archive_write_add_filter_lzma(arch_writer.data());
 #endif
         } else if (filename().right(3).toUpper() == QLatin1String( "TAR" )) {
             kDebug() << "Detected no compression for new file (pure tar)";
-            ret = archive_write_set_compression_none(arch_writer.data());
+        } else if (filename().right(4).toUpper() == QLatin1String( ".ZIP" )) {
+            // No filter for zip files
         } else {
             kDebug() << "Falling back to gzip";
-            ret = archive_write_set_compression_gzip(arch_writer.data());
+            ret = archive_write_add_filter_gzip(arch_writer.data());
         }
 
         if (ret != ARCHIVE_OK) {
-            emit error(i18nc("@info", "Setting the compression method failed with the following error: <message>%1</message>",
-                       QLatin1String(archive_error_string(arch_writer.data()))));
+            emit error(i18nc(
+                "@info",
+                "Setting the compression method failed with the following "
+                "error: <message>%1</message>",
+                QLatin1String(archive_error_string(arch_writer.data()))));
 
             return false;
         }
-    } else {
-        switch (archive_compression(arch_reader.data())) {
-        case ARCHIVE_COMPRESSION_GZIP:
-            ret = archive_write_set_compression_gzip(arch_writer.data());
-            break;
-        case ARCHIVE_COMPRESSION_BZIP2:
-            ret = archive_write_set_compression_bzip2(arch_writer.data());
-            break;
-#ifdef HAVE_LIBARCHIVE_XZ_SUPPORT
-        case ARCHIVE_COMPRESSION_XZ:
-            ret = archive_write_set_compression_xz(arch_writer.data());
-            break;
-#endif
-#ifdef HAVE_LIBARCHIVE_LZMA_SUPPORT
-        case ARCHIVE_COMPRESSION_LZMA:
-            ret = archive_write_set_compression_lzma(arch_writer.data());
-            break;
-#endif
-        case ARCHIVE_COMPRESSION_NONE:
-            ret = archive_write_set_compression_none(arch_writer.data());
-            break;
-        default:
-            emit error(i18n("The compression type '%1' is not supported by Ark.", QLatin1String(archive_compression_name(arch_reader.data()))));
+    }
+
+    struct archive_entry *entry;
+    int first_entry_ret;
+    if (!creatingNewFile) {
+
+        // Read first entry to have the format
+        first_entry_ret = archive_read_next_header(arch_reader.data(), &entry);
+        if ((ARCHIVE_OK != first_entry_ret) &&
+            (ARCHIVE_EOF != first_entry_ret)) {
+            emit error(i18nc(
+                "@info",
+                "Setting the compression method failed with the "
+                "following error: <message>%1</message>",
+                QLatin1String(archive_error_string(arch_writer.data()))));
             return false;
         }
-
+        int format_code = archive_format(arch_reader.data());
+        ret = archive_write_set_format(arch_writer.data(), format_code);
         if (ret != ARCHIVE_OK) {
-            emit error(i18nc("@info", "Setting the compression method failed with the following error: <message>%1</message>", QLatin1String(archive_error_string(arch_writer.data()))));
+            emit error(i18nc(
+                "@info",
+                "Setting the format failed with the following error: "
+                "<message>%1</message>",
+                QLatin1String(archive_error_string(arch_writer.data()))));
+            return false;
+        }
+        int filter_code = archive_filter_code(arch_reader.data(), 0);
+        ret = archive_write_add_filter(arch_writer.data(), filter_code);
+        if (ARCHIVE_OK != ret) {
+            emit error(i18nc(
+                "@info",
+                "Setting the compression method failed with the "
+                "following error: <message>%1</message>",
+                QLatin1String(archive_error_string(arch_writer.data()))));
             return false;
         }
     }
 
-    ret = archive_write_open_filename(arch_writer.data(), QFile::encodeName(tempFilename));
-    if (ret != ARCHIVE_OK) {
-        emit error(i18nc("@info", "Opening the archive for writing failed with the following error: <message>%1</message>", QLatin1String(archive_error_string(arch_writer.data()))));
+    ret = archive_write_open_filename(arch_writer.data(),
+                                      QFile::encodeName(tempFilename));
+    if (ARCHIVE_OK != ret) {
+        emit error(i18nc(
+            "@info",
+            "Opening the archive for writing failed with the following error: "
+            "<message>%1</message>",
+            QLatin1String(archive_error_string(arch_writer.data()))));
         return false;
     }
 
@@ -474,8 +500,9 @@
                     continue;
                 }
 
-                success = writeFile(path +
-                                    (it.fileInfo().isDir() ? QLatin1String( "/" ) : QLatin1String( "" )),
+                success = writeFile(path + (it.fileInfo().isDir()?
+                                            QLatin1String( "/" ) :
+                                            QLatin1String( "" )),
                                     arch_writer.data());
 
                 if (!success) {
@@ -486,33 +513,39 @@
         }
     }
 
-    struct archive_entry *entry;
-
     //and if we have old elements...
-    if (!creatingNewFile) {
+    if ((!creatingNewFile) && (first_entry_ret == ARCHIVE_OK)) {
         //********** copy old elements from previous archive to new archive
-        while (archive_read_next_header(arch_reader.data(), &entry) == ARCHIVE_OK) {
-            if (m_writtenFiles.contains(QFile::decodeName(archive_entry_pathname(entry)))) {
+        do {
+            if (m_writtenFiles.contains(
+                    QFile::decodeName(archive_entry_pathname(entry)))) {
                 archive_read_data_skip(arch_reader.data());
-                kDebug() << "Entry already existing, will be refresh: ===> " << archive_entry_pathname(entry);
+                kDebug() << "Entry already existing, will be refresh: ===> "
+                         << archive_entry_pathname(entry);
                 continue;
             }
 
             int header_response;
             //kDebug() << "Writing entry " << fn;
-            if ((header_response = archive_write_header(arch_writer.data(), entry)) == ARCHIVE_OK) {
+            if (ARCHIVE_OK ==
+                    (header_response = archive_write_header(arch_writer.data(),
+                                                            entry))) {
                 //if the whole archive is extracted and the total filesize is
                 //available, we use partial progress
                 copyData(arch_reader.data(), arch_writer.data(), false);
             } else {
-                kDebug() << "Writing header failed with error code " << header_response;
+                kDebug() << "Writing header failed with error code "
+                         << header_response;
                 QFile::remove(tempFilename);
                 return false;
             }
 
             archive_entry_clear(entry);
-        }
-
+        } while (ARCHIVE_OK == archive_read_next_header(arch_reader.data(),
+                                                        &entry));
+    }
+    // the previous compressed file could have been empty
+    if (!creatingNewFile) {
         //everything seems OK, so we remove the source file and replace it with
         //the new one.
         //TODO: do some extra checks to see if this is really OK
@@ -534,7 +567,7 @@
         return false;
     }
 
-    if (archive_read_support_compression_all(arch_reader.data()) != ARCHIVE_OK) {
+    if (archive_read_support_filter_all(arch_reader.data()) != ARCHIVE_OK) {
         return false;
     }
 
@@ -542,7 +575,9 @@
         return false;
     }
 
-    if (archive_read_open_filename(arch_reader.data(), QFile::encodeName(filename()), 10240) != ARCHIVE_OK) {
+    if (ARCHIVE_OK != archive_read_open_filename(arch_reader.data(),
+                                                 QFile::encodeName(filename()),
+                                                 10240)) {
         emit error(i18n("The source file could not be read."));
         return false;
     }
@@ -553,50 +588,53 @@
         return false;
     }
 
-    //pax_restricted is the libarchive default, let's go with that.
-    archive_write_set_format_pax_restricted(arch_writer.data());
-
     int ret;
-    switch (archive_compression(arch_reader.data())) {
-    case ARCHIVE_COMPRESSION_GZIP:
-        ret = archive_write_set_compression_gzip(arch_writer.data());
-        break;
-    case ARCHIVE_COMPRESSION_BZIP2:
-        ret = archive_write_set_compression_bzip2(arch_writer.data());
-        break;
-#ifdef HAVE_LIBARCHIVE_XZ_SUPPORT
-    case ARCHIVE_COMPRESSION_XZ:
-        ret = archive_write_set_compression_xz(arch_writer.data());
-        break;
-#endif
-#ifdef HAVE_LIBARCHIVE_LZMA_SUPPORT
-    case ARCHIVE_COMPRESSION_LZMA:
-        ret = archive_write_set_compression_lzma(arch_writer.data());
-        break;
-#endif
-    case ARCHIVE_COMPRESSION_NONE:
-        ret = archive_write_set_compression_none(arch_writer.data());
-        break;
-    default:
-        emit error(i18n("The compression type '%1' is not supported by Ark.", QLatin1String(archive_compression_name(arch_reader.data()))));
-        return false;
-    }
-
-    if (ret != ARCHIVE_OK) {
-        emit error(i18nc("@info", "Setting the compression method failed with the following error: <message>%1</message>", QLatin1String(archive_error_string(arch_writer.data()))));
-        return false;
-    }
-
-    ret = archive_write_open_filename(arch_writer.data(), QFile::encodeName(tempFilename));
-    if (ret != ARCHIVE_OK) {
-        emit error(i18nc("@info", "Opening the archive for writing failed with the following error: <message>%1</message>", QLatin1String(archive_error_string(arch_writer.data()))));
+    int filter_code = archive_filter_code(arch_reader.data(), 0);
+    ret = archive_write_add_filter(arch_writer.data(), filter_code);
+    if (ARCHIVE_OK != ret) {
+        emit error(i18nc(
+            "@info",
+            "Setting the compression method failed with the following error: "
+            "<message>%1</message>",
+            QLatin1String(archive_error_string(arch_writer.data()))));
         return false;
     }
-
+    int format_code;
     struct archive_entry *entry;
-
-    //********** copy old elements from previous archive to new archive
-    while (archive_read_next_header(arch_reader.data(), &entry) == ARCHIVE_OK) {
+    bool writer_opened = false;
+    while (ARCHIVE_OK ==
+            (ret = archive_read_next_header(arch_reader.data(), &entry))) {
+        int new_format = archive_format(arch_reader.data());
+        if ((!writer_opened) || (format_code != new_format)) {
+            format_code = new_format;
+            ret = archive_write_set_format(arch_writer.data(), format_code);
+            if (ret != ARCHIVE_OK) {
+                emit error(i18nc(
+                    "@info",
+                    "Setting the format failed with the following error: "
+                    "<message>%1</message>",
+                    QLatin1String(
+                        archive_error_string(arch_writer.data()))));
+                if (writer_opened) {
+                    QFile::remove(tempFilename);
+                }
+                return false;
+            }
+        }
+        if (!writer_opened) {
+            ret = archive_write_open_filename(arch_writer.data(),
+                                              QFile::encodeName(tempFilename));
+            if (ret != ARCHIVE_OK) {
+                emit error(i18nc(
+                    "@info",
+                    "Opening the archive for writing failed with the "
+                    "following error: <message>%1</message>",
+                    QLatin1String(archive_error_string(arch_writer.data()))));
+                return false;
+            }
+            writer_opened = true;
+        }
+        // Add the old files
         if (files.contains(QFile::decodeName(archive_entry_pathname(entry)))) {
             archive_read_data_skip(arch_reader.data());
             kDebug() << "Entry to be deleted, skipping"
@@ -604,17 +642,20 @@
             emit entryRemoved(QFile::decodeName(archive_entry_pathname(entry)));
             continue;
         }
-
         int header_response;
-        //kDebug() << "Writing entry " << fn;
-        if ((header_response = archive_write_header(arch_writer.data(), entry)) == ARCHIVE_OK) {
+        if (ARCHIVE_OK ==
+                (header_response = archive_write_header(arch_writer.data(),
+                                                        entry))) {
             //if the whole archive is extracted and the total filesize is
             //available, we use partial progress
             copyData(arch_reader.data(), arch_writer.data(), false);
         } else {
-            kDebug() << "Writing header failed with error code " << header_response;
+            kDebug() << "Writing header failed with error code "
+                     << header_response;
             return false;
         }
+
+        archive_entry_clear(entry);
     }
 
     //everything seems OK, so we remove the source file and replace it with
@@ -648,7 +689,7 @@
     }
 
     e[Size] = (qlonglong)archive_entry_size(aentry);
-    e[IsDirectory] = S_ISDIR(archive_entry_mode(aentry));
+    e[IsDirectory] = (archive_entry_filetype(aentry) == AE_IFDIR);
 
     if (archive_entry_symlink(aentry)) {
         e[Link] = QLatin1String( archive_entry_symlink(aentry) );
