From c9590ff7d4c100a40fd2fe7c06cec71d10677618 Mon Sep 17 00:00:00 2001 From: Guenter Obiltschnig Date: Mon, 8 Sep 2014 11:06:57 +0200 Subject: [PATCH] Added CM_AUTO, which automatically selects CM_STORE or CM_DEFLATE based on file extension. Used to avoid double-compression of already compressed file formats such as images. --- Zip/include/Poco/Zip/Compress.h | 27 +++++++++++++++++++++++++++ Zip/include/Poco/Zip/ZipCommon.h | 3 ++- Zip/src/Compress.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Zip/include/Poco/Zip/Compress.h b/Zip/include/Poco/Zip/Compress.h index bed4324c8..d00d4970b 100644 --- a/Zip/include/Poco/Zip/Compress.h +++ b/Zip/include/Poco/Zip/Compress.h @@ -25,6 +25,7 @@ #include "Poco/FIFOEvent.h" #include #include +#include namespace Poco { @@ -69,6 +70,25 @@ public: ZipArchive close(); /// Finalizes the ZipArchive, closes it. + void setStoreExtensions(const std::set& extensions); + /// Sets the file extensions for which the CM_STORE compression method + /// is used if CM_AUTO is specified in addFile() or addRecursive(). + /// For all other extensions, CM_DEFLATE is used. This is used to avoid + /// double compression of already compressed file formats, which usually + /// leads to worse results. Extensions will be converted to lower case. + /// + /// The default extensions are: + /// - gif + /// - jpg + /// - jpeg + /// - png + + const std::set& getStoreExtensions() const; + /// Returns the file extensions for which the CM_STORE compression method + /// is used if CM_AUTO is specified in addFile() or addRecursive(). + /// + /// See setStoreExtensions() for more information. + private: enum { @@ -86,6 +106,7 @@ private: /// copys an already compressed ZipEntry from in private: + std::set _storeExtensions; std::ostream& _out; bool _seekableOut; ZipArchive::FileHeaders _files; @@ -114,6 +135,12 @@ inline const std::string& Compress::getZipComment() const } +inline const std::set& Compress::getStoreExtensions() const +{ + return _storeExtensions; +} + + } } // namespace Poco::Zip diff --git a/Zip/include/Poco/Zip/ZipCommon.h b/Zip/include/Poco/Zip/ZipCommon.h index 108622495..a9e0d2390 100644 --- a/Zip/include/Poco/Zip/ZipCommon.h +++ b/Zip/include/Poco/Zip/ZipCommon.h @@ -49,7 +49,8 @@ public: CM_DEFLATE = 8, CM_ENHANCEDDEFLATE = 9, CM_DATECOMPRIMPLODING = 10, - CM_UNUSED = 11 + CM_UNUSED = 11, + CM_AUTO = 255 /// automatically select DM_DEFLATE or CM_STORE based on file type (extension) }; enum CompressionLevel diff --git a/Zip/src/Compress.cpp b/Zip/src/Compress.cpp index 7e5c8aed2..9e759e642 100644 --- a/Zip/src/Compress.cpp +++ b/Zip/src/Compress.cpp @@ -23,6 +23,7 @@ #include "Poco/StreamCopier.h" #include "Poco/File.h" #include "Poco/FileStream.h" +#include "Poco/String.h" namespace Poco { @@ -37,6 +38,10 @@ Compress::Compress(std::ostream& out, bool seekableOut): _dirs(), _offset(0) { + _storeExtensions.insert("gif"); + _storeExtensions.insert("png"); + _storeExtensions.insert("jpg"); + _storeExtensions.insert("jpeg"); } @@ -47,6 +52,15 @@ Compress::~Compress() void Compress::addEntry(std::istream& in, const Poco::DateTime& lastModifiedAt, const Poco::Path& fileName, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl) { + if (cm == ZipCommon::CM_AUTO) + { + std::string ext = Poco::toLower(fileName.getExtension()); + if (_storeExtensions.find(ext) != _storeExtensions.end()) + cm = ZipCommon::CM_STORE; + else + cm = ZipCommon::CM_DEFLATE; + } + std::string fn = ZipUtil::validZipEntryFileName(fileName); if (_files.size() >= 65535) @@ -300,4 +314,14 @@ ZipArchive Compress::close() } +void Compress::setStoreExtensions(const std::set& extensions) +{ + _storeExtensions.clear(); + for (std::set::const_iterator it = extensions.begin(); it != extensions.end(); ++it) + { + _storeExtensions.insert(Poco::toLower(*it)); + } +} + + } } // namespace Poco::Zip