mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-24 15:44:01 +02:00
170 lines
4.6 KiB
C++
170 lines
4.6 KiB
C++
/*
|
|
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
|
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3.
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "Unzip.hpp"
|
|
#include "Error.hpp"
|
|
|
|
#include <exception>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <unzip.h>
|
|
|
|
//
|
|
// Local Defines
|
|
//
|
|
|
|
#define UNZIP_READ_SIZE 67108860 /* 64 MiB */
|
|
|
|
//
|
|
// Exported Functions
|
|
//
|
|
|
|
bool CoreUnzip(std::filesystem::path file, std::filesystem::path path)
|
|
{
|
|
std::string error;
|
|
|
|
unzFile zipFile;
|
|
unz_global_info zipInfo;
|
|
std::ofstream outputStream;
|
|
char* read_buffer = (char*)malloc(UNZIP_READ_SIZE);
|
|
size_t bytes_read = 0;
|
|
|
|
if (read_buffer == nullptr)
|
|
{
|
|
error = "CoreUnzip: malloc Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
|
|
zipFile = unzOpen(file.string().c_str());
|
|
if (zipFile == nullptr)
|
|
{
|
|
free(read_buffer);
|
|
error = "CoreUnzip: unzOpen Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
|
|
if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
|
|
{
|
|
free(read_buffer);
|
|
error = "CoreUnzip: unzGetGlobalInfo Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
|
|
|
|
for (int i = 0; i < zipInfo.number_entry; i++)
|
|
{
|
|
unz_file_info fileInfo;
|
|
char fileName[PATH_MAX];
|
|
std::filesystem::path targetPath;
|
|
|
|
// ensure we can retrieve the current file info
|
|
if (unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, PATH_MAX, nullptr, 0, nullptr, 0) != UNZ_OK)
|
|
{
|
|
free(read_buffer);
|
|
unzClose(zipFile);
|
|
error = "CoreUnzip: unzGetCurrentFileInfo Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
|
|
targetPath = path;
|
|
targetPath += "/";
|
|
targetPath += fileName;
|
|
|
|
if (targetPath.string().ends_with("/"))
|
|
{ // directory
|
|
try
|
|
{
|
|
if (!std::filesystem::is_directory(targetPath) &&
|
|
!std::filesystem::create_directory(targetPath))
|
|
{
|
|
throw std::exception();
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
free(read_buffer);
|
|
unzClose(zipFile);
|
|
error = "CoreUnzip: std::filesystem::create_directory(";
|
|
error += targetPath.string();
|
|
error += ") Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{ // file
|
|
if (unzOpenCurrentFile(zipFile) != UNZ_OK)
|
|
{
|
|
free(read_buffer);
|
|
unzClose(zipFile);
|
|
error = "CoreUnzip: unzOpenCurrentFile Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
|
|
outputStream.open(targetPath, std::ios::trunc | std::ios::binary);
|
|
if (!outputStream.is_open())
|
|
{
|
|
free(read_buffer);
|
|
unzCloseCurrentFile(zipFile);
|
|
unzClose(zipFile);
|
|
error = "CoreUnzip: failed to open file!";
|
|
error += targetPath.string();
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
|
|
do
|
|
{
|
|
bytes_read = unzReadCurrentFile(zipFile, read_buffer, UNZIP_READ_SIZE);
|
|
if (bytes_read < 0)
|
|
{
|
|
free(read_buffer);
|
|
unzCloseCurrentFile(zipFile);
|
|
unzClose(zipFile);
|
|
error = "CoreUnzip: unzReadCurrentFile Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
else
|
|
{ // write data to file
|
|
outputStream.write(read_buffer, bytes_read);
|
|
}
|
|
} while (bytes_read > 0);
|
|
|
|
outputStream.close();
|
|
unzCloseCurrentFile(zipFile);
|
|
}
|
|
|
|
// break when we've iterated over all entries
|
|
if ((i + 1) >= zipInfo.number_entry)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// move to next file
|
|
if (unzGoToNextFile(zipFile) != UNZ_OK)
|
|
{
|
|
free(read_buffer);
|
|
unzClose(zipFile);
|
|
error = "CoreUnzip: unzGoToNextFile Failed!";
|
|
CoreSetError(error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
unzClose(zipFile);
|
|
free(read_buffer);
|
|
return true;
|
|
}
|