From d937ae17164388d34189528e2ff09b8fe90975f9 Mon Sep 17 00:00:00 2001 From: LiquidFenrir Date: Sat, 2 Dec 2017 16:09:38 +0100 Subject: [PATCH] Major rewrite: less repetition (#101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * first step of rewriting: at least it compiles™ * fix tabs/spaces * fix dabort on load * fix preview crash * sorting isnt done outside of loading * step one of making remake_file useless * camera/qr code cleanup * fix dabort when folder is empty, and bring back preview optimization * fix button for switching modes and show mode when folder is empty * fix scanning qrs * no more splash discrimination * add debug helpers * fix theme installing turns out that wasnt such a good idea * fix battery icon * mistake * themeplaza compatibility * make use of load_data * don't drink and copy-paste, kids * fix user-agent * remove useless * cleanup includes * not even used * add splash buttons * upgrade buttons drawing * fix controls while preview is up * improve positions --- Makefile | 2 +- include/camera.h | 5 +- include/common.h | 33 ++-- include/draw.h | 49 ++++- include/fs.h | 2 +- include/loading.h | 60 ++++++ include/splashes.h | 23 +-- include/themes.h | 31 +--- source/camera.c | 86 ++++----- source/draw.c | 409 +++++++++++++++++------------------------ source/fs.c | 6 +- source/loading.c | 197 ++++++++++++++++++++ source/main.c | 444 +++++++++++++++++++-------------------------- source/splashes.c | 242 ++---------------------- source/themes.c | 363 +++++++----------------------------- 15 files changed, 803 insertions(+), 1149 deletions(-) create mode 100644 include/loading.h create mode 100644 source/loading.c diff --git a/Makefile b/Makefile index ef4b42f..8efcd53 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ CFLAGS := -g -Wall -Wextra -O2 -mword-relocations \ revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/') -CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE -DVERSION="\"$(revision)\"" +CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE -DVERSION="\"$(revision)\"" -DUSER_AGENT="\"$(APP_TITLE)/$(revision)\"" CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 diff --git a/include/camera.h b/include/camera.h index 90739e0..405bbab 100644 --- a/include/camera.h +++ b/include/camera.h @@ -29,11 +29,10 @@ #include "common.h" -bool qr_mode; - void init_qr(void); void exit_qr(void); void take_picture(void); -Result http_get(char *url, char *path); +bool scan_qr(EntryMode current_mode); +Result http_get(char *url, const char *path); #endif \ No newline at end of file diff --git a/include/common.h b/include/common.h index db2f785..0e47d7e 100644 --- a/include/common.h +++ b/include/common.h @@ -33,25 +33,26 @@ #include #include -#define THEMES_PATH "/Themes/" -#define SPLASHES_PATH "/Splashes/" +#define ENTRIES_PER_SCREEN 4 -#define SINGLE_INSTALL 0 -#define SHUFFLE_INSTALL 1 -#define BGM_INSTALL 2 -#define UNINSTALL 3 -#define DOWNLOADING 3 +#define DEBUG(...) fprintf(stderr, __VA_ARGS__) +#define POS() DEBUG("%s (line %d)...\n", __func__, __LINE__) -#define ERROR 0 -#define WARNING 1 -static const int THEMES_PER_SCREEN = 4; +#define DEBUGPOS(...) \ + POS(); \ + DEBUG(__VA_ARGS__) -bool homebrew; -bool splash_mode; -int shuffle_theme_count; +typedef enum { + MODE_THEMES = 0, + MODE_SPLASHES, + + MODE_AMOUNT, +} EntryMode; + +extern const char * main_paths[MODE_AMOUNT]; enum TextureID { - TEXTURE_FONT_RESERVED = 0, //used by pp2d for the font + TEXTURE_FONT_RESERVED = 0, // used by pp2d for the font TEXTURE_ARROW, TEXTURE_SHUFFLE, TEXTURE_BATTERY_1, @@ -62,6 +63,10 @@ enum TextureID { TEXTURE_BATTERY_CHARGE, TEXTURE_QR, TEXTURE_PREVIEW, + + TEXTURE_ICON, // always the last }; +void exit_function(void); + #endif \ No newline at end of file diff --git a/include/draw.h b/include/draw.h index 4d1fb2c..7820e19 100644 --- a/include/draw.h +++ b/include/draw.h @@ -27,18 +27,49 @@ #ifndef DRAW_H #define DRAW_H -#include "themes.h" -#include "splashes.h" -#include "camera.h" +#include "common.h" +#include "loading.h" + +typedef enum { + INSTALL_SPLASH, + INSTALL_SPLASH_DELETE, + + INSTALL_SINGLE, + INSTALL_SHUFFLE, + INSTALL_BGM, + + INSTALL_DOWNLOAD, +} InstallType; + +typedef enum { + ERROR_LEVEL_ERROR, + ERROR_LEVEL_WARNING, +} ErrorLevel; + +#define BUTTONS_START_Y 140 +#define BUTTONS_STEP 25 + +enum { + BUTTONS_Y_PREVIEW = BUTTONS_START_Y+5, + + BUTTONS_Y_LINE_1 = BUTTONS_START_Y + BUTTONS_STEP*1, + BUTTONS_Y_LINE_2 = BUTTONS_START_Y + BUTTONS_STEP*2, + BUTTONS_Y_LINE_3 = BUTTONS_START_Y + BUTTONS_STEP*3, + + BUTTONS_X_LEFT = 20, + BUTTONS_X_RIGHT = 200, +} ButtonPos; void init_screens(void); void exit_screens(void); void draw_themext_error(void); -void draw_base_interface(void); -void draw_theme_install(int install_type); -void draw_theme_interface(Theme_s * themes_list, int theme_count, int selected_theme, bool preview_mode, int shuffle_theme_count); -void draw_splash_install(int install_type); -void draw_splash_interface(Splash_s *splashes_list, int splash_count, int selected_splash, bool preview_mode); -void throw_error(char* error, int error_type); +void throw_error(char* error, ErrorLevel level); + +void draw_preview(int preview_offset); + +void draw_install(InstallType type); + +void draw_interface(Entry_List_s* list, EntryMode current_mode); + #endif \ No newline at end of file diff --git a/include/fs.h b/include/fs.h index 9116186..6d663d8 100644 --- a/include/fs.h +++ b/include/fs.h @@ -36,7 +36,7 @@ FS_Archive ArchiveThemeExt; Result open_archives(void); Result close_archives(void); -u64 file_to_buf(FS_Path path, FS_Archive archive, char** buf); +u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf); u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf); Result buf_to_file(u32 size, char *path, FS_Archive archive, char *buf); diff --git a/include/loading.h b/include/loading.h new file mode 100644 index 0000000..db30da1 --- /dev/null +++ b/include/loading.h @@ -0,0 +1,60 @@ +/* +* This file is part of Anemone3DS +* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth") +* +* 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 . +* +* 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. +*/ + +#ifndef LOADING_H +#define LOADING_H + +#include "common.h" + +typedef struct { + u16 name[0x41]; + u16 desc[0x81]; + u16 author[0x41]; + + u32 placeholder_color; + ssize_t icon_id; + + u16 path[0x106]; + bool is_zip; + + bool in_shuffle; +} Entry_s; + +typedef struct { + Entry_s * entries; + int entries_count; + + int scroll; + int selected_entry; + + int shuffle_count; +} Entry_List_s; + +Result load_entries(const char * loading_path, Entry_List_s * list); +bool load_preview(Entry_List_s list, int * preview_offset); +u32 load_data(char * filename, Entry_s entry, char ** buf); + +#endif \ No newline at end of file diff --git a/include/splashes.h b/include/splashes.h index e372391..6c63b8d 100644 --- a/include/splashes.h +++ b/include/splashes.h @@ -28,26 +28,9 @@ #define SPLASHES_H #include "common.h" +#include "loading.h" -typedef struct { - u16 name[0x41]; - u16 desc[0x81]; - u16 author[0x41]; - - u32 placeholder_color; - ssize_t icon_id; - - u16 path[0x106]; - bool is_zip; -} Splash_s; - -Splash_s *splashes_list; -int splash_count; - -Result get_splashes(Splash_s** splashes_list, int *splash_count); -int splashcmp(const void* a, const void* b); -void splash_install(Splash_s splash_to_install); -void splash_delete(); -void load_splash_preview(Splash_s *splash); +void splash_delete(void); +void splash_install(Entry_s splash); #endif \ No newline at end of file diff --git a/include/themes.h b/include/themes.h index b5f82eb..c9095b3 100644 --- a/include/themes.h +++ b/include/themes.h @@ -28,33 +28,12 @@ #define THEMES_H #include "common.h" +#include "loading.h" -typedef struct { - u16 name[0x41]; - u16 desc[0x81]; - u16 author[0x41]; - - u32 placeholder_color; - ssize_t icon_id; - - bool has_preview; - int preview_offset; - - u16 path[0x106]; - bool is_zip; - - bool in_shuffle; -} Theme_s; +void delete_theme(Entry_s theme); +Result theme_install(Entry_s theme); -Theme_s * themes_list; -int theme_count; - -void load_theme_preview(Theme_s *theme); -Result get_themes(Theme_s **themes_list, int *theme_count); -int themecmp(const void* a, const void* b); -void del_theme(u16 *path); -Result single_install(Theme_s theme); -Result shuffle_install(Theme_s *themes_list, int theme_count); -Result bgm_install(Theme_s bgm_to_install); +Result shuffle_install(Entry_s* themes_list, int themes_count); +Result bgm_install(Entry_s bgm_to_install); #endif \ No newline at end of file diff --git a/source/camera.c b/source/camera.c index 48b151d..7cb9804 100644 --- a/source/camera.c +++ b/source/camera.c @@ -27,14 +27,16 @@ #include "camera.h" #include "quirc/quirc.h" -#include "draw.h" -#include "fs.h" -#include "themes.h" #include "pp2d/pp2d/pp2d.h" -u32 transfer_size; -Handle event; -struct quirc* context; +#include "draw.h" +#include "fs.h" +#include "loading.h" + +static u32 transfer_size; +static Handle event; +static struct quirc* context; +static u16 * camera_buf = NULL; void init_qr(void) { @@ -69,10 +71,14 @@ void exit_qr(void) CAMU_Activate(SELECT_NONE); camExit(); quirc_destroy(context); + free(camera_buf); + camera_buf = NULL; } -void scan_qr(u16 *buf) +bool scan_qr(EntryMode current_mode) { + if(camera_buf == NULL) return false; + int w; int h; @@ -82,7 +88,7 @@ void scan_qr(u16 *buf) { for (ssize_t y = 0; y < h; y++) { - u16 px = buf[y * 400 + x]; + u16 px = camera_buf[y * 400 + x]; image[y * w + x] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3); } } @@ -96,59 +102,49 @@ void scan_qr(u16 *buf) quirc_extract(context, 0, &code); if (!quirc_decode(&code, &data)) { - qr_mode = false; - - http_get((char*)data.payload, splash_mode ? "/Splashes/" : "/Themes/"); + http_get((char*)data.payload, main_paths[current_mode]); + exit_qr(); + return true; } } + + return false; } void take_picture(void) { - u16 *buf = malloc(sizeof(u16) * 400 * 240 * 4); - if (buf == NULL) return; - CAMU_SetReceiving(&event, buf, PORT_CAM1, 240 * 400 * 2, transfer_size); + pp2d_begin_draw(GFX_TOP, GFX_LEFT); + free(camera_buf); + + camera_buf = malloc(sizeof(u16) * 400 * 240 * 4); + if (camera_buf == NULL) return; + + CAMU_SetReceiving(&event, camera_buf, PORT_CAM1, 240 * 400 * 2, transfer_size); svcWaitSynchronization(event, U64_MAX); svcCloseHandle(event); - pp2d_begin_draw(GFX_TOP, GFX_LEFT); + u32 *rgba8_buf = malloc(240 * 400 * sizeof(u32)); if (rgba8_buf == NULL) return; for (int i = 0; i < 240 * 400; i++) { - rgba8_buf[i] = RGB565_TO_ABGR8(buf[i]); + rgba8_buf[i] = RGB565_TO_ABGR8(camera_buf[i]); } + pp2d_free_texture(TEXTURE_QR); pp2d_load_texture_memory(TEXTURE_QR, rgba8_buf, 400, 240); + free(rgba8_buf); + pp2d_draw_texture(TEXTURE_QR, 0, 0); pp2d_draw_rectangle(0, 216, 400, 24, RGBA8(55, 122, 168, 255)); pp2d_draw_text_center(GFX_TOP, 220, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE005 To Quit"); pp2d_draw_rectangle(0, 0, 400, 24, RGBA8(55, 122, 168, 255)); pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE004 To Scan"); - pp2d_end_draw(); - free(rgba8_buf); - pp2d_free_texture(TEXTURE_QR); - hidScanInput(); - u32 kDown = hidKeysDown(); - if (kDown & KEY_L) - { - CAMU_StopCapture(PORT_BOTH); - CAMU_Activate(SELECT_NONE); - scan_qr(buf); - CAMU_Activate(SELECT_OUT1_OUT2); - CAMU_StartCapture(PORT_BOTH); - } - if (kDown & KEY_R) - { - exit_qr(); - qr_mode = false; - } - free(buf); } /* Putting this in camera because I'm too lazy to make a network.c This'll probably get refactored later */ -Result http_get(char *url, char *path) +Result http_get(char *url, const char *path) { Result ret; httpcContext context; @@ -164,9 +160,10 @@ Result http_get(char *url, char *path) ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1); ret = httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); // should let us do https ret = httpcSetKeepAlive(&context, HTTPC_KEEPALIVE_ENABLED); - ret = httpcAddRequestHeaderField(&context, "User-Agent", "Anemone3DS/1.1.0"); + ret = httpcAddRequestHeaderField(&context, "User-Agent", USER_AGENT); ret = httpcAddRequestHeaderField(&context, "Connection", "Keep-Alive"); - draw_theme_install(DOWNLOADING); + draw_install(INSTALL_DOWNLOAD); + ret = httpcBeginRequest(&context); if (ret != 0) { @@ -234,9 +231,7 @@ Result http_get(char *url, char *path) free(content_disposition); free(new_url); free(buf); - char error[29] = {0}; - sprintf(error, "Target is not a valid %s", splash_mode ? "splash" : "theme"); - throw_error(error, WARNING); + throw_error("Target is not valid!", ERROR_LEVEL_WARNING); return -1; } for (size_t i = 0; i < strlen(filename); i++) @@ -283,14 +278,13 @@ Result http_get(char *url, char *path) char path_to_file[0x106] = {0}; strcpy(path_to_file, path); strcat(path_to_file, filename); + char * extension = strrchr(path_to_file, '.'); + if (extension == NULL || strcmp(extension, ".zip")) + strcat(path_to_file, ".zip"); + remake_file(path_to_file, ArchiveSD, size); buf_to_file(size, path_to_file, ArchiveSD, (char*)buf); - if (splash_mode) get_splashes(&splashes_list, &splash_count); - else get_themes(&themes_list, &theme_count); - - exit_qr(); - free(content_disposition); free(new_url); free(buf); diff --git a/source/draw.c b/source/draw.c index f2eb509..430c820 100644 --- a/source/draw.c +++ b/source/draw.c @@ -25,14 +25,12 @@ */ #include "draw.h" -#include "common.h" +#include "unicode.h" #include "pp2d/pp2d/pp2d.h" -#include "quirc/quirc.h" #include - enum Colors { COLOR_BACKGROUND = ABGR8(255, 32, 28, 35), //silver-y black COLOR_ACCENT = RGBA8(55, 122, 168, 255), @@ -46,10 +44,10 @@ enum Colors { void init_screens(void) { pp2d_init(); - + pp2d_set_screen_color(GFX_TOP, COLOR_BACKGROUND); pp2d_set_screen_color(GFX_BOTTOM, COLOR_BACKGROUND); - + pp2d_load_texture_png(TEXTURE_ARROW, "romfs:/arrow.png"); pp2d_load_texture_png(TEXTURE_SHUFFLE, "romfs:/shuffle.png"); pp2d_load_texture_png(TEXTURE_BATTERY_1, "romfs:/battery1.png"); @@ -65,42 +63,41 @@ void exit_screens(void) pp2d_exit(); } -static int theme_vertical_scroll = 0; -static int splash_vertical_scroll = 0; - - -void draw_base_interface(void) +static void draw_base_interface(void) { pp2d_begin_draw(GFX_TOP, GFX_LEFT); pp2d_draw_rectangle(0, 0, 400, 23, COLOR_ACCENT); time_t t = time(NULL); struct tm tm = *localtime(&t); - + pp2d_draw_textf(7, 2, 0.6, 0.6, COLOR_WHITE, "%.2i", tm.tm_hour); - pp2d_draw_text(28, 2, 0.6, 0.6, COLOR_WHITE, (tm.tm_sec % 2 == 1) ? ":" : " "); + pp2d_draw_text(28, 1, 0.6, 0.6, COLOR_WHITE, (tm.tm_sec % 2 == 1) ? ":" : " "); pp2d_draw_textf(34, 2, 0.6, 0.6, COLOR_WHITE, "%.2i", tm.tm_min); - u8 battery_charging; + u8 battery_charging = 0; PTMU_GetBatteryChargeState(&battery_charging); - u8 battery_status; + u8 battery_status = 0; PTMU_GetBatteryLevel(&battery_status); - pp2d_draw_texture(2 + battery_status, 357, 2); - - if (battery_charging) + pp2d_draw_texture(TEXTURE_BATTERY_1 + battery_status - 1, 357, 2); + + if(battery_charging) pp2d_draw_texture(TEXTURE_BATTERY_CHARGE, 357, 2); pp2d_draw_on(GFX_BOTTOM, GFX_LEFT); pp2d_draw_rectangle(0, 0, 320, 24, COLOR_ACCENT); pp2d_draw_rectangle(0, 216, 320, 24, COLOR_ACCENT); pp2d_draw_text(7, 219, 0.6, 0.6, COLOR_WHITE, VERSION); + pp2d_draw_on(GFX_TOP, GFX_LEFT); } -void throw_error(char* error, int error_type) { - switch (error_type) { - case ERROR: - while (aptMainLoop()) +void throw_error(char* error, ErrorLevel level) +{ + switch(level) + { + case ERROR_LEVEL_ERROR: + while(aptMainLoop()) { hidScanInput(); u32 kDown = hidKeysDown(); @@ -108,254 +105,190 @@ void throw_error(char* error, int error_type) { pp2d_draw_text_center(GFX_TOP, 120, 0.6, 0.6, COLOR_RED, error); pp2d_draw_wtext_center(GFX_TOP, 150, 0.6, 0.6, COLOR_WHITE, L"Press \uE000 to shut down."); pp2d_end_draw(); - if (kDown & KEY_A) { - if (homebrew) - APT_HardwareResetAsync(); - else { - srvPublishToSubscriber(0x202, 0); - } - } + if(kDown & KEY_A) exit_function(); + } + break; + case ERROR_LEVEL_WARNING: + while(aptMainLoop()) + { + hidScanInput(); + u32 kDown = hidKeysDown(); + draw_base_interface(); + pp2d_draw_text_center(GFX_TOP, 120, 0.6, 0.6, COLOR_YELLOW, error); + pp2d_draw_wtext_center(GFX_TOP, 150, 0.6, 0.6, COLOR_WHITE, L"Press \uE000 to continue."); + pp2d_end_draw(); + if(kDown & KEY_A) break; } - case WARNING: - while (aptMainLoop()) - { - hidScanInput(); - u32 kDown = hidKeysDown(); - draw_base_interface(); - pp2d_draw_text_center(GFX_TOP, 120, 0.6, 0.6, COLOR_YELLOW, error); - pp2d_draw_wtext_center(GFX_TOP, 150, 0.6, 0.6, COLOR_WHITE, L"Press \uE000 to continue."); - pp2d_end_draw(); - if (kDown & KEY_A) break; - } break; } - pp2d_end_draw(); } -void draw_theme_install(int install_type) + +void draw_preview(int preview_offset) +{ + pp2d_begin_draw(GFX_TOP, GFX_LEFT); + pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, preview_offset, 0, 400, 240); + pp2d_draw_on(GFX_BOTTOM, GFX_LEFT); + pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 40 + preview_offset, 240, 320, 240); +} + +void draw_install(InstallType type) { draw_base_interface(); - switch(install_type) + switch(type) { - case 0: + case INSTALL_SINGLE: pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a single theme..."); break; - case 1: + case INSTALL_SHUFFLE: pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a shuffle theme..."); break; - case 2: + case INSTALL_BGM: pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing BGM..."); break; - case 3: + case INSTALL_DOWNLOAD: pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Downloading..."); break; + case INSTALL_SPLASH: + pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing a splash..."); + break; + case INSTALL_SPLASH_DELETE: + pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Uninstalling a splash..."); + break; default: break; } pp2d_end_draw(); } -void draw_theme_interface(Theme_s * themes_list, int theme_count, int selected_theme, bool preview_mode, int shuffle_theme_count) -{ - - if (themes_list == NULL) - { - draw_base_interface(); - pp2d_draw_text_center(GFX_TOP, 80, 0.7, 0.7, COLOR_YELLOW, "No themes found!"); - pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_YELLOW, "Press \uE005 to download from QR"); - pp2d_draw_text_center(GFX_TOP, 140, 0.7, 0.7, COLOR_YELLOW, "Or \uE045 to quit"); - pp2d_end_draw(); - return; - } - - Theme_s current_theme = themes_list[selected_theme]; - - if (preview_mode) - { - if (current_theme.has_preview) - { - pp2d_begin_draw(GFX_TOP, GFX_LEFT); - pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, current_theme.preview_offset, 0, 400, 240); - pp2d_draw_on(GFX_BOTTOM, GFX_LEFT); - pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 40+current_theme.preview_offset, 240, 320, 240); - } - } - else - { - draw_base_interface(); - pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, "Theme mode"); - wchar_t title[0x41] = {0}; - utf16_to_utf32((u32*)title, current_theme.name, 0x40); - pp2d_draw_wtext_wrap(20, 30, 0.7, 0.7, COLOR_WHITE, 380, title); - wchar_t author[0x41] = {0}; - utf16_to_utf32((u32*)author, current_theme.author, 0x40); - pp2d_draw_text(20, 50, 0.5, 0.5, COLOR_WHITE, "By: "); - pp2d_draw_wtext_wrap(44, 50, 0.5, 0.5, COLOR_WHITE, 380, author); - wchar_t description[0x81] = {0}; - utf16_to_utf32((u32*)description, current_theme.desc, 0x80); - pp2d_draw_wtext_wrap(20, 65, 0.5, 0.5, COLOR_WHITE, 363, description); - - pp2d_draw_wtext(20, 150, 0.6, 0.6, COLOR_WHITE, L"\uE046 Install Shuffle Theme"); - pp2d_draw_wtext(200, 150, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Splashes"); - pp2d_draw_wtext(20, 180, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Theme"); - pp2d_draw_wtext(200, 180, 0.6, 0.6, COLOR_WHITE, L"\uE001 Queue Shuffle"); - pp2d_draw_wtext(20, 210, 0.6, 0.6, COLOR_WHITE, L"\uE002 Install BGM"); - pp2d_draw_wtext(200, 210, 0.6, 0.6, COLOR_WHITE, L"\uE003 Preview Theme"); - pp2d_draw_wtext(130, 120, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode"); - pp2d_draw_on(GFX_BOTTOM, GFX_LEFT); - - pp2d_draw_textf(7, 3, 0.6, 0.6, COLOR_WHITE, "Selected: %i/10", shuffle_theme_count); - - // Scroll the menu up or down if the selected theme is out of its bounds - //---------------------------------------------------------------- - for (int i = 0; i < theme_count; i++) { - if (theme_count <= THEMES_PER_SCREEN) - break; - - if (theme_vertical_scroll > selected_theme) - theme_vertical_scroll--; - - if ((i < selected_theme) && \ - ((selected_theme - theme_vertical_scroll) >= THEMES_PER_SCREEN) && \ - (theme_vertical_scroll != ( - THEMES_PER_SCREEN))) - theme_vertical_scroll++; - } - //---------------------------------------------------------------- - - // Show arrows if there are themes out of bounds - //---------------------------------------------------------------- - if (theme_vertical_scroll > 0) - pp2d_draw_texture(TEXTURE_ARROW, 155, 6); - if (theme_vertical_scroll + THEMES_PER_SCREEN < theme_count) - pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL); - - for (int i = theme_vertical_scroll; i < (THEMES_PER_SCREEN + theme_vertical_scroll); i++) - { - if (i >= theme_count) - break; - - current_theme = themes_list[i]; - wchar_t name[0x80] = {0}; - utf16_to_utf32((u32*)name, current_theme.name, 0x80); - - int vertical_offset = 48 * (i-theme_vertical_scroll); - u32 font_color = COLOR_WHITE; - - if (i == selected_theme) - { - font_color = COLOR_BLACK; - pp2d_draw_rectangle(0, 24 + vertical_offset, 320, 48, COLOR_CURSOR); - } - pp2d_draw_wtext(54, 40 + vertical_offset, 0.55, 0.55, font_color, name); - if (!current_theme.placeholder_color) - pp2d_draw_texture(current_theme.icon_id, 0, 24 + vertical_offset); - else - pp2d_draw_rectangle(0, 24 + vertical_offset, 48, 48, current_theme.placeholder_color); - - if (current_theme.in_shuffle) - pp2d_draw_texture_blend(TEXTURE_SHUFFLE, 280, 32 + vertical_offset, font_color); - } - } - - pp2d_end_draw(); -} - -void draw_splash_install(int install_type) +void draw_interface(Entry_List_s* list, EntryMode current_mode) { draw_base_interface(); - switch (install_type) - { - case SINGLE_INSTALL: - pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_WHITE, "Installing a splash..."); - break; - case UNINSTALL: - pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_WHITE, "Uninstalling a splash..."); - break; - default: - break; - } - pp2d_end_draw(); -} -void draw_splash_interface(Splash_s *splashes_list, int splash_count, int selected_splash, bool preview_mode) -{ - if (splashes_list == NULL) + const char* mode_string[] = { + "Theme mode", + "Splashes mode", + }; + + pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, mode_string[current_mode]); + + if(list->entries == NULL) { - draw_base_interface(); - pp2d_draw_text_center(GFX_TOP, 80, 0.7, 0.7, COLOR_YELLOW, "No splashes found!"); + const char* mode_found_string[] = { + "No themes found", + "No splashes found", + }; + pp2d_draw_text_center(GFX_TOP, 80, 0.7, 0.7, COLOR_YELLOW, mode_found_string[current_mode]); pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_YELLOW, "Press \uE005 to download from QR"); - pp2d_draw_text_center(GFX_TOP, 140, 0.7, 0.7, COLOR_YELLOW, "Or \uE045 to quit"); - pp2d_end_draw(); + const char* mode_switch_string[] = { + "Or \uE004 to switch to splashes", + "Or \uE004 to switch to themes", + }; + pp2d_draw_text_center(GFX_TOP, 140, 0.7, 0.7, COLOR_YELLOW, mode_switch_string[current_mode]); + pp2d_draw_text_center(GFX_TOP, 170, 0.7, 0.7, COLOR_YELLOW, "Or \uE045 to quit"); return; } - Splash_s current_splash = splashes_list[selected_splash]; - if (preview_mode) + + int selected_entry = list->selected_entry; + Entry_s current_entry = list->entries[selected_entry]; + + wchar_t title[0x41] = {0}; + utf16_to_utf32((u32*)title, current_entry.name, 0x40); + pp2d_draw_wtext_wrap(20, 30, 0.7, 0.7, COLOR_WHITE, 380, title); + + wchar_t author[0x41] = {0}; + utf16_to_utf32((u32*)author, current_entry.author, 0x40); + pp2d_draw_text(20, 50, 0.5, 0.5, COLOR_WHITE, "By: "); + pp2d_draw_wtext_wrap(44, 50, 0.5, 0.5, COLOR_WHITE, 380, author); + + wchar_t description[0x81] = {0}; + utf16_to_utf32((u32*)description, current_entry.desc, 0x80); + pp2d_draw_wtext_wrap(20, 65, 0.5, 0.5, COLOR_WHITE, 363, description); + + + switch(current_mode) { - pp2d_begin_draw(GFX_TOP, GFX_LEFT); - pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 0, 0, 400, 240); - pp2d_draw_on(GFX_BOTTOM, GFX_LEFT); - pp2d_draw_texture_part(TEXTURE_PREVIEW, 0, 0, 40, 240, 320, 240); - } else { - draw_base_interface(); - pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, "Splash mode"); - wchar_t title[0x40] = {0}; - utf16_to_utf32((u32*)title, current_splash.name, 0x40); - pp2d_draw_wtext_wrap(20, 30, 0.7, 0.7, COLOR_WHITE, 380, title); - wchar_t author[0x40] = {0}; - utf16_to_utf32((u32*)author, current_splash.author, 0x40); - pp2d_draw_text(20, 50, 0.5, 0.5, COLOR_WHITE, "By: "); - pp2d_draw_wtext_wrap(44, 50, 0.5, 0.5, COLOR_WHITE, 380, author); - wchar_t description[0xa6] = {0}; - utf16_to_utf32((u32*)description, current_splash.desc, 0xb0); - pp2d_draw_wtext_wrap(20, 65, 0.5, 0.5, COLOR_WHITE, 363, description); + case MODE_THEMES: + pp2d_draw_text_center(GFX_TOP, BUTTONS_Y_PREVIEW, 0.6, 0.6, COLOR_WHITE, "\uE003 Preview Theme"); + pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Splashes"); + pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode"); - pp2d_draw_wtext_center(GFX_TOP, 180, 0.7, 0.7, COLOR_WHITE, L"\uE000 Install Splash \uE004 Switch to Themes"); - pp2d_draw_wtext_center(GFX_TOP, 210, 0.7, 0.7, COLOR_WHITE, L"\uE002 Delete current Splash"); - pp2d_draw_wtext_center(GFX_TOP, 150, 0.7, 0.7, COLOR_WHITE, L"\uE003 Preview Splash \uE005 Scan QRCode"); - pp2d_draw_wtext(130, 120, 0.6, 0.6, COLOR_WHITE, L""); + pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Theme"); + pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE001 Queue Shuffle"); - pp2d_draw_on(GFX_BOTTOM, GFX_LEFT); - for (int i = 0; i < splash_count; i++) { - if (splash_count <= THEMES_PER_SCREEN) - break; + pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE002 Install BGM"); + pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE046 Install Shuffle Themes"); + break; + case MODE_SPLASHES: + pp2d_draw_text_center(GFX_TOP, BUTTONS_Y_PREVIEW, 0.6, 0.6, COLOR_WHITE, "\uE003 Preview Splash"); + pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Themes"); + pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode"); - if (splash_vertical_scroll > selected_splash) - splash_vertical_scroll--; - - if ((i < selected_splash) && \ - ((selected_splash - splash_vertical_scroll) >= THEMES_PER_SCREEN) && \ - (splash_vertical_scroll != ( - THEMES_PER_SCREEN))) - splash_vertical_scroll++; - } - - if (splash_vertical_scroll > 0) - pp2d_draw_texture(TEXTURE_ARROW, 155, 6); - if (splash_vertical_scroll + THEMES_PER_SCREEN < splash_count) - pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL); - - for (int i = splash_vertical_scroll; i < (THEMES_PER_SCREEN + splash_vertical_scroll); i++) - { - if (i >= splash_count) - break; - - current_splash = splashes_list[i]; - wchar_t name[0x106] = {0}; - utf16_to_utf32((u32*)name, current_splash.name, 0x106); - - int vertical_offset = 48 * (i-splash_vertical_scroll); - u32 font_color = COLOR_WHITE; - - if (i == selected_splash) - { - font_color = COLOR_BLACK; - pp2d_draw_rectangle(0, 24 + vertical_offset, 320, 48, COLOR_CURSOR); - } - pp2d_draw_wtext(54, 40 + vertical_offset, 0.55, 0.55, font_color, name); - - if (!current_splash.placeholder_color) - pp2d_draw_texture(current_splash.icon_id, 0, 24 + vertical_offset); - else - pp2d_draw_rectangle(0, 24 + vertical_offset, 48, 48, current_splash.placeholder_color); - } + pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Splash"); + pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE001 Delete installed Splash"); + break; + default: + break; + } + + + pp2d_draw_on(GFX_BOTTOM, GFX_LEFT); + + switch(current_mode) + { + case MODE_THEMES: + pp2d_draw_textf(7, 3, 0.6, 0.6, list->shuffle_count <= 10 ? COLOR_WHITE : COLOR_RED, "Selected: %i/10", list->shuffle_count); + break; + default: + break; + } + + // Scroll the menu up or down if the selected theme is out of its bounds + //---------------------------------------------------------------- + for(int i = 0; i < list->entries_count; i++) { + if(list->entries_count <= ENTRIES_PER_SCREEN) break; + + if(list->scroll > list->selected_entry) + list->scroll--; + + if((i < list->selected_entry) && \ + ((list->selected_entry - list->scroll) >= ENTRIES_PER_SCREEN) && \ + (list->scroll != (i - ENTRIES_PER_SCREEN))) + list->scroll++; + } + //---------------------------------------------------------------- + + // Show arrows if there are themes out of bounds + //---------------------------------------------------------------- + if(list->scroll > 0) + pp2d_draw_texture(TEXTURE_ARROW, 155, 6); + if(list->scroll + ENTRIES_PER_SCREEN < list->entries_count) + pp2d_draw_texture_flip(TEXTURE_ARROW, 155, 224, VERTICAL); + + for(int i = list->scroll; i < (ENTRIES_PER_SCREEN + list->scroll); i++) + { + if(i >= list->entries_count) break; + + current_entry = list->entries[i]; + + wchar_t name[0x41] = {0}; + utf16_to_utf32((u32*)name, current_entry.name, 0x40); + + int vertical_offset = 48 * (i - list->scroll); + u32 font_color = COLOR_WHITE; + + if(i == list->selected_entry) + { + font_color = COLOR_BLACK; + pp2d_draw_rectangle(0, 24 + vertical_offset, 320, 48, COLOR_CURSOR); + } + pp2d_draw_wtext(54, 40 + vertical_offset, 0.55, 0.55, font_color, name); + if(!current_entry.placeholder_color) + pp2d_draw_texture(current_entry.icon_id, 0, 24 + vertical_offset); + else + pp2d_draw_rectangle(0, 24 + vertical_offset, 48, 48, current_entry.placeholder_color); + + if(current_entry.in_shuffle) + pp2d_draw_texture_blend(TEXTURE_SHUFFLE, 280, 32 + vertical_offset, font_color); } - pp2d_end_draw(); } + diff --git a/source/fs.c b/source/fs.c index b1a4f53..71f27bb 100644 --- a/source/fs.c +++ b/source/fs.c @@ -99,11 +99,11 @@ Result close_archives(void) if(R_FAILED(res = FSUSER_CloseArchive(ArchiveSD))) return res; if(R_FAILED(res = FSUSER_CloseArchive(ArchiveHomeExt))) return res; if(R_FAILED(res = FSUSER_CloseArchive(ArchiveThemeExt))) return res; - + return 0; } -u64 file_to_buf(FS_Path path, FS_Archive archive, char** buf) +u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf) { Handle file; Result res = 0; @@ -114,7 +114,7 @@ u64 file_to_buf(FS_Path path, FS_Archive archive, char** buf) *buf = calloc(1, size); FSFILE_Read(file, NULL, 0, *buf, size); FSFILE_Close(file); - return size; + return (u32)size; } u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf) diff --git a/source/loading.c b/source/loading.c new file mode 100644 index 0000000..a05038f --- /dev/null +++ b/source/loading.c @@ -0,0 +1,197 @@ +/* +* This file is part of Anemone3DS +* Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth") +* +* 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 . +* +* 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. +*/ + +#include "loading.h" +#include "pp2d/pp2d/pp2d.h" +#include "fs.h" +#include "unicode.h" + +u32 load_data(char * filename, Entry_s entry, char ** buf) +{ + if(entry.is_zip) + { + return zip_file_to_buf(filename+1, entry.path, buf); //the first character will always be '/' because of the other case + } + else + { + u16 path[0x106] = {0}; + strucat(path, entry.path); + struacat(path, filename); + + return file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, buf); + } +} + +static void parse_smdh(Entry_s * entry, const ssize_t textureID, const u16 * fallback_name) +{ + pp2d_free_texture(textureID); + + char *info_buffer = NULL; + u64 size = load_data("/info.smdh", *entry, &info_buffer); + + if(!size) + { + free(info_buffer); + memcpy(entry->name, fallback_name, 0x80); + utf8_to_utf16(entry->desc, (u8*)"No description", 0x100); + utf8_to_utf16(entry->author, (u8*)"Unknown author", 0x80); + entry->placeholder_color = RGBA8(rand() % 255, rand() % 255, rand() % 255, 255); + return; + } + + memcpy(entry->name, info_buffer + 0x08, 0x80); + memcpy(entry->desc, info_buffer + 0x88, 0x100); + memcpy(entry->author, info_buffer + 0x188, 0x80); + + u16 *icon_data = malloc(0x1200); + memcpy(icon_data, info_buffer + 0x24C0, 0x1200); + free(info_buffer); + + const u32 width = 48, height = 48; + u32 *image = malloc(width*height*sizeof(u32)); + + for(u32 x = 0; x < width; x++) + { + for(u32 y = 0; y < height; y++) + { + unsigned int dest_pixel = (x + y*width); + unsigned int source_pixel = (((y >> 3) * (width >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3)); + + image[dest_pixel] = RGB565_TO_ABGR8(icon_data[source_pixel]); + } + } + + free(icon_data); + pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height); + free(image); + + entry->icon_id = textureID; +} + +static int compare_entries(const void * a, const void * b) +{ + Entry_s *entry_a = (Entry_s *)a; + Entry_s *entry_b = (Entry_s *)b; + + return memcmp(entry_a->name, entry_b->name, 0x40*sizeof(u16)); +} + +static void sort_list(Entry_List_s * list) +{ + qsort(list->entries, list->entries_count, sizeof(Entry_s), compare_entries); //alphabet sort +} + +Result load_entries(const char * loading_path, Entry_List_s * list) +{ + Handle dir_handle; + Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, loading_path)); + if(R_FAILED(res)) + return res; + + u32 entries_read = 1; + + while(entries_read) + { + FS_DirectoryEntry dir_entry = {0}; + res = FSDIR_Read(dir_handle, &entries_read, 1, &dir_entry); + if(R_FAILED(res) || entries_read == 0) + break; + + if(!(dir_entry.attributes & FS_ATTRIBUTE_DIRECTORY) && strcmp(dir_entry.shortExt, "ZIP")) + continue; + + list->entries_count++; + list->entries = realloc(list->entries, list->entries_count * sizeof(Entry_s)); + if(list->entries == NULL) + break; + + Entry_s * current_entry = &(list->entries[list->entries_count-1]); + memset(current_entry, 0, sizeof(Entry_s)); + + struacat(current_entry->path, loading_path); + strucat(current_entry->path, dir_entry.name); + + current_entry->is_zip = !strcmp(dir_entry.shortExt, "ZIP"); + + ssize_t iconID = TEXTURE_ICON + list->entries_count; + parse_smdh(current_entry, iconID, dir_entry.name); + } + + FSDIR_Close(dir_handle); + + sort_list(list); + + return res; +} + +static u16 previous_path[0x106] = {0}; + +bool load_preview(Entry_List_s list, int * preview_offset) +{ + if(list.entries == NULL) return false; + + Entry_s entry = list.entries[list.selected_entry]; + + if(!memcmp(&previous_path, &entry.path, 0x106*sizeof(u16))) return true; + else memcpy(&previous_path, &entry.path, 0x106*sizeof(u16)); + + // free the previously loaded preview. wont do anything if there wasnt one + pp2d_free_texture(TEXTURE_PREVIEW); + + char *preview_buffer = NULL; + u64 size = load_data("/preview.png", entry, &preview_buffer); + + if(!size) + { + free(preview_buffer); + return false; + } + + bool ret = false; + u8 * image = NULL; + unsigned int width = 0, height = 0; + + if((lodepng_decode32(&image, &width, &height, (u8*)preview_buffer, size)) == 0) // no error + { + for(u32 i = 0; i < width; i++) + { + for(u32 j = 0; j < height; j++) + { + u32* pixel = (u32*)(image + (i + j*width) * 4); + *pixel = __builtin_bswap32(*pixel); //swap from RGBA to ABGR, needed for pp2d + } + } + + pp2d_load_texture_memory(TEXTURE_PREVIEW, image, (u32)width, (u32)height); + *preview_offset = (width-400)/2; + ret = true; + } + + free(image); + free(preview_buffer); + + return ret; +} diff --git a/source/main.c b/source/main.c index a5ab4c9..2c6e4fb 100644 --- a/source/main.c +++ b/source/main.c @@ -25,354 +25,278 @@ */ #include "fs.h" +#include "loading.h" #include "themes.h" #include "splashes.h" #include "draw.h" -#include "common.h" #include "camera.h" +#include "pp2d/pp2d/pp2d.h" #include +static bool homebrew = false; int __stacksize__ = 64 * 1024; Result archive_result; -int init_services(void) +const char * main_paths[MODE_AMOUNT] = { + "/Themes/", + "/Splashes/", +}; + +void init_services(void) { + consoleDebugInit(debugDevice_SVC); cfguInit(); ptmuInit(); acInit(); httpcInit(0); archive_result = open_archives(); - homebrew = true; - if (!envIsHomebrew()) + if(envIsHomebrew()) { - homebrew = false; - } else { s64 out; svcGetSystemInfo(&out, 0x10000, 0); - if (out) - { - homebrew = false; - } + homebrew = !out; } - return homebrew; } -int exit_services(void) +void exit_services(void) { close_archives(); cfguExit(); ptmuExit(); httpcExit(); acExit(); - return 0; +} + +void exit_function(void) +{ + if(homebrew) + { + APT_HardwareResetAsync(); + } + else + { + srvPublishToSubscriber(0x202, 0); + } + + exit_screens(); + exit_services(); +} + +void change_selected(Entry_List_s * list, int change_value) +{ + list->selected_entry += change_value; + if(change_value < 0 && list->selected_entry < 0) + list->selected_entry = list->entries_count - 1; + else + list->selected_entry %= list->entries_count; } int main(void) { srand(time(NULL)); - bool homebrew = init_services(); + init_services(); init_screens(); - - themes_list = NULL; - theme_count = 0; - Result res = get_themes(&themes_list, &theme_count); - if (R_FAILED(res)) - { - //don't need to worry about possible textures (icons, previews), that's freed by pp2d itself - free(themes_list); - themes_list = NULL; - } - splash_count = 0; - splashes_list = NULL; - res = get_splashes(&splashes_list, &splash_count); - if (R_FAILED(res)) - { - //don't need to worry about possible textures (icons, previews), that's freed by pp2d itself - free(splashes_list); - splashes_list = NULL; - } - splash_mode = false; - int selected_splash = 0; - int selected_theme = 0; - int previously_selected = 0; - shuffle_theme_count = 0; + Entry_List_s lists[MODE_AMOUNT] = {0}; + + for(int i = 0; i < MODE_AMOUNT; i++) + load_entries(main_paths[i], &lists[i]); + + EntryMode current_mode = MODE_THEMES; + bool preview_mode = false; - + int preview_offset = 0; + + bool qr_mode = false; + while(aptMainLoop()) { hidScanInput(); u32 kDown = hidKeysDown(); u32 kHeld = hidKeysHeld(); - - if (qr_mode) + + Entry_List_s * current_list = &lists[current_mode]; + + if(qr_mode) take_picture(); + else if(preview_mode) draw_preview(preview_offset); + else draw_interface(current_list, current_mode); + pp2d_end_draw(); + + if(kDown & KEY_START) break; + + if(R_FAILED(archive_result) && current_mode == MODE_THEMES) { - take_picture(); - } else if (!splash_mode) - { - draw_theme_interface(themes_list, theme_count, selected_theme, preview_mode, shuffle_theme_count); - } else { - draw_splash_interface(splashes_list, splash_count, selected_splash, preview_mode); - } - - if (kDown & KEY_START) - { - if (homebrew) - APT_HardwareResetAsync(); - else { - srvPublishToSubscriber(0x202, 0); - } - } - else if (kDown & KEY_L) - { - splash_mode = !splash_mode; - } - - if (R_FAILED(archive_result) && !splash_mode) - { - throw_error("Theme extdata does not exist\nSet a default theme from the home menu", ERROR); + throw_error("Theme extdata does not exist!\nSet a default theme from the home menu.", ERROR_LEVEL_ERROR); continue; } - - if (kDown & KEY_R) + + if(!preview_mode && !qr_mode && kDown & KEY_L) //toggle between splashes and themes { - if (preview_mode) { - continue; - } else { - u32 out; - ACU_GetWifiStatus(&out); - if (out) - { - qr_mode = !qr_mode; - if (qr_mode) init_qr(); - else exit_qr(); - continue; - } else { - throw_error("Please connect to Wi-Fi before scanning QR", WARNING); - continue; - } - } + current_mode++; + current_mode %= MODE_AMOUNT; + continue; } - - if (qr_mode) continue; - - if (themes_list == NULL && !splash_mode) - continue; - - if (splashes_list == NULL && splash_mode) - continue; - - Theme_s * current_theme = &themes_list[selected_theme]; - Splash_s *current_splash = &splashes_list[selected_splash]; - - if (kDown & KEY_Y) + else if(!preview_mode && kDown & KEY_R) //toggle QR mode { - if (!preview_mode) + u32 out; + ACU_GetWifiStatus(&out); + if(out) { - if (!splash_mode) - { - if (!current_theme->has_preview) - load_theme_preview(current_theme); - - preview_mode = current_theme->has_preview; - } else { - load_splash_preview(current_splash); - preview_mode = true; - } + qr_mode = !qr_mode; + if(qr_mode) + init_qr(); + else + exit_qr(); } else - preview_mode = false; - } - - //don't allow anything while the preview is up - if (preview_mode) + { + throw_error("Please connect to Wi-Fi before scanning QR", ERROR_LEVEL_WARNING); + } continue; - + } + else if(!qr_mode && kDown & KEY_Y) //toggle preview mode + { + if(!preview_mode) + { + preview_mode = load_preview(*current_list, &preview_offset); + } + else + { + preview_mode = false; + } + continue; + } + else if(qr_mode && kDown & KEY_L) //scan a QR code while in QR mode + { + CAMU_StopCapture(PORT_BOTH); + CAMU_Activate(SELECT_NONE); + qr_mode = !scan_qr(current_mode); + CAMU_Activate(SELECT_OUT1_OUT2); + CAMU_StartCapture(PORT_BOTH); + + if(!qr_mode) + { + free(current_list->entries); + memset(current_list, 0, sizeof(Entry_List_s)); + load_entries(main_paths[current_mode], current_list); + } + continue; + } + + if(qr_mode || preview_mode || current_list->entries == NULL) + continue; + + int selected_entry = current_list->selected_entry; + Entry_s * current_entry = ¤t_list->entries[selected_entry]; + // Actions - else if (kDown & KEY_X) + if(kDown & KEY_X) { - if (splash_mode) { - draw_splash_install(UNINSTALL); - splash_delete(); - } else { - draw_theme_install(BGM_INSTALL); - bgm_install(*current_theme); + switch(current_mode) + { + case MODE_THEMES: + draw_install(INSTALL_BGM); + bgm_install(*current_entry); + break; + case MODE_SPLASHES: + break; + default: + break; } } - else if (kDown & KEY_A) + else if(kDown & KEY_A) { - if (splash_mode) + switch(current_mode) { - draw_splash_install(SINGLE_INSTALL); - splash_install(*current_splash); - svcSleepThread(5e8); - } else { - draw_theme_install(SINGLE_INSTALL); - single_install(*current_theme); + case MODE_THEMES: + draw_install(INSTALL_SINGLE); + theme_install(*current_entry); + break; + case MODE_SPLASHES: + draw_install(INSTALL_SPLASH); + splash_install(*current_entry); + break; + default: + break; } - //these are here just so I don't forget how to implement them - HM - //if (current_theme->in_shuffle) { - // shuffle_theme_count--; - // current_theme->in_shuffle = false; - //} - //del_theme(current_theme->path); - //get_themes(&themes_list, &theme_count); } - - else if (kDown & KEY_B) + else if(kDown & KEY_B) { - if (splash_mode) + switch(current_mode) { - - } else { - if (shuffle_theme_count < 10) - { - if (current_theme->in_shuffle) shuffle_theme_count--; - else shuffle_theme_count++; - current_theme->in_shuffle = !(current_theme->in_shuffle); - } else { - if (current_theme->in_shuffle) { - shuffle_theme_count--; - current_theme->in_shuffle = false; - } - } + case MODE_THEMES: + if(current_entry->in_shuffle) current_list->shuffle_count--; + else current_list->shuffle_count++; + current_entry->in_shuffle = !current_entry->in_shuffle; + break; + case MODE_SPLASHES: + draw_install(INSTALL_SPLASH_DELETE); + splash_delete(); + default: + break; } } - else if (kDown & KEY_SELECT) + else if(kDown & KEY_SELECT) { - if (splash_mode) + switch(current_mode) { - - } else { - if (shuffle_theme_count > 0) - { - draw_theme_install(SHUFFLE_INSTALL); - shuffle_install(themes_list, theme_count); - shuffle_theme_count = 0; - } - else { - throw_error("You dont have any Shuffle selected.", WARNING); - } + case MODE_THEMES: + if(current_list->shuffle_count > 0) + { + draw_install(INSTALL_SHUFFLE); + shuffle_install(current_list->entries, current_list->entries_count); + current_list->shuffle_count = 0; + } + else + { + throw_error("You dont have any Shuffle selected.", ERROR_LEVEL_WARNING); + } + break; + default: + break; } } // Movement in the UI - else if (kDown & KEY_DOWN) + else if(kDown & KEY_UP) { - if (splash_mode) - { - selected_splash++; - if (selected_splash >= splash_count) - selected_splash = 0; - } else { - selected_theme++; - if (selected_theme >= theme_count) - selected_theme = 0; - } + change_selected(current_list, -1); } - else if (kDown & KEY_UP) + else if(kDown & KEY_DOWN) { - if (splash_mode) - { - selected_splash--; - if (selected_splash < 0) - selected_splash = splash_count - 1; - } else { - selected_theme--; - if (selected_theme < 0) - selected_theme = theme_count - 1; - } + change_selected(current_list, 1); } // Quick moving - else if (kDown & KEY_LEFT) + else if(kDown & KEY_LEFT) { - if (splash_mode) - { - selected_splash -= 4; - if (selected_splash < 0) selected_splash = 0; - } else { - selected_theme -= 4; - if (selected_theme < 0) selected_theme = 0; - } + change_selected(current_list, -ENTRIES_PER_SCREEN); } - else if (kDown & KEY_RIGHT) + else if(kDown & KEY_RIGHT) { - if (splash_mode) - { - selected_splash += 4; - if (selected_splash >= splash_count) selected_splash = splash_count-1; - } else { - selected_theme += 4; - if (selected_theme >= theme_count) selected_theme = theme_count-1; - } + change_selected(current_list, ENTRIES_PER_SCREEN); } + // Fast scroll using circle pad - else if (kHeld & KEY_CPAD_UP) + else if(kHeld & KEY_CPAD_UP) { - svcSleepThread(100000000); - - if (splash_mode) - { - selected_splash--; - if (selected_splash < 0) - selected_splash = splash_count - 1; - } else { - selected_theme--; - if (selected_theme < 0) - selected_theme = theme_count - 1; - } + change_selected(current_list, -1); } - else if (kHeld & KEY_CPAD_DOWN) + else if(kHeld & KEY_CPAD_DOWN) { - svcSleepThread(100000000); - - if (splash_mode) - { - selected_splash++; - if (selected_splash >= splash_count) - selected_splash = 0; - } else { - selected_theme++; - if (selected_theme >= theme_count) - selected_theme = 0; - } + change_selected(current_list, 1); } - else if (kDown & KEY_CPAD_LEFT) + else if(kDown & KEY_CPAD_LEFT) { - svcSleepThread(100000000); - - if (splash_mode) - { - selected_splash -= 4; - if (selected_splash < 0) selected_splash = 0; - } else { - selected_theme -= 4; - if (selected_theme < 0) selected_theme = 0; - } + change_selected(current_list, -ENTRIES_PER_SCREEN); } - else if (kDown & KEY_CPAD_RIGHT) + else if(kDown & KEY_CPAD_RIGHT) { - svcSleepThread(100000000); - - if (splash_mode) - { - selected_splash += 4; - if (selected_splash >= splash_count) selected_splash = splash_count-1; - } else { - selected_theme += 4; - if (selected_theme >= theme_count) selected_theme = theme_count-1; - } - } - - if (!splash_mode && selected_theme != previously_selected) - { - current_theme->has_preview = false; - previously_selected = selected_theme; + change_selected(current_list, ENTRIES_PER_SCREEN); } } - exit_screens(); - exit_services(); + + exit_function(); return 0; } diff --git a/source/splashes.c b/source/splashes.c index 20abe6e..0782287 100644 --- a/source/splashes.c +++ b/source/splashes.c @@ -26,254 +26,34 @@ #include "splashes.h" #include "unicode.h" #include "fs.h" -#include "themes.h" -#include "pp2d/pp2d/pp2d.h" #include "draw.h" -void load_splash_preview(Splash_s *splash) -{ - //free the previously loaded preview. wont do anything if there wasnt one - pp2d_free_texture(TEXTURE_PREVIEW); - - char *preview_buffer = NULL; - u64 size = 0; - if (!(splash->is_zip)) - { - u16 path_to_preview[0x106] = {0}; - strucat(path_to_preview, splash->path); - struacat(path_to_preview, "/preview.png"); - size = file_to_buf(fsMakePath(PATH_UTF16, path_to_preview), ArchiveSD, &preview_buffer); - } else { - size = zip_file_to_buf("preview.png", splash->path, &preview_buffer); - } - - if (!size) - { - free(preview_buffer); - return; - } - - u8 * image = NULL; - unsigned int width = 0, height = 0; - - if ((lodepng_decode32(&image, &width, &height, (u8*)preview_buffer, size)) == 0) // no error - { - for (u32 i = 0; i < width; i++) - { - for (u32 j = 0; j < height; j++) - { - u32 p = (i + j*width) * 4; - - u8 r = *(u8*)(image + p); - u8 g = *(u8*)(image + p + 1); - u8 b = *(u8*)(image + p + 2); - u8 a = *(u8*)(image + p + 3); - - *(image + p) = a; - *(image + p + 1) = b; - *(image + p + 2) = g; - *(image + p + 3) = r; - } - } - - pp2d_load_texture_memory(TEXTURE_PREVIEW, image, (u32)width, (u32)height); - } - - free(image); - free(preview_buffer); -} - - -static void parse_smdh(Splash_s *splash, ssize_t textureID, u16 *splash_name) -{ - char *info_buffer = NULL; - u64 size = 0; - if (!(splash->is_zip)) - { - u16 path_to_smdh[0x106] = {0}; - strucat(path_to_smdh, splash->path); - struacat(path_to_smdh, "/info.smdh"); - - size = file_to_buf(fsMakePath(PATH_UTF16, path_to_smdh), ArchiveSD, &info_buffer); - } else { - size = zip_file_to_buf("info.smdh", splash->path, &info_buffer); - } - - if (!size) - { - free(info_buffer); - memset(splash->name, 0, 0x80); - memset(splash->desc, 0, 0x100); - memset(splash->author, 0, 0x80); - memcpy(splash->name, splash_name, 0x80); - utf8_to_utf16(splash->desc, (u8*)"No description", 0x100); - utf8_to_utf16(splash->author, (u8*)"Unknown author", 0x80); - splash->placeholder_color = RGBA8(rand() % 255, rand() % 255, rand() % 255, 255); - return; - } - - memcpy(splash->name, info_buffer + 0x08, 0x80); - memcpy(splash->desc, info_buffer + 0x88, 0x100); - memcpy(splash->author, info_buffer + 0x188, 0x80); - - u16 *icon_data = malloc(0x1200); - memcpy(icon_data, info_buffer + 0x24C0, 0x1200); - - const u32 width = 48, height = 48; - u32 *image = malloc(width*height*sizeof(u32)); - - for (u32 x = 0; x < width; x++) - { - for (u32 y = 0; y < height; y++) - { - unsigned int dest_pixel = (x + y*width); - unsigned int source_pixel = (((y >> 3) * (width >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3)); - - u8 r = ((icon_data[source_pixel] >> 11) & 0b11111) << 3; - u8 g = ((icon_data[source_pixel] >> 5) & 0b111111) << 2; - u8 b = (icon_data[source_pixel] & 0b11111) << 3; - u8 a = 0xFF; - - image[dest_pixel] = (r << 24) | (g << 16) | (b << 8) | a; - } - } - - pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height); - splash->icon_id = textureID; - - free(image); - free(icon_data); - free(info_buffer); -} - -Result get_splashes(Splash_s** splashes_list, int *splash_count) -{ - Result res = 0; - Handle dir_handle; - - if (R_FAILED(res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, SPLASHES_PATH)))) - return res; - - if (*splashes_list != NULL) - { - free(*splashes_list); - *splashes_list = NULL; - *splash_count = 0; - } - - u32 entries_read = 1; - while (entries_read) - { - FS_DirectoryEntry entry = {0}; - if (R_FAILED(res = FSDIR_Read(dir_handle, &entries_read, 1, &entry)) || entries_read == 0) - break; - - if (!(entry.attributes & FS_ATTRIBUTE_DIRECTORY) && strcmp(entry.shortExt, "ZIP")) - continue; - - *splash_count += entries_read; - *splashes_list= realloc(*splashes_list, (*splash_count) * sizeof(Splash_s)); - if (splashes_list == NULL) - break; - - Splash_s *current_splash = &(*splashes_list)[*splash_count-1]; - memset(current_splash, 0, sizeof(Splash_s)); - - u16 splash_path[0x106]= {0}; - struacat(splash_path, SPLASHES_PATH); - strucat(splash_path, entry.name); - - char pathchar[0x106] = {0}; - utf16_to_utf8((u8*) pathchar, splash_path, 0x106); - - memcpy(current_splash->path, splash_path, 0x106 * sizeof(u16)); - current_splash->is_zip = !strcmp(entry.shortExt, "ZIP"); - - ssize_t iconID = TEXTURE_PREVIEW + theme_count + *splash_count; - parse_smdh(current_splash, iconID, entry.name); - } - - FSDIR_Close(dir_handle); - - qsort(*splashes_list, (long)*splash_count, sizeof(Splash_s), splashcmp); - - return res; -} - -int splashcmp(const void* a, const void* b) //essentially a memcmp alias, so that it can be used properly with qsort -{ - Splash_s *splash_a = (Splash_s *)a; - Splash_s *splash_b = (Splash_s *)b; - - return memcmp(splash_a, splash_b, 0x40*sizeof(u16)); -} - -void splash_delete() +void splash_delete(void) { remove("/luma/splash.bin"); remove("/luma/splashbottom.bin"); } -void splash_install(Splash_s splash_to_install) +void splash_install(Entry_s splash) { char *screen_buf = NULL; - u32 size = 0; - if (splash_to_install.is_zip) - { - size = zip_file_to_buf("splash.bin", splash_to_install.path, &screen_buf); - if (size) - { - remake_file("/luma/splash.bin", ArchiveSD, sizeof(screen_buf)); - buf_to_file(size, "/luma/splash.bin", ArchiveSD, screen_buf); - free(screen_buf); - screen_buf = NULL; - size = 0; - } - size = zip_file_to_buf("splashbottom.bin", splash_to_install.path, &screen_buf); - if (size) - { - remake_file("/luma/splashbottom.bin", ArchiveSD, sizeof(screen_buf)); - buf_to_file(size, "/luma/splashbottom.bin", ArchiveSD, screen_buf); - free(screen_buf); - screen_buf = NULL; - size = 0; - } - } else { - u16 path[0x106] = {0}; - memcpy(path, splash_to_install.path, 0x106 * sizeof(u16)); - struacat(path, "/splash.bin"); - size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &screen_buf); - if (size) - { - remake_file("/luma/splash.bin", ArchiveSD, sizeof(screen_buf)); - buf_to_file(size, "/luma/splash.bin", ArchiveSD, screen_buf); - free(screen_buf); - screen_buf = NULL; - size = 0; - } + u32 size = load_data("/splash.bin", splash, &screen_buf); + remake_file("/luma/splash.bin", ArchiveSD, size); + buf_to_file(size, "/luma/splash.bin", ArchiveSD, screen_buf); - memcpy(path, splash_to_install.path, 0x106 * sizeof(u16)); - struacat(path, "/splashbottom.bin"); - size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &screen_buf); - if (size) - { - remake_file("/luma/splashbottom.bin", ArchiveSD, sizeof(screen_buf)); - buf_to_file(size, "/luma/splashbottom.bin", ArchiveSD, screen_buf); - free(screen_buf); - screen_buf = NULL; - size = 0; - } - } + size = load_data("/splashbottom.bin", splash, &screen_buf); + remake_file("/luma/splashbottom.bin", ArchiveSD, size); + buf_to_file(size, "/luma/splashbottom.bin", ArchiveSD, screen_buf); char *config_buf; size = file_to_buf(fsMakePath(PATH_ASCII, "/luma/config.bin"), ArchiveSD, &config_buf); - if (size) + if(size) { - if (config_buf[0xC] == 0) + if(config_buf[0xC] == 0) { free(config_buf); - throw_error("WARNING: Splashes are disabled in Luma Config", WARNING); + throw_error("WARNING: Splashes are disabled in Luma Config", ERROR_LEVEL_WARNING); } } } \ No newline at end of file diff --git a/source/themes.c b/source/themes.c index e2f9094..49b3401 100644 --- a/source/themes.c +++ b/source/themes.c @@ -27,209 +27,25 @@ #include "themes.h" #include "unicode.h" #include "fs.h" -#include +#include "draw.h" -#include "pp2d/pp2d/pp2d.h" -#include "pp2d/pp2d/lodepng.h" +#define BGM_MAX_SIZE 3371008 -void load_theme_preview(Theme_s *theme) -{ - //free the previously loaded preview. wont do anything if there wasnt one - pp2d_free_texture(TEXTURE_PREVIEW); - - char *preview_buffer = NULL; - u64 size = 0; - if (!(theme->is_zip)) - { - u16 path_to_preview[0x106] = {0}; - strucat(path_to_preview, theme->path); - struacat(path_to_preview, "/preview.png"); - size = file_to_buf(fsMakePath(PATH_UTF16, path_to_preview), ArchiveSD, &preview_buffer); - } else { - size = zip_file_to_buf("preview.png", theme->path, &preview_buffer); - } - - if (!size) - { - free(preview_buffer); - return; - } - - u8 * image = NULL; - unsigned int width = 0, height = 0; - - int result = lodepng_decode32(&image, &width, &height, (u8*)preview_buffer, size); - if (result == 0) // no error - { - for (u32 i = 0; i < width; i++) - { - for (u32 j = 0; j < height; j++) - { - u32 p = (i + j*width) * 4; - - u8 r = *(u8*)(image + p); - u8 g = *(u8*)(image + p + 1); - u8 b = *(u8*)(image + p + 2); - u8 a = *(u8*)(image + p + 3); - - *(image + p) = a; - *(image + p + 1) = b; - *(image + p + 2) = g; - *(image + p + 3) = r; - } - } - - theme->has_preview = true; - pp2d_load_texture_memory(TEXTURE_PREVIEW, image, (u32)width, (u32)height); - theme->preview_offset = (width-400)/2; - } - - free(image); - free(preview_buffer); -} - -static void parse_smdh(Theme_s *theme, ssize_t textureID, u16 *dir_name) -{ - char *info_buffer = NULL; - u64 size = 0; - if (!(theme->is_zip)) - { - u16 path_to_smdh[0x106] = {0}; - strucat(path_to_smdh, theme->path); - struacat(path_to_smdh, "/info.smdh"); - - size = file_to_buf(fsMakePath(PATH_UTF16, path_to_smdh), ArchiveSD, &info_buffer); - } else { - size = zip_file_to_buf("info.smdh", theme->path, &info_buffer); - } - - if (!size) - { - free(info_buffer); - memset(theme->name, 0, 0x80); - memset(theme->desc, 0, 0x100); - memset(theme->author, 0, 0x80); - memcpy(theme->name, dir_name, 0x80); - utf8_to_utf16(theme->desc, (u8*)"No description", 0x100); - utf8_to_utf16(theme->author, (u8*)"Unknown author", 0x80); - theme->placeholder_color = RGBA8(rand() % 255, rand() % 255, rand() % 255, 255); - return; - } - - memcpy(theme->name, info_buffer + 0x08, 0x80); - memcpy(theme->desc, info_buffer + 0x88, 0x100); - memcpy(theme->author, info_buffer + 0x188, 0x80); - - u16 *icon_data = malloc(0x1200); - memcpy(icon_data, info_buffer + 0x24C0, 0x1200); - - const u32 width = 48, height = 48; - u32 *image = malloc(width*height*sizeof(u32)); - - for (u32 x = 0; x < width; x++) - { - for (u32 y = 0; y < height; y++) - { - unsigned int dest_pixel = (x + y*width); - unsigned int source_pixel = (((y >> 3) * (width >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3)); - - u8 r = ((icon_data[source_pixel] >> 11) & 0b11111) << 3; - u8 g = ((icon_data[source_pixel] >> 5) & 0b111111) << 2; - u8 b = (icon_data[source_pixel] & 0b11111) << 3; - u8 a = 0xFF; - - image[dest_pixel] = (r << 24) | (g << 16) | (b << 8) | a; - } - } - - pp2d_load_texture_memory(textureID, (u8*)image, (u32)width, (u32)height); - theme->icon_id = textureID; - - free(image); - free(icon_data); - free(info_buffer); -} - -Result get_themes(Theme_s **themes_list, int *theme_count) -{ - shuffle_theme_count = 0; - Result res = 0; - Handle dir_handle; - res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, THEMES_PATH)); - if (R_FAILED(res)) - return res; - - if (*themes_list != NULL) //used for QR reading and also for theme deletion - { - free(*themes_list); - *themes_list = NULL; - *theme_count = 0; - } - - u32 entries_read = 1; - - while (entries_read) - { - FS_DirectoryEntry entry = {0}; - res = FSDIR_Read(dir_handle, &entries_read, 1, &entry); - if (R_FAILED(res) || entries_read == 0) - break; - - if (!(entry.attributes & FS_ATTRIBUTE_DIRECTORY) && strcmp(entry.shortExt, "ZIP")) - continue; - - *theme_count += entries_read; - *themes_list = realloc(*themes_list, (*theme_count) * sizeof(Theme_s)); - if (*themes_list == NULL) - break; - - Theme_s* current_theme = &(*themes_list)[*theme_count-1]; - memset(current_theme, 0, sizeof(Theme_s)); - - u16 theme_path[0x106] = {0}; - struacat(theme_path, THEMES_PATH); - strucat(theme_path, entry.name); - - char pathchar[0x106] = {0}; - utf16_to_utf8((u8*)pathchar, theme_path, 0x106); - - memcpy(current_theme->path, theme_path, 0x106 * sizeof(u16)); - current_theme->is_zip = !strcmp(entry.shortExt, "ZIP"); - - ssize_t iconID = TEXTURE_PREVIEW + *theme_count; - parse_smdh(current_theme, iconID, entry.name); - } - - FSDIR_Close(dir_handle); - - qsort(*themes_list, (long)*theme_count, sizeof(Theme_s), themecmp); //alphabet sort - - return res; -} - -int themecmp(const void* a, const void* b) //essentially a memcmp alias, so that it can be used properly with qsort -{ - Theme_s *theme_a = (Theme_s *)a; - Theme_s *theme_b = (Theme_s *)b; - - return memcmp(theme_a, theme_b, 0x40*sizeof(u16)); -} - -void del_theme(u16 *path) +void delete_theme(Entry_s theme) { Handle dir_handle; - Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_UTF16, path)); - if (R_SUCCEEDED(res)) + Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_UTF16, theme.path)); + if(R_SUCCEEDED(res)) { FSDIR_Close(dir_handle); - FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, path)); + FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, theme.path)); } else { - FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, path)); + FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, theme.path)); } } -Result bgm_install(Theme_s bgm_to_install) +Result bgm_install(Entry_s bgm_to_install) { char *savedata_buf; char *thememanage_buf; @@ -245,31 +61,23 @@ Result bgm_install(Theme_s bgm_to_install) Result result = buf_to_file(savedata_size, "/SaveData.dat", ArchiveHomeExt, savedata_buf); free(savedata_buf); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; - if (bgm_to_install.is_zip) // Same as above but this time with bgm - { - music_size = zip_file_to_buf("bgm.bcstm", bgm_to_install.path, &music); - } else { - u16 path[0x106] = {0}; - memcpy(path, bgm_to_install.path, 0x106 * sizeof(u16)); - struacat(path, "/bgm.bcstm"); - music_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &music); - } + music_size = load_data("/bgm.bcstm", bgm_to_install, &music); - if (music_size == 0) + if(music_size == 0) { - music = calloc(1, 3371008); - } else if (music_size > 3371008) { + music = calloc(1, BGM_MAX_SIZE); + } else if(music_size > BGM_MAX_SIZE) { free(music); puts("musicrip"); return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE); } - result = buf_to_file(music_size == 0 ? 3371008 : music_size, "/BgmCache.bin", ArchiveThemeExt, music); + result = buf_to_file(music_size == 0 ? BGM_MAX_SIZE : music_size, "/BgmCache.bin", ArchiveThemeExt, music); free(music); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf); thememanage_buf[0x00] = 1; @@ -296,23 +104,24 @@ Result bgm_install(Theme_s bgm_to_install) result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf); free(thememanage_buf); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; return 0; } // Install a single theme -Result single_install(Theme_s theme_to_install) +Result theme_install(Entry_s theme) { - char *body; - char *music; - char *savedata_buf; - char *thememanage_buf; - u32 body_size; - u32 music_size; - u32 savedata_size; + char *body = NULL; + char *music = NULL; + char *savedata_buf = NULL; + char *thememanage_buf = NULL; + u32 body_size = 0; + u32 music_size = 0; + u32 savedata_size = 0; savedata_size = file_to_buf(fsMakePath(PATH_ASCII, "/SaveData.dat"), ArchiveHomeExt, &savedata_buf); + DEBUGPOS("savedata: %p, %lx\n", savedata_buf, savedata_size); savedata_buf[0x141b] = 0; memset(&savedata_buf[0x13b8], 0, 8); savedata_buf[0x13bd] = 3; @@ -320,56 +129,38 @@ Result single_install(Theme_s theme_to_install) Result result = buf_to_file(savedata_size, "/SaveData.dat", ArchiveHomeExt, savedata_buf); free(savedata_buf); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; - // Open body cache file. Test if theme is zipped - if (theme_to_install.is_zip) - { - body_size = zip_file_to_buf("body_LZ.bin", theme_to_install.path, &body); - } - else - { - u16 path[0x106] = {0}; - memcpy(path, theme_to_install.path, 0x106 * sizeof(u16)); - struacat(path, "/body_lz.bin"); - body_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &body); - } + // Open body cache file. + body_size = load_data("/body_LZ.bin", theme, &body); - if (body_size == 0) + if(body_size == 0) { free(body); - puts("bodyrip"); + DEBUGPOS("bodyrip"); return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_NOT_FOUND); } result = buf_to_file(body_size, "/BodyCache.bin", ArchiveThemeExt, body); // Write body data to file free(body); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; - if (theme_to_install.is_zip) // Same as above but this time with bgm - { - music_size = zip_file_to_buf("bgm.bcstm", theme_to_install.path, &music); - } else { - u16 path[0x106] = {0}; - memcpy(path, theme_to_install.path, 0x106 * sizeof(u16)); - struacat(path, "/bgm.bcstm"); - music_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &music); - } + music_size = load_data("/bgm.bcstm", theme, &music); - if (music_size == 0) + if(music_size == 0) { - music = calloc(1, 3371008); - } else if (music_size > 3371008) { + music = calloc(1, BGM_MAX_SIZE); + } else if(music_size > BGM_MAX_SIZE) { free(music); - puts("musicrip"); + DEBUGPOS("musicrip"); return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE); } - result = buf_to_file(music_size == 0 ? 3371008 : music_size, "/BgmCache.bin", ArchiveThemeExt, music); + result = buf_to_file(music_size == 0 ? BGM_MAX_SIZE : music_size, "/BgmCache.bin", ArchiveThemeExt, music); free(music); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf); thememanage_buf[0x00] = 1; @@ -398,18 +189,18 @@ Result single_install(Theme_s theme_to_install) result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf); free(thememanage_buf); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; return 0; } -Result shuffle_install(Theme_s *themes_list, int theme_count) +Result shuffle_install(Entry_s* themes_list, int themes_count) { u8 count = 0; - Theme_s *shuffle_themes[10] = {0}; + Entry_s *shuffle_themes[10] = {0}; u32 body_sizes[10] = {0}; u32 bgm_sizes[10] = {0}; - for (int i = 0; i < theme_count; i++) + for (int i = 0; i < themes_count; i++) { if (count > 10) return MAKERESULT(RL_USAGE, RS_INVALIDARG, RM_COMMON, RD_INVALID_SELECTION); if (themes_list[i].in_shuffle) @@ -435,10 +226,10 @@ Result shuffle_install(Theme_s *themes_list, int theme_count) savedata_buf[0x13bd] = 3; savedata_buf[0x13b8] = 0xff; - for (int i = 0; i < 10; i++) + for(int i = 0; i < 10; i++) { memset(&savedata_buf[0x13c0 + 0x8 * i], 0, 8); // clear any existing theme structure. 8 is the length of the theme structure, so 8 * i is the pos of the current one - if (count > i) // if we are still installing themes... + if(count > i) // if we are still installing themes... { savedata_buf[0x13c0 + (8 * i)] = i; // index savedata_buf[0x13c0 + (8 * i) + 5] = 3; // persistence (?) @@ -448,61 +239,39 @@ Result shuffle_install(Theme_s *themes_list, int theme_count) Result result = buf_to_file(size, "/SaveData.dat", ArchiveHomeExt, savedata_buf); free(savedata_buf); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; remake_file("/BodyCache_rd.bin", ArchiveThemeExt, 0x150000 * 10); // Enough space for 10 theme files Handle body_cache_handle; FSUSER_OpenFile(&body_cache_handle, ArchiveThemeExt, fsMakePath(PATH_ASCII, "/BodyCache_rd.bin"), FS_OPEN_WRITE, 0); - for (int i = 0; i < 10; i++) + for(int i = 0; i < count; i++) { - if (count > i) - { - if (shuffle_themes[i]->is_zip) - { - char *body_buf; - u32 body_size = zip_file_to_buf("body_LZ.bin", shuffle_themes[i]->path, &body_buf); - body_sizes[i] = body_size; - FSFILE_Write(body_cache_handle, NULL, 0x150000 * i, body_buf, body_size, FS_WRITE_FLUSH); - free(body_buf); - } else { - u16 path[0x106] = {0}; - strucat(path, shuffle_themes[i]->path); - struacat(path, "/body_LZ.bin"); - char *body_buf; - u32 body_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &body_buf); - body_sizes[i] = body_size; - FSFILE_Write(body_cache_handle, NULL, 0x150000 * i, body_buf, body_size, FS_WRITE_FLUSH); - free(body_buf); - } - } + Entry_s * current_theme = shuffle_themes[i]; + char * body_buf = NULL; + u32 body_size = load_data("/body_LZ.bin", *current_theme, &body_buf); + + body_sizes[i] = body_size; + FSFILE_Write(body_cache_handle, NULL, 0x150000 * i, body_buf, body_size, FS_WRITE_FLUSH); + free(body_buf); } FSFILE_Close(body_cache_handle); - for (int i = 0; i < 10; i++) + for(int i = 0; i < 10; i++) { char bgm_cache_path[17] = {0}; sprintf(bgm_cache_path, "/BgmCache_%.2i.bin", i); - remake_file(bgm_cache_path, ArchiveThemeExt, 3371008); - if (count > i) + remake_file(bgm_cache_path, ArchiveThemeExt, BGM_MAX_SIZE); + if(count > i) { - char *music_buf; - u32 music_size; + Entry_s * current_theme = shuffle_themes[i]; + char *music_buf = NULL; + u32 music_size = music_size = load_data("/bgm.bcstm", *current_theme, &music_buf); - if (shuffle_themes[i]->is_zip) + if(!music_size) { - music_size = zip_file_to_buf("bgm.bcstm", shuffle_themes[i]->path, &music_buf); - } else { - u16 path[0x106] = {0}; - strucat(path, shuffle_themes[i]->path); - struacat(path, "/bgm.bcstm"); - music_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &music_buf); - } - - if (!music_size) - { - char *empty = calloc(1, 3371008); - buf_to_file(3371008, bgm_cache_path, ArchiveThemeExt, empty); + char *empty = calloc(1, BGM_MAX_SIZE); + buf_to_file(BGM_MAX_SIZE, bgm_cache_path, ArchiveThemeExt, empty); bgm_sizes[i] = 0; free(empty); continue; @@ -511,8 +280,8 @@ Result shuffle_install(Theme_s *themes_list, int theme_count) buf_to_file(music_size, bgm_cache_path, ArchiveThemeExt, music_buf); free(music_buf); } else { - char *empty = calloc(1, 3371008); - buf_to_file(3371008, bgm_cache_path, ArchiveThemeExt, empty); + char *empty = calloc(1, BGM_MAX_SIZE); + buf_to_file(BGM_MAX_SIZE, bgm_cache_path, ArchiveThemeExt, empty); bgm_sizes[i] = 0; free(empty); } @@ -538,7 +307,7 @@ Result shuffle_install(Theme_s *themes_list, int theme_count) *bodysizeloc = (u32) 0; *bgmsizeloc = (u32) 0; - for (int i = 0; i < 10; i++) + for(int i = 0; i < 10; i++) { bodysizeloc = (u32*) (&thememanage_buf[0x338 + (4 * i)]); // body size info for shuffle themes starts at 0x338 and is 4 bytes for each theme bgmsizeloc = (u32*) (&thememanage_buf[0x360 + (4 * i)]); // same thing for bgm but starting at 0x360 @@ -549,7 +318,7 @@ Result shuffle_install(Theme_s *themes_list, int theme_count) result = buf_to_file(0x800, "/ThemeManage.bin", ArchiveThemeExt, thememanage_buf); free(thememanage_buf); - if (!R_SUCCEEDED(result)) return result; + if(R_FAILED(result)) return result; return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_COMMON, RD_SUCCESS); }