fix: extractZipFile is not part of Client but more generic.

This solve a crash from mainmenu while extracting the zip
This commit is contained in:
Loic Blot 2021-05-06 09:02:11 +02:00 committed by Loïc Blot
parent ba40b39500
commit 225d4541ff
5 changed files with 72 additions and 69 deletions

@ -725,72 +725,6 @@ bool Client::loadMedia(const std::string &data, const std::string &filename,
return false; return false;
} }
bool Client::extractZipFile(const char *filename, const std::string &destination)
{
auto fs = m_rendering_engine->get_filesystem();
if (!fs->addFileArchive(filename, false, false, io::EFAT_ZIP)) {
return false;
}
sanity_check(fs->getFileArchiveCount() > 0);
/**********************************************************************/
/* WARNING this is not threadsafe!! */
/**********************************************************************/
io::IFileArchive* opened_zip = fs->getFileArchive(fs->getFileArchiveCount() - 1);
const io::IFileList* files_in_zip = opened_zip->getFileList();
unsigned int number_of_files = files_in_zip->getFileCount();
for (unsigned int i=0; i < number_of_files; i++) {
std::string fullpath = destination;
fullpath += DIR_DELIM;
fullpath += files_in_zip->getFullFileName(i).c_str();
std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
if (!files_in_zip->isDirectory(i)) {
if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
fs->removeFileArchive(fs->getFileArchiveCount()-1);
return false;
}
io::IReadFile* toread = opened_zip->createAndOpenFile(i);
FILE *targetfile = fopen(fullpath.c_str(),"wb");
if (targetfile == NULL) {
fs->removeFileArchive(fs->getFileArchiveCount()-1);
return false;
}
char read_buffer[1024];
long total_read = 0;
while (total_read < toread->getSize()) {
unsigned int bytes_read =
toread->read(read_buffer,sizeof(read_buffer));
if ((bytes_read == 0 ) ||
(fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
{
fclose(targetfile);
fs->removeFileArchive(fs->getFileArchiveCount() - 1);
return false;
}
total_read += bytes_read;
}
fclose(targetfile);
}
}
fs->removeFileArchive(fs->getFileArchiveCount() - 1);
return true;
}
// Virtual methods from con::PeerHandler // Virtual methods from con::PeerHandler
void Client::peerAdded(con::Peer *peer) void Client::peerAdded(con::Peer *peer)
{ {

@ -384,8 +384,6 @@ public:
bool loadMedia(const std::string &data, const std::string &filename, bool loadMedia(const std::string &data, const std::string &filename,
bool from_media_push = false); bool from_media_push = false);
bool extractZipFile(const char *filename, const std::string &destination);
// Send a request for conventional media transfer // Send a request for conventional media transfer
void request_media(const std::vector<std::string> &file_requests); void request_media(const std::vector<std::string> &file_requests);

@ -727,6 +727,70 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
return true; return true;
} }
bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string &destination)
{
if (!fs->addFileArchive(filename, false, false, io::EFAT_ZIP)) {
return false;
}
sanity_check(fs->getFileArchiveCount() > 0);
/**********************************************************************/
/* WARNING this is not threadsafe!! */
/**********************************************************************/
io::IFileArchive* opened_zip = fs->getFileArchive(fs->getFileArchiveCount() - 1);
const io::IFileList* files_in_zip = opened_zip->getFileList();
unsigned int number_of_files = files_in_zip->getFileCount();
for (unsigned int i=0; i < number_of_files; i++) {
std::string fullpath = destination;
fullpath += DIR_DELIM;
fullpath += files_in_zip->getFullFileName(i).c_str();
std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
if (!files_in_zip->isDirectory(i)) {
if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
fs->removeFileArchive(fs->getFileArchiveCount()-1);
return false;
}
io::IReadFile* toread = opened_zip->createAndOpenFile(i);
FILE *targetfile = fopen(fullpath.c_str(),"wb");
if (targetfile == NULL) {
fs->removeFileArchive(fs->getFileArchiveCount()-1);
return false;
}
char read_buffer[1024];
long total_read = 0;
while (total_read < toread->getSize()) {
unsigned int bytes_read =
toread->read(read_buffer,sizeof(read_buffer));
if ((bytes_read == 0 ) ||
(fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
{
fclose(targetfile);
fs->removeFileArchive(fs->getFileArchiveCount() - 1);
return false;
}
total_read += bytes_read;
}
fclose(targetfile);
}
}
fs->removeFileArchive(fs->getFileArchiveCount() - 1);
return true;
}
bool ReadFile(const std::string &path, std::string &out) bool ReadFile(const std::string &path, std::string &out)
{ {
std::ifstream is(path, std::ios::binary | std::ios::ate); std::ifstream is(path, std::ios::binary | std::ios::ate);

@ -36,6 +36,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PATH_DELIM ":" #define PATH_DELIM ":"
#endif #endif
namespace irr { namespace io {
class IFileSystem;
}}
namespace fs namespace fs
{ {
@ -125,6 +129,8 @@ const char *GetFilenameFromPath(const char *path);
bool safeWriteToFile(const std::string &path, const std::string &content); bool safeWriteToFile(const std::string &path, const std::string &content);
bool extractZipFile(irr::io::IFileSystem *fs, const char *filename, const std::string &destination);
bool ReadFile(const std::string &path, std::string &out); bool ReadFile(const std::string &path, std::string &out);
bool Rename(const std::string &from, const std::string &to); bool Rename(const std::string &from, const std::string &to);

@ -628,8 +628,9 @@ int ModApiMainMenu::l_extract_zip(lua_State *L)
std::string absolute_destination = fs::RemoveRelativePathComponents(destination); std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
if (ModApiMainMenu::mayModifyPath(absolute_destination)) { if (ModApiMainMenu::mayModifyPath(absolute_destination)) {
auto rendering_engine = getGuiEngine(L)->m_rendering_engine;
fs::CreateAllDirs(absolute_destination); fs::CreateAllDirs(absolute_destination);
lua_pushboolean(L, getClient(L)->extractZipFile(zipfile, destination)); lua_pushboolean(L, fs::extractZipFile(rendering_engine->get_filesystem(), zipfile, destination));
return 1; return 1;
} }