diff --git a/include/camera.h b/include/camera.h index 912da53..7f0e44b 100644 --- a/include/camera.h +++ b/include/camera.h @@ -30,7 +30,7 @@ #include "common.h" typedef struct { - u16* camera_buffer; + u16 * camera_buffer; Handle event_stop; Thread cam_thread, ui_thread; @@ -45,7 +45,7 @@ typedef struct { bool any_update; - struct quirc* context; + struct quirc * context; } qr_data; bool init_qr(void); diff --git a/include/common.h b/include/common.h index c820376..9e1abcc 100644 --- a/include/common.h +++ b/include/common.h @@ -38,9 +38,19 @@ #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define POS() DEBUG("%s (line %d)...\n", __func__, __LINE__) -#define DEBUGPOS(...) \ +#define DEBUGPOS(...) do {\ POS(); \ - DEBUG(__VA_ARGS__) + DEBUG(__VA_ARGS__); \ + } while(0) + +static inline int min(const int a, const int b) +{ + return a > b ? b : a; +} +static inline int max(const int a, const int b) +{ + return a < b ? b : a; +} #define FASTSCROLL_WAIT 1e8 diff --git a/include/draw.h b/include/draw.h index 5d18c66..2c02c96 100644 --- a/include/draw.h +++ b/include/draw.h @@ -33,7 +33,7 @@ #define MAX_LINES 10 -typedef enum { +typedef enum InstallType_e { INSTALL_LOADING_THEMES, INSTALL_LOADING_SPLASHES, INSTALL_LOADING_ICONS, @@ -149,8 +149,8 @@ typedef struct { const char * instructions[BUTTONS_INFO_LINES][BUTTONS_INFO_COLUNMNS]; } Instructions_s; -extern C3D_RenderTarget* top; -extern C3D_RenderTarget* bottom; +extern C3D_RenderTarget * top; +extern C3D_RenderTarget * bottom; extern C2D_TextBuf staticBuf, dynamicBuf; extern C2D_Text text[TEXT_AMOUNT]; @@ -162,8 +162,8 @@ void start_frame(void); void end_frame(void); void set_screen(C3D_RenderTarget * screen); -void throw_error(const char* error, ErrorLevel level); -bool draw_confirm(const char* conf_msg, Entry_List_s* list); +void throw_error(const char * error, ErrorLevel level); +bool draw_confirm(const char * conf_msg, Entry_List_s * list); void draw_preview(C2D_Image preview, int preview_offset); @@ -177,7 +177,7 @@ void draw_text_center(gfxScreen_t target, float y, float z, float scaleX, float void draw_home(u64 start_time, u64 cur_time); void draw_base_interface(void); -void draw_grid_interface(Entry_List_s* list, Instructions_s instructions); -void draw_interface(Entry_List_s* list, Instructions_s instructions); +void draw_grid_interface(Entry_List_s * list, Instructions_s instructions); +void draw_interface(Entry_List_s * list, Instructions_s instructions); #endif diff --git a/include/entries_list.h b/include/entries_list.h new file mode 100644 index 0000000..9778030 --- /dev/null +++ b/include/entries_list.h @@ -0,0 +1,106 @@ +/* +* 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 . +* +* 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 ENTRIES_LIST_H +#define ENTRIES_LIST_H + +#include "common.h" +#include + +typedef enum { + SORT_NONE, + + SORT_NAME, + SORT_AUTHOR, + SORT_PATH, +} SortMode; + +typedef struct { + u16 path[0x106]; + bool is_zip; + bool in_shuffle; + bool no_bgm_shuffle; + bool installed; + u32 placeholder_color; // doubles as not-info-loaded when == 0 + + json_int_t tp_download_id; + u16 name[0x41]; + u16 desc[0x81]; + u16 author[0x41]; +} Entry_s; + +typedef struct { + Tex3DS_SubTexture subtex; + u16 x, y; +} Entry_Icon_s; + +typedef struct { + Entry_s * entries; + int entries_count; + int entries_capacity; + + C3D_Tex icons_texture; + Entry_Icon_s * icons_info; + + int previous_scroll; + int scroll; + + int previous_selected; + int selected_entry; + + int shuffle_count; + + EntryMode mode; + int entries_per_screen_v; // rows of entries on 1 screen + int entries_per_screen_h; // columns of entries on 1 screen + int entries_loaded; // amount of entries on 1 screen + int entry_size; // size in pixels of an entry icon + + SortMode current_sort; + + json_int_t tp_current_page; + json_int_t tp_page_count; + char * tp_search; + const char * loading_path; +} Entry_List_s; + +void sort_by_name(Entry_List_s * list); +void sort_by_author(Entry_List_s * list); +void sort_by_filename(Entry_List_s * list); + +void delete_entry(Entry_s * entry, bool is_file); +// assumes list has been memset to 0 +typedef enum InstallType_e InstallType; +Result load_entries(const char * loading_path, Entry_List_s * list, const InstallType loading_screen); +u32 load_data(const char * filename, const Entry_s * entry, char ** buf); +C2D_Image get_icon_at(Entry_List_s * list, size_t index); + +// assumes list doesn't have any elements yet +void list_init_capacity(Entry_List_s * list, const int init_capacity); +// assumes list has been inited with a non zero capacity +ssize_t list_add_entry(Entry_List_s * list); + +#endif diff --git a/include/fs.h b/include/fs.h index 4a36e93..a57e71e 100644 --- a/include/fs.h +++ b/include/fs.h @@ -56,13 +56,13 @@ Result open_archives(void); Result close_archives(void); Result load_parental_controls(Parental_Restrictions_s *restrictions); -u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf); -u32 zip_memory_to_buf(char *file_name, void * zip_memory, size_t zip_size, char ** buf); -u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf); -u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char **buf); -u32 compress_lz_file_fast(FS_Path path, FS_Archive archive, char *in_buf, u32 size); +u32 file_to_buf(FS_Path path, FS_Archive archive, char ** buf); +u32 zip_memory_to_buf(const char * file_name, void * zip_memory, size_t zip_size, char ** buf); +u32 zip_file_to_buf(const char * file_name, const u16 * zip_path, char ** buf); +u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char ** buf); +u32 compress_lz_file_fast(FS_Path path, FS_Archive archive, char * in_buf, u32 size); -Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char *buf); +Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char * buf); void remake_file(FS_Path path, FS_Archive archive, u32 size); void save_zip_to_sd(char * filename, u32 size, char * buf, EntryMode mode); diff --git a/include/loading.h b/include/loading.h index 3a25152..5855566 100644 --- a/include/loading.h +++ b/include/loading.h @@ -28,6 +28,7 @@ #define LOADING_H #include "common.h" +#include "entries_list.h" #include "music.h" #include @@ -45,14 +46,6 @@ enum ICON_IDS_OFFSET { ICONS_OFFSET_AMOUNT, }; -typedef enum { - SORT_NONE, - - SORT_NAME, - SORT_AUTHOR, - SORT_PATH, -} SortMode; - typedef struct { u8 _padding1[4 + 2 + 2]; @@ -61,76 +54,26 @@ typedef struct { u16 author[0x40]; u8 _padding2[0x2000 - 0x200 + 0x30 + 0x8]; - u16 small_icon[24*24]; + u16 small_icon[24 * 24]; - u16 big_icon[48*48]; + u16 big_icon[48 * 48]; } Icon_s; -typedef struct { - u16 name[0x41]; - u16 desc[0x81]; - u16 author[0x41]; - - u32 placeholder_color; - - u16 path[0x106]; - bool is_zip; - - bool in_shuffle; - bool no_bgm_shuffle; - bool installed; - - json_int_t tp_download_id; -} Entry_s; - -typedef struct { - Entry_s * entries; - int entries_count; - - C2D_Image ** icons; - - int previous_scroll; - int scroll; - - int previous_selected; - int selected_entry; - - int shuffle_count; - - EntryMode mode; - int entries_per_screen_v; - int entries_per_screen_h; - int entries_loaded; - int entry_size; - - SortMode current_sort; - - json_int_t tp_current_page; - json_int_t tp_page_count; - char * tp_search; -} Entry_List_s; - typedef struct { void ** thread_arg; volatile bool run_thread; } Thread_Arg_s; -C2D_Image * loadTextureIcon(Icon_s *icon); -void parse_smdh(Icon_s *icon, Entry_s * entry, const u16 * fallback_name); +void copy_texture_data(C3D_Tex * texture, const u16 * src, const Entry_Icon_s * current_icon); +void parse_smdh(Icon_s * icon, Entry_s * entry, const u16 * fallback_name); -void sort_by_name(Entry_List_s * list); -void sort_by_author(Entry_List_s * list); -void sort_by_filename(Entry_List_s * list); -void delete_entry(Entry_s * entry, bool is_file); -Result load_entries(const char * loading_path, Entry_List_s * list); bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset); -bool load_preview(Entry_List_s list, C2D_Image * preview_image, int * preview_offset); +bool load_preview(const Entry_List_s * list, C2D_Image * preview_image, int * preview_offset); void free_preview(C2D_Image preview_image); -Result load_audio(Entry_s, audio_s *); +Result load_audio(const Entry_s *, audio_s *); void load_icons_first(Entry_List_s * current_list, bool silent); void handle_scrolling(Entry_List_s * list); void load_icons_thread(void * void_arg); -u32 load_data(char * filename, Entry_s entry, char ** buf); #endif diff --git a/include/music.h b/include/music.h index eb2c17c..4a71914 100644 --- a/include/music.h +++ b/include/music.h @@ -42,7 +42,7 @@ typedef struct { float mix[12]; u8 buf_pos; long data_read; - char *filebuf; + char * filebuf; u32 filesize; volatile bool stop; @@ -50,6 +50,6 @@ typedef struct { } audio_s; void play_audio(audio_s *); -void stop_audio(audio_s**); +void stop_audio(audio_s **); #endif diff --git a/include/remote.h b/include/remote.h index 1d7593a..ba34b7e 100644 --- a/include/remote.h +++ b/include/remote.h @@ -52,6 +52,6 @@ #define CACHE_PATH_FORMAT "/3ds/" APP_TITLE "/cache/%" JSON_INTEGER_FORMAT bool themeplaza_browser(EntryMode mode); -Result http_get(const char *url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types); +Result http_get(const char * url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types); #endif diff --git a/include/splashes.h b/include/splashes.h index 9488dd0..65ce662 100644 --- a/include/splashes.h +++ b/include/splashes.h @@ -31,7 +31,7 @@ #include "loading.h" void splash_delete(void); -void splash_install(Entry_s splash); +void splash_install(const Entry_s * splash); void splash_check_installed(void * void_arg); diff --git a/include/themes.h b/include/themes.h index e988ad8..de7a9dd 100644 --- a/include/themes.h +++ b/include/themes.h @@ -64,17 +64,17 @@ typedef struct { u32 dlc_theme_content_index; u32 use_theme_cache; - u8 _padding1[0x338 - 8*sizeof(u32)]; + u8 _padding1[0x338 - 8 * sizeof(u32)]; u32 shuffle_body_sizes[MAX_SHUFFLE_THEMES]; u32 shuffle_music_sizes[MAX_SHUFFLE_THEMES]; } ThemeManage_bin_s; -Result theme_install(Entry_s theme); -Result no_bgm_install(Entry_s theme); -Result bgm_install(Entry_s theme); +Result theme_install(Entry_s * theme); +Result no_bgm_install(Entry_s * theme); +Result bgm_install(Entry_s * theme); -Result shuffle_install(Entry_List_s themes); +Result shuffle_install(const Entry_List_s * themes); Result dump_current_theme(void); Result dump_all_themes(void); diff --git a/include/unicode.h b/include/unicode.h index ea31026..b50065f 100644 --- a/include/unicode.h +++ b/include/unicode.h @@ -29,9 +29,9 @@ #include "common.h" -ssize_t strulen(const u16*, ssize_t); -void struacat(u16 *input, const char *addition); -void printu(u16 *input); -u16 *strucat(u16 *destination, const u16 *source); +ssize_t strulen(const u16 *, ssize_t); +void struacat(u16 * input, const char * addition); +void printu(u16 * input); +u16 * strucat(u16 * destination, const u16 * source); #endif \ No newline at end of file diff --git a/source/camera.c b/source/camera.c index 26134e8..c0e1575 100644 --- a/source/camera.c +++ b/source/camera.c @@ -36,7 +36,7 @@ #include #include -static void start_read(qr_data *data) +static void start_read(qr_data * data) { LightLock_Lock(&data->mut); while(data->writer_waiting || data->writer_active) @@ -47,7 +47,7 @@ static void start_read(qr_data *data) AtomicIncrement(&data->num_readers_active); LightLock_Unlock(&data->mut); } -static void stop_read(qr_data *data) +static void stop_read(qr_data * data) { LightLock_Lock(&data->mut); AtomicDecrement(&data->num_readers_active); @@ -57,7 +57,7 @@ static void stop_read(qr_data *data) } LightLock_Unlock(&data->mut); } -static void start_write(qr_data *data) +static void start_write(qr_data * data) { LightLock_Lock(&data->mut); data->writer_waiting = true; @@ -72,7 +72,7 @@ static void start_write(qr_data *data) LightLock_Unlock(&data->mut); } -static void stop_write(qr_data *data) +static void stop_write(qr_data * data) { LightLock_Lock(&data->mut); @@ -82,16 +82,16 @@ static void stop_write(qr_data *data) LightLock_Unlock(&data->mut); } -static void capture_cam_thread(void *arg) +static void capture_cam_thread(void * arg) { - qr_data *data = (qr_data *) arg; + qr_data * data = (qr_data *) arg; Handle cam_events[3] = {0}; cam_events[0] = data->event_stop; u32 transferUnit; const u32 bufsz = 400 * 240 * sizeof(u16); - u16 *buffer = linearAlloc(bufsz); + u16 * buffer = linearAlloc(bufsz); camInit(); CAMU_SetSize(SELECT_OUT1, SIZE_CTR_TOP_LCD, CONTEXT_A); @@ -167,9 +167,9 @@ static void capture_cam_thread(void *arg) LightEvent_Signal(&data->event_cam_info); } -static void update_ui(void *arg) +static void update_ui(void * arg) { - qr_data* data = (qr_data*) arg; + qr_data * data = (qr_data *) arg; C3D_Tex tex; static const Tex3DS_SubTexture subt3x = { 400, 240, 0.0f, 1.0f, 400.0f/512.0f, 1.0f - (240.0f/256.0f) }; @@ -190,7 +190,7 @@ static void update_ui(void *arg) for(u32 x = 0; x < 400; x++) { const u32 dstPos = ((((y >> 3) * (512 >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))); - ((u16*)tex.data)[dstPos] = data->camera_buffer[srcPos + x]; + ((u16 *)tex.data)[dstPos] = data->camera_buffer[srcPos + x]; } } data->any_update = false; @@ -208,7 +208,7 @@ static void update_ui(void *arg) LightEvent_Signal(&data->event_ui_info); } -static bool start_capture_cam(qr_data *data) +static bool start_capture_cam(qr_data * data) { if((data->cam_thread = threadCreate(capture_cam_thread, data, 0x10000, 0x1A, 1, false)) == NULL) { @@ -225,11 +225,11 @@ static bool start_capture_cam(qr_data *data) return true; } -static bool update_qr(qr_data *data, struct quirc_data* scan_data) +static bool update_qr(qr_data * data, struct quirc_data * scan_data) { int w; int h; - u8 *image = (u8*) quirc_begin(data->context, &w, &h); + u8 * image = (u8 *)quirc_begin(data->context, &w, &h); start_read(data); for (int y = 0; y < h; y++) { @@ -256,7 +256,7 @@ static bool update_qr(qr_data *data, struct quirc_data* scan_data) return false; } -static void start_qr(qr_data *data) +static void start_qr(qr_data * data) { svcCreateEvent(&data->event_stop, RESET_STICKY); LightEvent_Init(&data->event_cam_info, RESET_STICKY); @@ -272,7 +272,7 @@ static void start_qr(qr_data *data) quirc_resize(data->context, 400, 240); data->camera_buffer = calloc(1, 400 * 240 * sizeof(u16)); } -static void exit_qr(qr_data *data) +static void exit_qr(qr_data * data) { svcSignalEvent(data->event_stop); @@ -308,7 +308,7 @@ bool init_qr(void) start_qr(&data); - struct quirc_data* scan_data = calloc(1, sizeof(struct quirc_data)); + struct quirc_data * scan_data = calloc(1, sizeof(struct quirc_data)); const bool ready = start_capture_cam(&data); bool finished = !ready; @@ -333,6 +333,7 @@ bool init_qr(void) char * zip_buf = NULL; char * filename = NULL; u32 zip_size; + Result res = http_get((char*)scan_data->payload, &filename, &zip_buf, &zip_size, INSTALL_DOWNLOAD, "application/zip; application/x-zip-compressed"); if (R_FAILED(res)) { @@ -350,7 +351,7 @@ bool init_qr(void) { draw_install(INSTALL_CHECKING_DOWNLOAD); - struct archive *a = archive_read_new(); + struct archive * a = archive_read_new(); archive_read_support_format_zip(a); int r = archive_read_open_memory(a, zip_buf, zip_size); diff --git a/source/draw.c b/source/draw.c index ff5f638..f2b6513 100644 --- a/source/draw.c +++ b/source/draw.c @@ -32,8 +32,8 @@ #include -C3D_RenderTarget* top; -C3D_RenderTarget* bottom; +C3D_RenderTarget * top; +C3D_RenderTarget * bottom; C2D_TextBuf staticBuf, dynamicBuf; static C2D_TextBuf widthBuf; @@ -285,7 +285,7 @@ void draw_base_interface(void) set_screen(top); } -void throw_error(const char* error, ErrorLevel level) +void throw_error(const char * error, ErrorLevel level) { Text bottom_text = TEXT_AMOUNT; Color text_color = COLOR_WHITE; @@ -318,7 +318,7 @@ void throw_error(const char* error, ErrorLevel level) } } -bool draw_confirm(const char* conf_msg, Entry_List_s* list) +bool draw_confirm(const char * conf_msg, Entry_List_s * list) { while(aptMainLoop()) { @@ -368,7 +368,7 @@ void draw_loading_bar(u32 current, u32 max, InstallType type) draw_base_interface(); draw_install_handler(type); set_screen(bottom); - double percent = 100*((double)current/(double)max); + double percent = 100 * ((double)current / (double)max); u32 width = (u32)percent; width *= 2; C2D_DrawRectSolid(60-1, 110-1, 0.5f, 200+2, 20+2, colors[COLOR_CURSOR]); @@ -442,13 +442,13 @@ void draw_text_wrap(float x, float y, float z, float scaleX, float scaleY, Color continue; } - if((consumed = decode_utf8(&codepoint, (unsigned char*)text)) == -1) + if((consumed = decode_utf8(&codepoint, (unsigned char *)text)) == -1) break; float character_width = scaleX * (fontGetCharWidthInfo(NULL, fontGlyphIndexFromCodePoint(NULL, codepoint))->charWidth); if((current_width += character_width) > max_width) { - char* last_space = NULL; + char * last_space = NULL; for(int i = idx; i >= 0; i--) { if(result[i] == ' ') @@ -498,27 +498,27 @@ void draw_text_wrap_scaled(float x, float y, float z, Color color, const char * static void draw_entry_info(Entry_s * entry) { char author[0x41] = {0}; - utf16_to_utf8((u8*)author, entry->author, 0x40); + utf16_to_utf8((u8 *)author, entry->author, 0x40); draw_c2d_text(20, 35, 0.5, 0.5, 0.5, colors[COLOR_WHITE], &text[TEXT_BY_AUTHOR]); float width = 0; C2D_TextGetDimensions(&text[TEXT_BY_AUTHOR], 0.5, 0.5, &width, NULL); draw_text(20+width, 35, 0.5, 0.5, 0.5, colors[COLOR_WHITE], author); char title[0x41] = {0}; - utf16_to_utf8((u8*)title, entry->name, 0x40); + utf16_to_utf8((u8 *)title, entry->name, 0x40); draw_text(20, 50, 0.5, 0.7, 0.7, colors[COLOR_WHITE], title); char description[0x81] = {0}; - utf16_to_utf8((u8*)description, entry->desc, 0x80); + utf16_to_utf8((u8 *)description, entry->desc, 0x80); draw_text_wrap(20, 70, 0.5, 0.5, 0.5, colors[COLOR_WHITE], description, 363); } -void draw_grid_interface(Entry_List_s* list, Instructions_s instructions) +void draw_grid_interface(Entry_List_s * list, Instructions_s instructions) { draw_base_interface(); EntryMode current_mode = list->mode; - C2D_Text* mode_string[MODE_AMOUNT] = { + C2D_Text * mode_string[MODE_AMOUNT] = { &text[TEXT_THEMEPLAZA_THEME_MODE], &text[TEXT_THEMEPLAZA_SPLASH_MODE], }; @@ -551,7 +551,7 @@ void draw_grid_interface(Entry_List_s* list, Instructions_s instructions) current_entry = &list->entries[i]; char name[0x41] = {0}; - utf16_to_utf8((u8*)name, current_entry->name, 0x40); + utf16_to_utf8((u8 *)name, current_entry->name, 0x40); int vertical_offset = 0; int horizontal_offset = i - list->scroll; @@ -563,18 +563,16 @@ void draw_grid_interface(Entry_List_s* list, Instructions_s instructions) vertical_offset += 24; horizontal_offset += 16; - // theoretically impossible to have no icon when from the api - /* - if(!current_entry->placeholder_color) + + if(current_entry->placeholder_color == 0) { - */ - C2D_Image * image = list->icons[i]; - C2D_DrawImageAt(*image, horizontal_offset, vertical_offset, 0.5f, NULL, 1.0f, 1.0f); - /* + const C2D_Image image = get_icon_at(list, i); + C2D_DrawImageAt(image, horizontal_offset, vertical_offset, 0.5f, NULL, 1.0f, 1.0f); } else + { C2D_DrawRectSolid(horizontal_offset, vertical_offset, 0.5f, list->entry_size, list->entry_size, current_entry->placeholder_color); - */ + } if(i == selected_entry) { @@ -603,12 +601,12 @@ void draw_grid_interface(Entry_List_s* list, Instructions_s instructions) draw_c2d_text(176, 219, 0.5, 0.6, 0.6, colors[COLOR_WHITE], &text[TEXT_PAGE]); } -void draw_interface(Entry_List_s* list, Instructions_s instructions) +void draw_interface(Entry_List_s * list, Instructions_s instructions) { draw_base_interface(); EntryMode current_mode = list->mode; - C2D_Text* mode_string[MODE_AMOUNT] = { + C2D_Text * mode_string[MODE_AMOUNT] = { &text[TEXT_THEME_MODE], &text[TEXT_SPLASH_MODE], }; @@ -617,7 +615,7 @@ void draw_interface(Entry_List_s* list, Instructions_s instructions) if(list->entries == NULL) { - C2D_Text* mode_found_string[MODE_AMOUNT] = { + C2D_Text * mode_found_string[MODE_AMOUNT] = { &text[TEXT_NO_THEME_FOUND], &text[TEXT_NO_SPLASH_FOUND], }; @@ -625,7 +623,7 @@ void draw_interface(Entry_List_s* list, Instructions_s instructions) draw_c2d_text_center(GFX_TOP, 80, 0.5f, 0.7f, 0.7f, colors[COLOR_YELLOW], mode_found_string[current_mode]); draw_c2d_text_center(GFX_TOP, 110, 0.5f, 0.7f, 0.7f, colors[COLOR_YELLOW], &text[TEXT_DOWNLOAD_FROM_QR]); - C2D_Text* mode_switch_string[MODE_AMOUNT] = { + C2D_Text * mode_switch_string[MODE_AMOUNT] = { &text[TEXT_SWITCH_TO_SPLASHES], &text[TEXT_SWITCH_TO_THEMES], }; @@ -691,7 +689,7 @@ void draw_interface(Entry_List_s* list, Instructions_s instructions) current_entry = &list->entries[i]; char name[0x41] = {0}; - utf16_to_utf8((u8*)name, current_entry->name, 0x40); + utf16_to_utf8((u8 *)name, current_entry->name, 0x40); int vertical_offset = i - list->scroll; int horizontal_offset = 0; @@ -729,14 +727,17 @@ void draw_interface(Entry_List_s* list, Instructions_s instructions) C2D_DrawSpriteTinted(&sprite_installed, &tint); } - if(!current_entry->placeholder_color) + if(current_entry->placeholder_color == 0) { - C2D_Image * image = NULL; - if(list->entries_count > list->entries_loaded*ICONS_OFFSET_AMOUNT) - image = list->icons[ICONS_VISIBLE*list->entries_loaded + (i - list->scroll)]; + C2D_Image image; + if(list->entries_count > list->entries_loaded * ICONS_OFFSET_AMOUNT) + { + const int offset_to_visible_icons = ICONS_VISIBLE * list->entries_loaded; + image = get_icon_at(list, offset_to_visible_icons + (i - list->scroll)); + } else - image = list->icons[i]; - C2D_DrawImageAt(*image, horizontal_offset, vertical_offset, 0.5f, NULL, 1.0f, 1.0f); + image = get_icon_at(list, i); + C2D_DrawImageAt(image, horizontal_offset, vertical_offset, 0.5f, NULL, 1.0f, 1.0f); } else { diff --git a/source/entries_list.c b/source/entries_list.c new file mode 100644 index 0000000..f5f83bf --- /dev/null +++ b/source/entries_list.c @@ -0,0 +1,231 @@ +/* +* 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 . +* +* 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 "entries_list.h" +#include "loading.h" +#include "draw.h" +#include "fs.h" +#include "unicode.h" + +void delete_entry(Entry_s * entry, bool is_file) +{ + if(is_file) + FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, entry->path)); + else + FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, entry->path)); +} + +u32 load_data(const char * filename, const 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); + } +} + +C2D_Image get_icon_at(Entry_List_s * list, size_t index) +{ + return (C2D_Image){ + .tex = &list->icons_texture, + .subtex = &list->icons_info[index].subtex, + }; +} + +static int compare_entries_base(const Entry_s * const a, const Entry_s * const b) +{ + // entry->placeholder_color == 0 means it is not filled (no name, author, description) + // if a is filled and b is filled, return == 0 + // if a is not filled and b is not filled, return == 0 + // if a is not filled, return < 0 + // if b is an unfilled entry, return > 0 + return ((int)(a->placeholder_color != 0)) - ((int)(b->placeholder_color != 0)); +} + +typedef int (*sort_comparator)(const void *, const void *); +static int compare_entries_by_name(const void * a, const void * b) +{ + const Entry_s * const entry_a = (const Entry_s *)a; + const Entry_s * const entry_b = (const Entry_s *)b; + const int base = compare_entries_base(entry_a, entry_b); + if(base) + return base; + + return memcmp(entry_a->name, entry_b->name, 0x40 * sizeof(u16)); +} +static int compare_entries_by_author(const void * a, const void * b) +{ + const Entry_s * const entry_a = (const Entry_s *)a; + const Entry_s * const entry_b = (const Entry_s *)b; + const int base = compare_entries_base(entry_a, entry_b); + if(base) + return base; + + return memcmp(entry_a->author, entry_b->author, 0x40 * sizeof(u16)); +} +static int compare_entries_by_filename(const void * a, const void * b) +{ + const Entry_s * const entry_a = (const Entry_s *)a; + const Entry_s * const entry_b = (const Entry_s *)b; + const int base = compare_entries_base(entry_a, entry_b); + if(base) + return base; + + return memcmp(entry_a->path, entry_b->path, 0x106 * sizeof(u16)); +} + +static void sort_list(Entry_List_s * list, sort_comparator compare_entries) +{ + if(list->entries != NULL && list->entries != NULL) + qsort(list->entries, list->entries_count, sizeof(Entry_s), compare_entries); //alphabet sort +} + +void sort_by_name(Entry_List_s * list) +{ + sort_list(list, compare_entries_by_name); + list->current_sort = SORT_NAME; +} +void sort_by_author(Entry_List_s * list) +{ + sort_list(list, compare_entries_by_author); + list->current_sort = SORT_AUTHOR; +} +void sort_by_filename(Entry_List_s * list) +{ + sort_list(list, compare_entries_by_filename); + list->current_sort = SORT_PATH; +} + +#define LOADING_DIR_ENTRIES_COUNT 16 +static FS_DirectoryEntry loading_dir_entries[LOADING_DIR_ENTRIES_COUNT]; +Result load_entries(const char * loading_path, Entry_List_s * list, const InstallType loading_screen) +{ + Handle dir_handle; + Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_ASCII, loading_path)); + if(R_FAILED(res)) + { + DEBUG("Failed to open folder: %s\n", loading_path); + return res; + } + + list_init_capacity(list, LOADING_DIR_ENTRIES_COUNT); + + u32 entries_read = LOADING_DIR_ENTRIES_COUNT; + while(entries_read == LOADING_DIR_ENTRIES_COUNT) + { + res = FSDIR_Read(dir_handle, &entries_read, LOADING_DIR_ENTRIES_COUNT, loading_dir_entries); + if(R_FAILED(res)) + break; + + for(u32 i = 0; i < entries_read; ++i) + { + const FS_DirectoryEntry * const dir_entry = &loading_dir_entries[i]; + const bool is_zip = !strcmp(dir_entry->shortExt, "ZIP"); + if(!(dir_entry->attributes & FS_ATTRIBUTE_DIRECTORY) && !is_zip) + continue; + + const ssize_t new_entry_index = list_add_entry(list); + if(new_entry_index < 0) + { + // out of memory: still allow use of currently loaded entries. + // Many things might die, depending on the heap layout after + entries_read = 0; + break; + } + + Entry_s * const current_entry = &list->entries[new_entry_index]; + memset(current_entry, 0, sizeof(Entry_s)); + struacat(current_entry->path, loading_path); + strucat(current_entry->path, dir_entry->name); + current_entry->is_zip = is_zip; + } + } + + FSDIR_Close(dir_handle); + + list->loading_path = loading_path; + const int loading_bar_ticks = list->entries_count / 10; + + for(int i = 0, j = 0; i < list->entries_count; ++i) + { + // replaces (i % loading_bar_ticks) == 0 + if(++j >= loading_bar_ticks) + { + j = 0; + draw_loading_bar(i, list->entries_count, loading_screen); + } + Entry_s * const current_entry = &list->entries[i]; + char * buf = NULL; + u32 buflen = load_data("/info.smdh", current_entry, &buf); + parse_smdh(buflen == sizeof(Icon_s) ? (Icon_s *)buf : NULL, current_entry, current_entry->path + strlen(loading_path)); + free(buf); + } + + return res; +} + +void list_init_capacity(Entry_List_s * list, const int init_capacity) +{ + list->entries = malloc(init_capacity * sizeof(Entry_s)); + list->entries_capacity = init_capacity; +} + +#define LIST_CAPACITY_THRESHOLD 512 +ssize_t list_add_entry(Entry_List_s * list) +{ + if(list->entries_count == list->entries_capacity) + { + int next_capacity = list->entries_capacity; + // expand by doubling until we hit LIST_CAPACITY_THRESHOLD + // then simply increment by that, to have less extra space leftover + if(next_capacity < LIST_CAPACITY_THRESHOLD) + { + next_capacity *= 2; + } + else + { + next_capacity += LIST_CAPACITY_THRESHOLD; + } + + Entry_s * const new_list = realloc(list->entries, next_capacity * sizeof(Entry_s)); + if(new_list == NULL) + { + return -1; + } + + list->entries = new_list; + list->entries_capacity = next_capacity; + } + + return list->entries_count++; +} diff --git a/source/fs.c b/source/fs.c index 5612f50..b0b093b 100644 --- a/source/fs.c +++ b/source/fs.c @@ -122,7 +122,7 @@ Result load_parental_controls(Parental_Restrictions_s *restrictions) return 0; } -u32 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; @@ -139,9 +139,9 @@ u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf) return (u32)size; } -static u32 zip_to_buf(struct archive *a, char *file_name, char ** buf) +static u32 zip_to_buf(struct archive * a, const char * file_name, char ** buf) { - struct archive_entry *entry; + struct archive_entry * entry; bool found = false; u64 file_size = 0; @@ -167,9 +167,9 @@ static u32 zip_to_buf(struct archive *a, char *file_name, char ** buf) return (u32)file_size; } -u32 zip_memory_to_buf(char *file_name, void * zip_memory, size_t zip_size, char ** buf) +u32 zip_memory_to_buf(const char * file_name, void * zip_memory, size_t zip_size, char ** buf) { - struct archive *a = archive_read_new(); + struct archive * a = archive_read_new(); archive_read_support_format_zip(a); int r = archive_read_open_memory(a, zip_memory, zip_size); @@ -182,13 +182,13 @@ u32 zip_memory_to_buf(char *file_name, void * zip_memory, size_t zip_size, char return zip_to_buf(a, file_name, buf); } -u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf) +u32 zip_file_to_buf(const char * file_name, const u16 * zip_path, char ** buf) { ssize_t len = strulen(zip_path, 0x106); - char *path = calloc(sizeof(char), len*sizeof(u16)); - utf16_to_utf8((u8*)path, zip_path, len*sizeof(u16)); + char * path = calloc(sizeof(char), len * sizeof(u16)); + utf16_to_utf8((u8 *)path, zip_path, len * sizeof(u16)); - struct archive *a = archive_read_new(); + struct archive * a = archive_read_new(); archive_read_support_format_zip(a); int r = archive_read_open_filename(a, path, 0x4000); @@ -202,7 +202,7 @@ u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf) return zip_to_buf(a, file_name, buf); } -Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char *buf) +Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char * buf) { Handle handle; Result res = 0; @@ -212,7 +212,7 @@ Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char *buf) return 0; } -u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char **buf) +u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char ** buf) { Handle handle; Result res = 0; @@ -223,7 +223,7 @@ u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char **buf) u64 size; FSFILE_GetSize(handle, &size); - char *temp_buf = NULL; + char * temp_buf = NULL; if(size != 0) { @@ -317,9 +317,9 @@ u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char **buf) // if i figure out a dynamic programming algorithm which ends up being significantly // faster. Otherwise, I think this is probably a fine implementation. -u32 compress_lz_file_fast(FS_Path path, FS_Archive archive, char *in_buf, u32 size) +u32 compress_lz_file_fast(FS_Path path, FS_Archive archive, char * in_buf, u32 size) { - char *output_buf = calloc(1, size * 2); + char * output_buf = calloc(1, size * 2); u32 output_size = 0; u32 mask_pos = 0; u32 bytes_processed = 0; @@ -363,12 +363,12 @@ void remake_file(FS_Path path, FS_Archive archive, u32 size) FSUSER_DeleteFile(archive, path); } FSUSER_CreateFile(archive, path, 0, size); - char *buf = calloc(size, 1); + char * buf = calloc(size, 1); buf_to_file(size, path, archive, buf); free(buf); } -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; diff --git a/source/loading.c b/source/loading.c index 8867621..6288f24 100644 --- a/source/loading.c +++ b/source/loading.c @@ -33,194 +33,48 @@ #include -void delete_entry(Entry_s * entry, bool is_file) +void copy_texture_data(C3D_Tex * texture, const u16 * src, const Entry_Icon_s * current_icon) { - if(is_file) - FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, entry->path)); - else - FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, entry->path)); -} - -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); - } -} - -// Function taken and adapted from https://github.com/BernardoGiordano/Checkpoint/blob/master/3ds/source/title.cpp -C2D_Image * loadTextureIcon(Icon_s *icon) -{ - if(icon == NULL) - return NULL; - - C2D_Image * image = calloc(1, sizeof(C2D_Image)); - C3D_Tex* tex = malloc(sizeof(C3D_Tex)); - static const Tex3DS_SubTexture subt3x = { 48, 48, 0.0f, 48/64.0f, 48/64.0f, 0.0f }; - image->tex = tex; - image->subtex = &subt3x; - C3D_TexInit(image->tex, 64, 64, GPU_RGB565); - - u16* dest = (u16*)image->tex->data + (64-48)*64; - u16* src = icon->big_icon; + // pointer to rgb565, offset by the number of rows and columns specified by current_icon + // (reminder that this is z order curve storage) + u16 * dest = ((u16 *)texture->data) + (current_icon->y * texture->width) + (current_icon->x * 8); for (int j = 0; j < 48; j += 8) { - memcpy(dest, src, 48*8*sizeof(u16)); - src += 48*8; - dest += 64*8; + memcpy(dest, src, 48 * 8 * sizeof(u16)); + src += 48 * 8; + dest += texture->width * 8; } - - return image; + GSPGPU_InvalidateDataCache(texture->data, texture->size); } -void parse_smdh(Icon_s *icon, Entry_s * entry, const u16 * fallback_name) +void parse_smdh(Icon_s * icon, Entry_s * entry, const u16 * fallback_name) { - if(icon == NULL) { memcpy(entry->name, fallback_name, 0x80); - utf8_to_utf16(entry->desc, (u8*)"No description", 0x100); - utf8_to_utf16(entry->author, (u8*)"Unknown author", 0x80); + utf8_to_utf16(entry->desc, (u8 *)"No description", 0x100); + utf8_to_utf16(entry->author, (u8 *)"Unknown author", 0x80); entry->placeholder_color = C2D_Color32(rand() % 255, rand() % 255, rand() % 255, 255); return; } - - memcpy(entry->name, icon->name, 0x40*sizeof(u16)); - memcpy(entry->desc, icon->desc, 0x80*sizeof(u16)); - memcpy(entry->author, icon->author, 0x40*sizeof(u16)); + memcpy(entry->name, icon->name, 0x40 * sizeof(u16)); + memcpy(entry->desc, icon->desc, 0x80 * sizeof(u16)); + memcpy(entry->author, icon->author, 0x40 * sizeof(u16)); + entry->placeholder_color = 0; } -static C2D_Image * load_entry_icon(Entry_s entry) +static Icon_s * load_entry_icon(const Entry_s * entry) { - char *info_buffer = NULL; - u64 size = load_data("/info.smdh", entry, &info_buffer); - if(!size) return NULL; - - Icon_s * smdh = (Icon_s *)info_buffer; - C2D_Image* out = loadTextureIcon(smdh); - free(info_buffer); - return out; -} - -typedef int (*sort_comparator)(const void *, const void *); -static int compare_entries_by_name(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 int compare_entries_by_author(const void * a, const void * b) -{ - Entry_s *entry_a = (Entry_s *)a; - Entry_s *entry_b = (Entry_s *)b; - - return memcmp(entry_a->author, entry_b->author, 0x40*sizeof(u16)); -} -static int compare_entries_by_filename(const void * a, const void * b) -{ - Entry_s *entry_a = (Entry_s *)a; - Entry_s *entry_b = (Entry_s *)b; - - return memcmp(entry_a->path, entry_b->path, 0x106*sizeof(u16)); -} - -static void sort_list(Entry_List_s * list, sort_comparator compare_entries) -{ - if(list->entries != NULL && list->entries != NULL) - qsort(list->entries, list->entries_count, sizeof(Entry_s), compare_entries); //alphabet sort -} - -void sort_by_name(Entry_List_s * list) -{ - sort_list(list, compare_entries_by_name); - list->current_sort = SORT_NAME; -} -void sort_by_author(Entry_List_s * list) -{ - sort_list(list, compare_entries_by_author); - list->current_sort = SORT_AUTHOR; -} -void sort_by_filename(Entry_List_s * list) -{ - sort_list(list, compare_entries_by_filename); - list->current_sort = SORT_PATH; -} - -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)) + char * info_buffer = NULL; + u32 size = load_data("/info.smdh", entry, &info_buffer); + if(size != sizeof(Icon_s)) { - DEBUG("Failed to open folder: %s\n", loading_path); - return res; + free(info_buffer); + return NULL; } - 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; - - u16 path[0x106] = {0}; - struacat(path, loading_path); - strucat(path, dir_entry.name); - char * buf = NULL; - - if (!strcmp(dir_entry.shortExt, "ZIP")) - { - zip_file_to_buf("info.smdh", path, &buf); - } - else - { - const ssize_t len = strulen(path, 0x106); - struacat(path, "/info.smdh"); - file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &buf); - memset(&path[len], 0, (0x106 - len) * sizeof(u16)); - } - - list->entries_count++; - Entry_s * new_list = realloc(list->entries, list->entries_count * sizeof(Entry_s)); - if(new_list == NULL) - { - // out of memory: still allow use of currently loaded entries. - // Many things might die, depending on the heap layout after - list->entries_count--; - free(buf); - break; - } - else - list->entries = new_list; - - Entry_s * current_entry = &(list->entries[list->entries_count-1]); - memset(current_entry, 0, sizeof(Entry_s)); - parse_smdh((Icon_s *)buf, current_entry, dir_entry.name); - free(buf); - - memcpy(current_entry->path, path, 0x106 * sizeof(u16)); - current_entry->is_zip = !strcmp(dir_entry.shortExt, "ZIP"); - } - - FSDIR_Close(dir_handle); - - return res; + return (Icon_s *)info_buffer; } void load_icons_first(Entry_List_s * list, bool silent) @@ -232,7 +86,7 @@ void load_icons_first(Entry_List_s * list, bool silent) int starti = 0, endi = 0; - if(list->entries_count <= list->entries_loaded*ICONS_OFFSET_AMOUNT) + if(list->entries_count <= list->entries_loaded * ICONS_OFFSET_AMOUNT) { DEBUG("small load\n"); // if the list is one that doesnt need swapping, load everything at once @@ -242,40 +96,44 @@ void load_icons_first(Entry_List_s * list, bool silent) { DEBUG("extended load\n"); // otherwise, load around to prepare for swapping - starti = list->scroll - list->entries_loaded*ICONS_VISIBLE; - endi = starti + list->entries_loaded*ICONS_OFFSET_AMOUNT; + starti = list->scroll - list->entries_loaded * ICONS_VISIBLE; + endi = starti + list->entries_loaded * ICONS_OFFSET_AMOUNT; } - list->icons = calloc(endi-starti, sizeof(C2D_Image*)); - - C2D_Image ** icons = list->icons; - - for(int i = starti; i < endi; i++) + for(int entry_i = starti, icon_i = 0; entry_i < endi; ++entry_i, ++icon_i) { if(!silent) - draw_loading_bar(i - starti, endi-starti, INSTALL_LOADING_ICONS); + draw_loading_bar(icon_i, endi-starti, INSTALL_LOADING_ICONS); - int offset = i; + int offset = entry_i; if(offset < 0) offset += list->entries_count; if(offset >= list->entries_count) offset -= list->entries_count; - Entry_s current_entry = list->entries[offset]; - icons[i-starti] = load_entry_icon(current_entry); + Entry_s * const current_entry = &list->entries[offset]; + Icon_s * const smdh = load_entry_icon(current_entry); + if(smdh != NULL) + { + if(current_entry->placeholder_color == 0) + parse_smdh(smdh, current_entry, current_entry->path + strlen(list->loading_path)); + copy_texture_data(&list->icons_texture, smdh->big_icon, &list->icons_info[icon_i]); + free(smdh); + } } } -static void reverse(C2D_Image * a[], int sz) { +static void reverse(Entry_Icon_s a[], int sz) { int i, j; + Entry_Icon_s tmp; for (i = 0, j = sz; i < j; i++, j--) { - C2D_Image * tmp = a[i]; - a[i] = a[j]; - a[j] = tmp; + memcpy(&tmp, &a[i], sizeof(Entry_Icon_s)); + memcpy(&a[i], &a[j], sizeof(Entry_Icon_s)); + memcpy(&a[j], &tmp, sizeof(Entry_Icon_s)); } } -static void rotate(C2D_Image * array[], int size, int amt) { +static void rotate(Entry_Icon_s array[], int size, int amt) { if (amt < 0) amt = size + amt; reverse(array, size-amt-1); @@ -293,11 +151,11 @@ void handle_scrolling(Entry_List_s * list) { int change = 0; - if(list->entries_count > list->entries_loaded*2 && list->previous_scroll < list->entries_loaded && list->selected_entry >= list->entries_count - list->entries_loaded) + if(list->entries_count > list->entries_loaded * 2 && list->previous_scroll < list->entries_loaded && list->selected_entry >= list->entries_count - list->entries_loaded) { list->scroll = list->entries_count - list->entries_loaded; } - else if(list->entries_count > list->entries_loaded*2 && list->selected_entry < list->entries_loaded && list->previous_selected >= list->entries_count - list->entries_loaded) + else if(list->entries_count > list->entries_loaded * 2 && list->selected_entry < list->entries_loaded && list->previous_selected >= list->entries_count - list->entries_loaded) { list->scroll = 0; } @@ -341,13 +199,13 @@ static bool load_icons(Entry_List_s * current_list, Handle mutex) handle_scrolling(current_list); - if(current_list->entries_count <= current_list->entries_loaded*ICONS_OFFSET_AMOUNT || current_list->previous_scroll == current_list->scroll) + if(current_list->entries_count <= current_list->entries_loaded * ICONS_OFFSET_AMOUNT || current_list->previous_scroll == current_list->scroll) return false; // return if the list is one that doesnt need swapping, or if nothing changed #define SIGN(x) (x > 0 ? 1 : ((x < 0) ? -1 : 0)) int delta = current_list->scroll - current_list->previous_scroll; - if(abs(delta) >= current_list->entries_count - current_list->entries_loaded*(ICONS_OFFSET_AMOUNT-1)) + if(abs(delta) >= current_list->entries_count - current_list->entries_loaded * (ICONS_OFFSET_AMOUNT-1)) delta = -SIGN(delta) * (current_list->entries_count - abs(delta)); int starti = current_list->scroll; @@ -360,28 +218,28 @@ static bool load_icons(Entry_List_s * current_list, Handle mutex) } int ctr = 0; - Entry_s ** entries = calloc(abs(delta), sizeof(Entry_s *)); - int * indexes = calloc(abs(delta), sizeof(int)); + Entry_s ** const entries = calloc(abs(delta), sizeof(Entry_s *)); + int * const indexes = calloc(abs(delta), sizeof(int)); bool released = false; - C2D_Image ** icons = current_list->icons; + Entry_Icon_s * const icons = current_list->icons_info; for(int i = starti; i != endi; i++, ctr++) { int index = 0; int offset = i; - rotate(icons, ICONS_OFFSET_AMOUNT*current_list->entries_loaded, -1*SIGN(delta)); + rotate(icons, ICONS_OFFSET_AMOUNT * current_list->entries_loaded, -SIGN(delta)); if(delta > 0) { - index = current_list->entries_loaded*ICONS_OFFSET_AMOUNT - delta + i - starti; - offset += current_list->entries_loaded*ICONS_UNDER - delta; + index = current_list->entries_loaded * ICONS_OFFSET_AMOUNT - delta + i - starti; + offset += current_list->entries_loaded * ICONS_UNDER - delta; } else { index = 0 - delta - 1 + i - starti; - offset -= current_list->entries_loaded*ICONS_VISIBLE; + offset -= current_list->entries_loaded * ICONS_VISIBLE; i -= 2; //i-- twice to counter the i++, needed only for this case } @@ -396,7 +254,7 @@ static bool load_icons(Entry_List_s * current_list, Handle mutex) #undef SIGN - if(abs(delta) < 4) + if(abs(delta) <= current_list->entries_loaded) { svcReleaseMutex(mutex); released = true; @@ -407,19 +265,19 @@ static bool load_icons(Entry_List_s * current_list, Handle mutex) endi = abs(delta); for(int i = starti; i < endi; i++) { - Entry_s * current_entry = entries[i]; - int index = indexes[i]; + Entry_s * const current_entry = entries[i]; + const int index = indexes[i]; + const Entry_Icon_s * const current_icon = &icons[index]; - C2D_Image * image = icons[index]; - if (icons[index] != NULL) + Icon_s * const smdh = load_entry_icon(current_entry); + if(smdh != NULL) { - C3D_TexDelete(image->tex); - free(image->tex); - free(image); + if(current_entry->placeholder_color == 0) + parse_smdh(smdh, current_entry, current_entry->path + strlen(current_list->loading_path)); + copy_texture_data(¤t_list->icons_texture, smdh->big_icon, current_icon); + free(smdh); } - icons[index] = load_entry_icon(*current_entry); - if(!released && i > endi/2) { svcReleaseMutex(mutex); @@ -439,15 +297,13 @@ void load_icons_thread(void * void_arg) { Thread_Arg_s * arg = (Thread_Arg_s *)void_arg; Handle mutex = *(Handle *)arg->thread_arg[1]; - do - { + do { svcWaitSynchronization(mutex, U64_MAX); - volatile Entry_List_s * current_list = *(volatile Entry_List_s **)arg->thread_arg[0]; - bool released = load_icons((Entry_List_s *)current_list, mutex); + Entry_List_s * const current_list = *(Entry_List_s ** volatile)arg->thread_arg[0]; + const bool released = load_icons(current_list, mutex); if(!released) svcReleaseMutex(mutex); - } - while(arg->run_thread); + } while(arg->run_thread); } bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset) @@ -457,7 +313,7 @@ bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview free_preview(*preview_image); - C3D_Tex* tex = malloc(sizeof(C3D_Tex)); + C3D_Tex * tex = malloc(sizeof(C3D_Tex)); preview_image->tex = tex; Tex3DS_SubTexture * subt3x = malloc(sizeof(Tex3DS_SubTexture)); @@ -489,16 +345,16 @@ bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview } static u16 previous_path_preview[0x106] = {0}; -bool load_preview(Entry_List_s list, C2D_Image * preview_image, int * preview_offset) +bool load_preview(const Entry_List_s * list, C2D_Image * preview_image, int * preview_offset) { - if(list.entries == NULL) return false; + if(list->entries == NULL) return false; - Entry_s entry = list.entries[list.selected_entry]; + const Entry_s * entry = &list->entries[list->selected_entry]; - if(!memcmp(&previous_path_preview, &entry.path, 0x106*sizeof(u16))) return true; + if(!memcmp(&previous_path_preview, &entry->path, 0x106 * sizeof(u16))) return true; - char *preview_buffer = NULL; - u64 size = load_data("/preview.png", entry, &preview_buffer); + char * preview_buffer = NULL; + u32 size = load_data("/preview.png", entry, &preview_buffer); if(size) { @@ -567,7 +423,7 @@ bool load_preview(Entry_List_s list, C2D_Image * preview_image, int * preview_of if(ret) { // mark the new preview as loaded for optimisation - memcpy(&previous_path_preview, &entry.path, 0x106*sizeof(u16)); + memcpy(&previous_path_preview, &entry->path, 0x106 * sizeof(u16)); } return ret; @@ -578,11 +434,11 @@ void free_preview(C2D_Image preview) if(preview.tex) C3D_TexDelete(preview.tex); free(preview.tex); - free((Tex3DS_SubTexture*)preview.subtex); + free((Tex3DS_SubTexture *)preview.subtex); } // Initialize the audio struct -Result load_audio(Entry_s entry, audio_s *audio) +Result load_audio(const Entry_s * entry, audio_s * audio) { audio->filesize = load_data("/bgm.ogg", entry, &audio->filebuf); if (audio->filesize == 0) { @@ -596,7 +452,7 @@ Result load_audio(Entry_s entry, audio_s *audio) ndspChnSetInterp(0, NDSP_INTERP_LINEAR); ndspChnSetMix(0, audio->mix); // See mix comment above - FILE *file = fmemopen(audio->filebuf, audio->filesize, "rb"); + FILE * file = fmemopen(audio->filebuf, audio->filesize, "rb"); DEBUG(" Filesize: %ld\n", audio->filesize); if(file != NULL) { @@ -610,7 +466,7 @@ Result load_audio(Entry_s entry, audio_s *audio) return MAKERESULT(RL_FATAL, RS_INVALIDARG, RM_APPLICATION, RD_NO_DATA); } - vorbis_info *vi = ov_info(&audio->vf, -1); + vorbis_info * vi = ov_info(&audio->vf, -1); ndspChnSetRate(0, vi->rate);// Set sample rate to what's read from the ogg file if (vi->channels == 2) { DEBUG(" Using stereo\n"); diff --git a/source/main.c b/source/main.c index c30400b..8853d6a 100644 --- a/source/main.c +++ b/source/main.c @@ -48,8 +48,8 @@ static Thread_Arg_s iconLoadingThread_arg = {0}; static Handle update_icons_mutex; static bool released = false; -static Thread installCheckThreads[MODE_AMOUNT] = {0}; -static Thread_Arg_s installCheckThreads_arg[MODE_AMOUNT] = {0}; +static Thread install_check_threads[MODE_AMOUNT] = {0}; +static Thread_Arg_s install_check_threads_arg[MODE_AMOUNT] = {0}; static Entry_List_s lists[MODE_AMOUNT] = {0}; @@ -108,13 +108,16 @@ static void stop_install_check(void) { for(int i = 0; i < MODE_AMOUNT; i++) { - installCheckThreads_arg[i].run_thread = false; + install_check_threads_arg[i].run_thread = false; } for(int i = 0; i < MODE_AMOUNT; i++) { - threadJoin(installCheckThreads[i], U64_MAX); - threadFree(installCheckThreads[i]); - installCheckThreads[i] = NULL; + if(install_check_threads[i] == NULL) + continue; + + threadJoin(install_check_threads[i], U64_MAX); + threadFree(install_check_threads[i]); + install_check_threads[i] = NULL; } } @@ -132,30 +135,14 @@ static void exit_thread(void) } } -static void free_icons(Entry_List_s * list) -{ - int amount = list->entries_count; - if(list->entries_count > list->entries_loaded*ICONS_OFFSET_AMOUNT) - amount = list->entries_loaded*ICONS_OFFSET_AMOUNT; - - for(int i = 0; i < amount; i++) - { - if (list->icons[i] == NULL) continue; - C3D_TexDelete(list->icons[i]->tex); - free(list->icons[i]->tex); - free(list->icons[i]); - } - free(list->icons); - list->icons = NULL; -} - void free_lists(void) { stop_install_check(); for(int i = 0; i < MODE_AMOUNT; i++) { - Entry_List_s * current_list = &lists[i]; - free_icons(current_list); + Entry_List_s * const current_list = &lists[i]; + C3D_TexDelete(¤t_list->icons_texture); + free(current_list->icons_info); free(current_list->entries); memset(current_list, 0, sizeof(Entry_List_s)); } @@ -195,6 +182,18 @@ static void start_thread(void) } } +static u32 next_or_equal_power_of_2(u32 v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + static void load_lists(Entry_List_s * lists) { free_lists(); @@ -208,37 +207,69 @@ static void load_lists(Entry_List_s * lists) draw_install(loading_screen); - Entry_List_s * current_list = &lists[i]; + Entry_List_s * const current_list = &lists[i]; current_list->mode = i; current_list->entries_per_screen_v = entries_per_screen_v[i]; current_list->entries_per_screen_h = 1; current_list->entries_loaded = current_list->entries_per_screen_v * current_list->entries_per_screen_h; current_list->entry_size = entry_size[i]; - Result res = load_entries(main_paths[i], current_list); + + const int x_component = max(current_list->entries_per_screen_h, current_list->entries_per_screen_v); + const int y_component = min(current_list->entries_per_screen_h, current_list->entries_per_screen_v); + // A texture must have power of 2 dimensions (not necessarily the same) + // so, get the power of two greater than or equal to: + // - the size of the largest length (row or column) of icons for the width + // - the size of all of those lengths to fit the total for the height + C3D_TexInit(¤t_list->icons_texture, + next_or_equal_power_of_2(x_component * current_list->entry_size), + next_or_equal_power_of_2(y_component * current_list->entry_size * ICONS_OFFSET_AMOUNT), + GPU_RGB565); + C3D_TexSetFilter(¤t_list->icons_texture, GPU_NEAREST, GPU_NEAREST); + + const float inv_width = 1.0f / current_list->icons_texture.width; + const float inv_height = 1.0f / current_list->icons_texture.height; + current_list->icons_info = (Entry_Icon_s *)calloc(x_component * y_component * ICONS_OFFSET_AMOUNT, sizeof(Entry_Icon_s)); + for(int j = 0; j < y_component * ICONS_OFFSET_AMOUNT; ++j) + { + const int index = j * x_component; + for(int h = 0; h < x_component; ++h) + { + Entry_Icon_s * const icon_info = ¤t_list->icons_info[index + h]; + icon_info->x = h * current_list->entry_size; + icon_info->y = j * current_list->entry_size; + icon_info->subtex.width = current_list->entry_size; + icon_info->subtex.height = current_list->entry_size; + icon_info->subtex.left = icon_info->x * inv_width; + icon_info->subtex.top = 1.0f - (icon_info->y * inv_height); + icon_info->subtex.right = icon_info->subtex.left + (icon_info->subtex.width * inv_width); + icon_info->subtex.bottom = icon_info->subtex.top - (icon_info->subtex.height * inv_height); + } + } + + Result res = load_entries(main_paths[i], current_list, loading_screen); if(R_SUCCEEDED(res)) { - if(current_list->entries_count > current_list->entries_loaded*ICONS_OFFSET_AMOUNT) + if(current_list->entries_count > current_list->entries_loaded * ICONS_OFFSET_AMOUNT) iconLoadingThread_arg.run_thread = true; - sort_by_name(current_list); - DEBUG("total: %i\n", current_list->entries_count); load_icons_first(current_list, false); + sort_by_name(current_list); - void (*install_check_function)(void*) = NULL; + void (*install_check_function)(void *) = NULL; if(i == MODE_THEMES) install_check_function = themes_check_installed; else if(i == MODE_SPLASHES) install_check_function = splash_check_installed; - Thread_Arg_s * current_arg = &installCheckThreads_arg[i]; + Thread_Arg_s * current_arg = &install_check_threads_arg[i]; current_arg->run_thread = true; - current_arg->thread_arg = (void**)current_list; + current_arg->thread_arg = (void **)current_list; if(install_check_function != NULL) { - installCheckThreads[i] = threadCreate(install_check_function, current_arg, __stacksize__, 0x3f, -2, false); + install_check_threads[i] = threadCreate(install_check_function, current_arg, __stacksize__, 0x3f, -2, false); svcSleepThread(1e8); } } @@ -246,11 +277,11 @@ static void load_lists(Entry_List_s * lists) start_thread(); } -static SwkbdCallbackResult jump_menu_callback(void* entries_count, const char** ppMessage, const char* text, size_t textlen) +static SwkbdCallbackResult jump_menu_callback(void * entries_count, const char ** ppMessage, const char * text, size_t textlen) { (void)textlen; int typed_value = atoi(text); - if(typed_value > *(int*)entries_count) + if(typed_value > *(int *)entries_count) { *ppMessage = "The new position has to be\nsmaller or equal to the\nnumber of entries!"; return SWKBD_CALLBACK_CONTINUE; @@ -505,7 +536,7 @@ int main(void) toggle_preview: if(!preview_mode) { - preview_mode = load_preview(*current_list, &preview, &preview_offset); + preview_mode = load_preview(current_list, &preview, &preview_offset); if(preview_mode) { end_frame(); @@ -514,7 +545,7 @@ int main(void) if(current_mode == MODE_THEMES && dspfirm) { audio = calloc(1, sizeof(audio_s)); - Result r = load_audio(current_list->entries[current_list->selected_entry], audio); + Result r = load_audio(¤t_list->entries[current_list->selected_entry], audio); if (R_SUCCEEDED(r)) play_audio(audio); else audio = NULL; } @@ -557,7 +588,7 @@ int main(void) { aptSetHomeAllowed(false); draw_install(INSTALL_BGM); - if(R_SUCCEEDED(bgm_install(*current_entry))) + if(R_SUCCEEDED(bgm_install(current_entry))) { for(int i = 0; i < current_list->entries_count; i++) { @@ -574,7 +605,7 @@ int main(void) { aptSetHomeAllowed(false); draw_install(INSTALL_SINGLE); - if(R_SUCCEEDED(theme_install(*current_entry))) + if(R_SUCCEEDED(theme_install(current_entry))) { for(int i = 0; i < current_list->entries_count; i++) { @@ -591,7 +622,7 @@ int main(void) { aptSetHomeAllowed(false); draw_install(INSTALL_NO_BGM); - if(R_SUCCEEDED(no_bgm_install(*current_entry))) + if(R_SUCCEEDED(no_bgm_install(current_entry))) { for(int i = 0; i < current_list->entries_count; i++) { @@ -618,7 +649,7 @@ int main(void) { aptSetHomeAllowed(false); draw_install(INSTALL_SHUFFLE); - Result res = shuffle_install(*current_list); + Result res = shuffle_install(current_list); if(R_FAILED(res)) DEBUG("shuffle install result: %lx\n", res); else { @@ -723,7 +754,7 @@ int main(void) break; case MODE_SPLASHES: draw_install(INSTALL_SPLASH); - splash_install(*current_entry); + splash_install(current_entry); for(int i = 0; i < current_list->entries_count; i++) { Entry_s * splash = ¤t_list->entries[i]; @@ -889,7 +920,7 @@ int main(void) { for(int i = 0; i < current_list->entries_loaded; i++) { - u16 miny = 24 + current_list->entry_size*i; + u16 miny = 24 + current_list->entry_size * i; u16 maxy = miny + current_list->entry_size; if(BETWEEN(miny, y, maxy) && current_list->scroll + i < current_list->entries_count) { diff --git a/source/music.c b/source/music.c index deb9106..768d162 100644 --- a/source/music.c +++ b/source/music.c @@ -28,7 +28,7 @@ #include "loading.h" // Play a given audio struct -Result update_audio(audio_s *audio) +Result update_audio(audio_s * audio) { u32 size = audio->wave_buf[audio->buf_pos].nsamples * 4 - audio->data_read; DEBUG(" Audio Size: %ld\n", size); @@ -36,7 +36,7 @@ Result update_audio(audio_s *audio) { DEBUG(" Attempting ov_read\n"); int bitstream; - u32 read = ov_read(&audio->vf, (char*)audio->wave_buf[audio->buf_pos].data_vaddr + audio->data_read, size, &bitstream); // read 1 vorbis packet into wave buffer + u32 read = ov_read(&audio->vf, (char *)audio->wave_buf[audio->buf_pos].data_vaddr + audio->data_read, size, &bitstream); // read 1 vorbis packet into wave buffer DEBUG(" ov_read successful\n"); if (read <= 0) // EoF or error @@ -64,8 +64,8 @@ Result update_audio(audio_s *audio) return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_APPLICATION, RD_SUCCESS); } -void thread_audio(void* data) { - audio_s *audio = (audio_s*)data; +void thread_audio(void * data) { + audio_s * audio = (audio_s *)data; while(!audio->stop) { update_audio(audio); } @@ -73,16 +73,16 @@ void thread_audio(void* data) { 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); + linearFree((void *)audio->wave_buf[0].data_vaddr); + linearFree((void *)audio->wave_buf[1].data_vaddr); } -void play_audio(audio_s *audio) { +void play_audio(audio_s * audio) { audio->playing_thread = threadCreate(thread_audio, audio, 0x1000, 0x3F, 1, false); } -void stop_audio(audio_s** audio_ptr) { - audio_s* audio = *audio_ptr; +void stop_audio(audio_s ** audio_ptr) { + audio_s * audio = *audio_ptr; if(audio->playing_thread) { audio->stop = true; diff --git a/source/remote.c b/source/remote.c index 955c60a..7964514 100644 --- a/source/remote.c +++ b/source/remote.c @@ -109,26 +109,18 @@ static void free_icons(Entry_List_s * list) { if (list != NULL) { - if (list->icons != NULL) - { - for (int i = 0; i < list->entries_count; i++) - { - C3D_TexDelete(list->icons[i]->tex); - free(list->icons[i]->tex); - free(list->icons[i]); - } - free(list->icons); - } + C3D_TexDelete(&list->icons_texture); + free(list->icons_info); } } -static C2D_Image * load_remote_smdh(Entry_s * entry, bool ignore_cache) +static void load_remote_smdh(Entry_s * entry, C3D_Tex * into_tex, const Entry_Icon_s * icon_info, bool ignore_cache) { bool not_cached = true; char * smdh_buf = NULL; - u32 smdh_size = load_data("/info.smdh", *entry, &smdh_buf); + u32 smdh_size = load_data("/info.smdh", entry, &smdh_buf); - not_cached = !smdh_size || ignore_cache; // if the size is 0, the file wasn't there + not_cached = (smdh_size != sizeof(Icon_s)) || ignore_cache; // if the size is 0, the file wasn't there if (not_cached) { @@ -137,15 +129,15 @@ static C2D_Image * load_remote_smdh(Entry_s * entry, bool ignore_cache) char * api_url = NULL; asprintf(&api_url, THEMEPLAZA_SMDH_FORMAT, entry->tp_download_id); Result res = http_get(api_url, NULL, &smdh_buf, &smdh_size, INSTALL_NONE, "application/octet-stream"); + free(api_url); if (R_FAILED(res)) { free(smdh_buf); - return false; + return; } - free(api_url); } - if (!smdh_size) + if (smdh_size != sizeof(Icon_s)) { free(smdh_buf); smdh_buf = NULL; @@ -157,29 +149,28 @@ static C2D_Image * load_remote_smdh(Entry_s * entry, bool ignore_cache) utf8_to_utf16(fallback_name, (u8 *)"No name", 0x80); parse_smdh(smdh, entry, fallback_name); - C2D_Image * image = loadTextureIcon(smdh); - if (not_cached) + if(smdh_buf != NULL) { - FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_UTF16, entry->path), FS_ATTRIBUTE_DIRECTORY); - u16 path[0x107] = { 0 }; - strucat(path, entry->path); - struacat(path, "/info.smdh"); - remake_file(fsMakePath(PATH_UTF16, path), ArchiveSD, smdh_size); - buf_to_file(smdh_size, fsMakePath(PATH_UTF16, path), ArchiveSD, smdh_buf); + copy_texture_data(into_tex, smdh->big_icon, icon_info); + if (not_cached) + { + FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_UTF16, entry->path), FS_ATTRIBUTE_DIRECTORY); + u16 path[0x107] = { 0 }; + strucat(path, entry->path); + struacat(path, "/info.smdh"); + remake_file(fsMakePath(PATH_UTF16, path), ArchiveSD, smdh_size); + buf_to_file(smdh_size, fsMakePath(PATH_UTF16, path), ArchiveSD, smdh_buf); + } + free(smdh_buf); } - free(smdh_buf); - - return image; } static void load_remote_entries(Entry_List_s * list, json_t * ids_array, bool ignore_cache, InstallType type) { - free_icons(list); - list->entries_count = json_array_size(ids_array); free(list->entries); + list->entries_count = json_array_size(ids_array); list->entries = calloc(list->entries_count, sizeof(Entry_s)); - list->icons = calloc(list->entries_count, sizeof(C2D_Image * )); list->entries_loaded = list->entries_count; size_t i = 0; @@ -195,7 +186,7 @@ static void load_remote_entries(Entry_List_s * list, json_t * ids_array, bool ig utf8_to_utf16(current_entry->path, (u8 *)entry_path, 0x106); free(entry_path); - list->icons[i] = load_remote_smdh(current_entry, ignore_cache); + load_remote_smdh(current_entry, &list->icons_texture, &list->icons_info[i], ignore_cache); } } @@ -231,9 +222,6 @@ static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mod { list->tp_current_page = page; list->mode = mode; - list->entry_size = entry_size[mode]; - list->entries_per_screen_v = entries_per_screen_v[mode]; - list->entries_per_screen_h = entries_per_screen_h[mode]; json_error_t error; json_t * root = json_loadb(page_json, json_len, 0, &error); @@ -263,16 +251,16 @@ static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mod free(page_json); } -static u16 previous_path_preview[0x106] = { 0 }; +static u16 previous_path_preview[0x106]; -static bool load_remote_preview(Entry_s * entry, C2D_Image * preview_image, int * preview_offset) +static bool load_remote_preview(const Entry_s * entry, C2D_Image * preview_image, int * preview_offset) { bool not_cached = true; if (!memcmp(&previous_path_preview, entry->path, 0x106 * sizeof(u16))) return true; char * preview_png = NULL; - u32 preview_size = load_data("/preview.png", *entry, &preview_png); + u32 preview_size = load_data("/preview.png", entry, &preview_png); not_cached = !preview_size; @@ -324,14 +312,14 @@ static bool load_remote_preview(Entry_s * entry, C2D_Image * preview_image, int return ret; } -static u16 previous_path_bgm[0x106] = { 0 }; +static u16 previous_path_bgm[0x106]; -static void load_remote_bgm(Entry_s * entry) +static void load_remote_bgm(const Entry_s * entry) { if (!memcmp(&previous_path_bgm, entry->path, 0x106 * sizeof(u16))) return; char * bgm_ogg = NULL; - u32 bgm_size = load_data("/bgm.ogg", *entry, &bgm_ogg); + u32 bgm_size = load_data("/bgm.ogg", entry, &bgm_ogg); if (!bgm_size) { @@ -518,6 +506,32 @@ bool themeplaza_browser(EntryMode mode) Entry_List_s list = { 0 }; Entry_List_s * current_list = &list; current_list->tp_search = strdup(""); + + list.entries_per_screen_v = entries_per_screen_v[mode]; + list.entries_per_screen_h = entries_per_screen_h[mode]; + list.entry_size = entry_size[mode]; + C3D_TexInit(¤t_list->icons_texture, 512, 256, GPU_RGB565); + C3D_TexSetFilter(¤t_list->icons_texture, GPU_NEAREST, GPU_NEAREST); + const int entries_icon_count = current_list->entries_per_screen_h * current_list->entries_per_screen_v; + current_list->icons_info = calloc(entries_icon_count, sizeof(Entry_Icon_s)); + + const float inv_width = 1.0f / current_list->icons_texture.width; + const float inv_height = 1.0f / current_list->icons_texture.height; + for(int i = 0; i < entries_icon_count; ++i) + { + Entry_Icon_s * const icon_info = ¤t_list->icons_info[i]; + // division by how many icons can fit horizontally + const div_t d = div(i, (current_list->icons_texture.width / 48)); + icon_info->x = d.rem * current_list->entry_size; + icon_info->y = d.quot * current_list->entry_size; + icon_info->subtex.width = current_list->entry_size; + icon_info->subtex.height = current_list->entry_size; + icon_info->subtex.left = icon_info->x * inv_width; + icon_info->subtex.top = 1.0f - (icon_info->y * inv_height); + icon_info->subtex.right = icon_info->subtex.left + (icon_info->subtex.width * inv_width); + icon_info->subtex.bottom = icon_info->subtex.top - (icon_info->subtex.height * inv_height); + } + load_remote_list(current_list, 1, mode, false); C2D_Image preview = { 0 }; @@ -615,7 +629,7 @@ bool themeplaza_browser(EntryMode mode) { load_remote_bgm(current_entry); audio = calloc(1, sizeof(audio_s)); - if (R_FAILED(load_audio(*current_entry, audio))) audio = NULL; + if (R_FAILED(load_audio(current_entry, audio))) audio = NULL; if (audio != NULL) play_audio(audio); } } @@ -812,7 +826,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; @@ -1131,7 +1145,7 @@ no_error:; // download exactly chunk_size bytes and toss them into buf. // size contains the current offset into buf. - ret = httpcDownloadData(&context, (u8*)(*buf) + *size, chunk_size, &read_size); + ret = httpcDownloadData(&context, (u8 *)(*buf) + *size, chunk_size, &read_size); /* FIXME: I have no idea why this doesn't work, but it causes problems. Look into it later if (R_FAILED(ret)) { diff --git a/source/splashes.c b/source/splashes.c index b764f43..477fd7d 100644 --- a/source/splashes.c +++ b/source/splashes.c @@ -34,7 +34,7 @@ void splash_delete(void) remove("/luma/splashbottom.bin"); } -void splash_install(Entry_s splash) +void splash_install(const Entry_s * splash) { char *screen_buf = NULL; @@ -103,8 +103,8 @@ void splash_check_installed(void * void_arg) for(int i = 0; i < list->entries_count && arg->run_thread; i++) { Entry_s * splash = &list->entries[i]; - top_size = load_data("/splash.bin", *splash, &top_buf); - bottom_size = load_data("/splashbottom.bin", *splash, &bottom_buf); + top_size = load_data("/splash.bin", splash, &top_buf); + bottom_size = load_data("/splashbottom.bin", splash, &bottom_buf); if(!top_size && !bottom_size) { diff --git a/source/themes.c b/source/themes.c index 9abc4ec..9075587 100644 --- a/source/themes.c +++ b/source/themes.c @@ -32,26 +32,26 @@ #define BODY_CACHE_SIZE 0x150000 #define BGM_MAX_SIZE 0x337000 -static Result install_theme_internal(Entry_List_s themes, int installmode) +static Result install_theme_internal(const Entry_List_s * themes, int installmode) { Result res = 0; - char* music = NULL; + char * music = NULL; u32 music_size = 0; u32 shuffle_music_sizes[MAX_SHUFFLE_THEMES] = {0}; - char* body = NULL; + char * body = NULL; u32 body_size = 0; u32 shuffle_body_sizes[MAX_SHUFFLE_THEMES] = {0}; bool mono_audio = false; if(installmode & THEME_INSTALL_SHUFFLE) { - if(themes.shuffle_count < 2) + if(themes->shuffle_count < 2) { DEBUG("not enough themes selected for shuffle\n"); return MAKERESULT(RL_USAGE, RS_INVALIDARG, RM_COMMON, RD_INVALID_SELECTION); } - if(themes.shuffle_count > MAX_SHUFFLE_THEMES) + if(themes->shuffle_count > MAX_SHUFFLE_THEMES) { DEBUG("too many themes selected for shuffle\n"); return MAKERESULT(RL_USAGE, RS_INVALIDARG, RM_COMMON, RD_INVALID_SELECTION); @@ -68,16 +68,15 @@ static Result install_theme_internal(Entry_List_s themes, int installmode) FSUSER_OpenFile(&body_cache_handle, ArchiveThemeExt, fsMakePath(PATH_ASCII, "/BodyCache_rd.bin"), FS_OPEN_WRITE, 0); } - - for(int i = 0; i < themes.entries_count; i++) + for(int i = 0; i < themes->entries_count; i++) { - Entry_s * current_theme = &themes.entries[i]; + const Entry_s * current_theme = &themes->entries[i]; if(current_theme->in_shuffle) { if(installmode & THEME_INSTALL_BODY) { - body_size = load_data("/body_LZ.bin", *current_theme, &body); + body_size = load_data("/body_LZ.bin", current_theme, &body); if(body_size == 0) { free(body); @@ -110,7 +109,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode) } else { - music_size = load_data("/bgm.bcstm", *current_theme, &music); + music_size = load_data("/bgm.bcstm", current_theme, &music); if(music_size > BGM_MAX_SIZE) { @@ -169,7 +168,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode) } else { - Entry_s current_theme = themes.entries[themes.selected_entry]; + const Entry_s * current_theme = &themes->entries[themes->selected_entry]; if(installmode & THEME_INSTALL_BODY) { @@ -209,7 +208,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode) res = buf_to_file(music_size, fsMakePath(PATH_ASCII, "/BgmCache.bin"), ArchiveThemeExt, music); free(music); - char *body_buf = NULL; + char * body_buf = NULL; u32 uncompressed_size = decompress_lz_file(fsMakePath(PATH_ASCII, "/BodyCache.bin"), ArchiveThemeExt, &body_buf); if (body_buf[5] != 1) { @@ -231,7 +230,7 @@ static Result install_theme_internal(Entry_List_s themes, int installmode) } //---------------------------------------- - char* thememanage_buf = NULL; + char * thememanage_buf = NULL; file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf); ThemeManage_bin_s * theme_manage = (ThemeManage_bin_s *)thememanage_buf; @@ -268,17 +267,17 @@ static Result install_theme_internal(Entry_List_s themes, int installmode) //---------------------------------------- //---------------------------------------- - char* savedata_buf = NULL; + char * savedata_buf = NULL; u32 savedata_size = file_to_buf(fsMakePath(PATH_ASCII, "/SaveData.dat"), ArchiveHomeExt, &savedata_buf); - SaveData_dat_s* savedata = (SaveData_dat_s*)savedata_buf; + SaveData_dat_s * savedata = (SaveData_dat_s *)savedata_buf; memset(&savedata->theme_entry, 0, sizeof(ThemeEntry_s)); savedata->shuffle = (installmode & THEME_INSTALL_SHUFFLE) ? 1 : 0; - memset(savedata->shuffle_themes, 0, sizeof(ThemeEntry_s)*MAX_SHUFFLE_THEMES); + memset(savedata->shuffle_themes, 0, sizeof(ThemeEntry_s) * MAX_SHUFFLE_THEMES); if(installmode & THEME_INSTALL_SHUFFLE) { - for(int i = 0; i < themes.shuffle_count; i++) + for(int i = 0; i < themes->shuffle_count; i++) { savedata->shuffle_themes[i].type = 3; savedata->shuffle_themes[i].index = i; @@ -304,40 +303,40 @@ static Result install_theme_internal(Entry_List_s themes, int installmode) return 0; } -inline Result theme_install(Entry_s theme) +Result theme_install(Entry_s * theme) { Entry_List_s list = {0}; list.entries_count = 1; - list.entries = &theme; + list.entries = theme; list.selected_entry = 0; - return install_theme_internal(list, THEME_INSTALL_BODY | THEME_INSTALL_BGM); + return install_theme_internal(&list, THEME_INSTALL_BODY | THEME_INSTALL_BGM); } -inline Result bgm_install(Entry_s theme) +Result bgm_install(Entry_s * theme) { Entry_List_s list = {0}; list.entries_count = 1; - list.entries = &theme; + list.entries = theme; list.selected_entry = 0; - return install_theme_internal(list, THEME_INSTALL_BGM); + return install_theme_internal(&list, THEME_INSTALL_BGM); } -inline Result no_bgm_install(Entry_s theme) +Result no_bgm_install(Entry_s * theme) { Entry_List_s list = {0}; list.entries_count = 1; - list.entries = &theme; + list.entries = theme; list.selected_entry = 0; - return install_theme_internal(list, THEME_INSTALL_BODY); + return install_theme_internal(&list, THEME_INSTALL_BODY); } -inline Result shuffle_install(Entry_List_s themes) +Result shuffle_install(const Entry_List_s * themes) { return install_theme_internal(themes, THEME_INSTALL_SHUFFLE | THEME_INSTALL_BODY | THEME_INSTALL_BGM); } static SwkbdCallbackResult -dir_name_callback(void *data, const char ** ppMessage, const char * text, size_t textlen) +dir_name_callback(void * data, const char ** ppMessage, const char * text, size_t textlen) { (void)textlen; (void)data; @@ -377,14 +376,14 @@ Result dump_current_theme(void) struacat(path, output_dir); FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_UTF16, path), FS_ATTRIBUTE_DIRECTORY); - char *thememanage_buf = NULL; + char * thememanage_buf = NULL; file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf); ThemeManage_bin_s * theme_manage = (ThemeManage_bin_s *)thememanage_buf; u32 theme_size = theme_manage->body_size; u32 bgm_size = theme_manage->music_size; free(thememanage_buf); - char *temp_buf = NULL; + char * temp_buf = NULL; file_to_buf(fsMakePath(PATH_ASCII, "/BodyCache.bin"), ArchiveThemeExt, &temp_buf); u16 path_output[0x107] = { 0 }; memcpy(path_output, path, 0x107); @@ -402,7 +401,7 @@ Result dump_current_theme(void) free(temp_buf); temp_buf = NULL; - char *smdh_file = calloc(1, 0x36c0); + char * smdh_file = calloc(1, 0x36c0); smdh_file[0] = 0x53; // SMDH magic smdh_file[1] = 0x4d; smdh_file[2] = 0x44; @@ -467,7 +466,7 @@ Result dump_all_themes(void) return -1; } - const char* region_arr[7] = { + const char * region_arr[7] = { "JPN", "USA", "EUR", @@ -477,7 +476,7 @@ Result dump_all_themes(void) "TWN", }; - const char* language_arr[12] = { + const char * language_arr[12] = { "jp", "en", "fr", @@ -496,14 +495,14 @@ Result dump_all_themes(void) if(R_FAILED(res)) return res; - Icon_s* smdh_data = calloc(1, sizeof(Icon_s)); + Icon_s * smdh_data = calloc(1, sizeof(Icon_s)); smdh_data->_padding1[0] = 0x53; // SMDH magic smdh_data->_padding1[1] = 0x4d; smdh_data->_padding1[2] = 0x44; smdh_data->_padding1[3] = 0x48; - utf8_to_utf16(smdh_data->author, (u8*)"Nintendo", 0x40); - utf8_to_utf16(smdh_data->desc, (u8*)"Official theme. For personal use only. Do not redistribute.", 0x80); + utf8_to_utf16(smdh_data->author, (u8 *)"Nintendo", 0x40); + utf8_to_utf16(smdh_data->desc, (u8 *)"Official theme. For personal use only. Do not redistribute.", 0x80); for(u32 dlc_index = 0; dlc_index <= 0xFF; ++dlc_index) { @@ -521,7 +520,7 @@ Result dump_all_themes(void) break; } - AM_ContentInfo* contentInfos = calloc(count, sizeof(AM_ContentInfo)); + AM_ContentInfo * contentInfos = calloc(count, sizeof(AM_ContentInfo)); u32 readcount = 0; res = AMAPP_ListDLCContentInfos(&readcount, MEDIATYPE_SD, titleId, count, 0, contentInfos); if(R_FAILED(res)) @@ -571,14 +570,14 @@ Result dump_all_themes(void) char contentinfoarchive_path[40] = {0}; sprintf(contentinfoarchive_path, "meta:/ContentInfoArchive_%s_%s.bin", region_arr[regionCode], language_arr[language]); - FILE* fh = fopen(contentinfoarchive_path, "rb"); + FILE * fh = fopen(contentinfoarchive_path, "rb"); if(fh != NULL) { for(u32 i = 0; i < readcount; ++i) { if(i == 0) continue; - AM_ContentInfo* content = &contentInfos[i]; + AM_ContentInfo * content = &contentInfos[i]; if((content->flags & (AM_CONTENT_DOWNLOADED | AM_CONTENT_OWNED)) == (AM_CONTENT_DOWNLOADED | AM_CONTENT_OWNED)) { long off = 0x8 + 0xC8 * i; @@ -614,15 +613,15 @@ Result dump_all_themes(void) 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); + utf8_to_utf16(smdh_data->name, (u8 *)(content_data + 0), 0x40); - FILE* theme_file = fopen("theme:/body_LZ.bin", "rb"); + 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); + char * theme_data = malloc(theme_size); fread(theme_data, 1, theme_size, theme_file); fclose(theme_file); @@ -633,13 +632,13 @@ Result dump_all_themes(void) free(theme_data); } - FILE* bgm_file = fopen("theme:/bgm.bcstm", "rb"); + 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); + char * bgm_data = malloc(bgm_size); fread(bgm_data, 1, bgm_size, bgm_file); fclose(bgm_file); @@ -653,13 +652,13 @@ Result dump_all_themes(void) romfsUnmount("theme"); char icondatapath[0x107] = {0}; sprintf(icondatapath, "meta:/icons/%ld.icn", extra_index); - FILE* iconfile = fopen(icondatapath, "rb"); + 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); + buf_to_file(0x36c0, fsMakePath(PATH_ASCII, path), ArchiveSD, (char *)smdh_data); } } @@ -686,25 +685,25 @@ void themes_check_installed(void * void_arg) if(list == NULL || list->entries == NULL) return; #ifndef CITRA_MODE - char* savedata_buf = NULL; + char * savedata_buf = NULL; u32 savedata_size = file_to_buf(fsMakePath(PATH_ASCII, "/SaveData.dat"), ArchiveHomeExt, &savedata_buf); if(!savedata_size) return; - SaveData_dat_s* savedata = (SaveData_dat_s*)savedata_buf; + SaveData_dat_s * savedata = (SaveData_dat_s *)savedata_buf; bool shuffle = savedata->shuffle; free(savedata_buf); #define HASH_SIZE_BYTES 256/8 u8 body_hash[MAX_SHUFFLE_THEMES][HASH_SIZE_BYTES]; - memset(body_hash, 0, MAX_SHUFFLE_THEMES*HASH_SIZE_BYTES); + memset(body_hash, 0, MAX_SHUFFLE_THEMES * HASH_SIZE_BYTES); - char* thememanage_buf = NULL; + char * thememanage_buf = NULL; u32 theme_manage_size = file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf); if(!theme_manage_size) return; ThemeManage_bin_s * theme_manage = (ThemeManage_bin_s *)thememanage_buf; u32 single_body_size = theme_manage->body_size; u32 shuffle_body_sizes[MAX_SHUFFLE_THEMES] = {0}; - memcpy(shuffle_body_sizes, theme_manage->shuffle_body_sizes, sizeof(u32)*MAX_SHUFFLE_THEMES); + memcpy(shuffle_body_sizes, theme_manage->shuffle_body_sizes, sizeof(u32) * MAX_SHUFFLE_THEMES); free(thememanage_buf); if(shuffle) @@ -715,7 +714,7 @@ void themes_check_installed(void * void_arg) for(int i = 0; i < MAX_SHUFFLE_THEMES; i++) { - FSUSER_UpdateSha256Context(body_buf + BODY_CACHE_SIZE*i, shuffle_body_sizes[i], body_hash[i]); + FSUSER_UpdateSha256Context(body_buf + BODY_CACHE_SIZE * i, shuffle_body_sizes[i], body_hash[i]); } free(body_buf); @@ -736,7 +735,7 @@ void themes_check_installed(void * void_arg) { Entry_s * theme = &list->entries[i]; char * theme_body = NULL; - u32 theme_body_size = load_data("/body_LZ.bin", *theme, &theme_body); + u32 theme_body_size = load_data("/body_LZ.bin", theme, &theme_body); if(!theme_body_size) return; u8 theme_body_hash[HASH_SIZE_BYTES]; diff --git a/source/unicode.c b/source/unicode.c index 57bbd2d..5dcf3e7 100644 --- a/source/unicode.c +++ b/source/unicode.c @@ -26,40 +26,42 @@ #include "unicode.h" -ssize_t strulen(const u16 *input, ssize_t max_len) +ssize_t strulen(const u16 * input, ssize_t max_len) { for (int i = 0; i < max_len; i++) if (input[i] == 0) return i; return max_len; } -void struacat(u16 *input, const char *addition) +void struacat(u16 * input, const char * addition) { - ssize_t len = strulen(input, 0x106); - for (u16 i = len; i < strlen(addition) + len; i++) + const ssize_t len = strulen(input, 0x106); + const u16 stop_at = strlen(addition); + for (u16 i = 0; i < stop_at; i++) { - input[i] = addition[i - len]; + input[i + len] = addition[i]; } - input[strlen(addition) + len] = 0; + input[stop_at + len] = 0; } -void printu(u16 *input) +void printu(u16 * input) { ssize_t in_len = strulen(input, 0x106); ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination - wchar_t *buf = calloc(buf_len, sizeof(wchar_t)); - utf16_to_utf32((u32*)buf, input, buf_len); + wchar_t * buf = calloc(buf_len, sizeof(wchar_t)); + utf16_to_utf32((u32 *)buf, input, buf_len); char cbuf[0x106]; sprintf(cbuf, "%ls\n", buf); DEBUG(cbuf); free(buf); } -u16 *strucat(u16 *destination, const u16 *source) +u16 * strucat(u16 * destination, const u16 * source) { ssize_t dest_len = strulen(destination, 0x106); ssize_t source_len = strulen(source, 0x106); memcpy(&destination[dest_len], source, source_len * sizeof(u16)); + destination[min(dest_len + source_len, 0x106 - 1)] = 0; return destination; } \ No newline at end of file