mirror of
https://github.com/wiiu-env/sdcafiine_plugin.git
synced 2024-11-21 19:09:16 +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