LibreVNA/Software/PC_Application/LibreVNA-GUI/Util/QMicroz/tools.cpp
2025-02-19 12:34:43 +01:00

275 lines
7.2 KiB
C++

/*
* This file is part of QMicroz,
* under the MIT License.
* https://github.com/artemvlas/qmicroz
*
* Copyright (c) 2024 Artem Vlasenko
*/
#include "tools.h"
#include <QDebug>
#include <QDirIterator>
#include <QStringBuilder>
namespace tools {
mz_zip_archive* za_new(const QString &zip_path, ZaType za_type)
{
// open zip archive
mz_zip_archive *_za = new mz_zip_archive();
// TODO: make a merge (for example, by pointer)
bool result = za_type ? mz_zip_writer_init_file(_za, zip_path.toUtf8().constData(), 0)
: mz_zip_reader_init_file(_za, zip_path.toUtf8().constData(), 0);
if (!result) {
qWarning() << "Failed to open zip file:" << zip_path;
delete _za;
return nullptr;
}
return _za;
}
mz_zip_archive_file_stat za_file_stat(mz_zip_archive* pZip, int file_index)
{
mz_zip_archive_file_stat file_stat;
if (mz_zip_reader_file_stat(pZip, file_index, &file_stat)) {
return file_stat;
}
qWarning() << "Failed to get file info:" << file_index;
return mz_zip_archive_file_stat();
}
bool za_close(mz_zip_archive* pZip)
{
if (pZip && mz_zip_end(pZip)) {
delete pZip;
qDebug() << "Archive closed";
return true;
}
qWarning() << "Failed to close archive";
return false;
}
QString za_item_name(mz_zip_archive* pZip, int file_index)
{
return za_file_stat(pZip, file_index).m_filename;
}
bool createArchive(const QString &zip_path, const QStringList &item_paths, const QString &zip_root)
{
if (item_paths.isEmpty()) {
qDebug() << "No input paths. Nothing to zip.";
return false;
}
// create and open the output zip file
mz_zip_archive *_za = za_new(zip_path, ZaWriter);
if (!_za) {
return false;
}
// process
const bool _res = add_item_list(_za, item_paths, zip_root);
if (_res) {
mz_zip_writer_finalize_archive(_za);
qDebug() << "Done";
}
// cleanup
za_close(_za);
return _res;
}
bool add_item_data(mz_zip_archive *p_zip, const QString &_item_path, const QByteArray &_data)
{
qDebug() << "Adding:" << _item_path;
if (!mz_zip_writer_add_mem(p_zip,
_item_path.toUtf8().constData(),
_data.constData(),
_data.size(),
compressLevel(_data.size())))
{
qWarning() << "Failed to compress file:" << _item_path;
return false;
}
return true;
}
bool add_item_folder(mz_zip_archive *p_zip, const QString &in_path)
{
return add_item_data(p_zip,
in_path.endsWith(s_sep) ? in_path : in_path + s_sep,
QByteArray());
}
bool add_item_file(mz_zip_archive *p_zip, const QString &fs_path, const QString &in_path)
{
qDebug() << "Adding:" << in_path;
return mz_zip_writer_add_file(p_zip, // zip archive
in_path.toUtf8().constData(), // path inside the zip
fs_path.toUtf8().constData(), // filesystem path
NULL, 0,
compressLevel(QFileInfo(fs_path).size()));
}
bool add_item_list(mz_zip_archive *p_zip, const QStringList &items, const QString &rootFolder)
{
QDir __d(rootFolder);
// parsing a list of paths
for (const QString &_item : items) {
QFileInfo __fi(_item);
const QString _relPath = __d.relativeFilePath(_item);
// adding item
if (__fi.isFile() && !add_item_file(p_zip, _item, _relPath) // file
|| (__fi.isDir() && !add_item_folder(p_zip, _relPath))) // subfolder
{
// adding failed
return false;
}
}
return true;
}
bool extract_to_file(mz_zip_archive* pZip, int file_index, const QString &outpath)
{
if (mz_zip_reader_extract_to_file(pZip,
file_index,
outpath.toUtf8().constData(),
0))
{
return true;
}
qWarning() << "Failed to extract file:" << file_index;
return false;
}
QByteArray extract_to_buffer(mz_zip_archive* pZip, int file_index, bool copy_data)
{
size_t __size = 0;
char *_c = (char*)mz_zip_reader_extract_to_heap(pZip, file_index, &__size, 0);
if (_c) {
if (copy_data) {
// COPY data to QByteArray
QByteArray __b(_c, __size);
// clear extracted from heap
delete _c;
return __b;
}
// Reference to the data in the QByteArray.
// Data should be deleted on the caller side: delete _array.constData();
return QByteArray::fromRawData(_c, __size);
}
qWarning() << "Failed to extract file:" << file_index;
return QByteArray();
}
bool extract_all_to_disk(mz_zip_archive *pZip, const QString &output_folder)
{
if (output_folder.isEmpty()) {
qDebug() << "No output folder provided";
return false;
}
const int _num_items = mz_zip_reader_get_num_files(pZip);
if (_num_items == 0) {
qDebug() << "No files to extract";
return false;
}
qDebug() << "Extracting" << _num_items << "items to:" << output_folder;
// extracting...
bool is_success = true;
for (int it = 0; it < _num_items; ++it) {
const QString _filename = za_item_name(pZip, it);
qDebug() << "Extracting:" << (it + 1) << '/' << _num_items << _filename;
const QString _outpath = joinPath(output_folder, _filename);
// create new path on the disk
const QString _parent_folder = QFileInfo(_outpath).absolutePath();
if (!createFolder(_parent_folder)) {
is_success = false;
break;
}
// subfolder, no data to extract
if (_filename.endsWith(s_sep))
continue;
// extract file
if (!extract_to_file(pZip, it, _outpath)) {
is_success = false;
break;
}
}
qDebug() << (is_success ? "Unzip complete." : "Unzip failed.");
return is_success;
}
QStringList folderContent(const QString &folder, bool addRoot)
{
QStringList _items;
if (addRoot) // add root folder
_items << folder;
QDirIterator it(folder,
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Hidden,
QDirIterator::Subdirectories);
while (it.hasNext()) {
_items << it.next();
}
return _items;
}
bool createFolder(const QString &path)
{
if (QFileInfo::exists(path)
|| QDir().mkpath(path))
{
return true;
}
qWarning() << "Failed to create directory:" << path;
return false;
}
bool endsWithSlash(const QString &path)
{
return (path.endsWith('/') || path.endsWith('\\'));
}
QString joinPath(const QString &abs_path, const QString &rel_path)
{
return endsWithSlash(abs_path) ? abs_path + rel_path
: abs_path % s_sep % rel_path;
}
mz_uint compressLevel(qint64 data_size)
{
return (data_size > 40) ? MZ_DEFAULT_COMPRESSION : MZ_NO_COMPRESSION;
}
}// namespace tools