Files
PatchExtractor/source/main.c
niklascfw e0a8fd8124
All checks were successful
Build NRO / build (push) Successful in 10s
Clean up Sphaira .star file on self-delete
Made-with: Cursor
2026-03-05 17:10:39 +01:00

202 lines
6.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <switch.h>
#include <minizip/unzip.h>
#define PATCHES_ZIP "sdmc:/SaltySD/plugins/FPSLocker/patches.zip"
#define EXTRACT_DIR "sdmc:/SaltySD/plugins/FPSLocker/"
#define SELF_NRO "sdmc:/switch/PatchExtractor.nro"
#define READ_BUF_SIZE 8192
#define STATUS_ROW 11
static PrintConsole *con;
static void status(const char *fmt, ...) {
printf("\x1b[%d;0H\x1b[2K", STATUS_ROW);
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
static int 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);
}
int main(int argc, char *argv[]) {
con = consoleInit(NULL);
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
PadState pad;
padInitializeDefault(&pad);
printf("\n");
printf(" ========================================\n");
printf(" PatchExtractor - OmniNX OC\n");
printf(" SaltyNX / FPSLocker Patch Installer\n");
printf(" ========================================\n\n");
unzFile zip = unzOpen(PATCHES_ZIP);
if (!zip) {
printf(" \x1b[31mFEHLER:\x1b[0m patches.zip nicht gefunden!\n\n");
printf(" Pfad: %s\n\n", PATCHES_ZIP);
printf(" Bist du sicher, dass du OmniNX OC installiert hast?\n\n");
printf(" Die Datei patches.zip muss unter\n");
printf(" sd:/SaltySD/plugins/FPSLocker/ liegen.\n\n");
printf(" ----------------------------------------\n");
printf(" Druecke + zum Beenden.\n");
while (appletMainLoop()) {
padUpdate(&pad);
if (padGetButtonsDown(&pad) & HidNpadButton_Plus) break;
consoleUpdate(NULL);
}
consoleExit(NULL);
return 1;
}
unz_global_info gi;
unzGetGlobalInfo(zip, &gi);
unsigned long total = gi.number_entry;
printf(" patches.zip gefunden! (%lu Eintraege)\n", total);
printf(" Druecke A zum Entpacken, + zum Abbrechen.\n\n");
consoleUpdate(NULL);
while (appletMainLoop()) {
padUpdate(&pad);
u64 kDown = padGetButtonsDown(&pad);
if (kDown & HidNpadButton_A) break;
if (kDown & HidNpadButton_Plus) {
unzClose(zip);
consoleExit(NULL);
return 0;
}
consoleUpdate(NULL);
}
printf("\x1b[10;0H \x1b[93mBitte nicht beenden, bis der Vorgang abgeschlossen ist!\x1b[0m\n");
consoleUpdate(NULL);
char filename[512];
char fullpath[1024];
unsigned char buf[READ_BUF_SIZE];
unsigned long extracted = 0;
unsigned long skipped = 0;
int err = unzGoToFirstFile(zip);
while (err == UNZ_OK) {
unz_file_info fi;
unzGetCurrentFileInfo(zip, &fi, filename, sizeof(filename), NULL, 0, NULL, 0);
snprintf(fullpath, sizeof(fullpath), "%s%s", EXTRACT_DIR, filename);
unsigned long progress = (unsigned long)((extracted * 100) / total);
size_t flen = strlen(filename);
if (flen > 0 && filename[flen - 1] == '/') {
mkdirs(fullpath);
status(" [%3lu%%] DIR %s", progress, filename);
} 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) {
status(" [%3lu%%] \x1b[31mERR\x1b[0m %s", progress, filename);
skipped++;
extracted++;
err = unzGoToNextFile(zip);
continue;
}
FILE *out = fopen(fullpath, "wb");
if (!out) {
status(" [%3lu%%] \x1b[31mERR\x1b[0m %s", progress, filename);
unzCloseCurrentFile(zip);
skipped++;
extracted++;
err = unzGoToNextFile(zip);
continue;
}
int bytes;
while ((bytes = unzReadCurrentFile(zip, buf, READ_BUF_SIZE)) > 0) {
fwrite(buf, 1, bytes, out);
}
fclose(out);
unzCloseCurrentFile(zip);
status(" [%3lu%%] FILE %s", progress, filename);
}
extracted++;
consoleUpdate(NULL);
err = unzGoToNextFile(zip);
}
unzClose(zip);
status(" [100%%] Fertig! %lu / %lu entpackt.", extracted - skipped, total);
consoleUpdate(NULL);
int cleanup_ok = 1;
printf("\x1b[%d;0H", STATUS_ROW + 2);
if (remove(PATCHES_ZIP) == 0) {
printf(" patches.zip geloescht.\n");
} else {
printf(" \x1b[31mpatches.zip konnte nicht geloescht werden.\x1b[0m\n");
cleanup_ok = 0;
}
if (remove(SELF_NRO) == 0) {
printf(" PatchExtractor.nro geloescht (Selbstreinigung).\n");
} else {
printf(" \x1b[31mPatchExtractor.nro konnte nicht geloescht werden.\x1b[0m\n");
cleanup_ok = 0;
}
remove("sdmc:/switch/.PatchExtractor.nro.star");
printf("\n ========================================\n");
if (skipped == 0 && cleanup_ok) {
printf(" \x1b[32mAlles erledigt!\x1b[0m\n");
} else {
printf(" \x1b[32mEntpacken abgeschlossen.\x1b[0m\n");
if (skipped > 0)
printf(" \x1b[31m%lu Eintraege fehlgeschlagen.\x1b[0m\n", skipped);
}
printf(" ========================================\n\n");
printf(" Druecke + zum Beenden.\n");
while (appletMainLoop()) {
padUpdate(&pad);
if (padGetButtonsDown(&pad) & HidNpadButton_Plus) break;
consoleUpdate(NULL);
}
consoleExit(NULL);
return 0;
}