#include #include #include #include #include #include #include #include #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, <); 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; } }