mirror of
https://github.com/astronautlevel2/Anemone3DS.git
synced 2026-01-24 08:42:43 -05:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adccc70cca | ||
|
|
b66ca12039 | ||
|
|
4a56a883fa | ||
|
|
9ebfe387a0 | ||
|
|
806d0033de | ||
|
|
4c053bb447 | ||
|
|
1ed6c46644 | ||
|
|
e22d09ba54 | ||
|
|
a0c16a64ec | ||
|
|
a1e7ed9924 | ||
|
|
7f7fdc010a |
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
A Theme and Splashscreen Manager for the Nintendo 3DS, written in C.\
|
||||
A Theme and Splashscreen Manager for the Nintendo 3DS, written in C.
|
||||
|
||||
# Dependencies
|
||||
* devkitARM, which can be installed following the instructions [here](https://devkitpro.org/wiki/Getting_Started).
|
||||
|
||||
@@ -46,9 +46,10 @@ typedef struct {
|
||||
u32 filesize;
|
||||
|
||||
volatile bool stop;
|
||||
Handle finished;
|
||||
Thread playing_thread;
|
||||
} audio_s;
|
||||
|
||||
void play_audio(audio_s *);
|
||||
void stop_audio(audio_s**);
|
||||
|
||||
#endif
|
||||
|
||||
88
include/urls.h
Normal file
88
include/urls.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
static char from_hex(char c)
|
||||
{
|
||||
return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10;
|
||||
}
|
||||
|
||||
static char to_hex(char code)
|
||||
{
|
||||
static char hex[] = "0123456789abcdef";
|
||||
return hex[code & 15];
|
||||
}
|
||||
|
||||
// ensure caller frees
|
||||
char * url_escape(char * url)
|
||||
{
|
||||
char * ptr = url;
|
||||
char * buf = malloc(3 * strlen(url) + 1);
|
||||
char * ptr_buf = buf;
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
if (isalnum((int)*ptr) || strchr("-_.~", *ptr))
|
||||
*ptr_buf++ = *ptr;
|
||||
else if (*ptr == ' ')
|
||||
*ptr_buf++ = '+';
|
||||
else
|
||||
{
|
||||
*ptr_buf++ = '%';
|
||||
*ptr_buf++ = to_hex(*ptr >> 4);
|
||||
*ptr_buf++ = to_hex(*ptr & 15);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
*ptr_buf = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
// ensure caller frees
|
||||
char * url_unescape(char * url)
|
||||
{
|
||||
char * ptr = url;
|
||||
char * buf = malloc(strlen(url) + 1);
|
||||
char * ptr_buf = buf;
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr == '%')
|
||||
{
|
||||
if (ptr[1] && ptr[2])
|
||||
{
|
||||
*ptr_buf++ = from_hex(ptr[1]) << 4 | from_hex(ptr[2]);
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
else if (*ptr == '+')
|
||||
*ptr_buf++ = ' ';
|
||||
else
|
||||
*ptr_buf++ = *ptr;
|
||||
ptr++;
|
||||
}
|
||||
*ptr_buf = '\0';
|
||||
return buf;
|
||||
}
|
||||
@@ -377,7 +377,7 @@ renamed:
|
||||
sprintf(path_to_file, "%s%s", main_paths[mode], filename);
|
||||
|
||||
// filter out characters illegal in FAT32 filenames
|
||||
char * curr_filename = strrchr(path_to_file, '/') + 1;
|
||||
char * curr_filename = path_to_file + strlen(main_paths[mode]);
|
||||
char * illegal_char = curr_filename;
|
||||
while ((illegal_char = strpbrk(illegal_char, ILLEGAL_CHARS)))
|
||||
{
|
||||
|
||||
@@ -608,7 +608,6 @@ Result load_audio(Entry_s entry, audio_s *audio)
|
||||
}
|
||||
|
||||
audio->mix[0] = audio->mix[1] = 1.0f; // Determines volume for the 12 (?) different outputs. See http://smealum.github.io/ctrulib/channel_8h.html#a30eb26f1972cc3ec28370263796c0444
|
||||
svcCreateEvent(&audio->finished, RESET_STICKY);
|
||||
|
||||
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
|
||||
ndspChnSetMix(0, audio->mix); // See mix comment above
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
bool quit = false;
|
||||
bool dspfirm = false;
|
||||
audio_s * audio = NULL;
|
||||
static audio_s * audio = NULL;
|
||||
static bool homebrew = false;
|
||||
static bool installed_themes = false;
|
||||
|
||||
@@ -109,6 +109,12 @@ static void stop_install_check(void)
|
||||
{
|
||||
installCheckThreads_arg[i].run_thread = false;
|
||||
}
|
||||
for(int i = 0; i < MODE_AMOUNT; i++)
|
||||
{
|
||||
threadJoin(installCheckThreads[i], U64_MAX);
|
||||
threadFree(installCheckThreads[i]);
|
||||
installCheckThreads[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void exit_thread(void)
|
||||
@@ -121,6 +127,7 @@ static void exit_thread(void)
|
||||
svcWaitSynchronization(update_icons_mutex, U64_MAX);
|
||||
threadJoin(iconLoadingThread, U64_MAX);
|
||||
threadFree(iconLoadingThread);
|
||||
iconLoadingThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +145,7 @@ static void free_icons(Entry_List_s * list)
|
||||
free(list->icons[i]);
|
||||
}
|
||||
free(list->icons);
|
||||
list->icons = NULL;
|
||||
}
|
||||
|
||||
void free_lists(void)
|
||||
@@ -157,8 +165,7 @@ void exit_function(bool power_pressed)
|
||||
{
|
||||
if(audio)
|
||||
{
|
||||
audio->stop = true;
|
||||
svcWaitSynchronization(audio->finished, U64_MAX);
|
||||
stop_audio(&audio);
|
||||
}
|
||||
free_lists();
|
||||
svcCloseHandle(update_icons_mutex);
|
||||
@@ -230,7 +237,7 @@ static void load_lists(Entry_List_s * lists)
|
||||
|
||||
if(install_check_function != NULL)
|
||||
{
|
||||
installCheckThreads[i] = threadCreate(install_check_function, current_arg, __stacksize__, 0x3f, -2, true);
|
||||
installCheckThreads[i] = threadCreate(install_check_function, current_arg, __stacksize__, 0x3f, -2, false);
|
||||
svcSleepThread(1e8);
|
||||
}
|
||||
}
|
||||
@@ -504,9 +511,7 @@ int main(void)
|
||||
preview_mode = false;
|
||||
if(current_mode == MODE_THEMES && audio)
|
||||
{
|
||||
audio->stop = true;
|
||||
svcWaitSynchronization(audio->finished, U64_MAX);
|
||||
audio = NULL;
|
||||
stop_audio(&audio);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@@ -516,9 +521,7 @@ int main(void)
|
||||
preview_mode = false;
|
||||
if(current_mode == MODE_THEMES && audio)
|
||||
{
|
||||
audio->stop = true;
|
||||
svcWaitSynchronization(audio->finished, U64_MAX);
|
||||
audio = NULL;
|
||||
stop_audio(&audio);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -69,17 +69,26 @@ void thread_audio(void* data) {
|
||||
while(!audio->stop) {
|
||||
update_audio(audio);
|
||||
}
|
||||
free(audio->filebuf);
|
||||
ndspChnWaveBufClear(0);
|
||||
ndspChnReset(0);
|
||||
ov_clear(&audio->vf);
|
||||
free(audio->filebuf);
|
||||
linearFree((void*)audio->wave_buf[0].data_vaddr);
|
||||
linearFree((void*)audio->wave_buf[1].data_vaddr);
|
||||
while (audio->wave_buf[0].status != NDSP_WBUF_DONE || audio->wave_buf[1].status != NDSP_WBUF_DONE) svcSleepThread(1e7);
|
||||
svcSignalEvent(audio->finished);
|
||||
svcSleepThread(1e8);
|
||||
svcCloseHandle(audio->finished);
|
||||
free(audio);
|
||||
}
|
||||
|
||||
void play_audio(audio_s *audio) {
|
||||
threadCreate(thread_audio, audio, 0x1000, 0x3F, 1, true);
|
||||
audio->playing_thread = threadCreate(thread_audio, audio, 0x1000, 0x3F, 1, false);
|
||||
}
|
||||
|
||||
void stop_audio(audio_s** audio_ptr) {
|
||||
audio_s* audio = *audio_ptr;
|
||||
if(audio->playing_thread)
|
||||
{
|
||||
audio->stop = true;
|
||||
threadJoin(audio->playing_thread, U64_MAX);
|
||||
threadFree(audio->playing_thread);
|
||||
}
|
||||
free(audio);
|
||||
*audio_ptr = NULL;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
#include "fs.h"
|
||||
#include "unicode.h"
|
||||
#include "music.h"
|
||||
#include "urls.h"
|
||||
|
||||
// forward declaration of special case used only here
|
||||
// TODO: replace this travesty with a proper handler
|
||||
static Result http_get_with_not_found_flag(const char * url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types, bool not_found_is_error);
|
||||
|
||||
static Instructions_s browser_instructions[MODE_AMOUNT] = {
|
||||
{
|
||||
@@ -326,10 +331,13 @@ static void load_remote_bgm(Entry_s * entry)
|
||||
|
||||
draw_install(INSTALL_LOADING_REMOTE_BGM);
|
||||
|
||||
Result res = http_get(bgm_url, NULL, &bgm_ogg, &bgm_size, INSTALL_LOADING_REMOTE_BGM, "application/ogg, audio/ogg");
|
||||
Result res = http_get_with_not_found_flag(bgm_url, NULL, &bgm_ogg, &bgm_size, INSTALL_LOADING_REMOTE_BGM, "application/ogg, audio/ogg", false);
|
||||
free(bgm_url);
|
||||
if (R_FAILED(res))
|
||||
return;
|
||||
// if bgm doesn't exist on the server
|
||||
if (R_SUMMARY(res) == RS_NOTFOUND && R_MODULE(res) == RM_FILE_SERVER)
|
||||
return;
|
||||
|
||||
u16 path[0x107] = { 0 };
|
||||
strucat(path, entry->path);
|
||||
@@ -436,18 +444,11 @@ static void search_menu(Entry_List_s * list)
|
||||
if (button == SWKBD_BUTTON_CONFIRM)
|
||||
{
|
||||
free(list->tp_search);
|
||||
for (unsigned int i = 0; i < strlen(search); i++)
|
||||
{
|
||||
if (search[i] == ' ')
|
||||
search[i] = '+';
|
||||
}
|
||||
list->tp_search = search;
|
||||
list->tp_search = url_escape(search);
|
||||
DEBUG("Search escaped: %s -> %s\n", search, list->tp_search);
|
||||
load_remote_list(list, 1, list->mode, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(search);
|
||||
}
|
||||
free(search);
|
||||
}
|
||||
|
||||
static void change_selected(Entry_List_s * list, int change_value)
|
||||
@@ -489,7 +490,7 @@ bool themeplaza_browser(EntryMode mode)
|
||||
|
||||
bool extra_mode = false;
|
||||
|
||||
while (aptMainLoop())
|
||||
while (aptMainLoop() && !quit)
|
||||
{
|
||||
if (current_list->entries == NULL)
|
||||
break;
|
||||
@@ -517,12 +518,6 @@ bool themeplaza_browser(EntryMode mode)
|
||||
exit:
|
||||
quit = true;
|
||||
downloaded = false;
|
||||
if (audio)
|
||||
{
|
||||
audio->stop = true;
|
||||
svcWaitSynchronization(audio->finished, U64_MAX);
|
||||
audio = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -581,9 +576,7 @@ bool themeplaza_browser(EntryMode mode)
|
||||
preview_mode = false;
|
||||
if (mode == MODE_THEMES && audio != NULL)
|
||||
{
|
||||
audio->stop = true;
|
||||
svcWaitSynchronization(audio->finished, U64_MAX);
|
||||
audio = NULL;
|
||||
stop_audio(&audio);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,9 +587,7 @@ bool themeplaza_browser(EntryMode mode)
|
||||
preview_mode = false;
|
||||
if (mode == MODE_THEMES && audio != NULL)
|
||||
{
|
||||
audio->stop = true;
|
||||
svcWaitSynchronization(audio->finished, U64_MAX);
|
||||
audio = NULL;
|
||||
stop_audio(&audio);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -662,9 +653,7 @@ bool themeplaza_browser(EntryMode mode)
|
||||
preview_mode = false;
|
||||
if (mode == MODE_THEMES && audio)
|
||||
{
|
||||
audio->stop = true;
|
||||
svcWaitSynchronization(audio->finished, U64_MAX);
|
||||
audio = NULL;
|
||||
stop_audio(&audio);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -731,6 +720,11 @@ bool themeplaza_browser(EntryMode mode)
|
||||
}
|
||||
}
|
||||
|
||||
if (audio)
|
||||
{
|
||||
stop_audio(&audio);
|
||||
}
|
||||
|
||||
free_preview(preview);
|
||||
|
||||
free_icons(current_list);
|
||||
@@ -770,7 +764,7 @@ typedef enum ParseResult
|
||||
HTTP_GATEWAY_TIMEOUT = 504,
|
||||
} ParseResult;
|
||||
|
||||
static SwkbdCallbackResult fat32filter(void *user, const char **ppMessage, const char *text, size_t textlen)
|
||||
/*static SwkbdCallbackResult fat32filter(void *user, const char **ppMessage, const char *text, size_t textlen)
|
||||
{
|
||||
(void)textlen;
|
||||
(void)user;
|
||||
@@ -782,7 +776,7 @@ static SwkbdCallbackResult fat32filter(void *user, const char **ppMessage, const
|
||||
}
|
||||
|
||||
return SWKBD_CALLBACK_OK;
|
||||
}
|
||||
}*/
|
||||
|
||||
// the good paths for this function return SUCCESS, ABORTED, or REDIRECT;
|
||||
// all other paths are failures
|
||||
@@ -900,6 +894,11 @@ static ParseResult parse_header(struct header * out, httpcContext * context, con
|
||||
* call example: written = http_get("url", &filename, &buffer_to_download_to, &filesize, INSTALL_DOWNLOAD, "application/json");
|
||||
*/
|
||||
Result http_get(const char * url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types)
|
||||
{
|
||||
return http_get_with_not_found_flag(url, filename, buf, size, install_type, acceptable_mime_types, true);
|
||||
}
|
||||
|
||||
static Result http_get_with_not_found_flag(const char * url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types, bool not_found_is_error)
|
||||
{
|
||||
Result ret;
|
||||
httpcContext context;
|
||||
@@ -936,6 +935,7 @@ redirect: // goto here if we need to redirect
|
||||
|
||||
#define ERROR_BUFFER_SIZE 0x80
|
||||
char err_buf[ERROR_BUFFER_SIZE];
|
||||
Result res;
|
||||
ParseResult parse = parse_header(&_header, &context, acceptable_mime_types);
|
||||
switch (parse)
|
||||
{
|
||||
@@ -981,7 +981,10 @@ redirect: // goto here if we need to redirect
|
||||
snprintf(err_buf, ERROR_BUFFER_SIZE, ZIP_NOT_AVAILABLE);
|
||||
goto error;
|
||||
case HTTP_NOT_FOUND:
|
||||
case HTTP_GONE: ;
|
||||
if (!not_found_is_error)
|
||||
goto not_found_non_error;
|
||||
[[fallthrough]];
|
||||
case HTTP_GONE:
|
||||
const char * http_error = parse == HTTP_NOT_FOUND ? "404 Not Found" : "410 Gone";
|
||||
DEBUG("HTTP %s; URL: %s\n", http_error, url);
|
||||
if (strstr(url, THEMEPLAZA_BASE_URL) && parse == HTTP_NOT_FOUND)
|
||||
@@ -1044,9 +1047,13 @@ redirect: // goto here if we need to redirect
|
||||
goto no_error;
|
||||
error:
|
||||
throw_error(err_buf, ERROR_LEVEL_WARNING);
|
||||
Result res = httpcCloseContext(&context);
|
||||
res = httpcCloseContext(&context);
|
||||
if (R_FAILED(res)) return res;
|
||||
return MAKERESULT(RL_TEMPORARY, RS_CANCELED, RM_APPLICATION, RD_NO_DATA);
|
||||
not_found_non_error:
|
||||
res = httpcCloseContext(&context);
|
||||
if (R_FAILED(res)) return res;
|
||||
return MAKERESULT(RL_SUCCESS, RS_NOTFOUND, RM_FILE_SERVER, RD_NO_DATA);
|
||||
no_error:;
|
||||
u32 chunk_size;
|
||||
if (_header.file_size)
|
||||
|
||||
179
source/themes.c
179
source/themes.c
@@ -505,6 +505,7 @@ Result dump_all_themes(void)
|
||||
res = AMAPP_ListDLCContentInfos(&readcount, MEDIATYPE_SD, titleId, count, 0, contentInfos);
|
||||
if(R_FAILED(res))
|
||||
{
|
||||
free(contentInfos);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -551,107 +552,105 @@ Result dump_all_themes(void)
|
||||
|
||||
FILE* fh = fopen(contentinfoarchive_path, "rb");
|
||||
|
||||
for(u32 i = 0; i < readcount; ++i)
|
||||
if(fh != NULL)
|
||||
{
|
||||
if(i == 0) continue;
|
||||
AM_ContentInfo* content = &contentInfos[i];
|
||||
if((content->flags & (AM_CONTENT_DOWNLOADED | AM_CONTENT_OWNED)) == (AM_CONTENT_DOWNLOADED | AM_CONTENT_OWNED))
|
||||
for(u32 i = 0; i < readcount; ++i)
|
||||
{
|
||||
long off = 0x8 + 0xC8 * i;
|
||||
fseek(fh, off, SEEK_SET);
|
||||
char content_data[0xc8] = {0};
|
||||
fread(content_data, 1, 0xc8, fh);
|
||||
u32 extra_index = 0;
|
||||
memcpy(&extra_index, content_data + 0xC0, 4);
|
||||
|
||||
metadataPath[1] = content->index;
|
||||
|
||||
Handle theme_fh;
|
||||
res = FSUSER_OpenFile(&theme_fh, ncch_archive, metadata_path, FS_OPEN_READ, 0);
|
||||
if(R_FAILED(res))
|
||||
if(i == 0) continue;
|
||||
AM_ContentInfo* content = &contentInfos[i];
|
||||
if((content->flags & (AM_CONTENT_DOWNLOADED | AM_CONTENT_OWNED)) == (AM_CONTENT_DOWNLOADED | AM_CONTENT_OWNED))
|
||||
{
|
||||
DEBUG("theme open romfs error: %08lx\n", res);
|
||||
fclose(fh);
|
||||
free(contentInfos);
|
||||
romfsUnmount("meta");
|
||||
FSUSER_CloseArchive(ncch_archive);
|
||||
free(contentInfos);
|
||||
break;
|
||||
long off = 0x8 + 0xC8 * i;
|
||||
fseek(fh, off, SEEK_SET);
|
||||
char content_data[0xc8] = {0};
|
||||
fread(content_data, 1, 0xc8, fh);
|
||||
u32 extra_index = 0;
|
||||
memcpy(&extra_index, content_data + 0xC0, 4);
|
||||
|
||||
metadataPath[1] = content->index;
|
||||
|
||||
Handle theme_fh;
|
||||
res = FSUSER_OpenFile(&theme_fh, ncch_archive, metadata_path, FS_OPEN_READ, 0);
|
||||
if(R_FAILED(res))
|
||||
{
|
||||
DEBUG("theme open romfs error: %08lx\n", res);
|
||||
break;
|
||||
}
|
||||
|
||||
romfsMountFromFile(theme_fh, 0, "theme");
|
||||
|
||||
char themename[0x41] = {0};
|
||||
memcpy(themename, content_data, 0x40);
|
||||
char * illegal_char = themename;
|
||||
while ((illegal_char = strpbrk(illegal_char, ILLEGAL_CHARS)))
|
||||
{
|
||||
*illegal_char = '-';
|
||||
}
|
||||
|
||||
char path[0x107] = { 0 };
|
||||
sprintf(path, "/Themes/Dump-%02lx-%ld-%s", dlc_index, extra_index, themename);
|
||||
DEBUG("theme folder to create: %s\n", path);
|
||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, path), FS_ATTRIBUTE_DIRECTORY);
|
||||
|
||||
memset(smdh_data->name, 0, sizeof(smdh_data->name));
|
||||
utf8_to_utf16(smdh_data->name, (u8*)(content_data + 0), 0x40);
|
||||
|
||||
FILE* theme_file = fopen("theme:/body_LZ.bin", "rb");
|
||||
if(theme_file)
|
||||
{
|
||||
fseek(theme_file, 0, SEEK_END);
|
||||
long theme_size = ftell(theme_file);
|
||||
fseek(theme_file, 0, SEEK_SET);
|
||||
char* theme_data = malloc(theme_size);
|
||||
fread(theme_data, 1, theme_size, theme_file);
|
||||
fclose(theme_file);
|
||||
|
||||
char themepath[0x107] = {0};
|
||||
sprintf(themepath, "%s/body_LZ.bin", path);
|
||||
remake_file(fsMakePath(PATH_ASCII, themepath), ArchiveSD, theme_size);
|
||||
buf_to_file(theme_size, fsMakePath(PATH_ASCII, themepath), ArchiveSD, theme_data);
|
||||
free(theme_data);
|
||||
}
|
||||
|
||||
FILE* bgm_file = fopen("theme:/bgm.bcstm", "rb");
|
||||
if(bgm_file)
|
||||
{
|
||||
fseek(bgm_file, 0, SEEK_END);
|
||||
long bgm_size = ftell(bgm_file);
|
||||
fseek(bgm_file, 0, SEEK_SET);
|
||||
char* bgm_data = malloc(bgm_size);
|
||||
fread(bgm_data, 1, bgm_size, bgm_file);
|
||||
fclose(bgm_file);
|
||||
|
||||
char bgmpath[0x107] = {0};
|
||||
sprintf(bgmpath, "%s/bgm.bcstm", path);
|
||||
remake_file(fsMakePath(PATH_ASCII, bgmpath), ArchiveSD, bgm_size);
|
||||
buf_to_file(bgm_size, fsMakePath(PATH_ASCII, bgmpath), ArchiveSD, bgm_data);
|
||||
free(bgm_data);
|
||||
}
|
||||
|
||||
romfsUnmount("theme");
|
||||
char icondatapath[0x107] = {0};
|
||||
sprintf(icondatapath, "meta:/icons/%ld.icn", extra_index);
|
||||
FILE* iconfile = fopen(icondatapath, "rb");
|
||||
fread(smdh_data->big_icon, 1, sizeof(smdh_data->big_icon), iconfile);
|
||||
fclose(iconfile);
|
||||
|
||||
strcat(path, "/info.smdh");
|
||||
remake_file(fsMakePath(PATH_ASCII, path), ArchiveSD, 0x36c0);
|
||||
buf_to_file(0x36c0, fsMakePath(PATH_ASCII, path), ArchiveSD, (char*)smdh_data);
|
||||
}
|
||||
|
||||
romfsMountFromFile(theme_fh, 0, "theme");
|
||||
|
||||
char themename[0x41] = {0};
|
||||
memcpy(themename, content_data, 0x40);
|
||||
char * illegal_char = themename;
|
||||
while ((illegal_char = strpbrk(illegal_char, ILLEGAL_CHARS)))
|
||||
{
|
||||
*illegal_char = '-';
|
||||
}
|
||||
|
||||
char path[0x107] = { 0 };
|
||||
sprintf(path, "/Themes/Dump-%02lx-%ld-%s", dlc_index, extra_index, themename);
|
||||
DEBUG("theme folder to create: %s\n", path);
|
||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, path), FS_ATTRIBUTE_DIRECTORY);
|
||||
|
||||
memset(smdh_data->name, 0, sizeof(smdh_data->name));
|
||||
utf8_to_utf16(smdh_data->name, (u8*)(content_data + 0), 0x40);
|
||||
|
||||
FILE* theme_file = fopen("theme:/body_LZ.bin", "rb");
|
||||
if(theme_file)
|
||||
{
|
||||
fseek(theme_file, 0, SEEK_END);
|
||||
long theme_size = ftell(theme_file);
|
||||
fseek(theme_file, 0, SEEK_CUR);
|
||||
char* theme_data = malloc(theme_size);
|
||||
fread(theme_data, 1, theme_size, theme_file);
|
||||
fclose(theme_file);
|
||||
|
||||
char themepath[0x107] = {0};
|
||||
sprintf(themepath, "%s/body_LZ.bin", path);
|
||||
remake_file(fsMakePath(PATH_ASCII, themepath), ArchiveSD, theme_size);
|
||||
buf_to_file(theme_size, fsMakePath(PATH_ASCII, themepath), ArchiveSD, theme_data);
|
||||
free(theme_data);
|
||||
}
|
||||
|
||||
FILE* bgm_file = fopen("theme:/bgm.bcstm", "rb");
|
||||
if(bgm_file)
|
||||
{
|
||||
fseek(bgm_file, 0, SEEK_END);
|
||||
long bgm_size = ftell(bgm_file);
|
||||
fseek(bgm_file, 0, SEEK_CUR);
|
||||
char* bgm_data = malloc(bgm_size);
|
||||
fread(bgm_data, 1, bgm_size, bgm_file);
|
||||
fclose(bgm_file);
|
||||
|
||||
char bgmpath[0x107] = {0};
|
||||
sprintf(bgmpath, "%s/bgm.bcstm", path);
|
||||
remake_file(fsMakePath(PATH_ASCII, bgmpath), ArchiveSD, bgm_size);
|
||||
buf_to_file(bgm_size, fsMakePath(PATH_ASCII, bgmpath), ArchiveSD, bgm_data);
|
||||
free(bgm_data);
|
||||
}
|
||||
|
||||
romfsUnmount("theme");
|
||||
char icondatapath[0x107] = {0};
|
||||
sprintf(icondatapath, "meta:/icons/%ld.icn", extra_index);
|
||||
FILE* iconfile = fopen(icondatapath, "rb");
|
||||
fread(smdh_data->big_icon, 1, sizeof(smdh_data->big_icon), iconfile);
|
||||
fclose(iconfile);
|
||||
|
||||
strcat(path, "/info.smdh");
|
||||
remake_file(fsMakePath(PATH_ASCII, path), ArchiveSD, 0x36c0);
|
||||
buf_to_file(0x36c0, fsMakePath(PATH_ASCII, path), ArchiveSD, (char*)smdh_data);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
fh = NULL;
|
||||
fclose(fh);
|
||||
fh = NULL;
|
||||
}
|
||||
free(contentInfos);
|
||||
contentInfos = NULL;
|
||||
|
||||
romfsUnmount("meta");
|
||||
// don't need to close the file opened for the metadata, romfsUnmount took ownership
|
||||
FSUSER_CloseArchive(ncch_archive);
|
||||
FSUSER_CloseArchive(ncch_archive);
|
||||
}
|
||||
|
||||
free(smdh_data);
|
||||
|
||||
Reference in New Issue
Block a user