Changed: One class per files operation

This commit is contained in:
kervala 2016-05-16 11:10:01 +02:00
parent c57c1526a4
commit debf070ec1
8 changed files with 571 additions and 411 deletions

View file

@ -1,100 +0,0 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef ARCHIVE_H
#define ARCHIVE_H
/**
* Files copy, decompression, extraction
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CArchive : public QObject
{
Q_OBJECT
public:
CArchive(QObject *parent = NULL);
virtual ~CArchive();
bool extract(const QString &filename, const QString &dest);
bool copyServerFiles(const QString &src, const QString &dst);
bool copyProfileFiles(const QString &src, const QString &dst);
bool cleanServerFiles(const QString &directory);
void stop();
bool mustStop();
signals:
// emitted when requesting real URL
void extractPrepare();
// emitted when we got the initial (local) and total (remote) size of file
void extractInit(qint64 current, qint64 total);
// emitted when we begin to download
void extractStart();
// emitted when the download stopped
void extractStop();
// emitted when extracting
void extractProgress(qint64 current, const QString &filename);
// emitted when the whole file is downloaded
void extractSuccess(qint64 total);
// emitted when an error occurs
void extractFail(const QString &error);
// emitted when done and should process next step
void done();
protected:
struct FileToCopy
{
QString filename;
QString src;
QString dst;
qint64 size;
QDateTime date;
};
typedef QList<FileToCopy> FilesToCopy;
bool extract7z();
bool extractZip();
bool extractBnp();
bool progress(const std::string &filename, uint32 currentFile, uint32 totalFiles);
bool copyServerFiles();
bool copyProfileFiles();
bool copyFiles(const FilesToCopy &files);
static void getFilesList(const QString &srcDir, const QString &dstDir, const QStringList &filter, FilesToCopy &files);
QString m_filename;
QString m_dest;
QMutex m_mutex;
bool m_mustStop;
};
#endif

View file

@ -0,0 +1,79 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "filescleaner.h"
#include "operation.h"
#include "utils.h"
#include "nel/misc/big_file.h"
#include "nel/misc/callback.h"
#include "nel/misc/file.h"
#include "nel/misc/path.h"
#include "7z.h"
#include "7zAlloc.h"
#include "7zBuf.h"
#include "7zCrc.h"
#include "qzipreader.h"
#include <sys/stat.h>
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
CFilesCleaner::CFilesCleaner(IOperationProgressListener *listener):m_listener(listener)
{
}
CFilesCleaner::~CFilesCleaner()
{
}
void CFilesCleaner::setDirectory(const QString &src)
{
m_directory = src;
}
bool CFilesCleaner::exec()
{
QDir dir(m_directory);
// directory doesn't exist
if (!dir.exists()) return false;
if (!dir.cd("data") && dir.exists()) return false;
// temporary files
QStringList files = dir.entryList(QStringList() << "*.string_cache" << "*.packed_sheets" << "*.packed" << "*.pem", QDir::Files);
foreach(const QString &file, files)
{
dir.remove(file);
}
// fonts directory is not needed anymore
if (dir.cd("fonts") && dir.exists())
{
dir.removeRecursively();
}
if (m_listener) m_listener->operationFinish();
return true;
}

View file

@ -0,0 +1,45 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef FILESCLEANER_H
#define FILESCLEANER_H
class IOperationProgressListener;
/**
* Files cleaner
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CFilesCleaner
{
public:
CFilesCleaner(IOperationProgressListener *listener);
virtual ~CFilesCleaner();
void setDirectory(const QString &src);
bool exec();
protected:
IOperationProgressListener *m_listener;
QString m_directory;
};
#endif

View file

@ -0,0 +1,188 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "filescopier.h"
#include "utils.h"
#include "operation.h"
#include "nel/misc/path.h"
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
CFilesCopier::CFilesCopier(IOperationProgressListener *listener):m_listener(listener)
{
}
CFilesCopier::~CFilesCopier()
{
}
void CFilesCopier::setSourceDirectory(const QString &src)
{
m_sourceDirectory = src;
}
void CFilesCopier::setDesinationDirectory(const QString &dst)
{
m_destinationDirectory = dst;
}
void CFilesCopier::setIncludeFilter(const QStringList &filter)
{
m_includeFilter = filter;
}
void CFilesCopier::setExcludeFilter(const QStringList &filter)
{
m_excludeFilter = filter;
}
bool CFilesCopier::exec()
{
if (m_sourceDirectory.isEmpty() || m_destinationDirectory.isEmpty()) return false;
if (m_listener) m_listener->operationPrepare();
QDir().mkpath(m_destinationDirectory);
FilesToCopy files;
CFilesCopier::getFilesList(files);
return copyFiles(files);
}
void CFilesCopier::getFilesList(FilesToCopy &files)
{
QDir dir(m_sourceDirectory);
QFileInfoList entries = dir.entryInfoList(m_includeFilter);
foreach(const QFileInfo &entry, entries)
{
QString fullPath = entry.absoluteFilePath();
QString dstPath = m_destinationDirectory + "/" + dir.relativeFilePath(fullPath);
if (entry.isDir())
{
QDir().mkpath(dstPath);
QDir subDir(fullPath);
QDirIterator it(subDir, QDirIterator::Subdirectories);
while (it.hasNext())
{
fullPath = it.next();
if (it.fileName().startsWith('.')) continue;
QFileInfo fileInfo = it.fileInfo();
dstPath = m_destinationDirectory + "/" + dir.relativeFilePath(fullPath);
if (fileInfo.isDir())
{
QDir().mkpath(dstPath);
}
else
{
FileToCopy file;
file.filename = it.fileName();
file.src = it.filePath();
file.dst = dstPath;
file.size = it.fileInfo().size();
file.date = it.fileInfo().lastModified().toTime_t();
files << file;
}
}
}
else
{
FileToCopy file;
file.filename = entry.fileName();
file.src = entry.filePath();
file.dst = dstPath;
file.size = entry.size();
file.date = entry.lastModified().toTime_t();
files << file;
}
}
}
bool CFilesCopier::copyFiles(const FilesToCopy &files)
{
qint64 totalSize = 0;
foreach(const FileToCopy &file, files)
{
totalSize += file.size;
}
if (m_listener)
{
m_listener->operationInit(0, totalSize);
m_listener->operationStart();
}
qint64 processedSize = 0;
foreach(const FileToCopy &file, files)
{
if (m_listener && m_listener->operationShouldStop())
{
m_listener->operationStop();
return true;
}
if (m_listener) m_listener->operationProgress(processedSize, file.filename);
QFileInfo dstFileInfo(file.dst);
if (dstFileInfo.size() != file.size || dstFileInfo.lastModified().toTime_t() != file.date)
{
// force deleting previous file since it was incomplete
QFile::remove(file.dst);
if (!QFile::copy(file.src, file.dst))
{
if (m_listener) m_listener->operationFail(QApplication::tr("Unable to copy file %1").arg(file.src));
return false;
}
if (!NLMISC::CFile::setFileModificationDate(qToUtf8(file.dst), file.date))
{
qDebug() << "Unable to change date of " << file.dst;
}
}
processedSize += file.size;
}
if (m_listener)
{
m_listener->operationSuccess(totalSize);
m_listener->operationFinish();
}
return true;
}

View file

@ -0,0 +1,67 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef FILESCOPIER_H
#define FILESCOPIER_H
class IOperationProgressListener;
/**
* Files copier
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CFilesCopier
{
public:
CFilesCopier(IOperationProgressListener *listener);
virtual ~CFilesCopier();
void setSourceDirectory(const QString &src);
void setDesinationDirectory(const QString &src);
void setIncludeFilter(const QStringList &filter);
void setExcludeFilter(const QStringList &filter);
bool exec();
protected:
struct FileToCopy
{
QString filename;
QString src;
QString dst;
qint64 size;
uint date;
};
typedef QList<FileToCopy> FilesToCopy;
void getFilesList(FilesToCopy &files);
bool copyFiles(const FilesToCopy &files);
IOperationProgressListener *m_listener;
QString m_sourceDirectory;
QString m_destinationDirectory;
QStringList m_includeFilter;
QStringList m_excludeFilter;
};
#endif

View file

@ -15,7 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h" #include "stdpch.h"
#include "archive.h" #include "filesextractor.h"
#include "operation.h"
#include "utils.h" #include "utils.h"
#include "nel/misc/big_file.h" #include "nel/misc/big_file.h"
@ -32,10 +33,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#ifdef Q_OS_WIN
#include <Windows.h>
#endif
#ifndef FILE_ATTRIBUTE_READONLY #ifndef FILE_ATTRIBUTE_READONLY
#define FILE_ATTRIBUTE_READONLY 0x1 #define FILE_ATTRIBUTE_READONLY 0x1
#endif #endif
@ -244,20 +241,31 @@ public:
} }
}; };
CArchive::CArchive(QObject *parent):QObject(parent), m_mustStop(false) CFilesExtractor::CFilesExtractor(IOperationProgressListener *listener):m_listener(listener)
{ {
} }
CArchive::~CArchive() CFilesExtractor::~CFilesExtractor()
{ {
} }
bool CArchive::extract(const QString &filename, const QString &dest) void CFilesExtractor::setSourceFile(const QString &src)
{ {
m_filename = filename; m_sourceFile = src;
m_dest = dest; }
QFile file(m_filename); void CFilesExtractor::setDesinationDirectory(const QString &dst)
{
m_destinationDirectory = dst;
}
bool CFilesExtractor::exec()
{
if (m_sourceFile.isEmpty() || m_destinationDirectory.isEmpty()) return false;
if (m_listener) m_listener->operationPrepare();
QFile file(m_sourceFile);
// open archive file to check format // open archive file to check format
if (!file.open(QFile::ReadOnly)) return false; if (!file.open(QFile::ReadOnly)) return false;
@ -270,253 +278,38 @@ bool CArchive::extract(const QString &filename, const QString &dest)
// create destination directory // create destination directory
QDir dir; QDir dir;
dir.mkpath(dest); dir.mkpath(m_destinationDirectory);
QFuture<bool> future;
// compare to supported formats and call the appropriate decompressor // compare to supported formats and call the appropriate decompressor
if (header == "7z") if (header == "7z")
{ {
future = QtConcurrent::run(this, &CArchive::extract7z); return extract7z();
} }
else if (header == "PK")
if (header == "PK")
{ {
future = QtConcurrent::run(this, &CArchive::extractZip); return extractZip();
} }
else if (QFileInfo(filename).suffix().toLower() == "bnp")
if (QFileInfo(m_sourceFile).suffix().toLower() == "bnp")
{ {
future = QtConcurrent::run(this, &CArchive::extractBnp); return extractBnp();
} }
else
{
qDebug() << "Unsupported format"; qDebug() << "Unsupported format";
return false; return false;
} }
return true; bool CFilesExtractor::extract7z()
}
void CArchive::getFilesList(const QString &srcDir, const QString &dstDir, const QStringList &filter, FilesToCopy &files)
{ {
QDir dir(srcDir); Q7zFile inFile(m_sourceFile);
QFileInfoList entries = dir.entryInfoList(filter);
foreach(const QFileInfo &entry, entries)
{
QString fullPath = entry.absoluteFilePath();
QString dstPath = dstDir + "/" + dir.relativeFilePath(fullPath);
if (entry.isDir())
{
QDir().mkpath(dstPath);
QDir subDir(fullPath);
QDirIterator it(subDir, QDirIterator::Subdirectories);
while (it.hasNext())
{
fullPath = it.next();
if (it.fileName().startsWith('.')) continue;
QFileInfo fileInfo = it.fileInfo();
dstPath = dstDir + "/" + dir.relativeFilePath(fullPath);
if (fileInfo.isDir())
{
QDir().mkpath(dstPath);
}
else
{
FileToCopy file;
file.filename = it.fileName();
file.src = it.filePath();
file.dst = dstPath;
file.size = it.fileInfo().size();
file.date = it.fileInfo().lastModified();
files << file;
}
}
}
else
{
FileToCopy file;
file.filename = entry.fileName();
file.src = entry.filePath();
file.dst = dstPath;
file.size = entry.size();
file.date = entry.lastModified();
files << file;
}
}
}
bool CArchive::copyServerFiles()
{
emit extractPrepare();
FilesToCopy files;
QStringList serverFiles;
serverFiles << "cfg";
serverFiles << "data";
serverFiles << "examples";
serverFiles << "patch";
serverFiles << "unpack";
serverFiles << "client_default.cfg";
CArchive::getFilesList(m_filename, m_dest, serverFiles, files);
return copyFiles(files);
}
bool CArchive::copyProfileFiles()
{
emit extractPrepare();
FilesToCopy files;
QStringList configFiles;
configFiles << "cache";
configFiles << "save";
configFiles << "user";
configFiles << "screenshots";
configFiles << "client.cfg";
configFiles << "*.log";
CArchive::getFilesList(m_filename, m_dest, configFiles, files);
return copyFiles(files);
}
bool CArchive::cleanServerFiles(const QString &directory)
{
QDir dir(directory);
// directory doesn't exist
if (!dir.exists()) return false;
if (!dir.cd("data") && dir.exists()) return false;
// temporary files
QStringList files = dir.entryList(QStringList() << "*.string_cache" << "*.packed_sheets" << "*.packed" << "*.pem", QDir::Files);
foreach(const QString &file, files)
{
dir.remove(file);
}
// fonts directory is not needed anymore
if (dir.cd("fonts") && dir.exists())
{
dir.removeRecursively();
}
emit done();
return true;
}
bool CArchive::copyServerFiles(const QString &src, const QString &dst)
{
if (src.isEmpty() || dst.isEmpty()) return false;
m_filename = src;
m_dest = dst;
// create destination directory
QDir().mkpath(dst);
QFuture<bool> future = QtConcurrent::run(this, &CArchive::copyServerFiles);
return true;
}
bool CArchive::copyProfileFiles(const QString &src, const QString &dst)
{
if (src.isEmpty() || dst.isEmpty()) return false;
m_filename = src;
m_dest = dst;
// create destination directory
QDir().mkpath(dst);
QFuture<bool> future = QtConcurrent::run(this, &CArchive::copyProfileFiles);
return true;
}
bool CArchive::copyFiles(const FilesToCopy &files)
{
qint64 totalSize = 0;
foreach(const FileToCopy &file, files)
{
totalSize += file.size;
qDebug() << file.filename;
}
emit extractInit(0, totalSize);
emit extractStart();
qint64 processedSize = 0;
foreach(const FileToCopy &file, files)
{
if (mustStop())
{
emit extractStop();
return true;
}
emit extractProgress(processedSize, file.filename);
QFileInfo dstFileInfo(file.dst);
if (dstFileInfo.size() != file.size || dstFileInfo.lastModified() != file.date)
{
if (!QFile::copy(file.src, file.dst))
{
emit extractFail(tr("Unable to copy file %1").arg(file.src));
return false;
}
if (!NLMISC::CFile::setFileModificationDate(qToUtf8(file.dst), file.date.toTime_t()))
{
qDebug() << "Unable to change date";
}
}
processedSize += file.size;
}
emit extractSuccess(totalSize);
emit done();
return true;
}
bool CArchive::extract7z()
{
Q7zFile inFile(m_filename);
if (!inFile.open()) if (!inFile.open())
{ {
emit extractFail(tr("Unable to open %1").arg(m_filename)); if (m_listener) m_listener->operationFail(QApplication::tr("Unable to open %1").arg(m_sourceFile));
return false; return false;
} }
emit extractPrepare();
UInt16 *temp = NULL; UInt16 *temp = NULL;
size_t tempSize = 0; size_t tempSize = 0;
@ -558,9 +351,11 @@ bool CArchive::extract7z()
if (!isDir) total += SzArEx_GetFileSize(&db, i); if (!isDir) total += SzArEx_GetFileSize(&db, i);
} }
emit extractInit(0, total); if (m_listener)
{
emit extractStart(); m_listener->operationInit(0, total);
m_listener->operationStart();
}
// variables used for decompression // variables used for decompression
UInt32 blockIndex = 0xFFFFFFFF; UInt32 blockIndex = 0xFFFFFFFF;
@ -570,7 +365,7 @@ bool CArchive::extract7z()
// process each file in archive // process each file in archive
for (UInt32 i = 0; i < db.NumFiles; ++i) for (UInt32 i = 0; i < db.NumFiles; ++i)
{ {
if (mustStop()) if (m_listener && m_listener->operationShouldStop())
{ {
res = SZ_ERROR_INTERRUPTED; res = SZ_ERROR_INTERRUPTED;
break; break;
@ -602,7 +397,7 @@ bool CArchive::extract7z()
if (!isDir) if (!isDir)
{ {
emit extractProgress(totalUncompressed, filename); if (m_listener) m_listener->operationProgress(totalUncompressed, filename);
res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize,
&offset, &outSizeProcessed, &allocImp, &allocTempImp); &offset, &outSizeProcessed, &allocImp, &allocTempImp);
@ -610,7 +405,7 @@ bool CArchive::extract7z()
if (res != SZ_OK) break; if (res != SZ_OK) break;
} }
QString destPath = m_dest + '/' + path; QString destPath = m_destinationDirectory + '/' + path;
QDir dir; QDir dir;
@ -626,7 +421,7 @@ bool CArchive::extract7z()
if (!outFile.open(QFile::WriteOnly)) if (!outFile.open(QFile::WriteOnly))
{ {
error = tr("Unable to open output file"); error = QApplication::tr("Unable to open output file");
res = SZ_ERROR_FAIL; res = SZ_ERROR_FAIL;
break; break;
} }
@ -635,7 +430,7 @@ bool CArchive::extract7z()
if (processedSize != outSizeProcessed) if (processedSize != outSizeProcessed)
{ {
error = tr("Unable to write output file"); error = QApplication::tr("Unable to write output file");
res = SZ_ERROR_FAIL; res = SZ_ERROR_FAIL;
break; break;
} }
@ -644,7 +439,7 @@ bool CArchive::extract7z()
totalUncompressed += SzArEx_GetFileSize(&db, i); totalUncompressed += SzArEx_GetFileSize(&db, i);
emit extractProgress(totalUncompressed, filename); if (m_listener) m_listener->operationProgress(totalUncompressed, filename);
if (SzBitWithVals_Check(&db.Attribs, i)) if (SzBitWithVals_Check(&db.Attribs, i))
Set7zFileAttrib(destPath, db.Attribs.Vals[i]); Set7zFileAttrib(destPath, db.Attribs.Vals[i]);
@ -659,24 +454,27 @@ bool CArchive::extract7z()
switch(res) switch(res)
{ {
case SZ_OK: case SZ_OK:
emit extractSuccess(totalUncompressed); if (m_listener)
emit done(); {
m_listener->operationSuccess(totalUncompressed);
m_listener->operationFinish();
}
return true; return true;
case SZ_ERROR_INTERRUPTED: case SZ_ERROR_INTERRUPTED:
emit extractStop(); if (m_listener) m_listener->operationStop();
return true; return true;
case SZ_ERROR_UNSUPPORTED: case SZ_ERROR_UNSUPPORTED:
error = tr("7zip decoder doesn't support this archive"); error = QApplication::tr("7zip decoder doesn't support this archive");
break; break;
case SZ_ERROR_MEM: case SZ_ERROR_MEM:
error = tr("Unable to allocate memory"); error = QApplication::tr("Unable to allocate memory");
break; break;
case SZ_ERROR_CRC: case SZ_ERROR_CRC:
error = tr("7zip decoder doesn't support this archive"); error = QApplication::tr("7zip decoder doesn't support this archive");
break; break;
case SZ_ERROR_FAIL: case SZ_ERROR_FAIL:
@ -684,21 +482,19 @@ bool CArchive::extract7z()
break; break;
default: default:
error = tr("Error %1").arg(res); error = QApplication::tr("Error %1").arg(res);
} }
emit extractFail(error); if (m_listener) m_listener->operationFail(error);
return false; return false;
} }
bool CArchive::extractZip() bool CFilesExtractor::extractZip()
{ {
emit extractPrepare(); QZipReader reader(m_sourceFile);
QZipReader reader(m_filename); QDir baseDir(m_destinationDirectory);
QDir baseDir(m_dest);
// create directories first // create directories first
QList<QZipReader::FileInfo> allFiles = reader.fileInfoList(); QList<QZipReader::FileInfo> allFiles = reader.fileInfoList();
@ -709,17 +505,17 @@ bool CArchive::extractZip()
{ {
if (fi.isDir) if (fi.isDir)
{ {
const QString absPath = m_dest + QDir::separator() + fi.filePath; const QString absPath = m_destinationDirectory + QDir::separator() + fi.filePath;
if (!baseDir.mkpath(fi.filePath)) if (!baseDir.mkpath(fi.filePath))
{ {
emit extractFail(tr("Unable to create directory %1").arg(absPath)); if (m_listener) m_listener->operationFail(QApplication::tr("Unable to create directory %1").arg(absPath));
return false; return false;
} }
if (!QFile::setPermissions(absPath, fi.permissions)) if (!QFile::setPermissions(absPath, fi.permissions))
{ {
emit extractFail(tr("Unable to set permissions of %1").arg(absPath)); if (m_listener) m_listener->operationFail(QApplication::tr("Unable to set permissions of %1").arg(absPath));
return false; return false;
} }
} }
@ -727,20 +523,23 @@ bool CArchive::extractZip()
totalSize += fi.size; totalSize += fi.size;
} }
emit extractInit(0, totalSize); if (m_listener)
emit extractStart(); {
m_listener->operationInit(0, totalSize);
m_listener->operationStart();
}
// client won't use symbolic links so don't process them // client won't use symbolic links so don't process them
foreach (const QZipReader::FileInfo &fi, allFiles) foreach (const QZipReader::FileInfo &fi, allFiles)
{ {
const QString absPath = m_dest + QDir::separator() + fi.filePath; const QString absPath = m_destinationDirectory + QDir::separator() + fi.filePath;
if (fi.isFile) if (fi.isFile)
{ {
if (mustStop()) if (m_listener && m_listener->operationShouldStop())
{ {
emit extractStop(); m_listener->operationStop();
return true; return true;
} }
@ -748,7 +547,7 @@ bool CArchive::extractZip()
if (!f.open(QIODevice::WriteOnly)) if (!f.open(QIODevice::WriteOnly))
{ {
emit extractFail(tr("Unable to open %1").arg(absPath)); if (m_listener) m_listener->operationFail(QApplication::tr("Unable to open %1").arg(absPath));
return false; return false;
} }
@ -757,58 +556,65 @@ bool CArchive::extractZip()
f.setPermissions(fi.permissions); f.setPermissions(fi.permissions);
f.close(); f.close();
emit extractProgress(currentSize, QFileInfo(absPath).fileName()); if (m_listener) m_listener->operationProgress(currentSize, QFileInfo(absPath).fileName());
} }
} }
emit extractSuccess(totalSize); if (m_listener)
emit done(); {
m_listener->operationSuccess(totalSize);
m_listener->operationFinish();
}
return true; return true;
} }
bool CArchive::progress(const std::string &filename, uint32 currentSize, uint32 totalSize) bool CFilesExtractor::progress(const std::string &filename, uint32 currentSize, uint32 totalSize)
{ {
if (mustStop()) if (m_listener && m_listener->operationShouldStop())
{ {
emit extractStop(); m_listener->operationStop();
return false; return false;
} }
if (currentSize == 0) if (currentSize == 0)
{ {
emit extractInit(0, (qint64)totalSize); if (m_listener)
emit extractStart(); {
m_listener->operationInit(0, (qint64)totalSize);
m_listener->operationStart();
}
} }
emit extractProgress((qint64)currentSize, qFromUtf8(filename)); if (m_listener) m_listener->operationProgress((qint64)currentSize, qFromUtf8(filename));
if (currentSize == totalSize) if (currentSize == totalSize)
{ {
emit extractSuccess((qint64)totalSize); if (m_listener)
emit done(); {
m_listener->operationSuccess((qint64)totalSize);
m_listener->operationFinish();
}
} }
return true; return true;
} }
bool CArchive::extractBnp() bool CFilesExtractor::extractBnp()
{ {
QString error; QString error;
emit extractPrepare(); NLMISC::CBigFile::TUnpackProgressCallback cbMethod = NLMISC::CBigFile::TUnpackProgressCallback(this, &CFilesExtractor::progress);
NLMISC::CBigFile::TUnpackProgressCallback cbMethod = NLMISC::CBigFile::TUnpackProgressCallback(this, &CArchive::progress);
try try
{ {
if (NLMISC::CBigFile::unpack(qToUtf8(m_filename), qToUtf8(m_dest), &cbMethod)) if (NLMISC::CBigFile::unpack(qToUtf8(m_sourceFile), qToUtf8(m_destinationDirectory), &cbMethod))
{ {
return true; return true;
} }
if (mustStop()) if (m_listener && m_listener->operationShouldStop())
{ {
// stopped // stopped
@ -819,37 +625,22 @@ bool CArchive::extractBnp()
} }
catch(const NLMISC::EDiskFullError &e) catch(const NLMISC::EDiskFullError &e)
{ {
error = tr("disk full"); error = QApplication::tr("disk full");
} }
catch(const NLMISC::EWriteError &e) catch(const NLMISC::EWriteError &e)
{ {
error = tr("unable to write %1").arg(qFromUtf8(e.Filename)); error = QApplication::tr("unable to write %1").arg(qFromUtf8(e.Filename));
} }
catch(const NLMISC::EReadError &e) catch(const NLMISC::EReadError &e)
{ {
error = tr("unable to read %1").arg(qFromUtf8(e.Filename)); error = QApplication::tr("unable to read %1").arg(qFromUtf8(e.Filename));
} }
catch(const std::exception &e) catch(const std::exception &e)
{ {
error = tr("failed (%1)").arg(qFromUtf8(e.what())); error = QApplication::tr("failed (%1)").arg(qFromUtf8(e.what()));
} }
emit extractFail(tr("Unable to unpack %1 to %2: %3").arg(m_filename).arg(m_dest).arg(error)); if (m_listener) m_listener->operationFail(QApplication::tr("Unable to unpack %1 to %2: %3").arg(m_sourceFile).arg(m_destinationDirectory).arg(error));
return false; return false;
} }
void CArchive::stop()
{
QMutexLocker locker(&m_mutex);
m_mustStop = true;
}
bool CArchive::mustStop()
{
QMutexLocker locker(&m_mutex);
return m_mustStop;
}

View file

@ -0,0 +1,53 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef FILEXTRACTOR_H
#define FILEXTRACTOR_H
class IOperationProgressListener;
/**
* Files extractor
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CFilesExtractor
{
public:
CFilesExtractor(IOperationProgressListener *listener);
virtual ~CFilesExtractor();
void setSourceFile(const QString &src);
void setDesinationDirectory(const QString &src);
bool exec();
protected:
bool extract7z();
bool extractZip();
bool extractBnp();
bool progress(const std::string &filename, uint32 currentFile, uint32 totalFiles);
IOperationProgressListener *m_listener;
QString m_sourceFile;
QString m_destinationDirectory;
};
#endif

View file

@ -0,0 +1,37 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef OPERATION_H
#define OPERATION_H
class IOperationProgressListener
{
public:
virtual ~IOperationProgressListener() {}
virtual void operationPrepare() =0;
virtual void operationInit(qint64 current, qint64 total) =0;
virtual void operationStart() =0;
virtual void operationStop() =0;
virtual void operationProgress(qint64 current, const QString &filename) =0;
virtual void operationSuccess(qint64 total) =0;
virtual void operationFail(const QString &error) =0;
virtual void operationFinish() =0;
virtual bool operationShouldStop() =0;
};
#endif