mirror of
https://github.com/wiiu-env/homebrew_on_menu_plugin.git
synced 2024-11-22 10:39:16 +01:00
Add option to hide .rpx if a .wuhb with the same name exists
This commit is contained in:
parent
fa50152356
commit
3bdde5c1d4
18
README.md
18
README.md
@ -1,6 +1,10 @@
|
|||||||
[![CI-Release](https://github.com/wiiu-env/homebrew_on_menu_plugin/actions/workflows/ci.yml/badge.svg)](https://github.com/wiiu-env/homebrew_on_menu_plugin/actions/workflows/ci.yml)
|
[![CI-Release](https://github.com/wiiu-env/homebrew_on_menu_plugin/actions/workflows/ci.yml/badge.svg)](https://github.com/wiiu-env/homebrew_on_menu_plugin/actions/workflows/ci.yml)
|
||||||
|
|
||||||
## Usage
|
# Homebrew on menu
|
||||||
|
|
||||||
|
This plugin allows you to boot homebrew directly from your Wii U Menu.
|
||||||
|
|
||||||
|
## Installation
|
||||||
(`[ENVIRONMENT]` is a placeholder for the actual environment name.)
|
(`[ENVIRONMENT]` is a placeholder for the actual environment name.)
|
||||||
|
|
||||||
1. Copy the file `homebrew_on_menu.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`.
|
1. Copy the file `homebrew_on_menu.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`.
|
||||||
@ -10,10 +14,22 @@
|
|||||||
5. Requires the [ContentRedirectionModule](https://github.com/wiiu-env/ContentRedirectionModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
5. Requires the [ContentRedirectionModule](https://github.com/wiiu-env/ContentRedirectionModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||||
6. Requires the [SDHotSwapModule](https://github.com/wiiu-env/SDHotSwapModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
6. Requires the [SDHotSwapModule](https://github.com/wiiu-env/SDHotSwapModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Place your homebrew (`.rpx` or `.wuhb`) in `sd:/wiiu/apps` or any subdirectory inside `sd:/wiiu/apps`.
|
||||||
|
|
||||||
|
Via the plugin config menu (press L, DPAD Down and Minus on the gamepad) you can configure the plugin. The available options are the following:
|
||||||
|
- **Features**:
|
||||||
|
- Hide all homebrew except Homebrew Launcher: (Default is false)
|
||||||
|
- Hides all homebrew from the Wii U Menu except the `sd:/wiiu/apps/homebrew_launcher.wuhb` and `sd:/wiiu/apps/homebrew_launcher/homebrew_launcher.wuhb`
|
||||||
|
- Prefer .wuhb over .rpx (Default is true)
|
||||||
|
- Hides a `.rpx` from the Wii U Menu if a `.wuhb` with the same name exists in the same directory.
|
||||||
## Save data redirection
|
## Save data redirection
|
||||||
In order to preserve the order of homebrew apps even when you run the Wii U Menu without this plugin, this plugin will redirect the Wii U Menu save data to `sd:/wiiu/homebrew_on_menu_plugin`.
|
In order to preserve the order of homebrew apps even when you run the Wii U Menu without this plugin, this plugin will redirect the Wii U Menu save data to `sd:/wiiu/homebrew_on_menu_plugin`.
|
||||||
When no save data is found on the sd card, the current save data is copied from the console, but after that it's never updated.
|
When no save data is found on the sd card, the current save data is copied from the console, but after that it's never updated.
|
||||||
|
|
||||||
|
**If the plugin is configured to hide any homebrew except a Homebrew Launcher, the redirection is disabled.**
|
||||||
|
|
||||||
## Buildflags
|
## Buildflags
|
||||||
|
|
||||||
### Logging
|
### Logging
|
||||||
|
122
src/main.cpp
122
src/main.cpp
@ -19,6 +19,7 @@
|
|||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
#include <fs/DirList.h>
|
#include <fs/DirList.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <nn/acp.h>
|
#include <nn/acp.h>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -61,8 +62,20 @@ void readCustomTitlesFromSD();
|
|||||||
WUPS_USE_WUT_DEVOPTAB();
|
WUPS_USE_WUT_DEVOPTAB();
|
||||||
WUPS_USE_STORAGE("homebrew_on_menu"); // Use the storage API
|
WUPS_USE_STORAGE("homebrew_on_menu"); // Use the storage API
|
||||||
|
|
||||||
|
#define HIDE_HOMEBREW_STRING "hideHomebrew"
|
||||||
|
#define PREFER_WUHB_OVER_RPX_STRING "hideRPXIfWUHBExists"
|
||||||
|
|
||||||
|
#define HOMEBREW_APPS_DIRECTORY "fs:/vol/external01/wiiu/apps"
|
||||||
|
#define HOMEBREW_LAUNCHER_FILENAME "homebrew_launcher.wuhb"
|
||||||
|
#define HOMEBREW_LAUNCHER_OPTIONAL_DIRECTORY "homebrew_launcher"
|
||||||
|
|
||||||
|
#define HOMEBREW_LAUNCHER_PATH HOMEBREW_APPS_DIRECTORY "/" HOMEBREW_LAUNCHER_FILENAME
|
||||||
|
#define HOMEBREW_LAUNCHER_PATH2 HOMEBREW_APPS_DIRECTORY "/" HOMEBREW_LAUNCHER_OPTIONAL_DIRECTORY "/" HOMEBREW_LAUNCHER_FILENAME
|
||||||
|
|
||||||
bool gHideHomebrew = false;
|
bool gHideHomebrew = false;
|
||||||
|
bool gPreferWUHBOverRPX = true;
|
||||||
bool prevHideValue = false;
|
bool prevHideValue = false;
|
||||||
|
bool prevPreferWUHBOverRPXValue = false;
|
||||||
|
|
||||||
INITIALIZE_PLUGIN() {
|
INITIALIZE_PLUGIN() {
|
||||||
memset((void *) ¤t_launched_title_info, 0, sizeof(current_launched_title_info));
|
memset((void *) ¤t_launched_title_info, 0, sizeof(current_launched_title_info));
|
||||||
@ -96,9 +109,21 @@ INITIALIZE_PLUGIN() {
|
|||||||
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
} else {
|
} else {
|
||||||
// Try to get value from storage
|
// Try to get value from storage
|
||||||
if ((storageRes = WUPS_GetBool(nullptr, "hideHomebrew", &gHideHomebrew)) == WUPS_STORAGE_ERROR_NOT_FOUND) {
|
if ((storageRes = WUPS_GetBool(nullptr, HIDE_HOMEBREW_STRING, &gHideHomebrew)) == WUPS_STORAGE_ERROR_NOT_FOUND) {
|
||||||
// Add the value to the storage if it's missing.
|
// Add the value to the storage if it's missing.
|
||||||
storageRes = WUPS_StoreBool(nullptr, "hideHomebrew", gHideHomebrew);
|
storageRes = WUPS_StoreBool(nullptr, HIDE_HOMEBREW_STRING, gHideHomebrew);
|
||||||
|
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to store bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((storageRes = WUPS_GetBool(nullptr, PREFER_WUHB_OVER_RPX_STRING, &gPreferWUHBOverRPX)) == WUPS_STORAGE_ERROR_NOT_FOUND) {
|
||||||
|
// Add the value to the storage if it's missing.
|
||||||
|
storageRes = WUPS_StoreBool(nullptr, PREFER_WUHB_OVER_RPX_STRING, gPreferWUHBOverRPX);
|
||||||
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to store bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
DEBUG_FUNCTION_LINE_ERR("Failed to store bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
}
|
}
|
||||||
@ -109,6 +134,7 @@ INITIALIZE_PLUGIN() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prevHideValue = gHideHomebrew;
|
prevHideValue = gHideHomebrew;
|
||||||
|
prevPreferWUHBOverRPXValue = gPreferWUHBOverRPX;
|
||||||
|
|
||||||
// Close storage
|
// Close storage
|
||||||
WUPS_CloseStorage();
|
WUPS_CloseStorage();
|
||||||
@ -118,9 +144,20 @@ INITIALIZE_PLUGIN() {
|
|||||||
void hideHomebrewChanged(ConfigItemBoolean *item, bool newValue) {
|
void hideHomebrewChanged(ConfigItemBoolean *item, bool newValue) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("New value in gHideHomebrew: %d", newValue);
|
DEBUG_FUNCTION_LINE_VERBOSE("New value in gHideHomebrew: %d", newValue);
|
||||||
gHideHomebrew = newValue;
|
gHideHomebrew = newValue;
|
||||||
// If the value has changed, we store it in the storage.
|
|
||||||
|
|
||||||
WUPSStorageError storageRes = WUPS_StoreBool(nullptr, "hideHomebrew", gHideHomebrew);
|
// If the value has changed, we store it in the storage.
|
||||||
|
WUPSStorageError storageRes = WUPS_StoreBool(nullptr, HIDE_HOMEBREW_STRING, gHideHomebrew);
|
||||||
|
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to store bool: %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferWUHBOverRPXChanged(ConfigItemBoolean *item, bool newValue) {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("New value in gPreferWUHBOverRPX: %d", newValue);
|
||||||
|
gPreferWUHBOverRPX = newValue;
|
||||||
|
|
||||||
|
// If the value has changed, we store it in the storage.
|
||||||
|
WUPSStorageError storageRes = WUPS_StoreBool(nullptr, PREFER_WUHB_OVER_RPX_STRING, gPreferWUHBOverRPX);
|
||||||
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to store bool: %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
DEBUG_FUNCTION_LINE_ERR("Failed to store bool: %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
}
|
}
|
||||||
@ -141,7 +178,8 @@ WUPS_GET_CONFIG() {
|
|||||||
WUPSConfigCategoryHandle cat;
|
WUPSConfigCategoryHandle cat;
|
||||||
WUPSConfig_AddCategoryByNameHandled(config, "Features", &cat);
|
WUPSConfig_AddCategoryByNameHandled(config, "Features", &cat);
|
||||||
|
|
||||||
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, "hideHomebrew", "Hide all homebrew except Homebrew Launcher", gHideHomebrew, &hideHomebrewChanged);
|
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, HIDE_HOMEBREW_STRING, "Hide all homebrew except Homebrew Launcher", gHideHomebrew, &hideHomebrewChanged);
|
||||||
|
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, PREFER_WUHB_OVER_RPX_STRING, "Prefer .wuhb over .rpx", gPreferWUHBOverRPX, &preferWUHBOverRPXChanged);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@ -157,13 +195,14 @@ WUPS_CONFIG_CLOSED() {
|
|||||||
DEBUG_FUNCTION_LINE_ERR("Failed to close storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
DEBUG_FUNCTION_LINE_ERR("Failed to close storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevHideValue != gHideHomebrew) {
|
if (prevHideValue != gHideHomebrew || prevPreferWUHBOverRPXValue != gPreferWUHBOverRPX) {
|
||||||
if (!sTitleRebooting) {
|
if (!sTitleRebooting) {
|
||||||
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
||||||
sTitleRebooting = true;
|
sTitleRebooting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prevHideValue = gHideHomebrew;
|
prevHideValue = gHideHomebrew;
|
||||||
|
prevPreferWUHBOverRPXValue = gPreferWUHBOverRPX;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup() {
|
void Cleanup() {
|
||||||
@ -303,42 +342,74 @@ void readCustomTitlesFromSD() {
|
|||||||
DEBUG_FUNCTION_LINE_VERBOSE("Using cached value");
|
DEBUG_FUNCTION_LINE_VERBOSE("Using cached value");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> listOfExecutables;
|
||||||
|
|
||||||
|
if (gHideHomebrew) {
|
||||||
|
struct stat st {};
|
||||||
|
if (stat(HOMEBREW_LAUNCHER_PATH, &st) >= 0) {
|
||||||
|
listOfExecutables.emplace_back(HOMEBREW_LAUNCHER_PATH);
|
||||||
|
} else if (stat(HOMEBREW_LAUNCHER_PATH2, &st) >= 0) {
|
||||||
|
listOfExecutables.emplace_back(HOMEBREW_LAUNCHER_PATH2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Reset current infos
|
// Reset current infos
|
||||||
DirList dirList("fs:/vol/external01/wiiu/apps", ".rpx,.wuhb", DirList::Files | DirList::CheckSubfolders, 1);
|
DirList dirList(HOMEBREW_APPS_DIRECTORY, ".rpx,.wuhb", DirList::Files | DirList::CheckSubfolders, 1);
|
||||||
dirList.SortList();
|
dirList.SortList();
|
||||||
|
|
||||||
|
if (gPreferWUHBOverRPX) {
|
||||||
|
// map<[path without extension], vector<[extension]>>
|
||||||
|
std::map<std::string, std::vector<std::string>> pathWithoutExtensionMap;
|
||||||
for (int i = 0; i < dirList.GetFilecount(); i++) {
|
for (int i = 0; i < dirList.GetFilecount(); i++) {
|
||||||
|
std::string pathNoExtension = StringTools::remove_extension(dirList.GetFilepath(i));
|
||||||
|
if (pathWithoutExtensionMap.count(pathNoExtension) == 0) {
|
||||||
|
pathWithoutExtensionMap[pathNoExtension] = std::vector<std::string>();
|
||||||
|
}
|
||||||
|
pathWithoutExtensionMap[pathNoExtension].push_back(StringTools::get_extension(dirList.GetFilename(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &l : pathWithoutExtensionMap) {
|
||||||
|
if (l.second.size() == 1 && l.second.at(0) == ".rpx") {
|
||||||
|
listOfExecutables.push_back(l.first + ".rpx");
|
||||||
|
} else {
|
||||||
|
listOfExecutables.push_back(l.first + ".wuhb");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < dirList.GetFilecount(); i++) {
|
||||||
|
listOfExecutables.emplace_back(dirList.GetFilepath(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &filePath : listOfExecutables) {
|
||||||
|
auto filename = StringTools::FullpathToFilename(filePath.c_str());
|
||||||
|
|
||||||
//! skip wiiload temp files
|
//! skip wiiload temp files
|
||||||
if (gHideHomebrew && strcasecmp(dirList.GetFilename(i), "homebrew_launcher.wuhb") != 0) {
|
if (strcasecmp(filename, "temp.rpx") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! skip wiiload temp files
|
//! skip wiiload temp files
|
||||||
if (strcasecmp(dirList.GetFilename(i), "temp.rpx") == 0) {
|
if (strcasecmp(filename, "temp.wuhb") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! skip wiiload temp files
|
//! skip wiiload temp files
|
||||||
if (strcasecmp(dirList.GetFilename(i), "temp.wuhb") == 0) {
|
if (strcasecmp(filename, "temp2.wuhb") == 0) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! skip wiiload temp files
|
|
||||||
if (strcasecmp(dirList.GetFilename(i), "temp2.wuhb") == 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! skip hidden linux and mac files
|
//! skip hidden linux and mac files
|
||||||
if (dirList.GetFilename(i)[0] == '.' || dirList.GetFilename(i)[0] == '_') {
|
if (filename[0] == '.' || filename[0] == '_') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto repl = "fs:/vol/external01/";
|
auto repl = "fs:/vol/external01/";
|
||||||
auto input = dirList.GetFilepath(i);
|
auto input = filePath.c_str();
|
||||||
const char *relativeFilepath;
|
const char *relativeFilepath;
|
||||||
|
|
||||||
if (std::string_view(input).starts_with(repl)) {
|
if (filePath.starts_with(repl)) {
|
||||||
relativeFilepath = &input[strlen(repl)];
|
relativeFilepath = &input[strlen(repl)];
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Skip %s, Path doesn't start with %s (This should never happen", input, repl);
|
DEBUG_FUNCTION_LINE_ERR("Skip %s, Path doesn't start with %s (This should never happen", input, repl);
|
||||||
@ -360,10 +431,10 @@ void readCustomTitlesFromSD() {
|
|||||||
const char *indexedDevice = "mlc";
|
const char *indexedDevice = "mlc";
|
||||||
strncpy(cur_title_info->indexedDevice, indexedDevice, sizeof(cur_title_info->indexedDevice) - 1);
|
strncpy(cur_title_info->indexedDevice, indexedDevice, sizeof(cur_title_info->indexedDevice) - 1);
|
||||||
|
|
||||||
fileInfo->filename = dirList.GetFilename(i);
|
fileInfo->filename = filename;
|
||||||
fileInfo->longname = dirList.GetFilename(i);
|
fileInfo->longname = filename;
|
||||||
fileInfo->shortname = dirList.GetFilename(i);
|
fileInfo->shortname = filename;
|
||||||
fileInfo->author = dirList.GetFilename(i);
|
fileInfo->author = filename;
|
||||||
|
|
||||||
// System apps don't have a splash screen.
|
// System apps don't have a splash screen.
|
||||||
cur_title_info->appType = MCP_APP_TYPE_SYSTEM_APPS;
|
cur_title_info->appType = MCP_APP_TYPE_SYSTEM_APPS;
|
||||||
@ -376,7 +447,7 @@ void readCustomTitlesFromSD() {
|
|||||||
|
|
||||||
#define TMP_BUNDLE_NAME "romfscheck"
|
#define TMP_BUNDLE_NAME "romfscheck"
|
||||||
|
|
||||||
if (WUHBUtils_MountBundle(TMP_BUNDLE_NAME, dirList.GetFilepath(i), BundleSource_FileDescriptor, &result) == WUHB_UTILS_RESULT_SUCCESS && result >= 0) {
|
if (WUHBUtils_MountBundle(TMP_BUNDLE_NAME, filePath.c_str(), BundleSource_FileDescriptor, &result) == WUHB_UTILS_RESULT_SUCCESS && result >= 0) {
|
||||||
fileInfo->isBundle = true;
|
fileInfo->isBundle = true;
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
uint32_t bufferSize;
|
uint32_t bufferSize;
|
||||||
@ -410,7 +481,7 @@ void readCustomTitlesFromSD() {
|
|||||||
DEBUG_FUNCTION_LINE_ERR("Failed to unmount \"%s\"", TMP_BUNDLE_NAME);
|
DEBUG_FUNCTION_LINE_ERR("Failed to unmount \"%s\"", TMP_BUNDLE_NAME);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("%s is not a valid .wuhb file: %d", dirList.GetFilepath(i), result);
|
DEBUG_FUNCTION_LINE_ERR("%s is not a valid .wuhb file: %d", filePath.c_str(), result);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,6 +496,7 @@ void readCustomTitlesFromSD() {
|
|||||||
|
|
||||||
fileInfos.push_front(fileInfo);
|
fileInfos.push_front(fileInfo);
|
||||||
}
|
}
|
||||||
|
OSMemoryBarrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckFileExistsHelper(const char *path) {
|
bool CheckFileExistsHelper(const char *path) {
|
||||||
|
@ -30,6 +30,19 @@
|
|||||||
#include <utils/StringTools.h>
|
#include <utils/StringTools.h>
|
||||||
#include <wut_types.h>
|
#include <wut_types.h>
|
||||||
|
|
||||||
|
std::string StringTools::remove_extension(const std::string &filename) {
|
||||||
|
size_t lastdot = filename.find_last_of('.');
|
||||||
|
if (lastdot == std::string::npos) return filename;
|
||||||
|
return filename.substr(0, lastdot);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringTools::get_extension(const std::string &filename) {
|
||||||
|
size_t lastdot = filename.find_last_of('.');
|
||||||
|
if (lastdot == std::string::npos) return "";
|
||||||
|
return filename.substr(lastdot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||||
if (!string || !compare)
|
if (!string || !compare)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -40,6 +40,10 @@ std::string string_format(const std::string &format, Args... args) {
|
|||||||
|
|
||||||
class StringTools {
|
class StringTools {
|
||||||
public:
|
public:
|
||||||
|
static std::string remove_extension(const std::string &filename);
|
||||||
|
|
||||||
|
static std::string get_extension(const std::string &filename);
|
||||||
|
|
||||||
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||||
|
|
||||||
static const char *FullpathToFilename(const char *path);
|
static const char *FullpathToFilename(const char *path);
|
||||||
|
Loading…
Reference in New Issue
Block a user