Skip to content

Commit

Permalink
Feature/jlcompress options (#203)
Browse files Browse the repository at this point in the history
* Initial support for extended options in JlCompress, provide a fixed dateTime for compressed files (last modified), mostly useful for reproducible archives and unit tests.

* bump macos runners

* fix winqtdeploy for debug builds
  • Loading branch information
cen1 authored Oct 2, 2024
1 parent ddc9ddf commit c3e8780
Show file tree
Hide file tree
Showing 10 changed files with 324 additions and 63 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,12 @@ jobs:
strategy:
fail-fast: false
matrix:
macos_version: [11, 12]
macos_version: [14, 13]
qt_version: [5.15.2, 6.6.2]
shared: [ON, OFF]
exclude:
- macos_version: 14
qt_version: 5.15.2 #Not available on macos-14 due to ARM arch

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/qt-zlib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ jobs:
- name: Run tests
shell: cmd
working-directory: ${{github.workspace}}/build
run: ctest --verbose -C Release
run: ctest --verbose --output-on-failure -C Release

use-qt5-zlib-windows:
if: true
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/doc
/build
/build_release
/build_debug
/lib
*.tags
*.user
Expand Down
3 changes: 2 additions & 1 deletion cmake/windeployqt.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ function(windeployqt target)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${_qt_bin_dir}/windeployqt.exe"
--verbose 1
--release
$<$<CONFIG:Debug>:--debug>
$<$<CONFIG:Release>:--release>
--no-plugins
--no-translations
--no-system-d3d-compiler
Expand Down
152 changes: 93 additions & 59 deletions quazip/JlCompress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/

#include "JlCompress.h"
#include <memory>

bool JlCompress::copyData(QIODevice &inFile, QIODevice &outFile)
{
Expand All @@ -39,6 +40,10 @@ bool JlCompress::copyData(QIODevice &inFile, QIODevice &outFile)
}

bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) {
return compressFile(zip, fileName, fileDest, Options());
}

bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest, const Options& options) {
// zip: object where to add the file
// fileName: real file name
// fileDest: file name inside the zip object
Expand All @@ -49,7 +54,12 @@ bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) {
zip->getMode()!=QuaZip::mdAdd) return false;

QuaZipFile outFile(zip);
if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, fileName))) return false;
if (options.getDateTime().isNull()) {
if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, fileName))) return false;
}
else {
if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, fileName, options.getDateTime()))) return false;
}

QFileInfo input(fileName);
if (quazip_is_symlink(input)) {
Expand All @@ -74,6 +84,10 @@ bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) {
}

bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive, QDir::Filters filters) {
return compressSubDir(zip, dir, origDir, recursive, filters, Options());
}

bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive, QDir::Filters filters, const Options& options) {
// zip: object where to add the file
// dir: current real directory
// origDir: original real directory
Expand All @@ -88,14 +102,20 @@ bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool
if (!directory.exists()) return false;

QDir origDirectory(origDir);
if (dir != origDir) {
QuaZipFile dirZipFile(zip);
if (!dirZipFile.open(QIODevice::WriteOnly,
QuaZipNewInfo(origDirectory.relativeFilePath(dir) + QLatin1String("/"), dir), nullptr, 0, 0)) {
return false;
}
dirZipFile.close();
}
if (dir != origDir) {
QuaZipFile dirZipFile(zip);
std::unique_ptr<QuaZipNewInfo> qzni;
if (options.getDateTime().isNull()) {
qzni = std::make_unique<QuaZipNewInfo>(origDirectory.relativeFilePath(dir) + QLatin1String("/"), dir);
}
else {
qzni = std::make_unique<QuaZipNewInfo>(origDirectory.relativeFilePath(dir) + QLatin1String("/"), dir, options.getDateTime());
}
if (!dirZipFile.open(QIODevice::WriteOnly, *qzni, nullptr, 0, 0)) {
return false;
}
dirZipFile.close();
}

// Whether to compress the subfolders, recursion
if (recursive) {
Expand All @@ -105,7 +125,7 @@ bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool
if (!file.isDir()) // needed for Qt < 4.7 because it doesn't understand AllDirs
continue;
// Compress subdirectory
if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive,filters)) return false;
if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive,filters, options)) return false;
}
}

