diff --git a/source/.theme.c.swp b/source/.theme.c.swp deleted file mode 100644 index 9bcf684..0000000 Binary files a/source/.theme.c.swp and /dev/null differ diff --git a/source/linked_lists.h b/source/linked_lists.h index 27766b8..e979bd3 100644 --- a/source/linked_lists.h +++ b/source/linked_lists.h @@ -2,11 +2,9 @@ #include "3ds.h" -struct theme_data; - typedef struct { - struct theme_data *data; + void *data; void *next; } node; diff --git a/source/main.c b/source/main.c index 26c1dbf..23e9f76 100644 --- a/source/main.c +++ b/source/main.c @@ -4,47 +4,45 @@ #include #include "theme.h" +#include "splashes.h" #include "unicode.h" int main(void) { - gfxInitDefault(); - cfguInit(); - srvInit(); - hidInit(); - fsInit(); - ptmSysmInit(); - consoleInit(GFX_TOP, NULL); + gfxInitDefault(); + cfguInit(); + srvInit(); + hidInit(); + fsInit(); + ptmSysmInit(); + consoleInit(GFX_TOP, NULL); - while (aptMainLoop()) - { - hidScanInput(); - u32 kDown = hidKeysDown(); + while (aptMainLoop()) + { + hidScanInput(); + u32 kDown = hidKeysDown(); - if (kDown & KEY_A) { - node *first_node = malloc(sizeof(node)); - first_node->data = NULL; - first_node->next = NULL; - prepareThemes(first_node); - node *current_node = first_node->next; - while (current_node != NULL) - { - printu(current_node->data->title); - current_node = current_node->next; - } - puts("Done!"); - } - if (kDown & KEY_START) - { - closeThemeArchives(); - PTMSYSM_ShutdownAsync(0); - ptmSysmExit(); - } - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank(); - } + if (kDown & KEY_A) { + node *theme_node = malloc(sizeof(node)); + theme_node->data = NULL; + theme_node->next = NULL; + prepareThemes(theme_node); + node *splashes_node = malloc(sizeof(node)); + splashes_node->data = NULL; + splashes_node->next = NULL; + prepare_splashes(splashes_node); + } + if (kDown & KEY_START) + { + closeThemeArchives(); + PTMSYSM_ShutdownAsync(0); + ptmSysmExit(); + } + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + } - gfxExit(); - return 0; + gfxExit(); + return 0; } diff --git a/source/splashes.c b/source/splashes.c new file mode 100644 index 0000000..10fc952 --- /dev/null +++ b/source/splashes.c @@ -0,0 +1,147 @@ +#include <3ds.h> +#include +#include +#include + +#include "theme.h" +#include "unicode.h" +#include "splashes.h" +#include "linked_lists.h" + +Result prepare_splashes(node* first_node) +{ + Handle splashes_dir; + FSUSER_OpenDirectory(&splashes_dir, ArchiveSD, fsMakePath(PATH_ASCII, "/Splashes"));; // Open up splashes directory + while (true) // Honestly this repeated code triggers me but I'm too lazy to refactor (now at least) + { + FS_DirectoryEntry *entry = malloc(sizeof(FS_DirectoryEntry)); + u32 entries_read; + FSDIR_Read(splashes_dir, &entries_read, 1, entry); + if (entries_read) // If there is a new entry + { + if (!strcmp(entry->shortExt, "ZIP")) // if that entry is a zip + { + u16 sanitized_zip[sizeof(entry->name)] = {0}; + bool changed = strip_unicode(sanitized_zip, entry->name, sizeof(entry->name)); // Here we strip out the non-ASCII characters in the zip name, as minizip doesn't like them + if (changed) // If there were any non-ascii characters + { + u16 zip_path[550] = {0}; + ssize_t len = atow(zip_path, "/Splashes/"); // Copy the unicode equivalent of "/Splashes/" into zip_path + memcpy(&zip_path[len], entry->name, sizeof(entry->name)); // Copy the name of the zip (with unicode chars) into zip_path + u16 sanitized_zip_path[550] = {0}; // Same thing as above, this time with sanitized names + atow(sanitized_zip_path, "/Splashes/"); + memcpy(&sanitized_zip_path[len], sanitized_zip, sizeof(entry->name)); + FSUSER_RenameFile(ArchiveSD, fsMakePath(PATH_UTF16, zip_path), ArchiveSD, fsMakePath(PATH_UTF16, sanitized_zip_path)); // Rename the zip to the sanitized one + unzip_file("/Splashes/", entry, sanitized_zip); // And unzip it + } else unzip_file("/Splashes/", entry, entry->name); // If it's the same, unzip it anyway + } + free(entry); + } else { + free(entry); + break; + } + } + FSDIR_Close(splashes_dir); + FSUSER_OpenDirectory(&splashes_dir, ArchiveSD, fsMakePath(PATH_ASCII, "/Splashes")); + while (true) + { + FS_DirectoryEntry *entry = malloc(sizeof(FS_DirectoryEntry)); + u32 entries_read; + FSDIR_Read(splashes_dir, &entries_read, 1, entry); + if (entries_read) + { + if (entry->attributes == 1) + { + u16 *splash_path = malloc(533); + memset(splash_path, 0, 533); + atow(splash_path, "/Splashes/"); + strucat(splash_path, entry->name); + node *current_splash = malloc(sizeof(node)); + current_splash->data = splash_path; + current_splash->next = NULL; + add_node(first_node, current_splash); + } + free(entry); + } else { + free(entry); + break; + } + } + return 0; +} + +Result install_splash(u16 *path) +{ + printu(path); + int splashes_installed = 0; + u16 file_path[0x106] = {0}; + strucpy(file_path, path); + struacat(file_path, "/splash.bin"); + + Handle file_handle; + Result res = FSUSER_OpenFile(&file_handle, ArchiveSD, fsMakePath(PATH_UTF16, file_path), FS_OPEN_READ, 0); + if (R_FAILED(res) && R_SUMMARY(res) != RS_NOTFOUND) return res; + else if (R_SUCCEEDED(res)) + { + u64 file_size; + u32 bytes; + FSFILE_GetSize(file_handle, &file_size); + char *splash_data = malloc(file_size); + memset(splash_data, 0, file_size); + FSFILE_Read(file_handle, &bytes, 0, splash_data, file_size); + FSFILE_Close(file_handle); + FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_ASCII, "/Luma/splash.bin")); + FSUSER_CreateFile(ArchiveSD, fsMakePath(PATH_ASCII, "/Luma/splash.bin"), 0, file_size); + FSUSER_OpenFile(&file_handle, ArchiveSD, fsMakePath(PATH_ASCII, "/Luma/splash.bin"), FS_OPEN_WRITE, 0); + Result res = FSFILE_Write(file_handle, &bytes, 0, splash_data, file_size, FS_WRITE_FLUSH); + if (R_FAILED(res)) printf("Write: %lX\n", res); + free(splash_data); + FSFILE_Close(file_handle); + splashes_installed++; + } + + memset(file_path, 0, 0x106); + strucpy(file_path, path); + struacat(file_path, "/splashbottom.bin"); + + res = FSUSER_OpenFile(&file_handle, ArchiveSD, fsMakePath(PATH_UTF16, file_path), FS_OPEN_READ, 0); + if (R_FAILED(res) && R_SUMMARY(res) != RS_NOTFOUND) return res; + else if (R_SUCCEEDED(res)) + { + u64 file_size; + u32 bytes; + FSFILE_GetSize(file_handle, &file_size); + char *splash_data = malloc(file_size); + memset(splash_data, 0, file_size); + FSFILE_Read(file_handle, &bytes, 0, splash_data, file_size); + FSFILE_Close(file_handle); + FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_ASCII, "/Luma/splashbottom.bin")); + FSUSER_CreateFile(ArchiveSD, fsMakePath(PATH_ASCII, "/Luma/splashbottom.bin"), 0, file_size); + FSUSER_OpenFile(&file_handle, ArchiveSD, fsMakePath(PATH_ASCII, "/Luma/splashbottom.bin"), FS_OPEN_WRITE, 0); + FSFILE_Write(file_handle, &bytes, 0, splash_data, file_size, FS_WRITE_FLUSH); + FSFILE_Close(file_handle); + free(splash_data); + splashes_installed += 2; + } + + switch(splashes_installed) + { + case 0: + printf("No splashes installed\n"); + break; + + case 1: + printf("Top splash installed\n"); + break; + + case 2: + printf("Bottom splash installed\n"); + break; + + case 3: + printf("Both splashes installed\n"); + break; + } + + return 0; +} \ No newline at end of file diff --git a/source/splashes.h b/source/splashes.h new file mode 100644 index 0000000..dbaee39 --- /dev/null +++ b/source/splashes.h @@ -0,0 +1,7 @@ +#pragma once + +#include "minizip/unzip.h" +#include "linked_lists.h" + +Result prepare_splashes(node*); +Result install_splash(u16 *); \ No newline at end of file diff --git a/source/theme.c b/source/theme.c index 53165ff..5b2a4d1 100644 --- a/source/theme.c +++ b/source/theme.c @@ -73,9 +73,8 @@ Result extract_current_file(unzFile zip_handle, u16 *theme_path) } // TODO: There's a lot of duplicated code here, especially considering that we already built the paths in prepare_themes(). Maybe clean it up a bit later -Result unzip_theme(FS_DirectoryEntry *entry, u16 *sanitized_name) +Result unzip_file(char* base_path, FS_DirectoryEntry *entry, u16 *sanitized_name) { - char *base_path = "/Themes/"; u16 zip_path[sizeof(entry->name) + 18] = {0}; // Make two u16*s that are big enough to hold the entire path u16 uzipfile[sizeof(entry->name) + 18] = {0}; atow(zip_path, base_path); // Copy "/Themes/" unicode equivalent into a path @@ -109,8 +108,13 @@ Result unzip_theme(FS_DirectoryEntry *entry, u16 *sanitized_name) extract_current_file(zip_handle, theme_path_u16); while(unzGoToNextFile(zip_handle) == UNZ_OK) extract_current_file(zip_handle, theme_path_u16); // While next file exists, unzip it unzClose(zip_handle); + res = FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_ASCII, zipfile)); + if (R_FAILED(res)) + { + free(zipfile); + return res; + } free(zipfile); - FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_ASCII, zipfile)); return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_COMMON, RD_SUCCESS); // And return success \o/ } @@ -182,8 +186,8 @@ Result prepareThemes(node *first_node) atow(sanitized_zip_path, "/Themes/"); memcpy(&sanitized_zip_path[len], sanitized_zip, sizeof(entry->name)); FSUSER_RenameFile(ArchiveSD, fsMakePath(PATH_UTF16, zip_path), ArchiveSD, fsMakePath(PATH_UTF16, sanitized_zip_path)); // Rename the zip to the sanitized one - unzip_theme(entry, sanitized_zip); // And unzip it - } else unzip_theme(entry, entry->name); // If it's the same, unzip it anyway + unzip_file("/Themes/", entry, sanitized_zip); // And unzip it + } else unzip_file("/Themes/", entry, entry->name); // If it's the same, unzip it anyway } free(entry); } else { diff --git a/source/theme.h b/source/theme.h index 32cd8f0..e179cb7 100644 --- a/source/theme.h +++ b/source/theme.h @@ -23,7 +23,7 @@ FS_Archive ArchiveSD; FS_Archive ArchiveHomeExt; FS_Archive ArchiveThemeExt; -Result unzip_theme(FS_DirectoryEntry*, u16*); +Result unzip_file(char*, FS_DirectoryEntry*, u16*); Result prepareThemes(node*); Result themeInstall(theme_data); Result closeThemeArchives(); diff --git a/source/unicode.c b/source/unicode.c index 8b552e3..8235606 100644 --- a/source/unicode.c +++ b/source/unicode.c @@ -117,6 +117,17 @@ u16 *strucat(u16 *destination, const u16 *source) return destination; } +u16 *struacat(u16 *destination, const char *source) +{ + ssize_t len = strulen(destination); + for (u16 i = len; i < strlen(source) + len; i++) + { + destination[i] = source[i - len]; + } + destination[strlen(source) + len] = 0; + return destination; +} + // Prints a u16* for debug purposes // Must be properly null-terminated void printu(u16 *input) @@ -124,7 +135,7 @@ void printu(u16 *input) ssize_t in_len = strulen(input); ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination wchar_t *buf = calloc(buf_len, sizeof(wchar_t)); - for (int i = 0; i < buf_len; i++) buf[i] = input[i]; + for (u16 i = 0; i < buf_len; i++) buf[i] = input[i]; printf("%ls\n", buf); free(buf); } diff --git a/source/unicode.h b/source/unicode.h index 6b0644a..259a919 100644 --- a/source/unicode.h +++ b/source/unicode.h @@ -7,4 +7,5 @@ bool strip_unicode(u16*, u16*, ssize_t); u16 *strucpy(u16*, const u16*); ssize_t strulen(const u16*); u16 *strucat(u16*, const u16*); +u16 *struacat(u16*, const char*); void printu(u16*); \ No newline at end of file