This repository has been archived on 2026-06-05. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
PatchExtractor/source/extractor.cpp
niklascfw abea3f8765
All checks were successful
Build NRO / build (push) Successful in 1m44s
Fix self-delete to run only after successful extraction (v1.1.1).
Only remove PatchExtractor.nro on exit when the Done screen was reached;
early quit no longer deletes the NRO. Drop the ineffective mid-run self-delete.
2026-05-28 22:46:02 +02:00

132 lines
3.0 KiB
C++

#include "extractor.hpp"
#include <cstdio>
#include <cstring>
#include <sys/stat.h>
#ifdef __SWITCH__
#include <switch.h>
#endif
static constexpr size_t READ_BUF_SIZE = 8192;
int PatchExtractor::mkdirs(const char* path) {
char tmp[512];
snprintf(tmp, sizeof(tmp), "%s", path);
size_t len = strlen(tmp);
if (len == 0) return 0;
if (tmp[len - 1] == '/') tmp[len - 1] = '\0';
for (char* p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = '\0';
mkdir(tmp, 0755);
*p = '/';
}
}
return mkdir(tmp, 0755);
}
bool PatchExtractor::open() {
zip = unzOpen(PATCHES_ZIP);
if (!zip) return false;
unz_global_info gi{};
if (unzGetGlobalInfo(zip, &gi) != UNZ_OK) {
close();
return false;
}
total = gi.number_entry;
extracted = 0;
skipped = 0;
finished = false;
err = unzGoToFirstFile(zip);
return true;
}
void PatchExtractor::close() {
if (zip) {
unzClose(zip);
zip = nullptr;
}
}
int PatchExtractor::getProgressPercent() const {
if (total == 0) return 100;
return static_cast<int>((extracted * 100) / total);
}
bool PatchExtractor::step() {
if (!zip || finished) return false;
if (err != UNZ_OK) {
finished = true;
return false;
}
char filename[512];
char fullpath[1024];
unz_file_info fi{};
unzGetCurrentFileInfo(zip, &fi, filename, sizeof(filename), nullptr, 0, nullptr, 0);
snprintf(fullpath, sizeof(fullpath), "%s%s", EXTRACT_DIR, filename);
currentFile = filename;
size_t flen = strlen(filename);
if (flen > 0 && filename[flen - 1] == '/') {
mkdirs(fullpath);
} else {
char dirpart[1024];
snprintf(dirpart, sizeof(dirpart), "%s", fullpath);
char* last_slash = strrchr(dirpart, '/');
if (last_slash) {
*last_slash = '\0';
mkdirs(dirpart);
}
if (unzOpenCurrentFile(zip) == UNZ_OK) {
FILE* out = fopen(fullpath, "wb");
if (out) {
unsigned char buf[READ_BUF_SIZE];
int bytes;
while ((bytes = unzReadCurrentFile(zip, buf, READ_BUF_SIZE)) > 0) {
fwrite(buf, 1, static_cast<size_t>(bytes), out);
}
fclose(out);
} else {
skipped++;
}
unzCloseCurrentFile(zip);
} else {
skipped++;
}
}
extracted++;
err = unzGoToNextFile(zip);
if (err != UNZ_OK) finished = true;
return !finished;
}
bool PatchExtractor::cleanup() {
cleanupOk_ = true;
if (remove(PATCHES_ZIP) != 0)
cleanupOk_ = false;
remove("sdmc:/switch/.PatchExtractor.nro.star");
remove("sdmc:/switch/.packages/boot_package.ini");
return cleanupOk_;
}
void PatchExtractor::tryDeleteSelfOnExit() {
#ifdef __SWITCH__
// Embedded ROMFS keeps the .nro open on SD; unmount before unlink (console build had no ROMFS).
romfsExit();
#endif
remove(SELF_NRO);
}