mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-12-25 01:31:51 +01:00
Menu improvements (#9)
<!--- Provide a general summary of your changes in the Title above --> ## Description <!--- Describe your changes in detail --> This PR adds docfx to the CI to target documentation for the N64FlashcartMenu and updates the libdragon submodule. It also adds a number of menu improvements. ## Motivation and Context <!--- What does this sample do? What problem does it solve? --> <!--- If it fixes/closes/resolves an open issue, please link to the issue here --> Will eventually stop us from being lazy, however as the project is very much WiP, Currently the CI only runs it to show what warnings need to be "fixed". In future, it needs to "error" when things are incorrect AND deploy to the WIKI. ## How Has This Been Tested? <!-- (if applicable) --> <!--- Please describe in detail how you tested your sample/changes. --> <!--- Include details of your testing environment, and the tests you ran to --> <!--- see how your change affects other areas of the code, etc. --> Builds on my fork. ## Screenshots <!-- (if appropriate): --> ![image](https://github.com/Polprzewodnikowy/N64FlashcartMenu/assets/11439699/04511e4a-e522-4b69-a8cb-59057c1c66aa) ## Types of changes <!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [x] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: <!--- Go over all the following points, and put an `x` in all the boxes that apply. --> <!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. <!--- It would be nice if you could sign off your contribution by replacing the name with your GitHub user name and GitHub email contact. --> Signed-off-by: GITHUB_USER <GITHUB_USER_EMAIL> --------- Co-authored-by: Mateusz Faderewski <sc@mateuszfaderewski.pl>
This commit is contained in:
parent
b53bbf7dae
commit
b3509f4295
@ -2,7 +2,7 @@ FROM debian:bookworm-slim
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade -y && \
|
||||
apt-get install build-essential git python3 wget -y && \
|
||||
apt-get install build-essential doxygen git python3 wget -y && \
|
||||
wget https://github.com/DragonMinded/libdragon/releases/download/toolchain-continuous-prerelease/gcc-toolchain-mips64-x86_64.deb && \
|
||||
dpkg -i gcc-toolchain-mips64-x86_64.deb && \
|
||||
rm gcc-toolchain-mips64-x86_64.deb && \
|
||||
|
33
.github/workflows/build.yml
vendored
33
.github/workflows/build.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: build
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -9,14 +9,11 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-sc64-menu:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
# - name: Check for dockerenv file
|
||||
# run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv)
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
@ -49,7 +46,7 @@ jobs:
|
||||
|
||||
minify-sc64-menu:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
needs: build-sc64-menu
|
||||
|
||||
steps:
|
||||
|
||||
@ -69,7 +66,7 @@ jobs:
|
||||
name: N64FlashcartMenu
|
||||
path: ./
|
||||
|
||||
- name: Finalize rom
|
||||
- name: Finalize ROM
|
||||
run: |
|
||||
# make all
|
||||
python ./tools/sc64/minify.py ./build/N64FlashcartMenu.elf ./output/N64FlashcartMenu.z64 ./output/sc64menu.n64
|
||||
@ -83,6 +80,28 @@ jobs:
|
||||
./output/sc64menu.n64
|
||||
if-no-files-found: ignore
|
||||
|
||||
generate-docs:
|
||||
runs-on: ubuntu-latest
|
||||
# needs: build-sc64-menu
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 1 # we only require the last check-in, unless we want to create a changelog.
|
||||
|
||||
- name: Run Doxygen
|
||||
uses: mattnotmitt/doxygen-action@1.9.5
|
||||
with:
|
||||
doxyfile-path: './Doxyfile'
|
||||
|
||||
# - name: Deploy
|
||||
# uses: peaceiris/actions-gh-pages@v3
|
||||
# with:
|
||||
# github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# publish_dir: ./docs
|
||||
|
||||
|
||||
# release-sc64-menu:
|
||||
# runs-on: ubuntu-latest
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
/.vscode
|
||||
/build
|
||||
/output
|
||||
/docs
|
||||
tools/sc64/sc64.exe
|
||||
tools/sc64/sc64deployer.exe
|
||||
# There should never be ROMs uploaded, but just incase, make sure they are excluded.
|
||||
|
11
Makefile
11
Makefile
@ -37,6 +37,7 @@ SRCS = \
|
||||
menu/views/load.c \
|
||||
menu/views/player.c \
|
||||
menu/views/startup.c \
|
||||
menu/views/system_info.c \
|
||||
utils/fs.c
|
||||
|
||||
ASSETS = \
|
||||
@ -70,12 +71,16 @@ clean:
|
||||
$(shell rm -rf ./$(BUILD_DIR) ./$(OUTPUT_DIR))
|
||||
.PHONY: clean
|
||||
|
||||
# run:
|
||||
# $(shell ./remotedeploy.sh -d)
|
||||
run: $(PROJECT_NAME)
|
||||
./remotedeploy.sh
|
||||
# FIXME: improve ability to deploy.
|
||||
# if devcontainer, use remotedeploy.sh, else
|
||||
# $(shell sc64deployer --boot direct-rom %~dp0$(OUTPUT_DIR))\$(PROJECT_NAME).z64)
|
||||
# .PHONY: run
|
||||
.PHONY: run
|
||||
|
||||
run-debug: $(PROJECT_NAME)
|
||||
./remotedeploy.sh -d
|
||||
.PHONY: run-debug
|
||||
|
||||
# test:
|
||||
# TODO: run tests
|
||||
|
12
README.md
12
README.md
@ -62,11 +62,11 @@ You can use a dev container in VSCode to ease development.
|
||||
|
||||
## To deploy:
|
||||
|
||||
* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.15.1/sc64-deployer-windows-v2.15.1.zip)
|
||||
* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.16.0/sc64-deployer-windows-v2.16.0.zip)
|
||||
* Extract and place `sc64deployer.exe` in the `tools/sc64` directory.
|
||||
|
||||
Make sure that your firmware is compatible (currently v2.15.1+)
|
||||
See: https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.15.1/docs/00_quick_startup_guide.md#firmware-backupupdate
|
||||
Make sure that your firmware is compatible (currently v2.16.0+)
|
||||
See: https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.16.0/docs/00_quick_startup_guide.md#firmware-backupupdate
|
||||
|
||||
|
||||
|
||||
@ -92,6 +92,10 @@ The ROM can be found in the `output` directory.
|
||||
|
||||
NOTE: a "release" version of the SC64 menu is called `sc64menu.n64` and can be created for when you want to add it directly to the SDCard. This is generated by running `make all` or running `make sc64_minify`.
|
||||
|
||||
# Update Libdragon
|
||||
# Update Libdragon submodule
|
||||
This repo currently uses the `unstable` branch as a submodule at a specific commit.
|
||||
To update to the latest version, use `git submodule update --remote ` from the terminal.
|
||||
|
||||
# Generate documentation
|
||||
Run `doxygen` from the dev container terminal.
|
||||
Make sure you fix the warnings before creating a PR!
|
||||
|
0
assets/images/.gitkeep
Normal file
0
assets/images/.gitkeep
Normal file
@ -5,6 +5,7 @@
|
||||
|
||||
#define ACTIONS_REPEAT_DELAY 16
|
||||
#define ACTIONS_REPEAT_RATE 2
|
||||
#define JOYSTICK_DEADZONE 32
|
||||
|
||||
|
||||
static void actions_clear (menu_t *menu) {
|
||||
@ -15,7 +16,8 @@ static void actions_clear (menu_t *menu) {
|
||||
menu->actions.fast = false;
|
||||
menu->actions.enter = false;
|
||||
menu->actions.back = false;
|
||||
menu->actions.info = false;
|
||||
menu->actions.file_info = false;
|
||||
menu->actions.system_info = false;
|
||||
menu->actions.settings = false;
|
||||
menu->actions.override = false;
|
||||
}
|
||||
@ -26,6 +28,7 @@ void actions_update (menu_t *menu) {
|
||||
|
||||
struct controller_data down = get_keys_down();
|
||||
struct controller_data held = get_keys_held();
|
||||
struct controller_data pressed = get_keys_pressed();
|
||||
|
||||
if (down.c[0].err != ERROR_NONE) {
|
||||
return;
|
||||
@ -61,6 +64,22 @@ void actions_update (menu_t *menu) {
|
||||
menu->actions.fast = true;
|
||||
}
|
||||
}
|
||||
} else if (pressed.c[0].y > +JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness
|
||||
menu->actions.vertical_held_counter += 1;
|
||||
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) {
|
||||
menu->actions.go_up = true;
|
||||
if (pressed.c[0].y < +75) {
|
||||
menu->actions.vertical_held_counter = 0;
|
||||
}
|
||||
}
|
||||
} else if (pressed.c[0].y < -JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness
|
||||
menu->actions.vertical_held_counter += 1;
|
||||
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) {
|
||||
menu->actions.go_down = true;
|
||||
if (pressed.c[0].y > -75) {
|
||||
menu->actions.vertical_held_counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (down.c[0].left) {
|
||||
@ -85,9 +104,11 @@ void actions_update (menu_t *menu) {
|
||||
menu->actions.enter = true;
|
||||
} else if (down.c[0].B) {
|
||||
menu->actions.back = true;
|
||||
} else if (down.c[0].Z) {
|
||||
menu->actions.info = true;
|
||||
} else if (down.c[0].R) {
|
||||
menu->actions.file_info = true;
|
||||
} else if (down.c[0].L) {
|
||||
menu->actions.system_info = true;
|
||||
} else if (down.c[0].start) {
|
||||
menu->actions.settings = true;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@ static bool boot_pending;
|
||||
|
||||
static void menu_init (settings_t *settings) {
|
||||
controller_init();
|
||||
timer_init();
|
||||
rtc_init();
|
||||
audio_init(44100, 2);
|
||||
mixer_init(2);
|
||||
display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_OFF);
|
||||
@ -53,6 +55,8 @@ static void menu_deinit (menu_t *menu) {
|
||||
display_close();
|
||||
mixer_close();
|
||||
audio_close();
|
||||
rtc_close();
|
||||
timer_close();
|
||||
}
|
||||
|
||||
|
||||
@ -80,6 +84,10 @@ void menu_run (settings_t *settings) {
|
||||
view_file_info_display(menu, display);
|
||||
break;
|
||||
|
||||
case MENU_MODE_SYSTEM_INFO:
|
||||
view_system_info_display(menu, display);
|
||||
break;
|
||||
|
||||
case MENU_MODE_PLAYER:
|
||||
view_player_display(menu, display);
|
||||
break;
|
||||
@ -118,6 +126,10 @@ void menu_run (settings_t *settings) {
|
||||
view_file_info_init(menu);
|
||||
break;
|
||||
|
||||
case MENU_MODE_SYSTEM_INFO:
|
||||
view_system_info_init(menu);
|
||||
break;
|
||||
|
||||
case MENU_MODE_PLAYER:
|
||||
view_player_init(menu);
|
||||
break;
|
||||
|
@ -15,6 +15,7 @@ typedef enum {
|
||||
MENU_MODE_STARTUP,
|
||||
MENU_MODE_BROWSER,
|
||||
MENU_MODE_FILE_INFO,
|
||||
MENU_MODE_SYSTEM_INFO,
|
||||
MENU_MODE_PLAYER,
|
||||
MENU_MODE_CREDITS,
|
||||
MENU_MODE_LOAD,
|
||||
@ -56,7 +57,8 @@ typedef struct {
|
||||
|
||||
bool enter;
|
||||
bool back;
|
||||
bool info;
|
||||
bool file_info;
|
||||
bool system_info;
|
||||
bool settings;
|
||||
bool override;
|
||||
} actions;
|
||||
|
@ -11,22 +11,22 @@ uint8_t extract_homebrew_setting(uint8_t setting, uint8_t bit_position) {
|
||||
|
||||
uint8_t extract_homebrew_save_type(uint8_t save_type) {
|
||||
switch (save_type) {
|
||||
case 0x00:
|
||||
case HB_SAVE_TYPE_NONE:
|
||||
return DB_SAVE_TYPE_NONE;
|
||||
case 0x01:
|
||||
case HB_SAVE_TYPE_EEPROM_4K:
|
||||
return DB_SAVE_TYPE_EEPROM_4K;
|
||||
case 0x02:
|
||||
case HB_SAVE_TYPE_EEPROM_16K:
|
||||
return DB_SAVE_TYPE_EEPROM_16K;
|
||||
case 0x03:
|
||||
case HB_SAVE_TYPE_SRAM:
|
||||
return DB_SAVE_TYPE_SRAM;
|
||||
case 0x04:
|
||||
case HB_SAVE_TYPE_SRAM_BANKED:
|
||||
return DB_SAVE_TYPE_SRAM_BANKED;
|
||||
case 0x05:
|
||||
case HB_SAVE_TYPE_FLASHRAM:
|
||||
return DB_SAVE_TYPE_FLASHRAM;
|
||||
case 0x06:
|
||||
case HB_SAVE_TYPE_SRAM_128K:
|
||||
return DB_SAVE_TYPE_SRAM_128K;
|
||||
default:
|
||||
return DB_SAVE_TYPE_CART_SPECIFIED; // Invalid save type, handle accordingly
|
||||
return DB_SAVE_TYPE_INVALID; // Invalid save type, handle accordingly
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,11 +43,13 @@ rom_header_t file_read_rom_header(char *path) {
|
||||
|
||||
rom_header_t *rom_header = malloc(sizeof(rom_header_t));
|
||||
|
||||
fseek(fp, 0x00, SEEK_SET);
|
||||
fread(&(rom_header->endian), sizeof(uint32_t), 1, fp);
|
||||
// FIXME: handle endian appropriately, perhaps: cart_card_byteswap
|
||||
fseek(fp, 0x10, SEEK_SET);
|
||||
fread(&(rom_header->checksum), sizeof(uint64_t), 1, fp);
|
||||
fseek(fp, 0x20, SEEK_SET);
|
||||
fread(&(rom_header->title), sizeof(rom_header->title), 1, fp);
|
||||
rom_header->title[20] = '\0';
|
||||
fgets(rom_header->title, sizeof(rom_header->title), fp);
|
||||
fseek(fp, 0x3b, SEEK_SET);
|
||||
fread(&(rom_header->metadata.media_type), sizeof(rom_header->metadata.media_type), 1, fp);
|
||||
//fseek(fp, 0x3c, SEEK_SET); // Consecutive read (no need to seek).
|
||||
@ -70,28 +72,28 @@ uint8_t rom_db_match_save_type(rom_header_t rom_header) {
|
||||
|
||||
// These are ordered to ensure they are handled correctly...
|
||||
|
||||
// First: Match by the `ED` Developer ID
|
||||
// TODO: if appropriate this can be improved with other unused codes... e.g. | `AA` | `ZZ`
|
||||
if (rom_header.metadata.unique_identifier == *(uint16_t *)"ED") {
|
||||
|
||||
// uint8_t low_nibble = rom_header.version & 0x0F;
|
||||
// uint8_t rtc_enabled = extract_homebrew_setting(low_nibble, 0); // Bit 0
|
||||
// uint8_t region_free_enabled = extract_homebrew_setting(low_nibble, 1); // Bit 1
|
||||
// First: Match by the `ED` or `HB` Developer ID
|
||||
if (rom_header.metadata.unique_identifier == *(uint16_t *)"ED" || rom_header.metadata.unique_identifier == *(uint16_t *)"HB") {
|
||||
// #ifdef ED64_COMPATIBLE
|
||||
// uint8_t low_nibble = rom_header.version & 0x0F;
|
||||
// uint8_t rtc_enabled = extract_homebrew_setting(low_nibble, 0); // Bit 0
|
||||
// uint8_t region_free_enabled = extract_homebrew_setting(low_nibble, 1); // Bit 1
|
||||
// #endif
|
||||
|
||||
uint8_t high_nibble = (rom_header.version >> 4) & 0x0F;
|
||||
|
||||
return extract_homebrew_save_type(high_nibble);
|
||||
}
|
||||
|
||||
// // Second: Match the default entries for crc_high.
|
||||
// // FIXME: use full check code, or pad.
|
||||
// if (rom_header.checksum == 0xbcb1f89f)return DB_SAVE_TYPE_EEPROM_4K; // kirby v1.3
|
||||
// if (rom_header.checksum == 0x46039fb4)return DB_SAVE_TYPE_EEPROM_16K; // kirby U
|
||||
// if (rom_header.checksum == 0x0d93ba11)return DB_SAVE_TYPE_EEPROM_16K; // kirby U
|
||||
// if (rom_header.checksum == 0xce84793d)return DB_SAVE_TYPE_SRAM; // donkey kong f2
|
||||
// if (rom_header.checksum == 0x4cbc3b56)return DB_SAVE_TYPE_SRAM; // DMTJ 64DD game
|
||||
// if (rom_header.checksum == 0x0dd4abab)return DB_SAVE_TYPE_EEPROM_16K; // DK Retail kiosk demo (shares ID with Dinosaur planet, but hacks are unlikely)!
|
||||
// if (rom_header.checksum == 0xeb85ebc9)return DB_SAVE_TYPE_FLASHRAM; // DOUBUTSU BANCHOU (ANIMAL LEADER, Cubivore) - Contains no game ID
|
||||
// Second: Match the default entries for crc.
|
||||
// DOUBUTSU BANCHOU (ANIMAL LEADER, Cubivore) - Contains no game ID
|
||||
if (rom_header.checksum == 16971230020836426415U) return DB_SAVE_TYPE_FLASHRAM;
|
||||
// DK Retail kiosk demo (shares ID with Dinosaur planet, but hacks are unlikely)!
|
||||
if (rom_header.checksum == 996610171530815774U) return DB_SAVE_TYPE_EEPROM_16K;
|
||||
// donkey kong f2
|
||||
// if (rom_header.checksum == 0xce84793d) return DB_SAVE_TYPE_SRAM;
|
||||
// DMTJ 64DD game
|
||||
// if (rom_header.checksum == 0x4cbc3b56) return DB_SAVE_TYPE_SRAM;
|
||||
|
||||
|
||||
// FIXME: we need to take into account the Category (first char) and the Region code (last char) before a general match of the ID.
|
||||
@ -119,6 +121,10 @@ uint8_t rom_db_match_save_type(rom_header_t rom_header) {
|
||||
// FLASHRAM
|
||||
"AF", "CC", "CK", "DL", "DP", "JD", "JF", "KJ", "M6", "MQ", "P2", "P3", "PF", "PH", "PN", "PO",
|
||||
"PS", "RH", "SI", "SQ", "T9", "W4", "ZS",
|
||||
|
||||
// Controller Pak only
|
||||
"BX", "BQ", "NS",
|
||||
|
||||
// Last entry
|
||||
"!!"
|
||||
|
||||
@ -144,6 +150,10 @@ uint8_t rom_db_match_save_type(rom_header_t rom_header) {
|
||||
// FLASHRAM
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
|
||||
// Controller Pak only
|
||||
0x10, 0x10, 0x10,
|
||||
|
||||
// Last entry.
|
||||
0xff
|
||||
};
|
||||
|
@ -12,8 +12,26 @@
|
||||
#define DB_SAVE_TYPE_SRAM_BANKED 0x04
|
||||
#define DB_SAVE_TYPE_SRAM_128K 0x05
|
||||
#define DB_SAVE_TYPE_FLASHRAM 0x06
|
||||
#define DB_SAVE_TYPE_CART_SPECIFIED 0xff
|
||||
#define DB_SAVE_TYPE_CPAK 0x10
|
||||
#define DB_SAVE_TYPE_DD 0x20
|
||||
#define DB_SAVE_TYPE_INVALID 0xff
|
||||
|
||||
typedef enum {
|
||||
HB_SAVE_TYPE_NONE = 0x00,
|
||||
HB_SAVE_TYPE_EEPROM_4K = 0x01,
|
||||
HB_SAVE_TYPE_EEPROM_16K = 0x02,
|
||||
HB_SAVE_TYPE_SRAM = 0x03,
|
||||
HB_SAVE_TYPE_SRAM_BANKED = 0x04,
|
||||
HB_SAVE_TYPE_FLASHRAM = 0x05,
|
||||
HB_SAVE_TYPE_SRAM_128K = 0x06,
|
||||
} homebrew_savetype_t;
|
||||
|
||||
typedef enum {
|
||||
ROM_BIG_ENDIAN = 2151092800U,
|
||||
ROM_LITTLE_ENDIAN = 1074935680U,
|
||||
ROM_MID_BIG_ENDIAN = 931151890U,
|
||||
ROM_MID_LITTLE_ENDIAN = 306217015U
|
||||
} rom_endian_type_t;
|
||||
|
||||
//Rom Info
|
||||
// CheckCode 0x10, 8 bytes (sometimes refered to as CRC Hi and CRC Lo)
|
||||
@ -24,54 +42,54 @@
|
||||
// DestinationCode 0x3e
|
||||
// RomVersion 0x3f
|
||||
|
||||
// typedef enum {
|
||||
// N64_CART = 'N',
|
||||
// N64_DISK = 'D',
|
||||
// N64_CART_EXPANDABLE = 'C',
|
||||
// N64_DISK_EXPANDABLE = 'E',
|
||||
// N64_ALECK64 = 'Z',
|
||||
// //TYPE_UNKNOWN = '\0'
|
||||
// } rom_media_type_t;
|
||||
typedef enum {
|
||||
N64_CART = 'N',
|
||||
N64_DISK = 'D',
|
||||
N64_CART_EXPANDABLE = 'C',
|
||||
N64_DISK_EXPANDABLE = 'E',
|
||||
N64_ALECK64 = 'Z'
|
||||
} rom_media_type_t;
|
||||
|
||||
typedef enum {
|
||||
MARKET_ALL = 'A',
|
||||
MARKET_BRAZIL = 'B',
|
||||
MARKET_CHINA = 'C',
|
||||
MARKET_GERMANY = 'D',
|
||||
MARKET_USA = 'E',
|
||||
MARKET_FRANCE = 'F',
|
||||
MARKET_GATEWAY64_NTSC = 'G',
|
||||
MARKET_NETHERLANDS = 'H',
|
||||
MARKET_ITALY = 'I',
|
||||
MARKET_JAPAN = 'J',
|
||||
MARKET_KOREA = 'K',
|
||||
MARKET_GATEWAY64_PAL = 'L',
|
||||
// MARKET_UNKNOWN_M = 'M',
|
||||
MARKET_CANADA = 'N',
|
||||
// MARKET_UNKNOWN_O = 'O',
|
||||
MARKET_EUROPE_P = 'P',
|
||||
// MARKET_UNKNOWN_Q = 'Q',
|
||||
// MARKET_UNKNOWN_R = 'R',
|
||||
MARKET_SPAIN = 'S',
|
||||
// MARKET_UNKNOWN_T = 'T',
|
||||
MARKET_AUSTRAILA = 'U',
|
||||
// MARKET_UNKNOWN_V = 'V',
|
||||
MARKET_SCANDINAVAIA = 'W',
|
||||
MARKET_EUROPE_X = 'X',
|
||||
MARKET_EUROPE_Y = 'Y',
|
||||
MARKET_EUROPE_Z = 'Z'
|
||||
} rom_destination_market_t;
|
||||
|
||||
// typedef enum {
|
||||
// MARKET_ALL = 'A',
|
||||
// MARKET_BRAZIL = 'B',
|
||||
// MARKET_CHINA = 'C',
|
||||
// MARKET_GERMANY = 'D',
|
||||
// MARKET_USA = 'E',
|
||||
// MARKET_FRANCE = 'F',
|
||||
// MARKET_GATEWAY64_NTSC = 'G',
|
||||
// MARKET_NETHERLANDS = 'H',
|
||||
// MARKET_ITALY = 'I',
|
||||
// MARKET_JAPAN = 'J',
|
||||
// MARKET_KOREA = 'K',
|
||||
// MARKET_GATEWAY64_PAL = 'L',
|
||||
// MARKET_UNKNOWN_M = 'M',
|
||||
// MARKET_CANADA = 'N',
|
||||
// MARKET_UNKNOWN_O = 'O',
|
||||
// MARKET_EUROPE_P = 'P',
|
||||
// MARKET_UNKNOWN_Q = 'Q',
|
||||
// MARKET_UNKNOWN_R = 'R',
|
||||
// MARKET_SPAIN = 'S',
|
||||
// MARKET_UNKNOWN_T = 'T',
|
||||
// MARKET_AUSTRAILA = 'U',
|
||||
// MARKET_UNKNOWN_V = 'V',
|
||||
// MARKET_SCANDINAVAIA = 'W',
|
||||
// MARKET_EUROPE_X = 'X',
|
||||
// MARKET_EUROPE_Y = 'Y',
|
||||
// MARKET_EUROPE_Z = 'Z',
|
||||
// //MARKET_UNKNOWN = '\0'
|
||||
// } rom_destination_market_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t media_type; // rom_media_type_t
|
||||
uint16_t unique_identifier;
|
||||
uint8_t destination_market; //rom_destination_market_t
|
||||
uint8_t destination_market; // rom_destination_market_t
|
||||
} rom_metadata_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t endian; // rom_endian_type_t
|
||||
uint64_t checksum;
|
||||
uint8_t title[21];
|
||||
char title[21]; // 20 chars + null
|
||||
rom_metadata_t metadata;
|
||||
uint8_t version;
|
||||
} rom_header_t;
|
||||
|
@ -215,10 +215,12 @@ static void process (menu_t *menu) {
|
||||
menu->browser.valid = false;
|
||||
menu->next_mode = MENU_MODE_ERROR;
|
||||
}
|
||||
} else if (menu->actions.info) {
|
||||
} else if (menu->actions.file_info) {
|
||||
if (menu->browser.selected >= 0) {
|
||||
menu->next_mode = MENU_MODE_FILE_INFO;
|
||||
}
|
||||
} else if (menu->actions.system_info) {
|
||||
menu->next_mode = MENU_MODE_SYSTEM_INFO;
|
||||
} else if (menu->actions.settings) {
|
||||
menu->next_mode = MENU_MODE_CREDITS;
|
||||
}
|
||||
|
@ -4,8 +4,9 @@
|
||||
|
||||
#include "../menu_res_setup.h"
|
||||
|
||||
|
||||
#define MENU_VERSION "V0.0.0.3"
|
||||
#ifndef MENU_VERSION
|
||||
#define MENU_VERSION "0.0.0.4"
|
||||
#endif
|
||||
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
@ -22,17 +23,21 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
int16_t vertical_position = 40;
|
||||
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position, "Menu Version:");
|
||||
graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, MENU_VERSION);
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position, "Menu Revision: V");
|
||||
graphics_draw_text(d, horizontal_start_position + 16 * 8, vertical_position, MENU_VERSION);
|
||||
vertical_position += (font_vertical_pixels * 2);
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position, "Authors:");
|
||||
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "JonesAlmighty / NetworkFusion");
|
||||
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "korgeaux / Polprzewodnikowy");
|
||||
vertical_position += (font_vertical_pixels * 2);
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "Credits:");
|
||||
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "N64Brew / libdragon contributors.");
|
||||
vertical_position += (font_vertical_pixels * 2);
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "Github:");
|
||||
// graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/SummerCart64");
|
||||
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/N64FlashcartMenu");
|
||||
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/NetworkFusion/N64FlashcartMenu");
|
||||
//graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/dragonminded/libdragon");
|
||||
vertical_position += (font_vertical_pixels * 2);
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position, "OSS licenses used:");
|
||||
graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, "UNLICENSE");
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <libdragon.h>
|
||||
|
||||
#include "views.h"
|
||||
#include "../menu_res_setup.h"
|
||||
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
@ -12,7 +13,7 @@ static void process (menu_t *menu) {
|
||||
static void draw (menu_t *menu, surface_t *d) {
|
||||
graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255));
|
||||
|
||||
graphics_draw_text(d, 24, 36, "ERROR!");
|
||||
graphics_draw_text(d, overscan_horizontal_pixels, overscan_vertical_pixels, "ERROR!");
|
||||
|
||||
display_show(d);
|
||||
}
|
||||
|
@ -5,35 +5,123 @@
|
||||
|
||||
#include "../menu_res_setup.h"
|
||||
#include "../../utils/str_utils.h"
|
||||
#include "../rom_database.h"
|
||||
|
||||
#include "fragments/fragments.h"
|
||||
|
||||
|
||||
static FILINFO info;
|
||||
|
||||
static char *get_rom_endian_s (uint32_t endian) {
|
||||
switch (endian)
|
||||
{
|
||||
case ROM_BIG_ENDIAN:
|
||||
return "Big (default)"; // expected
|
||||
break;
|
||||
case ROM_LITTLE_ENDIAN:
|
||||
return "Little";
|
||||
break;
|
||||
case ROM_MID_LITTLE_ENDIAN:
|
||||
return "Middle Little";
|
||||
break;
|
||||
case ROM_MID_BIG_ENDIAN:
|
||||
return "Middle Big";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *get_file_type (void) {
|
||||
static char *get_rom_mediatype_s (uint8_t type) {
|
||||
switch (type)
|
||||
{
|
||||
case N64_CART:
|
||||
return "N - Cartridge";
|
||||
break;
|
||||
case N64_DISK:
|
||||
return "D - Disk";
|
||||
break;
|
||||
case N64_CART_EXPANDABLE:
|
||||
return "C - Cart Expandable";
|
||||
break;
|
||||
case N64_DISK_EXPANDABLE:
|
||||
return "E - Disk Expandable";
|
||||
break;
|
||||
case N64_ALECK64:
|
||||
return "Z - Aleck64";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *get_rom_savetype_s (uint8_t type) {
|
||||
switch (type)
|
||||
{
|
||||
case DB_SAVE_TYPE_EEPROM_4K:
|
||||
return "EEPROM 4K";
|
||||
break;
|
||||
case DB_SAVE_TYPE_EEPROM_16K:
|
||||
return "EEPROM 16K";
|
||||
break;
|
||||
case DB_SAVE_TYPE_SRAM:
|
||||
return "SRAM";
|
||||
break;
|
||||
case DB_SAVE_TYPE_SRAM_BANKED:
|
||||
return "SRAM Banked";
|
||||
break;
|
||||
case DB_SAVE_TYPE_SRAM_128K:
|
||||
return "SRAM 128K [ED64]";
|
||||
break;
|
||||
case DB_SAVE_TYPE_FLASHRAM:
|
||||
return "FLASH RAM";
|
||||
break;
|
||||
case DB_SAVE_TYPE_CPAK:
|
||||
return "Controller PAK";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *get_file_type_s (void) {
|
||||
// TODO: should be at least a switch statement!
|
||||
if (str_endswith(info.fname, ".z64") || str_endswith(info.fname, ".n64") || str_endswith(info.fname, ".v64") || str_endswith(info.fname, ".rom")) {
|
||||
if (str_endswith(info.fname, ".z64", false) ||
|
||||
str_endswith(info.fname, ".n64", false) ||
|
||||
str_endswith(info.fname, ".v64", false) ||
|
||||
str_endswith(info.fname, ".rom", false)
|
||||
) {
|
||||
// TODO: check the necessary bytes in the header to ensure!
|
||||
return "N64 ROM";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".txt")) {
|
||||
else if (str_endswith(info.fname, ".txt", false)) {
|
||||
return "Text File";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".ini")) {
|
||||
else if (str_endswith(info.fname, ".ini", false)) {
|
||||
return "INI File";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".yml") || str_endswith(info.fname, ".yaml")) {
|
||||
else if (str_endswith(info.fname, ".yml", false) || str_endswith(info.fname, ".yaml", false)) {
|
||||
return "YAML File";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".toml")) {
|
||||
else if (str_endswith(info.fname, ".toml", false)) {
|
||||
return "TOML File";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".sav")) {
|
||||
return "Save File";
|
||||
else if (str_endswith(info.fname, ".sav", false) || str_endswith(info.fname, ".eep", false) || str_endswith(info.fname, ".sra", false) || str_endswith(info.fname, ".srm", false)|| str_endswith(info.fname, ".fla", false)) {
|
||||
return "ROM Save File";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".emu")) {
|
||||
else if (str_endswith(info.fname, ".ips", false) || str_endswith(info.fname, ".aps", false) || str_endswith(info.fname, ".pps", false) || str_endswith(info.fname, ".xdelta", false)) {
|
||||
return "ROM Patch File";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".zip", false)) {
|
||||
return "ZIP Archive";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".mpk", false)) {
|
||||
return "DexDrive CPak Backup File";
|
||||
}
|
||||
else if (str_endswith(info.fname, ".emu", false)) {
|
||||
return "Emulator File";
|
||||
}
|
||||
else {
|
||||
@ -92,9 +180,43 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
vertical_position += (font_vertical_pixels * 2);
|
||||
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position, "Type:");
|
||||
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type());
|
||||
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type_s());
|
||||
|
||||
//menu_fileinfo_draw_n64_rom_info(d);
|
||||
// TODO: split into a seperate menu item.
|
||||
if (strcmp(get_file_type_s(), "N64 ROM") == 0) {
|
||||
graphics_draw_line(d, d->width / 2, 67, d->width / 2, d->height - 45, 0xff);
|
||||
int x_start_position = (d->width / 2) + horizontal_start_position;
|
||||
int y_position = 67;
|
||||
graphics_draw_text(d, x_start_position, y_position, "N64 ROM Information:\n\n");
|
||||
y_position += (font_vertical_pixels * 2);
|
||||
|
||||
path_t *path = path_clone(menu->browser.directory);
|
||||
path_push(path, menu->browser.list[menu->browser.selected].name);
|
||||
|
||||
rom_header_t temp_header = file_read_rom_header(path_get(path));
|
||||
|
||||
sprintf(str_buffer,"File Endian: %s\n", get_rom_endian_s(temp_header.endian));
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
y_position += (font_vertical_pixels * 2);
|
||||
sprintf(str_buffer,"Title: %s\n", temp_header.title);
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer,"Media Type: %s\n", get_rom_mediatype_s(temp_header.metadata.media_type));
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer,"Unique ID: %.2s\n", (char*)&(temp_header.metadata.unique_identifier));
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer,"Destination Market: %c\n", temp_header.metadata.destination_market);
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer,"Version: %hhu\n", temp_header.version);
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer,"Checksum: %llu\n", temp_header.checksum);
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
y_position += (font_vertical_pixels * 2);
|
||||
uint8_t save_type = rom_db_match_save_type(temp_header);
|
||||
sprintf(str_buffer,"Save Type: %s\n", get_rom_savetype_s(save_type));
|
||||
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
|
||||
|
||||
//menu_fileinfo_draw_n64_rom_info(d);
|
||||
}
|
||||
|
||||
graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
|
||||
graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2
|
||||
|
@ -21,7 +21,7 @@ static void load (menu_t *menu) {
|
||||
|
||||
uint8_t save_type = rom_db_match_save_type(temp_header);
|
||||
|
||||
if (flashcart_load_rom(path_get(path), false) != FLASHCART_OK) {
|
||||
if (flashcart_load_rom(path_get(path), temp_header.endian == ROM_MID_BIG_ENDIAN) != FLASHCART_OK) {
|
||||
menu->next_mode = MENU_MODE_ERROR;
|
||||
path_free(path);
|
||||
return;
|
||||
@ -57,6 +57,8 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
// Layout
|
||||
fragment_borders(d);
|
||||
|
||||
// TODO: Display ROM information here
|
||||
|
||||
rdpq_detach_show();
|
||||
}
|
||||
|
||||
|
97
src/menu/views/system_info.c
Normal file
97
src/menu/views/system_info.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include <time.h>
|
||||
#include <libdragon.h>
|
||||
|
||||
#include "views.h"
|
||||
#include "../menu_res_setup.h"
|
||||
|
||||
|
||||
char *accessory_type_s( int accessory )
|
||||
{
|
||||
switch( accessory )
|
||||
{
|
||||
case ACCESSORY_RUMBLEPAK:
|
||||
return "[RumblePak]";
|
||||
case ACCESSORY_MEMPAK:
|
||||
return "[ControllerPak]";
|
||||
case ACCESSORY_VRU:
|
||||
return "[VRU]";
|
||||
case ACCESSORY_TRANSFERPAK:
|
||||
return "[TransferPak]";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
}
|
||||
}
|
||||
|
||||
static void draw (menu_t *menu, surface_t *d) {
|
||||
char str_buffer[512];
|
||||
|
||||
graphics_fill_screen(d, 0x00);
|
||||
|
||||
graphics_draw_text(d, (d->width / 2) - 64, vertical_start_position, "N64 SYSTEM INFORMATION"); // centre = numchars * font_horizontal_pixels / 2
|
||||
graphics_draw_line(d, 0, 30, d->width, 30, 0xff);
|
||||
|
||||
int16_t vertical_position = 40;
|
||||
|
||||
time_t current_time = -1;
|
||||
current_time = time( NULL );
|
||||
if( current_time != -1 )
|
||||
{
|
||||
sprintf(str_buffer, "Current date & time: %s\n\n", ctime( ¤t_time ));
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "To change the time, use USB App...");
|
||||
}
|
||||
|
||||
vertical_position += font_vertical_pixels;
|
||||
|
||||
int controllers = get_controllers_present();
|
||||
|
||||
sprintf(str_buffer, "JoyPad 1 is %sconnected\n", (controllers & CONTROLLER_1_INSERTED) ? "" : "not " );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer, "JoyPad 2 is %sconnected\n", (controllers & CONTROLLER_2_INSERTED) ? "" : "not " );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer, "JoyPad 3 is %sconnected\n", (controllers & CONTROLLER_3_INSERTED) ? "" : "not " );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer, "JoyPad 4 is %sconnected\n", (controllers & CONTROLLER_4_INSERTED) ? "" : "not " );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
|
||||
vertical_position += font_vertical_pixels;
|
||||
|
||||
struct controller_data output;
|
||||
int accessories = get_accessories_present( &output );
|
||||
|
||||
sprintf(str_buffer, "JoyPad 1 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_1_INSERTED) ? "" : "not ",
|
||||
(accessories & CONTROLLER_1_INSERTED) ? accessory_type_s( identify_accessory( 0 ) ) : "" );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer, "JoyPad 2 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_2_INSERTED) ? "" : "not ",
|
||||
(accessories & CONTROLLER_2_INSERTED) ? accessory_type_s( identify_accessory( 1 ) ) : "" );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer, "JoyPad 3 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_3_INSERTED) ? "" : "not ",
|
||||
(accessories & CONTROLLER_3_INSERTED) ? accessory_type_s( identify_accessory( 2 ) ) : "" );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
sprintf(str_buffer, "JoyPad 4 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_4_INSERTED) ? "" : "not ",
|
||||
(accessories & CONTROLLER_4_INSERTED) ? accessory_type_s( identify_accessory( 3 ) ) : "" );
|
||||
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
|
||||
|
||||
|
||||
graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
|
||||
graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2
|
||||
|
||||
display_show(d);
|
||||
}
|
||||
|
||||
|
||||
void view_system_info_init (menu_t *menu) {
|
||||
// Nothing to initialize (yet)
|
||||
}
|
||||
|
||||
void view_system_info_display (menu_t *menu, surface_t *display) {
|
||||
process(menu);
|
||||
draw(menu, display);
|
||||
}
|
@ -13,6 +13,9 @@ void view_startup_display (menu_t *menu, surface_t *display);
|
||||
void view_browser_init (menu_t *menu);
|
||||
void view_browser_display (menu_t *menu, surface_t *display);
|
||||
|
||||
void view_system_info_init (menu_t *menu);
|
||||
void view_system_info_display (menu_t *menu, surface_t *display);
|
||||
|
||||
void view_file_info_init (menu_t *menu);
|
||||
void view_file_info_display (menu_t *menu, surface_t *display);
|
||||
|
||||
|
@ -3,13 +3,31 @@
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
//#include <stdlib.h> // TODO: does this work... will unlock qsort!
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// e.g. if (str_endswith(cur_rom, ".z64") || str_endswith(cur_rom, ".n64"))
|
||||
static bool str_endswith(const char *str, const char *suffix) {
|
||||
char *p = strstr(str, suffix);
|
||||
return p && p[strlen(suffix)] == '\0';
|
||||
// e.g. if (str_endswith(cur_rom, ".z64", false) || str_endswith(cur_rom, ".n64", false))
|
||||
static bool str_endswith(const char *str, const char *suffix, bool case_sensitive) {
|
||||
size_t str_len = strlen(str);
|
||||
size_t suffix_len = strlen(suffix);
|
||||
|
||||
if (str_len < suffix_len)
|
||||
return false;
|
||||
|
||||
if (!case_sensitive) {
|
||||
for (size_t i = 0; i < suffix_len; i++) {
|
||||
if (tolower(str[str_len - suffix_len + i]) != tolower(suffix[i]))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < suffix_len; i++) {
|
||||
if (str[str_len - suffix_len + i] != suffix[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user