add ability to create zip

This commit is contained in:
Chee Yee
2023-02-07 22:21:36 -08:00
parent 26e29ff3c2
commit f904aa4243
10 changed files with 422 additions and 65 deletions
+1
View File
@@ -35,6 +35,7 @@ add_executable(ezremote_client
source/smbclient.cpp
source/windows.cpp
source/webdavclient.cpp
source/zip_util.cpp
source/imgui_draw.cpp
source/imgui_impl_sdl.cpp
source/imgui_impl_sdlrenderer.cpp
+4
View File
@@ -90,3 +90,7 @@ STR_EXTRACT=Extract
STR_EXTRACTING=Extracting
STR_FAILED_TO_EXTRACT=Failed to extract
STR_EXTRACT_LOCATION=Extract Location
STR_COMPRESS=Compress
STR_ZIP_FILE_PATH=Zip Filename
STR_COMPRESSING=Compressing
STR_ERROR_CREATE_ZIP=Error occured while creating zip
+40 -61
View File
@@ -18,6 +18,7 @@
#include "ftpclient.h"
#include "smbclient.h"
#include "webdavclient.h"
#include "zip_util.h"
namespace Actions
{
@@ -735,75 +736,15 @@ namespace Actions
}
}
int Extract(const DirEntry &file, const std::string &dir)
{
unz_global_info global_info;
unz_file_info file_info;
unzFile zipfile = unzOpen(file.path);
std::string dest_dir = std::string(dir);
if (dest_dir[dest_dir.length()-1] != '/')
{
dest_dir = dest_dir + "/";
}
if (zipfile == NULL)
{
return 0;
}
unzGetGlobalInfo(zipfile, &global_info);
unzGoToFirstFile(zipfile);
uint64_t curr_extracted_bytes = 0;
uint64_t curr_file_bytes = 0;
int num_files = global_info.number_entry;
char fname[512];
char ext_fname[512];
char read_buffer[32768];
for (int zip_idx = 0; zip_idx < num_files; ++zip_idx)
{
if (stop_activity)
break;
unzGetCurrentFileInfo(zipfile, &file_info, fname, 512, NULL, 0, NULL, 0);
sprintf(ext_fname, "%s%s", dest_dir.c_str(), fname);
const size_t filename_length = strlen(ext_fname);
if (ext_fname[filename_length - 1] != '/')
{
snprintf(activity_message, 255, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, fname);
curr_file_bytes = 0;
unzOpenCurrentFile(zipfile);
FS::MkDirs(ext_fname, true);
FILE *f = fopen(ext_fname, "wb");
while (curr_file_bytes < file_info.uncompressed_size)
{
int rbytes = unzReadCurrentFile(zipfile, read_buffer, 32768);
if (rbytes > 0)
{
fwrite(read_buffer, 1, rbytes, f);
curr_extracted_bytes += rbytes;
curr_file_bytes += rbytes;
}
}
fclose(f);
unzCloseCurrentFile(zipfile);
}
if ((zip_idx + 1) < num_files)
{
unzGoToNextFile(zipfile);
}
}
unzClose(zipfile);
return 1;
}
void *ExtractZipThread(void *argp)
{
file_transfering = true;
for (std::set<DirEntry>::iterator it = multi_selected_local_files.begin(); it != multi_selected_local_files.end(); ++it)
{
if (stop_activity)
break;
if (!it->isDir)
{
int ret = Extract(*it, extract_zip_folder);
int ret = ZipUtil::Extract(*it, extract_zip_folder);
if (ret == 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAILED_TO_EXTRACT], it->name);
@@ -831,6 +772,44 @@ namespace Actions
}
}
void *MakeZipThread(void *argp)
{
zipFile zf = zipOpen64(zip_file_path, APPEND_STATUS_CREATE);
if (zf != NULL)
{
for (std::set<DirEntry>::iterator it = multi_selected_local_files.begin(); it != multi_selected_local_files.end(); ++it)
{
if (stop_activity)
break;
int res = ZipUtil::ZipAddPath(zf, it->path, strlen(it->directory)+1, Z_DEFAULT_COMPRESSION);
if (res <= 0)
{
sprintf(status_message, "%s", lang_strings[STR_ERROR_CREATE_ZIP]);
sceKernelUsleep(2000000);
}
}
zipClose(zf, NULL);
}
activity_inprogess = false;
multi_selected_local_files.clear();
Windows::SetModalMode(false);
selected_action = ACTION_REFRESH_LOCAL_FILES;
return NULL;
}
void MakeLocalZip()
{
sprintf(status_message, "%s", "");
int res = pthread_create(&bk_activity_thid, NULL, MakeZipThread, NULL);
if (res != 0)
{
file_transfering = false;
activity_inprogess = false;
multi_selected_local_files.clear();
Windows::SetModalMode(false);
}
}
std::string GetGoogleDownloadUrl(std::string &url)
{
size_t scheme_pos = url.find_first_of("://");
+2
View File
@@ -86,6 +86,8 @@ namespace Actions
void *KeepAliveThread(void *argp);
void *ExtractZipThread(void *argp);
void ExtractLocalZips();
void *MakeZipThread(void *argp);
void MakeLocalZip();
}
#endif
+5 -1
View File
@@ -101,7 +101,11 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
"Extract", // STR_EXTRACT
"Extracting", // STR_EXTRACTING
"Failed to extract", // STR_FAILED_TO_EXTRACT
"Extract Location" // STR_EXTRACT_LOCATION
"Extract Location", // STR_EXTRACT_LOCATION
"Compress", // STR_COMPRESS
"Zip Filename", // STR_ZIP_FILE_PATH
"Compressing", // STR_COMPRESSING
"Error occured while creating zip" // STR_ERROR_CREATE_ZIP
};
bool needs_extended_font = false;
+6 -2
View File
@@ -95,7 +95,11 @@
FUNC(STR_EXTRACT) \
FUNC(STR_EXTRACTING) \
FUNC(STR_FAILED_TO_EXTRACT) \
FUNC(STR_EXTRACT_LOCATION)
FUNC(STR_EXTRACT_LOCATION) \
FUNC(STR_COMPRESS) \
FUNC(STR_ZIP_FILE_PATH) \
FUNC(STR_COMPRESSING) \
FUNC(STR_ERROR_CREATE_ZIP)
#define GET_VALUE(x) x,
#define GET_STRING(x) #x,
@@ -105,7 +109,7 @@ enum
FOREACH_STR(GET_VALUE)
};
#define LANG_STRINGS_NUM 92
#define LANG_STRINGS_NUM 96
#define LANG_ID_SIZE LANG_STRINGS_NUM
#define LANG_STR_SIZE 256
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
+76 -1
View File
@@ -59,6 +59,7 @@ bool set_focus_to_remote = false;
bool select_url_inprogress = false;
int favorite_url_idx = 0;
char extract_zip_folder[256];
char zip_file_path[384];
bool dont_prompt_overwrite = false;
bool dont_prompt_overwrite_cb = false;
@@ -157,6 +158,46 @@ namespace Windows
paused = modal;
}
std::string getUniqueZipFilename()
{
std::string zipfolder;
std::string zipname;
if (strcmp(multi_selected_local_files.begin()->directory, "/") == 0)
{
zipfolder = "/data";
}
else
{
zipfolder = multi_selected_local_files.begin()->directory;
}
if (multi_selected_local_files.size() == 1)
{
zipname = multi_selected_local_files.begin()->name;
}
else if (strcmp(multi_selected_local_files.begin()->directory, "/") == 0)
{
zipname = "new_zip";
}
else
{
zipname = std::string(multi_selected_local_files.begin()->directory);
zipname = zipname.substr(zipname.find_last_of("/")+1);
}
std::string zip_path;
zip_path = zipfolder + "/" + zipname;
int i = 0;
while (true)
{
std::string temp_path;
i > 0 ? temp_path = zip_path + "(" + std::to_string(i) + ").zip" : temp_path = zip_path + ".zip";
if (!FS::FileExists(temp_path))
return temp_path;
i++;
}
}
void ConnectionPanel()
{
ImGuiStyle *style = &ImGui::GetStyle();
@@ -738,6 +779,28 @@ namespace Windows
ime_after_update = AfterExtractFolderCallback;
Dialog::initImeDialog(lang_strings[STR_EXTRACT_LOCATION], extract_zip_folder, 255, ORBIS_TYPE_BASIC_LATIN, 600, 350);
gui_mode = GUI_MODE_IME;
file_transfering = true;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("Compress##settings");
if (ImGui::Selectable(lang_strings[STR_COMPRESS], false, flags | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
std::string zipname;
std::string zipfolder;
ResetImeCallbacks();
sprintf(zip_file_path, "%s", getUniqueZipFilename().c_str());
ime_single_field = zip_file_path;
ime_field_size = 383;
ime_callback = SingleValueImeCallback;
ime_after_update = AfterZipFileCallback;
Dialog::initImeDialog(lang_strings[STR_ZIP_FILE_PATH], zip_file_path, 383, ORBIS_TYPE_BASIC_LATIN, 600, 350);
gui_mode = GUI_MODE_IME;
file_transfering = true;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
@@ -1219,10 +1282,17 @@ namespace Windows
case ACTION_EXTRACT_LOCAL_ZIP:
activity_inprogess = true;
stop_activity = false;
file_transfering = false;
file_transfering = true;
selected_action = ACTION_NONE;
Actions::ExtractLocalZips();
break;
case ACTION_CREATE_LOCAL_ZIP:
activity_inprogess = true;
stop_activity = false;
file_transfering = true;
selected_action = ACTION_NONE;
Actions::MakeLocalZip();
break;
case ACTION_RENAME_LOCAL:
if (gui_mode != GUI_MODE_IME)
{
@@ -1437,4 +1507,9 @@ namespace Windows
{
selected_action = ACTION_EXTRACT_LOCAL_ZIP;
}
void AfterZipFileCallback(int ime_result)
{
selected_action = ACTION_CREATE_LOCAL_ZIP;
}
}
+2
View File
@@ -37,6 +37,7 @@ extern int overwrite_type;
extern ACTIONS action_to_take;
extern bool file_transfering;
extern char extract_zip_folder[];
extern char zip_file_path[];
static ImVector<ImRect> s_GroupPanelLabelStack;
@@ -201,6 +202,7 @@ namespace Windows
void AfterPackageUrlCallback(int ime_result);
void AfterFavoriteUrlCallback(int ime_result);
void AfterExtractFolderCallback(int ime_result);
void AfterZipFileCallback(int ime_result);
}
#endif
+270
View File
@@ -0,0 +1,270 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <minizip/unzip.h>
#include <minizip/zip.h>
#include "common.h"
#include "fs.h"
#include "lang.h"
#include "rtc.h"
#include "windows.h"
#define TRANSFER_SIZE (128 * 1024)
namespace ZipUtil
{
void convertToZipTime(time_t time, tm_zip *tmzip)
{
OrbisDateTime gmt;
OrbisDateTime lt;
struct tm tm = *localtime(&time);
gmt.day = tm.tm_mday;
gmt.month = tm.tm_mon + 1;
gmt.year = tm.tm_year + 1900;
gmt.hour = tm.tm_hour;
gmt.minute = tm.tm_min;
gmt.second = tm.tm_sec;
convertUtcToLocalTime(&gmt, &lt);
tmzip->tm_sec = lt.second;
tmzip->tm_min = lt.minute;
tmzip->tm_hour = lt.hour;
tmzip->tm_mday = lt.day;
tmzip->tm_mon = lt.month;
tmzip->tm_year = lt.year;
}
int ZipAddFile(zipFile zf, const std::string &path, int filename_start, int level)
{
int res;
// Get file stat
struct stat file_stat;
memset(&file_stat, 0, sizeof(file_stat));
res = stat(path.c_str(), &file_stat);
if (res < 0)
return res;
// Get file local time
zip_fileinfo zi;
memset(&zi, 0, sizeof(zip_fileinfo));
convertToZipTime(file_stat.st_mtim.tv_sec, &zi.tmz_date);
bytes_transfered = 0;
bytes_to_download = file_stat.st_size;
// Large file?
int use_zip64 = (file_stat.st_size >= 0xFFFFFFFF);
// Open new file in zip
res = zipOpenNewFileInZip3_64(zf, path.substr(filename_start).c_str(), &zi,
NULL, 0, NULL, 0, NULL,
(level != 0) ? Z_DEFLATED : 0,
level, 0,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, use_zip64);
if (res < 0)
return res;
// Open file to add
FILE *fd = FS::OpenRead(path);
if (fd == NULL)
{
zipCloseFileInZip(zf);
return 0;
}
// Add file to zip
void *buf = memalign(4096, TRANSFER_SIZE);
uint64_t seek = 0;
while (1)
{
int read = FS::Read(fd, buf, TRANSFER_SIZE);
if (read < 0)
{
free(buf);
FS::Close(fd);
zipCloseFileInZip(zf);
return read;
}
if (read == 0)
break;
int written = zipWriteInFileInZip(zf, buf, read);
if (written < 0)
{
free(buf);
FS::Close(fd);
zipCloseFileInZip(zf);
return written;
}
seek += written;
bytes_transfered += read;
}
free(buf);
FS::Close(fd);
zipCloseFileInZip(zf);
return 1;
}
int ZipAddFolder(zipFile zf, const std::string &path, int filename_start, int level)
{
int res;
// Get file stat
struct stat file_stat;
memset(&file_stat, 0, sizeof(file_stat));
res = stat(path.c_str(), &file_stat);
if (res < 0)
return res;
// Get file local time
zip_fileinfo zi;
memset(&zi, 0, sizeof(zip_fileinfo));
convertToZipTime(file_stat.st_mtim.tv_sec, &zi.tmz_date);
// Open new file in zip
std::string folder = path.substr(filename_start);
if (folder[folder.length()-1] != '/')
folder = folder + "/";
res = zipOpenNewFileInZip3_64(zf, folder.c_str(), &zi,
NULL, 0, NULL, 0, NULL,
(level != 0) ? Z_DEFLATED : 0,
level, 0,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, 0);
if (res < 0)
return res;
zipCloseFileInZip(zf);
return 1;
}
int ZipAddPath(zipFile zf, const std::string &path, int filename_start, int level)
{
DIR *dfd = opendir(path.c_str());
if (dfd != NULL)
{
int ret = ZipAddFolder(zf, path, filename_start, level);
if (ret <= 0)
return ret;
struct dirent *dirent;
do
{
dirent = readdir(dfd);
if (stop_activity)
return 1;
if (dirent != NULL && strcmp(dirent->d_name, ".") != 0 && strcmp(dirent->d_name, "..") != 0)
{
int new_path_length = path.length() + strlen(dirent->d_name) + 2;
char *new_path = (char*)malloc(new_path_length);
snprintf(new_path, new_path_length, "%s%s%s", path.c_str(), FS::hasEndSlash(path.c_str()) ? "" : "/", dirent->d_name);
int ret = 0;
if (dirent->d_type & DT_DIR)
{
ret = ZipAddPath(zf, new_path, filename_start, level);
}
else
{
sprintf(activity_message, "%s %s", lang_strings[STR_COMPRESSING], new_path);
ret = ZipAddFile(zf, new_path, filename_start, level);
}
free(new_path);
// Some folders are protected and return 0x80010001. Bypass them
if (ret <= 0)
{
closedir(dfd);
return ret;
}
}
} while (dirent != NULL);
closedir(dfd);
}
else
{
return ZipAddFile(zf, path, filename_start, level);
}
return 1;
}
int Extract(const DirEntry &file, const std::string &dir)
{
unz_global_info global_info;
unz_file_info file_info;
unzFile zipfile = unzOpen(file.path);
std::string dest_dir = std::string(dir);
if (dest_dir[dest_dir.length() - 1] != '/')
{
dest_dir = dest_dir + "/";
}
if (zipfile == NULL)
{
return 0;
}
unzGetGlobalInfo(zipfile, &global_info);
unzGoToFirstFile(zipfile);
uint64_t curr_extracted_bytes = 0;
uint64_t curr_file_bytes = 0;
int num_files = global_info.number_entry;
char fname[512];
char ext_fname[512];
char read_buffer[TRANSFER_SIZE];
for (int zip_idx = 0; zip_idx < num_files; ++zip_idx)
{
if (stop_activity)
break;
unzGetCurrentFileInfo(zipfile, &file_info, fname, 512, NULL, 0, NULL, 0);
sprintf(ext_fname, "%s%s", dest_dir.c_str(), fname);
const size_t filename_length = strlen(ext_fname);
bytes_transfered = 0;
bytes_to_download = file_info.uncompressed_size;
if (ext_fname[filename_length - 1] != '/')
{
snprintf(activity_message, 255, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, fname);
curr_file_bytes = 0;
unzOpenCurrentFile(zipfile);
FS::MkDirs(ext_fname, true);
FILE *f = fopen(ext_fname, "wb");
while (curr_file_bytes < file_info.uncompressed_size)
{
int rbytes = unzReadCurrentFile(zipfile, read_buffer, TRANSFER_SIZE);
if (rbytes > 0)
{
fwrite(read_buffer, 1, rbytes, f);
curr_extracted_bytes += rbytes;
curr_file_bytes += rbytes;
bytes_transfered = curr_file_bytes;
}
}
fclose(f);
unzCloseCurrentFile(zipfile);
}
if ((zip_idx + 1) < num_files)
{
unzGoToNextFile(zipfile);
}
}
unzClose(zipfile);
return 1;
}
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef ZIP_UTIL_H
#define ZIP_UTIL_H
#include <string.h>
#include <stdlib.h>
#include <minizip/unzip.h>
#include <minizip/zip.h>
#include "common.h"
#include "fs.h"
namespace ZipUtil
{
int ZipAddPath(zipFile zf, const std::string &path, int filename_start, int level);
int Extract(const DirEntry &file, const std::string &dir);
}
#endif