mirror of
https://github.com/wiiu-env/sdcafiine_plugin.git
synced 2024-11-25 04:36:56 +01:00
first commit
This commit is contained in:
commit
54750ac330
58
.github/workflows/ci.yml
vendored
Normal file
58
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
name: CI-Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-binary:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: build binary
|
||||||
|
run: |
|
||||||
|
docker build . -t builder
|
||||||
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: binary
|
||||||
|
path: "*.wps"
|
||||||
|
deploy-binary:
|
||||||
|
needs: build-binary
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: Get environment variables
|
||||||
|
id: get_repository_name
|
||||||
|
run: |
|
||||||
|
echo REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//") >> $GITHUB_ENV
|
||||||
|
echo DATETIME=$(echo $(date '+%Y%m%d-%H%M%S')) >> $GITHUB_ENV
|
||||||
|
- uses: actions/download-artifact@master
|
||||||
|
with:
|
||||||
|
name: binary
|
||||||
|
path: wiiu/plugins
|
||||||
|
- name: zip artifact
|
||||||
|
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip wiiu
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||||
|
release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||||
|
draft: false
|
||||||
|
prerelease: true
|
||||||
|
body: |
|
||||||
|
Not a stable release:
|
||||||
|
${{ github.event.head_commit.message }}
|
||||||
|
- name: Upload Release Asset
|
||||||
|
id: upload-release-asset
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
||||||
|
asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
||||||
|
asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
||||||
|
asset_content_type: application/unknown
|
17
.github/workflows/pr.yml
vendored
Normal file
17
.github/workflows/pr.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: CI-PR
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-binary:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: build binary
|
||||||
|
run: |
|
||||||
|
docker build . -t builder
|
||||||
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: binary
|
||||||
|
path: "*.wps"
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
build/*
|
||||||
|
*.mod
|
||||||
|
sysapp.layout
|
||||||
|
sysapp.cbp
|
||||||
|
sysapp.cscope_file_list
|
||||||
|
*.wps
|
||||||
|
*.elf
|
||||||
|
cmake-build-debug/
|
||||||
|
.idea/
|
||||||
|
*.rpx
|
||||||
|
*.txt
|
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM wiiuenv/devkitppc:20210101
|
||||||
|
|
||||||
|
COPY --from=wiiuenv/libmappedmemory:20210403 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/librpxloader:20210406 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/wiiupluginsystem:20210316 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
|
WORKDIR project
|
139
Makefile
Normal file
139
Makefile
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
|
||||||
|
include $(DEVKITPRO)/wups/share/wups_rules
|
||||||
|
|
||||||
|
WUT_ROOT := $(DEVKITPRO)/wut
|
||||||
|
WUMS_ROOT := $(DEVKITPRO)/wums
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# TARGET is the name of the output
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# DATA is a list of directories containing data files
|
||||||
|
# INCLUDES is a list of directories containing header files
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
TARGET := sdcafiine
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := src \
|
||||||
|
src/fs \
|
||||||
|
src/utils
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := src
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||||
|
$(MACHDEP)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -std=gnu++17
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld -T$(WUMS_ROOT)/share/librpxloader.ld $(WUPSSPECS)
|
||||||
|
|
||||||
|
LIBS := -lwups -lwut -lmappedmemory -lrpxloader
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level
|
||||||
|
# containing include and lib
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT) $(WUMS_ROOT)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||||
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD)
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).wps
|
||||||
|
|
||||||
|
$(OUTPUT).wps : $(OUTPUT).elf
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#-------------------------------------------------------------------------------
|
54
README.md
Normal file
54
README.md
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# SDCafiine Plugin
|
||||||
|
|
||||||
|
## What is SDCafiine
|
||||||
|
The main feature of this application is the **on-the-fly replacing of files**, which can be used used to loaded modified content from external media (**SD**). It hooks into the file system functions of the WiiU. Whenever a file is accessed, SDCafiine checks if a (modified) version of it present on the SD device, and redirect the file operations if needed.
|
||||||
|
|
||||||
|
## Dependecies
|
||||||
|
Requires the [RPXLoadingModule](https://github.com/wiiu-env/RPXLoadingModule) to be loaded.
|
||||||
|
|
||||||
|
|
||||||
|
### Installation of the mods
|
||||||
|
Before the mods can be loaded, they need to be copied to a SD device.
|
||||||
|
**In the following "root:/" is corresponding to the root of your SD device**. The basic filepath structure is this:
|
||||||
|
|
||||||
|
```
|
||||||
|
root:/sdcafiine/[TITLEID]/[MODPACK]/content/ <-- for game files. Maps to /vol/content/
|
||||||
|
```
|
||||||
|
Replace the following:
|
||||||
|
- "[TITLEID]" need to be replaced the TitleID of the games that should be modded. A list of can be found [here](http://wiiubrew.org/w/index.php?title=Title_database#00050000:_eShop_and_disc_titles) (without the "-"). Example for SSBU "0005000010145000". Make sure to use the ID of the fullgame and not the update title ID.
|
||||||
|
- "[MODPACK]" name of the modpack. This folder name can be everything but "content" or "aoc".
|
||||||
|
|
||||||
|
Example path for the EUR version of SuperSmashBros for Wii U:
|
||||||
|
```
|
||||||
|
root:/sdcafiine/0005000010145000/SpecialChars/content/ <-- for game files. Maps to /vol/content/
|
||||||
|
```
|
||||||
|
|
||||||
|
For replacing the file /vol/content/movie/intro.mp4, put a modified file into:
|
||||||
|
```
|
||||||
|
root:/sdcafiine/0005000010145000/SpecialChars/content/movie/intro.mp4
|
||||||
|
```
|
||||||
|
|
||||||
|
*NOTES: paths like "root:/sdcafiine/0005000010145000/content/" are still supported for compatibility, but **not recommended** *
|
||||||
|
|
||||||
|
### Handling multiple mod packs
|
||||||
|
SDCafiine supports multiple different mods for a single game on the same SDCard. Each mod has an own subfolder.
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
sd:/sdcafiine/0005000010145000/ModPack1/content/
|
||||||
|
sd:/sdcafiine/0005000010145000/ModPack2/content/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building using the Dockerfile
|
||||||
|
|
||||||
|
It's possible to use a docker image for building. This way you don't need anything installed on your host system.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Build docker image (only needed once)
|
||||||
|
docker build . -t sdcafiineplugin-builder
|
||||||
|
|
||||||
|
# make
|
||||||
|
docker run -it --rm -v ${PWD}:/project sdcafiineplugin-builder make
|
||||||
|
|
||||||
|
# make clean
|
||||||
|
docker run -it --rm -v ${PWD}:/project sdcafiineplugin-builder make clean
|
||||||
|
```
|
213
src/fs/DirList.cpp
Normal file
213
src/fs/DirList.cpp
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Copyright (C) 2010
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* DirList Class
|
||||||
|
* for WiiXplorer 2010
|
||||||
|
***************************************************************************/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/dirent.h>
|
||||||
|
|
||||||
|
#include <fs/DirList.h>
|
||||||
|
#include <utils/StringTools.h>
|
||||||
|
|
||||||
|
DirList::DirList() {
|
||||||
|
Flags = 0;
|
||||||
|
Filter = 0;
|
||||||
|
Depth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirList::DirList(const std::string &path, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||||
|
this->LoadPath(path, filter, flags, maxDepth);
|
||||||
|
this->SortList();
|
||||||
|
}
|
||||||
|
|
||||||
|
DirList::~DirList() {
|
||||||
|
ClearList();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL DirList::LoadPath(const std::string &folder, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||||
|
if (folder.empty()) return false;
|
||||||
|
|
||||||
|
Flags = flags;
|
||||||
|
Filter = filter;
|
||||||
|
Depth = maxDepth;
|
||||||
|
|
||||||
|
std::string folderpath(folder);
|
||||||
|
uint32_t length = folderpath.size();
|
||||||
|
|
||||||
|
//! clear path of double slashes
|
||||||
|
StringTools::RemoveDoubleSlashs(folderpath);
|
||||||
|
|
||||||
|
//! remove last slash if exists
|
||||||
|
if (length > 0 && folderpath[length - 1] == '/')
|
||||||
|
folderpath.erase(length - 1);
|
||||||
|
|
||||||
|
//! add root slash if missing
|
||||||
|
if (folderpath.find('/') == std::string::npos) {
|
||||||
|
folderpath += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return InternalLoadPath(folderpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL DirList::InternalLoadPath(std::string &folderpath) {
|
||||||
|
if (folderpath.size() < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct dirent *dirent = NULL;
|
||||||
|
DIR *dir = NULL;
|
||||||
|
|
||||||
|
dir = opendir(folderpath.c_str());
|
||||||
|
if (dir == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while ((dirent = readdir(dir)) != 0) {
|
||||||
|
BOOL isDir = dirent->d_type & DT_DIR;
|
||||||
|
const char *filename = dirent->d_name;
|
||||||
|
|
||||||
|
if (isDir) {
|
||||||
|
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((Flags & CheckSubfolders) && (Depth > 0)) {
|
||||||
|
int32_t length = folderpath.size();
|
||||||
|
if (length > 2 && folderpath[length - 1] != '/') {
|
||||||
|
folderpath += '/';
|
||||||
|
}
|
||||||
|
folderpath += filename;
|
||||||
|
|
||||||
|
Depth--;
|
||||||
|
InternalLoadPath(folderpath);
|
||||||
|
folderpath.erase(length);
|
||||||
|
Depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Flags & Dirs))
|
||||||
|
continue;
|
||||||
|
} else if (!(Flags & Files)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Filter) {
|
||||||
|
char *fileext = strrchr(filename, '.');
|
||||||
|
if (!fileext)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (StringTools::strtokcmp(fileext, Filter, ",") == 0)
|
||||||
|
AddEntrie(folderpath, filename, isDir);
|
||||||
|
} else {
|
||||||
|
AddEntrie(folderpath, filename, isDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirList::AddEntrie(const std::string &filepath, const char *filename, BOOL isDir) {
|
||||||
|
if (!filename)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int32_t pos = FileInfo.size();
|
||||||
|
|
||||||
|
FileInfo.resize(pos + 1);
|
||||||
|
|
||||||
|
FileInfo[pos].FilePath = (char *) malloc(filepath.size() + strlen(filename) + 2);
|
||||||
|
if (!FileInfo[pos].FilePath) {
|
||||||
|
FileInfo.resize(pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(FileInfo[pos].FilePath, "%s/%s", filepath.c_str(), filename);
|
||||||
|
FileInfo[pos].isDir = isDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirList::ClearList() {
|
||||||
|
for (uint32_t i = 0; i < FileInfo.size(); ++i) {
|
||||||
|
if (FileInfo[i].FilePath) {
|
||||||
|
free(FileInfo[i].FilePath);
|
||||||
|
FileInfo[i].FilePath = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInfo.clear();
|
||||||
|
std::vector<DirEntry>().swap(FileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *DirList::GetFilename(int32_t ind) const {
|
||||||
|
if (!valid(ind))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return StringTools::FullpathToFilename(FileInfo[ind].FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL SortCallback(const DirEntry &f1, const DirEntry &f2) {
|
||||||
|
if (f1.isDir && !(f2.isDir)) return true;
|
||||||
|
if (!(f1.isDir) && f2.isDir) return false;
|
||||||
|
|
||||||
|
if (f1.FilePath && !f2.FilePath) return true;
|
||||||
|
if (!f1.FilePath) return false;
|
||||||
|
|
||||||
|
if (strcasecmp(f1.FilePath, f2.FilePath) > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirList::SortList() {
|
||||||
|
if (FileInfo.size() > 1)
|
||||||
|
std::sort(FileInfo.begin(), FileInfo.end(), SortCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirList::SortList(BOOL (*SortFunc)(const DirEntry &a, const DirEntry &b)) {
|
||||||
|
if (FileInfo.size() > 1)
|
||||||
|
std::sort(FileInfo.begin(), FileInfo.end(), SortFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t DirList::GetFilesize(int32_t index) const {
|
||||||
|
struct stat st;
|
||||||
|
const char *path = GetFilepath(index);
|
||||||
|
|
||||||
|
if (!path || stat(path, &st) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return st.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t DirList::GetFileIndex(const char *filename) const {
|
||||||
|
if (!filename)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < FileInfo.size(); ++i) {
|
||||||
|
if (strcasecmp(GetFilename(i), filename) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
118
src/fs/DirList.h
Normal file
118
src/fs/DirList.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Copyright (C) 2010
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* DirList Class
|
||||||
|
* for WiiXplorer 2010
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ___DIRLIST_H_
|
||||||
|
#define ___DIRLIST_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <wut_types.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *FilePath;
|
||||||
|
BOOL isDir;
|
||||||
|
} DirEntry;
|
||||||
|
|
||||||
|
class DirList {
|
||||||
|
public:
|
||||||
|
//!Constructor
|
||||||
|
DirList(void);
|
||||||
|
|
||||||
|
//!\param path Path from where to load the filelist of all files
|
||||||
|
//!\param filter A fileext that needs to be filtered
|
||||||
|
//!\param flags search/filter flags from the enum
|
||||||
|
DirList(const std::string &path, const char *filter = NULL, uint32_t flags = Files | Dirs, uint32_t maxDepth = 0xffffffff);
|
||||||
|
|
||||||
|
//!Destructor
|
||||||
|
virtual ~DirList();
|
||||||
|
|
||||||
|
//! Load all the files from a directory
|
||||||
|
BOOL LoadPath(const std::string &path, const char *filter = NULL, uint32_t flags = Files | Dirs, uint32_t maxDepth = 0xffffffff);
|
||||||
|
|
||||||
|
//! Get a filename of the list
|
||||||
|
//!\param list index
|
||||||
|
const char *GetFilename(int32_t index) const;
|
||||||
|
|
||||||
|
//! Get the a filepath of the list
|
||||||
|
//!\param list index
|
||||||
|
const char *GetFilepath(int32_t index) const {
|
||||||
|
if (!valid(index)) return "";
|
||||||
|
else return FileInfo[index].FilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the a filesize of the list
|
||||||
|
//!\param list index
|
||||||
|
uint64_t GetFilesize(int32_t index) const;
|
||||||
|
|
||||||
|
//! Is index a dir or a file
|
||||||
|
//!\param list index
|
||||||
|
BOOL IsDir(int32_t index) const {
|
||||||
|
if (!valid(index)) return false;
|
||||||
|
return FileInfo[index].isDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Get the filecount of the whole list
|
||||||
|
int32_t GetFilecount() const {
|
||||||
|
return FileInfo.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Sort list by filepath
|
||||||
|
void SortList();
|
||||||
|
|
||||||
|
//! Custom sort command for custom sort functions definitions
|
||||||
|
void SortList(BOOL (*SortFunc)(const DirEntry &a, const DirEntry &b));
|
||||||
|
|
||||||
|
//! Get the index of the specified filename
|
||||||
|
int32_t GetFileIndex(const char *filename) const;
|
||||||
|
|
||||||
|
//! Enum for search/filter flags
|
||||||
|
enum {
|
||||||
|
Files = 0x01,
|
||||||
|
Dirs = 0x02,
|
||||||
|
CheckSubfolders = 0x08,
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
// Internal parser
|
||||||
|
BOOL InternalLoadPath(std::string &path);
|
||||||
|
|
||||||
|
//!Add a list entrie
|
||||||
|
void AddEntrie(const std::string &filepath, const char *filename, BOOL isDir);
|
||||||
|
|
||||||
|
//! Clear the list
|
||||||
|
void ClearList();
|
||||||
|
|
||||||
|
//! Check if valid pos is requested
|
||||||
|
inline BOOL valid(uint32_t pos) const {
|
||||||
|
return (pos < FileInfo.size());
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t Flags;
|
||||||
|
uint32_t Depth;
|
||||||
|
const char *Filter;
|
||||||
|
std::vector<DirEntry> FileInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
18
src/main.cpp
Normal file
18
src/main.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <wups.h>
|
||||||
|
#include <whb/log_udp.h>
|
||||||
|
#include "modpackSelector.h"
|
||||||
|
#include <coreinit/title.h>
|
||||||
|
|
||||||
|
WUPS_PLUGIN_NAME("SDCafiine");
|
||||||
|
WUPS_PLUGIN_DESCRIPTION("Wiiload Server");
|
||||||
|
WUPS_PLUGIN_VERSION("0.1");
|
||||||
|
WUPS_PLUGIN_AUTHOR("Maschell");
|
||||||
|
WUPS_PLUGIN_LICENSE("GPL");
|
||||||
|
|
||||||
|
WUPS_USE_WUT_DEVOPTAB()
|
||||||
|
|
||||||
|
/* Entry point */
|
||||||
|
ON_APPLICATION_START() {
|
||||||
|
WHBLogUdpInit();
|
||||||
|
HandleMultiModPacks(OSGetTitleID());
|
||||||
|
}
|
15
src/main.h
Normal file
15
src/main.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* Main */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <nsysnet/socket.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
199
src/modpackSelector.cpp
Normal file
199
src/modpackSelector.cpp
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include "modpackSelector.h"
|
||||||
|
|
||||||
|
#include <coreinit/thread.h>
|
||||||
|
#include <memory/mappedmemory.h>
|
||||||
|
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <fs/DirList.h>
|
||||||
|
#include <coreinit/screen.h>
|
||||||
|
#include <vpad/input.h>
|
||||||
|
#include <rpxloader.h>
|
||||||
|
|
||||||
|
#define TEXT_SEL(x, text1, text2) ((x) ? (text1) : (text2))
|
||||||
|
|
||||||
|
|
||||||
|
void ReplaceContent(const std::string &basePath);
|
||||||
|
|
||||||
|
void HandleMultiModPacks(uint64_t titleID) {
|
||||||
|
char TitleIDString[17];
|
||||||
|
snprintf(TitleIDString, 17, "%016llX", titleID);
|
||||||
|
|
||||||
|
std::map<std::string, std::string> modTitlePath;
|
||||||
|
|
||||||
|
std::map<std::string, std::string> mounting_points;
|
||||||
|
|
||||||
|
|
||||||
|
std::string modTitleIDPath = std::string("fs:/vol/external01/sdcafiine/") + TitleIDString;
|
||||||
|
DirList modTitleDirList(modTitleIDPath.c_str(), nullptr, DirList::Dirs);
|
||||||
|
|
||||||
|
modTitleDirList.SortList();
|
||||||
|
|
||||||
|
for (int index = 0; index < modTitleDirList.GetFilecount(); index++) {
|
||||||
|
std::string curFile = modTitleDirList.GetFilename(index);
|
||||||
|
//DEBUG_FUNCTION_LINE("curFile %s \n",curFile.c_str());
|
||||||
|
if (curFile.compare(".") == 0 || curFile.compare("..") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string packageName = curFile;
|
||||||
|
modTitlePath[packageName] = modTitleIDPath.append("/").append(curFile);
|
||||||
|
DEBUG_FUNCTION_LINE("found %s", packageName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modTitlePath.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int selected = 0;
|
||||||
|
int initScreen = 1;
|
||||||
|
int x_offset = -2;
|
||||||
|
|
||||||
|
// Init screen and screen buffers
|
||||||
|
OSScreenInit();
|
||||||
|
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||||
|
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||||
|
uint8_t *screenBuffer = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size + screen_buf1_size, 0x100
|
||||||
|
);
|
||||||
|
if (screenBuffer == nullptr) {
|
||||||
|
DEBUG_FUNCTION_LINE("Failed to alloc");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OSScreenSetBufferEx(SCREEN_TV, (void *) screenBuffer);
|
||||||
|
OSScreenSetBufferEx(SCREEN_DRC, (void *) (screenBuffer + screen_buf0_size));
|
||||||
|
|
||||||
|
OSScreenEnableEx(SCREEN_TV, 1);
|
||||||
|
OSScreenEnableEx(SCREEN_DRC, 1);
|
||||||
|
|
||||||
|
// Clear screens
|
||||||
|
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||||
|
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||||
|
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||||
|
|
||||||
|
VPADStatus vpad_data;
|
||||||
|
VPADReadError error;
|
||||||
|
|
||||||
|
int wantToExit = 0;
|
||||||
|
int page = 0;
|
||||||
|
int per_page = 13;
|
||||||
|
int max_pages = (modTitlePath.size() / per_page) + 1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
error = VPAD_READ_NO_SAMPLES;
|
||||||
|
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &error);
|
||||||
|
|
||||||
|
if (error == VPAD_READ_SUCCESS) {
|
||||||
|
if (vpad_data.trigger & VPAD_BUTTON_A) {
|
||||||
|
wantToExit = 1;
|
||||||
|
initScreen = 1;
|
||||||
|
} else if (vpad_data.trigger & VPAD_BUTTON_B) {
|
||||||
|
break;
|
||||||
|
} else if (vpad_data.trigger & VPAD_BUTTON_DOWN) {
|
||||||
|
selected++;
|
||||||
|
initScreen = 1;
|
||||||
|
} else if (vpad_data.trigger & VPAD_BUTTON_UP) {
|
||||||
|
selected--;
|
||||||
|
initScreen = 1;
|
||||||
|
} else if (vpad_data.trigger & VPAD_BUTTON_L) {
|
||||||
|
selected -= per_page;
|
||||||
|
initScreen = 1;
|
||||||
|
} else if (vpad_data.trigger & VPAD_BUTTON_R) {
|
||||||
|
selected += per_page;
|
||||||
|
initScreen = 1;
|
||||||
|
}
|
||||||
|
if (selected < 0) { selected = 0; }
|
||||||
|
if (selected >= modTitlePath.size()) { selected = modTitlePath.size() - 1; }
|
||||||
|
page = selected / per_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initScreen) {
|
||||||
|
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||||
|
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||||
|
console_print_pos(x_offset, -1, " -- SDCafiine plugin %s by Maschell --");
|
||||||
|
console_print_pos(x_offset, 1, "Select your options and press A to launch.");
|
||||||
|
console_print_pos(x_offset, 2, "Press B to launch without mods");
|
||||||
|
int y_offset = 4;
|
||||||
|
int cur_ = 0;
|
||||||
|
|
||||||
|
for (auto &it : modTitlePath) {
|
||||||
|
std::string key = it.first;
|
||||||
|
std::string value = it.second;
|
||||||
|
|
||||||
|
if (wantToExit && cur_ == selected) {
|
||||||
|
ReplaceContent(value.append("/content"));
|
||||||
|
//snprintf(gModFolder, FS_MAX_ENTNAME_SIZE, "%s", value.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_ >= (page * per_page) && cur_ < ((page + 1) * per_page)) {
|
||||||
|
console_print_pos(x_offset, y_offset++, "%s %s", TEXT_SEL((selected == cur_), "--->", " "), key.c_str());
|
||||||
|
}
|
||||||
|
cur_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wantToExit) { //just in case.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_pages > 0) {
|
||||||
|
console_print_pos(x_offset, 17, "Page %02d/%02d. Press L/R to change page.", page + 1, max_pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flip buffers
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||||
|
|
||||||
|
initScreen = 0;
|
||||||
|
}
|
||||||
|
OSSleepTicks(OSMillisecondsToTicks(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||||
|
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||||
|
|
||||||
|
// Flip buffers
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||||
|
|
||||||
|
MEMFreeToMappedMemory(screenBuffer);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplaceContent(const std::string &basePath) {
|
||||||
|
if (RL_RedirectContentWithFallback(basePath.c_str())) {
|
||||||
|
DEBUG_FUNCTION_LINE("redirect /vol/content to %s", basePath.c_str());
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("ERROR: Failed to redirect /vol/content to %s", basePath.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_print_pos(int x, int y, const char *format, ...) {
|
||||||
|
char *tmp = NULL;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vasprintf(&tmp, format, va) >= 0) && tmp) {
|
||||||
|
if (strlen(tmp) > 79) {
|
||||||
|
tmp[79] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSScreenPutFontEx(SCREEN_TV, x, y, tmp);
|
||||||
|
OSScreenPutFontEx(SCREEN_DRC, x, y, tmp);
|
||||||
|
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
if (tmp) {
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
15
src/modpackSelector.h
Normal file
15
src/modpackSelector.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _MODPACK_SELECTOR_H_
|
||||||
|
#define _MODPACK_SELECTOR_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void HandleMultiModPacks(uint64_t titleid/*,bool showMenu = true*/);
|
||||||
|
void console_print_pos(int x, int y, const char *format, ...);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //_MODPACK_SELECTOR_H_
|
210
src/utils/StringTools.cpp
Normal file
210
src/utils/StringTools.cpp
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* for WiiXplorer 2010
|
||||||
|
***************************************************************************/
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <wut_types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <utils/StringTools.h>
|
||||||
|
|
||||||
|
|
||||||
|
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
||||||
|
if (b.size() > a.size()) return false;
|
||||||
|
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StringTools::byte_to_binary(int32_t x) {
|
||||||
|
static char b[9];
|
||||||
|
b[0] = '\0';
|
||||||
|
|
||||||
|
int32_t z;
|
||||||
|
for (z = 128; z > 0; z >>= 1) {
|
||||||
|
strcat(b, ((x & z) == z) ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
|
||||||
|
std::string output = input;
|
||||||
|
size_t position;
|
||||||
|
while (1) {
|
||||||
|
position = output.find(toBeRemoved);
|
||||||
|
if (position == std::string::npos)
|
||||||
|
break;
|
||||||
|
output.erase(position, 1);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StringTools::fmt(const char *format, ...) {
|
||||||
|
static char strChar[512];
|
||||||
|
strChar[0] = 0;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(strChar, format, va) >= 0)) {
|
||||||
|
va_end(va);
|
||||||
|
return (const char *) strChar;
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||||
|
static char tmp[512];
|
||||||
|
static wchar_t strWChar[512];
|
||||||
|
strWChar[0] = 0;
|
||||||
|
tmp[0] = 0;
|
||||||
|
|
||||||
|
if (!format)
|
||||||
|
return (const wchar_t *) strWChar;
|
||||||
|
|
||||||
|
if (strcmp(format, "") == 0)
|
||||||
|
return (const wchar_t *) strWChar;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||||
|
int bt;
|
||||||
|
int32_t strlength = strlen(tmp);
|
||||||
|
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
||||||
|
|
||||||
|
if (bt > 0) {
|
||||||
|
strWChar[bt] = 0;
|
||||||
|
return (const wchar_t *) strWChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
||||||
|
static char tmp[512];
|
||||||
|
tmp[0] = 0;
|
||||||
|
int32_t result = 0;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||||
|
str = tmp;
|
||||||
|
result = str.size();
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringTools::strfmt(const char *format, ...) {
|
||||||
|
std::string str;
|
||||||
|
static char tmp[512];
|
||||||
|
tmp[0] = 0;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||||
|
str = tmp;
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
|
||||||
|
if (!strChar || !dest)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int bt;
|
||||||
|
bt = mbstowcs(dest, strChar, strlen(strChar));
|
||||||
|
if (bt > 0) {
|
||||||
|
dest[bt] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||||
|
if (!string || !compare)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char TokCopy[512];
|
||||||
|
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||||
|
TokCopy[511] = '\0';
|
||||||
|
|
||||||
|
char *strTok = strtok(TokCopy, separator);
|
||||||
|
|
||||||
|
while (strTok != NULL) {
|
||||||
|
if (strcasecmp(string, strTok) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strTok = strtok(NULL, separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
|
||||||
|
if (!string || !extension)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char *ptr = strrchr(string, seperator);
|
||||||
|
if (!ptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return strcasecmp(ptr + 1, extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
|
||||||
|
std::string value = inValue;
|
||||||
|
std::vector<std::string> result;
|
||||||
|
while (true) {
|
||||||
|
uint32_t index = value.find(splitter);
|
||||||
|
if (index == std::string::npos) {
|
||||||
|
result.push_back(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::string first = value.substr(0, index);
|
||||||
|
result.push_back(first);
|
||||||
|
if (index + splitter.size() == value.length()) {
|
||||||
|
result.push_back("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (index + splitter.size() > value.length()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = value.substr(index + splitter.size(), value.length());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
88
src/utils/StringTools.h
Normal file
88
src/utils/StringTools.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* for WiiXplorer 2010
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef __STRING_TOOLS_H
|
||||||
|
#define __STRING_TOOLS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <wut_types.h>
|
||||||
|
|
||||||
|
class StringTools {
|
||||||
|
public:
|
||||||
|
static BOOL EndsWith(const std::string &a, const std::string &b);
|
||||||
|
|
||||||
|
static const char *byte_to_binary(int32_t x);
|
||||||
|
|
||||||
|
static std::string removeCharFromString(std::string &input, char toBeRemoved);
|
||||||
|
|
||||||
|
static const char *fmt(const char *format, ...);
|
||||||
|
|
||||||
|
static const wchar_t *wfmt(const char *format, ...);
|
||||||
|
|
||||||
|
static int32_t strprintf(std::string &str, const char *format, ...);
|
||||||
|
|
||||||
|
static std::string strfmt(const char *format, ...);
|
||||||
|
|
||||||
|
static BOOL char2wchar_t(const char *src, wchar_t *dest);
|
||||||
|
|
||||||
|
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||||
|
|
||||||
|
static int32_t strextcmp(const char *string, const char *extension, char seperator);
|
||||||
|
|
||||||
|
static const char *FullpathToFilename(const char *path) {
|
||||||
|
if (!path) return path;
|
||||||
|
|
||||||
|
const char *ptr = path;
|
||||||
|
const char *Filename = ptr;
|
||||||
|
|
||||||
|
while (*ptr != '\0') {
|
||||||
|
if (ptr[0] == '/' && ptr[1] != '\0')
|
||||||
|
Filename = ptr + 1;
|
||||||
|
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RemoveDoubleSlashs(std::string &str) {
|
||||||
|
uint32_t length = str.size();
|
||||||
|
|
||||||
|
//! clear path of double slashes
|
||||||
|
for (uint32_t i = 1; i < length; ++i) {
|
||||||
|
if (str[i - 1] == '/' && str[i] == '/') {
|
||||||
|
str.erase(i, 1);
|
||||||
|
i--;
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __STRING_TOOLS_H */
|
||||||
|
|
27
src/utils/logger.h
Normal file
27
src/utils/logger.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
|
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||||
|
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||||
|
|
||||||
|
#define OSFATAL_FUNCTION_LINE(FMT, ARGS...)do { \
|
||||||
|
OSFatal_printf("[%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
|
||||||
|
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \
|
||||||
|
WHBLogWritef("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user