Added splash support (#2)
Combination of quality of life improvements, bugfixes and splash support: * unzip_file now works with any file, not just a theme * Made linked list nodes generic so they work for both splashes and themes * Fixed bug in previous commit with deleting the zip file once it was unzipped * All zips in /Splashes/ are now extracted, as with /Themes/ * Splashes are all added to the linked list properly * Splashes can be installed given a path, but only works on Luma. Undecided as to whether or not I'm going to change this. TODO: * Automatically change the luma configuration to enable splash screens * MAYBE add support for other CFWs (if there's an interest). Maybe set a folder to extract splashes to in some kind of user settings?
This commit is contained in:
Binary file not shown.
@@ -2,11 +2,9 @@
|
|||||||
|
|
||||||
#include "3ds.h"
|
#include "3ds.h"
|
||||||
|
|
||||||
struct theme_data;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
struct theme_data *data;
|
void *data;
|
||||||
void *next;
|
void *next;
|
||||||
} node;
|
} node;
|
||||||
|
|
||||||
|
|||||||
@@ -4,47 +4,45 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
#include "splashes.h"
|
||||||
#include "unicode.h"
|
#include "unicode.h"
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
gfxInitDefault();
|
gfxInitDefault();
|
||||||
cfguInit();
|
cfguInit();
|
||||||
srvInit();
|
srvInit();
|
||||||
hidInit();
|
hidInit();
|
||||||
fsInit();
|
fsInit();
|
||||||
ptmSysmInit();
|
ptmSysmInit();
|
||||||
consoleInit(GFX_TOP, NULL);
|
consoleInit(GFX_TOP, NULL);
|
||||||
|
|
||||||
while (aptMainLoop())
|
while (aptMainLoop())
|
||||||
{
|
{
|
||||||
hidScanInput();
|
hidScanInput();
|
||||||
u32 kDown = hidKeysDown();
|
u32 kDown = hidKeysDown();
|
||||||
|
|
||||||
if (kDown & KEY_A) {
|
if (kDown & KEY_A) {
|
||||||
node *first_node = malloc(sizeof(node));
|
node *theme_node = malloc(sizeof(node));
|
||||||
first_node->data = NULL;
|
theme_node->data = NULL;
|
||||||
first_node->next = NULL;
|
theme_node->next = NULL;
|
||||||
prepareThemes(first_node);
|
prepareThemes(theme_node);
|
||||||
node *current_node = first_node->next;
|
node *splashes_node = malloc(sizeof(node));
|
||||||
while (current_node != NULL)
|
splashes_node->data = NULL;
|
||||||
{
|
splashes_node->next = NULL;
|
||||||
printu(current_node->data->title);
|
prepare_splashes(splashes_node);
|
||||||
current_node = current_node->next;
|
}
|
||||||
}
|
if (kDown & KEY_START)
|
||||||
puts("Done!");
|
{
|
||||||
}
|
closeThemeArchives();
|
||||||
if (kDown & KEY_START)
|
PTMSYSM_ShutdownAsync(0);
|
||||||
{
|
ptmSysmExit();
|
||||||
closeThemeArchives();
|
}
|
||||||
PTMSYSM_ShutdownAsync(0);
|
gfxFlushBuffers();
|
||||||
ptmSysmExit();
|
gfxSwapBuffers();
|
||||||
}
|
gspWaitForVBlank();
|
||||||
gfxFlushBuffers();
|
}
|
||||||
gfxSwapBuffers();
|
|
||||||
gspWaitForVBlank();
|
|
||||||
}
|
|
||||||
|
|
||||||
gfxExit();
|
gfxExit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
147
source/splashes.c
Normal file
147
source/splashes.c
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#include <3ds.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
7
source/splashes.h
Normal file
7
source/splashes.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "minizip/unzip.h"
|
||||||
|
#include "linked_lists.h"
|
||||||
|
|
||||||
|
Result prepare_splashes(node*);
|
||||||
|
Result install_splash(u16 *);
|
||||||
@@ -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
|
// 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 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};
|
u16 uzipfile[sizeof(entry->name) + 18] = {0};
|
||||||
atow(zip_path, base_path); // Copy "/Themes/" unicode equivalent into a path
|
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);
|
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
|
while(unzGoToNextFile(zip_handle) == UNZ_OK) extract_current_file(zip_handle, theme_path_u16); // While next file exists, unzip it
|
||||||
unzClose(zip_handle);
|
unzClose(zip_handle);
|
||||||
|
res = FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_ASCII, zipfile));
|
||||||
|
if (R_FAILED(res))
|
||||||
|
{
|
||||||
|
free(zipfile);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
free(zipfile);
|
free(zipfile);
|
||||||
FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_ASCII, zipfile));
|
|
||||||
return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_COMMON, RD_SUCCESS); // And return success \o/
|
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/");
|
atow(sanitized_zip_path, "/Themes/");
|
||||||
memcpy(&sanitized_zip_path[len], sanitized_zip, sizeof(entry->name));
|
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
|
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
|
unzip_file("/Themes/", entry, sanitized_zip); // And unzip it
|
||||||
} else unzip_theme(entry, entry->name); // If it's the same, unzip it anyway
|
} else unzip_file("/Themes/", entry, entry->name); // If it's the same, unzip it anyway
|
||||||
}
|
}
|
||||||
free(entry);
|
free(entry);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ FS_Archive ArchiveSD;
|
|||||||
FS_Archive ArchiveHomeExt;
|
FS_Archive ArchiveHomeExt;
|
||||||
FS_Archive ArchiveThemeExt;
|
FS_Archive ArchiveThemeExt;
|
||||||
|
|
||||||
Result unzip_theme(FS_DirectoryEntry*, u16*);
|
Result unzip_file(char*, FS_DirectoryEntry*, u16*);
|
||||||
Result prepareThemes(node*);
|
Result prepareThemes(node*);
|
||||||
Result themeInstall(theme_data);
|
Result themeInstall(theme_data);
|
||||||
Result closeThemeArchives();
|
Result closeThemeArchives();
|
||||||
|
|||||||
@@ -117,6 +117,17 @@ u16 *strucat(u16 *destination, const u16 *source)
|
|||||||
return destination;
|
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
|
// Prints a u16* for debug purposes
|
||||||
// Must be properly null-terminated
|
// Must be properly null-terminated
|
||||||
void printu(u16 *input)
|
void printu(u16 *input)
|
||||||
@@ -124,7 +135,7 @@ void printu(u16 *input)
|
|||||||
ssize_t in_len = strulen(input);
|
ssize_t in_len = strulen(input);
|
||||||
ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination
|
ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination
|
||||||
wchar_t *buf = calloc(buf_len, sizeof(wchar_t));
|
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);
|
printf("%ls\n", buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ bool strip_unicode(u16*, u16*, ssize_t);
|
|||||||
u16 *strucpy(u16*, const u16*);
|
u16 *strucpy(u16*, const u16*);
|
||||||
ssize_t strulen(const u16*);
|
ssize_t strulen(const u16*);
|
||||||
u16 *strucat(u16*, const u16*);
|
u16 *strucat(u16*, const u16*);
|
||||||
|
u16 *struacat(u16*, const char*);
|
||||||
void printu(u16*);
|
void printu(u16*);
|
||||||
Reference in New Issue
Block a user