Expand All @@ -119,7 +139,7 @@ bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool
QString filename = origDirectory.relativeFilePath(file.absoluteFilePath());

// Compress the file
if (!compressFile(zip,file.absoluteFilePath(),filename)) return false;
if (!compressFile(zip,file.absoluteFilePath(),filename, options)) return false;
}

return true;
Expand Down Expand Up @@ -204,6 +224,10 @@ bool JlCompress::removeFile(QStringList listFile) {
}

bool JlCompress::compressFile(QString fileCompressed, QString file) {
return compressFile(fileCompressed, file, JlCompress::Options());
}

bool JlCompress::compressFile(QString fileCompressed, QString file, const Options& options) {
// Create zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
Expand All @@ -213,7 +237,7 @@ bool JlCompress::compressFile(QString fileCompressed, QString file) {
}

// Add file
if (!compressFile(&zip,file,QFileInfo(file).fileName())) {
if (!compressFile(&zip,file,QFileInfo(file).fileName(), options)) {
QFile::remove(fileCompressed);
return false;
}
Expand All @@ -229,33 +253,37 @@ bool JlCompress::compressFile(QString fileCompressed, QString file) {
}

bool JlCompress::compressFiles(QString fileCompressed, QStringList files) {
// Create zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}

// Compress files
QFileInfo info;
for (int index = 0; index < files.size(); ++index ) {
const QString & file( files.at( index ) );
info.setFile(file);
if (!info.exists() || !compressFile(&zip,file,info.fileName())) {
QFile::remove(fileCompressed);
return false;
}
}

// Close zip
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}
return compressFiles(fileCompressed, files, Options());
}

return true;
bool JlCompress::compressFiles(QString fileCompressed, QStringList files, const Options& options) {
// Create zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}

// Compress files
QFileInfo info;
for (int index = 0; index < files.size(); ++index ) {
const QString & file( files.at( index ) );
info.setFile(file);
if (!info.exists() || !compressFile(&zip,file,info.fileName(), options)) {
QFile::remove(fileCompressed);
return false;
}
}

// Close zip
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}

return true;
}

bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive) {
Expand All @@ -265,28 +293,34 @@ bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive
bool JlCompress::compressDir(QString fileCompressed, QString dir,
bool recursive, QDir::Filters filters)
{
// Create zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}

// Add the files and subdirectories
if (!compressSubDir(&zip,dir,dir,recursive, filters)) {
QFile::remove(fileCompressed);
return false;
}

// Close zip
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}
return compressDir(fileCompressed, dir, recursive, filters, Options());
}

return true;
bool JlCompress::compressDir(QString fileCompressed, QString dir,
bool recursive, QDir::Filters filters, const Options& options)
{
// Create zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}

// Add the files and subdirectories
if (!compressSubDir(&zip,dir,dir,recursive, filters, options)) {
QFile::remove(fileCompressed);
return false;
}

// Close zip
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}

return true;
}

