diff --git a/src/menu/menu.c b/src/menu/menu.c index 0672cf56..f82dd897 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -15,7 +15,7 @@ #include "views/views.h" -#define TV_TYPE_RAM *((uint32_t *) (0x80000300)) +#define TV_TYPE_RAM *((uint32_t *) (0x80000300)) #define CACHE_DIRECTORY "sd:/menu/cache" #define BACKGROUND_CACHE "sd:/menu/cache/background.data" @@ -62,9 +62,10 @@ static void menu_init (boot_params_t *boot_params) { menu->boot_params = boot_params; bool default_directory_exists = directory_exists(menu->settings.default_directory); + char *init_directory = default_directory_exists ? menu->settings.default_directory : ""; menu->browser.valid = false; - menu->browser.directory = path_init(default_directory_exists ? menu->settings.default_directory : NULL); + menu->browser.directory = path_init("sd:/", init_directory); tv_type = get_tv_type(); if ((tv_type == TV_PAL) && menu->settings.pal60) { diff --git a/src/menu/menu_state.h b/src/menu/menu_state.h index 4088bcb3..074f5dba 100644 --- a/src/menu/menu_state.h +++ b/src/menu/menu_state.h @@ -84,6 +84,7 @@ typedef struct { path_t *directory; entry_t list[BROWSER_LIST_SIZE]; int entries; + entry_t *entry; int selected; } browser; } menu_t; diff --git a/src/menu/path.c b/src/menu/path.c index 55a2aa1e..2e49eadf 100644 --- a/src/menu/path.c +++ b/src/menu/path.c @@ -19,7 +19,7 @@ static void path_resize (path_t *path, size_t min_length) { assert(path->buffer != NULL); } -path_t *path_init (char *string) { +static path_t *path_create (char *string) { if (string == NULL) { string = ""; } @@ -28,6 +28,31 @@ path_t *path_init (char *string) { path_resize(path, strlen(string)); memset(path->buffer, 0, path->capacity + 1); strcpy(path->buffer, string); + path->root = path->buffer; + return path; +} + +static void path_append (path_t *path, char *string) { + size_t buffer_length = strlen(path->buffer); + size_t string_length = strlen(string); + size_t new_path_length = buffer_length + string_length; + if (new_path_length > path->capacity) { + path_resize(path, new_path_length); + } + strcat(path->buffer, string); +} + + +path_t *path_init (char *prefix, char *string) { + path_t *path = path_create(prefix); + size_t prefix_length = strlen(prefix); + if ((prefix_length > 0) && (prefix[prefix_length - 1] == '/')) { + path->root = path->buffer + prefix_length - 1; + } else { + path->root = path->buffer + prefix_length; + path_append(path, "/"); + } + path_push(path, string); return path; } @@ -39,7 +64,15 @@ void path_free (path_t *path) { } path_t *path_clone (path_t *path) { - return path_init(path->buffer); + path_t *cloned = path_create(path->buffer); + cloned->root = cloned->buffer + (path->root - path->buffer); + return cloned; +} + +path_t *path_clone_push (path_t *path, char *string) { + path_t *cloned = path_clone(path); + path_push(cloned, string); + return cloned; } char *path_get (path_t *path) { @@ -47,26 +80,12 @@ char *path_get (path_t *path) { } char *path_last_get (path_t *path) { - char *last_slash = strrchr(path->buffer, '/'); - return (last_slash == NULL) ? path->buffer : (last_slash + 1); + char *last_slash = strrchr(path->root, '/'); + return (last_slash == NULL) ? path->root : (last_slash + 1); } bool path_is_root (path_t *path) { - return (strcmp(path->buffer, "") == 0) || (strcmp(path->buffer, "/") == 0); -} - -void path_append (path_t *path, char *string) { - size_t buffer_length = strlen(path->buffer); - size_t string_length = strlen(string); - size_t new_path_length = buffer_length + string_length; - if (new_path_length > path->capacity) { - path_resize(path, new_path_length); - } - strcat(path->buffer, string); -} - -void path_concat (path_t *dst, path_t *src) { - path_append(dst, src->buffer); + return (strcmp(path->root, "/") == 0); } void path_push (path_t *path, char *string) { @@ -80,8 +99,13 @@ void path_push (path_t *path, char *string) { } void path_pop (path_t *path) { - char *last_slash = strrchr(path->buffer, '/'); - if (last_slash != NULL) { + if (path_is_root(path)) { + return; + } + char *last_slash = strrchr(path->root, '/'); + if (last_slash == path->root) { + *(last_slash + 1) = '\0'; + } else if (last_slash != NULL) { *last_slash = '\0'; } } diff --git a/src/menu/path.h b/src/menu/path.h index e53dc363..9c02c179 100644 --- a/src/menu/path.h +++ b/src/menu/path.h @@ -14,18 +14,18 @@ /** @brief Path Structure */ typedef struct { char *buffer; + char *root; size_t capacity; } path_t; -path_t *path_init (char *string); +path_t *path_init (char *prefix, char *string); void path_free (path_t *path); path_t *path_clone (path_t *string); +path_t *path_clone_push (path_t *path, char *string); char *path_get (path_t *path); char *path_last_get (path_t *path); bool path_is_root (path_t *path); -void path_append (path_t *path, char *string); -void path_concat (path_t *dst, path_t *str); void path_push (path_t *path, char *string); void path_pop (path_t *path); char *path_ext_get (path_t *path); diff --git a/src/menu/rom_database.c b/src/menu/rom_database.c index 2d16b4cf..840dfb9d 100644 --- a/src/menu/rom_database.c +++ b/src/menu/rom_database.c @@ -38,12 +38,9 @@ uint8_t extract_homebrew_save_type(uint8_t save_type) { * @brief Reads the N64 ROM header from a file. @see https://n64brew.dev/wiki/ROM_Header */ rom_header_t file_read_rom_header(char *path) { - char *sd_path = calloc(4 + strlen(path) + 1, sizeof(char)); - sprintf(sd_path, "sd:/%s", path); + FILE *fp = fopen(path, "rb"); - FILE *fp = fopen(sd_path, "rb"); - - debugf("loading path: %s\n", sd_path); + debugf("loading path: %s\n", path); if (!fp) { debugf("Error loading rom file header\n"); } @@ -82,8 +79,7 @@ rom_header_t file_read_rom_header(char *path) { fclose(fp); - free(sd_path); - + // FIXME: memory leak, rom header is copied, pointer should be returned instead or data freed before returning return *rom_header; } diff --git a/src/menu/views/browser.c b/src/menu/views/browser.c index 5288d396..cec47fae 100644 --- a/src/menu/views/browser.c +++ b/src/menu/views/browser.c @@ -58,10 +58,12 @@ static bool load_directory (menu_t *menu) { for (int i = menu->browser.entries - 1; i >= 0; i--) { free(menu->browser.list[i].name); } + menu->browser.entries = 0; menu->browser.selected = -1; + menu->browser.entry = NULL; - if (f_opendir(&dir, path_get(menu->browser.directory)) != FR_OK) { + if (f_opendir(&dir, strip_sd_prefix(path_get(menu->browser.directory))) != FR_OK) { return true; } @@ -118,6 +120,7 @@ static bool load_directory (menu_t *menu) { if (menu->browser.entries > 0) { menu->browser.selected = 0; + menu->browser.entry = &menu->browser.list[menu->browser.selected]; } qsort(menu->browser.list, menu->browser.entries, sizeof(entry_t), compare_entry); @@ -155,6 +158,7 @@ static bool pop_directory (menu_t *menu) { for (int i = 0; i < menu->browser.entries; i++) { if (strcmp(menu->browser.list[i].name, path_last_get(previous_directory)) == 0) { menu->browser.selected = i; + menu->browser.entry = &menu->browser.list[menu->browser.selected]; break; } } @@ -180,14 +184,13 @@ static void process (menu_t *menu) { menu->browser.selected = menu->browser.entries - 1; } } + menu->browser.entry = &menu->browser.list[menu->browser.selected]; } - if (menu->actions.enter && menu->browser.selected >= 0) { - entry_t *entry = &menu->browser.list[menu->browser.selected]; - - switch (entry->type) { + if (menu->actions.enter && menu->browser.entry) { + switch (menu->browser.entry->type) { case ENTRY_TYPE_DIR: - if (push_directory(menu, entry->name)) { + if (push_directory(menu, menu->browser.entry->name)) { menu->browser.valid = false; menu_show_error(menu, "Couldn't open next directory"); } @@ -213,7 +216,7 @@ static void process (menu_t *menu) { menu->browser.valid = false; menu_show_error(menu, "Couldn't open last directory"); } - } else if (menu->actions.file_info && menu->browser.selected >= 0) { + } else if (menu->actions.file_info && menu->browser.entry) { menu->next_mode = MENU_MODE_FILE_INFO; } else if (menu->actions.system_info) { menu->next_mode = MENU_MODE_SYSTEM_INFO; @@ -234,12 +237,14 @@ static void draw (menu_t *menu, surface_t *d) { const char *action = NULL; - switch (menu->browser.list[menu->browser.selected].type) { - case ENTRY_TYPE_DIR: action = "A: Enter"; break; - case ENTRY_TYPE_ROM: action = "A: Load"; break; - case ENTRY_TYPE_IMAGE: action = "A: Show"; break; - case ENTRY_TYPE_MUSIC: action = "A: Play"; break; - default: action = "A: Info"; break; + if (menu->browser.entry) { + switch (menu->browser.entry->type) { + case ENTRY_TYPE_DIR: action = "A: Enter"; break; + case ENTRY_TYPE_ROM: action = "A: Load"; break; + case ENTRY_TYPE_IMAGE: action = "A: Show"; break; + case ENTRY_TYPE_MUSIC: action = "A: Play"; break; + default: action = "A: Info"; break; + } } component_actions_bar_text_draw( @@ -276,7 +281,7 @@ void view_browser_init (menu_t *menu) { if (!menu->browser.valid) { if (load_directory(menu)) { path_free(menu->browser.directory); - menu->browser.directory = path_init(NULL); + menu->browser.directory = path_init("sd:/", ""); menu_show_error(menu, "Error while opening initial directory"); } else { menu->browser.valid = true; diff --git a/src/menu/views/file_info.c b/src/menu/views/file_info.c index 105751b2..ec73119a 100644 --- a/src/menu/views/file_info.c +++ b/src/menu/views/file_info.c @@ -65,7 +65,7 @@ static void draw (menu_t *menu, surface_t *d) { "ENTRY INFORMATION\n" "\n" "%s", - menu->browser.list[menu->browser.selected].name + menu->browser.entry->name ); component_main_text_draw( @@ -99,14 +99,13 @@ static void draw (menu_t *menu, surface_t *d) { void view_file_info_init (menu_t *menu) { - path_t *file = path_clone(menu->browser.directory); - path_push(file, menu->browser.list[menu->browser.selected].name); + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); - if (f_stat(strip_sd_prefix(path_get(file)), &info) != FR_OK) { + if (f_stat(strip_sd_prefix(path_get(path)), &info) != FR_OK) { menu_show_error(menu, "Couldn't obtain file information"); } - path_free(file); + path_free(path); } void view_file_info_display (menu_t *menu, surface_t *display) { diff --git a/src/menu/views/image_viewer.c b/src/menu/views/image_viewer.c index 2c452dff..21c153b3 100644 --- a/src/menu/views/image_viewer.c +++ b/src/menu/views/image_viewer.c @@ -73,7 +73,7 @@ static void draw (menu_t *menu, surface_t *d) { component_messagebox_draw( "Set \"%s\" as background image?\n\n" "A: Yes, B: Back", - menu->browser.list[menu->browser.selected].name + menu->browser.entry->name ); } else if (image_set_as_background) { component_messagebox_draw("Preparing background…"); @@ -105,8 +105,7 @@ void view_image_viewer_init (menu_t *menu) { image_set_as_background = false; image = NULL; - path_t *path = path_clone(menu->browser.directory); - path_push(path, menu->browser.list[menu->browser.selected].name); + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); png_err_t err = png_decoder_start(path_get(path), 640, 480, image_callback, menu); if (err != PNG_OK) { diff --git a/src/menu/views/load.c b/src/menu/views/load.c index 1a9bfc2f..bfa96385 100644 --- a/src/menu/views/load.c +++ b/src/menu/views/load.c @@ -158,7 +158,7 @@ static void draw (menu_t *menu, surface_t *d) { "N64 ROM information\n" "\n" "%s", - menu->browser.list[menu->browser.selected].name + menu->browser.entry->name ); component_main_text_draw( @@ -243,8 +243,7 @@ static flashcart_save_type_t convert_save_type (db_savetype_t save_type) { static void load (menu_t *menu) { menu->next_mode = MENU_MODE_BOOT; - path_t *path = path_clone(menu->browser.directory); - path_push(path, menu->browser.list[menu->browser.selected].name); + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); bool byte_swap = (rom_header.config_flags == ROM_MID_BIG_ENDIAN); menu->flashcart_error = flashcart_load_rom(path_get(path), byte_swap, draw_progress); @@ -279,8 +278,7 @@ static void deinit (void) { void view_load_init (menu_t *menu) { load_pending = false; - path_t *path = path_clone(menu->browser.directory); - path_push(path, menu->browser.list[menu->browser.selected].name); + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); rom_header = file_read_rom_header(path_get(path)); diff --git a/src/menu/views/load_emulator.c b/src/menu/views/load_emulator.c index 740d39d3..c96cde80 100644 --- a/src/menu/views/load_emulator.c +++ b/src/menu/views/load_emulator.c @@ -2,8 +2,8 @@ #include "boot/boot.h" #include "flashcart/flashcart.h" -#include "views.h" #include "utils/fs.h" +#include "views.h" #ifndef EMULATOR_FOLDER #define EMULATOR_FOLDER "/emulators/" @@ -14,127 +14,10 @@ static const char *emu_gameboy_rom_extensions[] = { "gb", NULL }; static const char *emu_gameboy_color_rom_extensions[] = { "gbc", NULL }; static const char *emu_sega_rom_extensions[] = {"smc", "gen", "smd", NULL }; -const uint32_t eum_rom_start_address = 0x200000; +static const uint32_t eum_rom_start_address = 0x200000; static bool load_pending; -static void draw_progress (float progress) { - surface_t *d = display_try_get(); - - if (d) { - rdpq_attach(d, NULL); - - component_background_draw(); - - component_loader_draw(progress); - - rdpq_detach_show(); - } -} - - -static void load_emulator_nes_rom (path_t *path, menu_t *menu) { - - if (file_exists(EMULATOR_FOLDER"emu.nes")) { // || neon64bu.rom - - menu->flashcart_error = flashcart_load_rom(EMULATOR_FOLDER"emu.nes", false, draw_progress); - /* Combine EMU and ROM before loading. See https://github.com/hcs64/neon64v2/tree/master/pkg */ - menu->flashcart_error = flashcart_load_file(path_get(path), eum_rom_start_address); - if (menu->flashcart_error != FLASHCART_OK) { - menu->next_mode = MENU_MODE_FAULT; - path_free(path); - return; - } - - path_ext_replace(path, "sav"); - menu->flashcart_error = flashcart_load_save(path_get(path), FLASHCART_SAVE_TYPE_SRAM_BANKED); - if (menu->flashcart_error != FLASHCART_OK) { - menu->next_mode = MENU_MODE_FAULT; - path_free(path); - return; - } - - } - -} - -static void load_emulator_gameboy_rom (path_t *path, menu_t *menu) { - - if (file_exists(EMULATOR_FOLDER"emu.gb")) { // || gb.v64 - - menu->flashcart_error = flashcart_load_rom(EMULATOR_FOLDER"emu.gb", false, draw_progress); - /* Combine EMU and ROM before loading. */ - menu->flashcart_error = flashcart_load_file(path_get(path), eum_rom_start_address); - if (menu->flashcart_error != FLASHCART_OK) { - menu->next_mode = MENU_MODE_FAULT; - path_free(path); - return; - } - - path_ext_replace(path, "sav"); - menu->flashcart_error = flashcart_load_save(path_get(path), FLASHCART_SAVE_TYPE_FLASHRAM); - if (menu->flashcart_error != FLASHCART_OK) { - menu->next_mode = MENU_MODE_FAULT; - path_free(path); - return; - } - - } - -} - -static void load_emulator_gameboy_color_rom (path_t *path, menu_t *menu) { - - if (file_exists(EMULATOR_FOLDER"emu.gbc")) { // || gbc.v64 - - menu->flashcart_error = flashcart_load_rom(EMULATOR_FOLDER"emu.gbc", false, draw_progress); - /* Combine EMU and ROM before loading. */ - menu->flashcart_error = flashcart_load_file(path_get(path), eum_rom_start_address); - if (menu->flashcart_error != FLASHCART_OK) { - menu->next_mode = MENU_MODE_FAULT; - path_free(path); - return; - } - - path_ext_replace(path, "sav"); - menu->flashcart_error = flashcart_load_save(path_get(path), FLASHCART_SAVE_TYPE_FLASHRAM); - if (menu->flashcart_error != FLASHCART_OK) { - menu->next_mode = MENU_MODE_FAULT; - path_free(path); - return; - } - - } - -} - - -static void load (menu_t *menu) { - menu->next_mode = MENU_MODE_BOOT; - - path_t *path = path_clone(menu->browser.directory); - path_push(path, menu->browser.list[menu->browser.selected].name); - - if (file_has_extensions (path_get(path), emu_nes_rom_extensions)) { - load_emulator_nes_rom(path, menu); - } - else if (file_has_extensions (path_get(path), emu_gameboy_rom_extensions)) { - load_emulator_gameboy_rom(path, menu); - } - else if (file_has_extensions (path_get(path), emu_gameboy_color_rom_extensions)) { - load_emulator_gameboy_color_rom(path, menu); - } - else if (file_has_extensions (path_get(path), emu_sega_rom_extensions)) { - //load_emulator_sega_rom(path, menu); - } - - path_free(path); - - menu->boot_params->device_type = BOOT_DEVICE_TYPE_ROM; - menu->boot_params->tv_type = BOOT_TV_TYPE_PASSTHROUGH; - menu->boot_params->detect_cic_seed = true; -} - static void process (menu_t *menu) { if (menu->actions.enter) { @@ -161,35 +44,128 @@ static void draw (menu_t *menu, surface_t *d) { "Rom Name\n" "\n" "%s", - menu->browser.list[menu->browser.selected].name + menu->browser.entry->name ); - - component_actions_bar_text_draw( ALIGN_LEFT, VALIGN_TOP, "A: Load and run Emulator ROM\n" "B: Exit" ); - } rdpq_detach_show(); } +static void draw_progress (float progress) { + surface_t *d = display_try_get(); + + if (d) { + rdpq_attach(d, NULL); + + component_background_draw(); + + component_loader_draw(progress); + + rdpq_detach_show(); + } +} + +static void load_emulator_nes_rom (path_t *path, menu_t *menu) { + if (file_exists(EMULATOR_FOLDER"emu.nes")) { // || neon64bu.rom + menu->flashcart_error = flashcart_load_rom(EMULATOR_FOLDER"emu.nes", false, draw_progress); + /* Combine EMU and ROM before loading. See https://github.com/hcs64/neon64v2/tree/master/pkg */ + menu->flashcart_error = flashcart_load_file(path_get(path), eum_rom_start_address); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; + path_free(path); + return; + } + + path_ext_replace(path, "sav"); + menu->flashcart_error = flashcart_load_save(path_get(path), FLASHCART_SAVE_TYPE_SRAM_BANKED); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; + path_free(path); + return; + } + } +} + +static void load_emulator_gameboy_rom (path_t *path, menu_t *menu) { + if (file_exists(EMULATOR_FOLDER"emu.gb")) { // || gb.v64 + menu->flashcart_error = flashcart_load_rom(EMULATOR_FOLDER"emu.gb", false, draw_progress); + /* Combine EMU and ROM before loading. */ + menu->flashcart_error = flashcart_load_file(path_get(path), eum_rom_start_address); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; + path_free(path); + return; + } + + path_ext_replace(path, "sav"); + menu->flashcart_error = flashcart_load_save(path_get(path), FLASHCART_SAVE_TYPE_FLASHRAM); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; + path_free(path); + return; + } + } +} + +static void load_emulator_gameboy_color_rom (path_t *path, menu_t *menu) { + if (file_exists(EMULATOR_FOLDER"emu.gbc")) { // || gbc.v64 + menu->flashcart_error = flashcart_load_rom(EMULATOR_FOLDER"emu.gbc", false, draw_progress); + /* Combine EMU and ROM before loading. */ + menu->flashcart_error = flashcart_load_file(path_get(path), eum_rom_start_address); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; + path_free(path); + return; + } + + path_ext_replace(path, "sav"); + menu->flashcart_error = flashcart_load_save(path_get(path), FLASHCART_SAVE_TYPE_FLASHRAM); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; + path_free(path); + return; + } + } +} + +static void load (menu_t *menu) { + menu->next_mode = MENU_MODE_BOOT; + + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); + + if (file_has_extensions(path_get(path), emu_nes_rom_extensions)) { + load_emulator_nes_rom(path, menu); + } else if (file_has_extensions(path_get(path), emu_gameboy_rom_extensions)) { + load_emulator_gameboy_rom(path, menu); + } else if (file_has_extensions(path_get(path), emu_gameboy_color_rom_extensions)) { + load_emulator_gameboy_color_rom(path, menu); + } else if (file_has_extensions(path_get(path), emu_sega_rom_extensions)) { + //load_emulator_sega_rom(path, menu); + } + + path_free(path); + + menu->boot_params->device_type = BOOT_DEVICE_TYPE_ROM; + menu->boot_params->tv_type = BOOT_TV_TYPE_PASSTHROUGH; + menu->boot_params->detect_cic_seed = true; +} + void view_load_emulator_init (menu_t *menu) { load_pending = false; - - path_t *path = path_clone(menu->browser.directory); - path_push(path, menu->browser.list[menu->browser.selected].name); - - path_free(path); } void view_load_emulator_display (menu_t *menu, surface_t *display) { process(menu); + draw(menu, display); + if (load_pending) { load_pending = false; load(menu); diff --git a/src/menu/views/music_player.c b/src/menu/views/music_player.c index 768e1304..dc9a670b 100644 --- a/src/menu/views/music_player.c +++ b/src/menu/views/music_player.c @@ -81,7 +81,7 @@ static void draw (menu_t *menu, surface_t *d) { "MUSIC PLAYER\n" "\n" "%s", - menu->browser.list[menu->browser.selected].name + menu->browser.entry->name ); char formatted_track_elapsed_length[64]; @@ -138,8 +138,7 @@ void view_music_player_init (menu_t *menu) { return; } - path_t *path = path_clone(menu->browser.directory); - path_push(path, menu->browser.list[menu->browser.selected].name); + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); err = mp3player_load(path_get(path)); if (err != MP3PLAYER_OK) {