All checks were successful
Build NRO / build (push) Successful in 10s
Made-with: Cursor
202 lines
6.0 KiB
C
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;
|
|
}
|