QString JlCompress::extractFile(QString fileCompressed, QString fileName, QString fileDest) {
Expand Down
78 changes: 78 additions & 0 deletions quazip/JlCompress.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
class QUAZIP_EXPORT JlCompress {
public:
class Options {
public:
explicit Options(const QDateTime& dateTime = QDateTime())
: m_dateTime(dateTime) {}

QDateTime getDateTime() const {
return m_dateTime;
}

void setDateTime(const QDateTime &dateTime) {
m_dateTime = dateTime;
}

private:
// If set, used as last modified on file inside the archive.
// If compressing a directory, used for all files.
QDateTime m_dateTime;
};

static bool copyData(QIODevice &inFile, QIODevice &outFile);
static QStringList extractDir(QuaZip &zip, const QString &dir);
static QStringList getFileList(QuaZip *zip);
Expand All @@ -55,6 +74,15 @@ class QUAZIP_EXPORT JlCompress {
\return true if success, false otherwise.
*/
static bool compressFile(QuaZip* zip, QString fileName, QString fileDest);
/// Compress a single file.
/**
\param zip Opened zip to compress the file to.
\param fileName The full path to the source file.
\param fileDest The full name of the file inside the archive.
\param options Options for fixed file timestamp, compression level, encryption..
\return true if success, false otherwise.
*/
static bool compressFile(QuaZip* zip, QString fileName, QString fileDest, const Options& options);
/// Compress a subdirectory.
/**
\param parentZip Opened zip containing the parent directory.
Expand All @@ -67,6 +95,21 @@ class QUAZIP_EXPORT JlCompress {
*/
static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive,
QDir::Filters filters);
/// Compress a subdirectory.
/**
\param parentZip Opened zip containing the parent directory.
\param dir The full path to the directory to pack.
\param parentDir The full path to the directory corresponding to
the root of the ZIP.
\param recursive Whether to pack sub-directories as well or only
\param filters what to pack, filters are applied both when searching
* for subdirs (if packing recursively) and when looking for files to pack
\param options Options for fixed file timestamp, compression level, encryption..
files.
\return true if success, false otherwise.
*/
static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive,
QDir::Filters filters, const Options& options);
/// Extract a single file.
/**
\param zip The opened zip archive to extract from.
Expand All @@ -89,13 +132,29 @@ class QUAZIP_EXPORT JlCompress {
\return true if success, false otherwise.
*/
static bool compressFile(QString fileCompressed, QString file);
/// Compress a single file with advanced options.
/**
\param fileCompressed The name of the archive.
\param file The file to compress.
\param options Options for fixed file timestamp, compression level, encryption..
\return true if success, false otherwise.
*/
static bool compressFile(QString fileCompressed, QString file, const Options& options);
/// Compress a list of files.
/**
\param fileCompressed The name of the archive.
\param files The file list to compress.
\return true if success, false otherwise.
*/
static bool compressFiles(QString fileCompressed, QStringList files);
/// Compress a list of files.
/**
\param fileCompressed The name of the archive.
\param files The file list to compress.
\param options Options for fixed file timestamp, compression level, encryption..
\return true if success, false otherwise.
*/
static bool compressFiles(QString fileCompressed, QStringList files, const Options& options);
/// Compress a whole directory.
/**
Does not compress hidden files. See compressDir(QString, QString, bool, QDir::Filters).
Expand Down Expand Up @@ -125,6 +184,25 @@ class QUAZIP_EXPORT JlCompress {
*/
static bool compressDir(QString fileCompressed, QString dir,
bool recursive, QDir::Filters filters);
/**
* @brief Compress a whole directory.
*
* Unless filters are specified explicitly, packs
* only regular non-hidden files (and subdirs, if @c recursive is true).
* If filters are specified, they are OR-combined with
* <tt>%QDir::AllDirs|%QDir::NoDotAndDotDot</tt> when searching for dirs
* and with <tt>QDir::Files</tt> when searching for files.
*
* @param fileCompressed path to the resulting archive
* @param dir path to the directory being compressed
* @param recursive if true, then the subdirectories are packed as well
* @param filters what to pack, filters are applied both when searching
* for subdirs (if packing recursively) and when looking for files to pack
* @param options Options for fixed file timestamp, compression level, encryption..
* @return true on success, false otherwise
*/
static bool compressDir(QString fileCompressed, QString dir,
bool recursive, QDir::Filters filters, const Options& options);

/// Extract a single file.
/**
Expand Down
Loading

0 comments on commit c3e8780

Please sign in to comment.