mirror of
https://github.com/wiiu-env/WUHBUtilsModule.git
synced 2024-11-22 03:19:19 +01:00
first commit
This commit is contained in:
commit
55b2c3da32
67
.clang-format
Normal file
67
.clang-format
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# Generated from CLion C/C++ Code Style settings
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: Consecutive
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||||
|
AlignOperands: Align
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
ColumnLimit: 0
|
||||||
|
CompactNamespaces: false
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
65
.github/workflows/ci.yml
vendored
Normal file
65
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
name: CI-Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: clang-format
|
||||||
|
run: |
|
||||||
|
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src
|
||||||
|
build-binary:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
needs: clang-format
|
||||||
|
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: "*.wms"
|
||||||
|
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
|
||||||
|
- name: zip artifact
|
||||||
|
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.wms
|
||||||
|
- 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/zip
|
25
.github/workflows/pr.yml
vendored
Normal file
25
.github/workflows/pr.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: CI-PR
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: clang-format
|
||||||
|
run: |
|
||||||
|
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src
|
||||||
|
build-binary:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
needs: clang-format
|
||||||
|
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: "*.wms"
|
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
*.cbp
|
||||||
|
*.elf
|
||||||
|
*.layout
|
||||||
|
*.rpx
|
||||||
|
build/
|
||||||
|
*.save-failed
|
||||||
|
.idea/
|
||||||
|
cmake-build-debug/
|
||||||
|
CMakeLists.txt
|
||||||
|
*.wms
|
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM wiiuenv/devkitppc:20220303
|
||||||
|
|
||||||
|
COPY --from=wiiuenv/wiiumodulesystem:20220204 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/libromfs_wiiu:20220305 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/libwuhbutils:20220415 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
|
WORKDIR project
|
155
Makefile
Normal file
155
Makefile
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
|
||||||
|
include $(DEVKITPRO)/wums/share/wums_rules
|
||||||
|
|
||||||
|
WUMS_ROOT := $(DEVKITPRO)/wums
|
||||||
|
WUT_ROOT := $(DEVKITPRO)/wut
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# 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 := WUHBUtilsModule
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := src \
|
||||||
|
src/utils
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := src
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
CFLAGS := -Wall -Wextra -Os -ffunction-sections\
|
||||||
|
$(MACHDEP)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUMSSPECS)
|
||||||
|
|
||||||
|
ifeq ($(DEBUG),1)
|
||||||
|
CXXFLAGS += -DDEBUG -g
|
||||||
|
CFLAGS += -DDEBUG -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIBS := -lwums -lwut -lromfs -lz
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level
|
||||||
|
# containing include and lib
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr $(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)))
|
||||||
|
DEFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.def)))
|
||||||
|
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 := $(DEFFILES:.def=.o) $(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).wms $(TARGET).elf
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).wms
|
||||||
|
|
||||||
|
$(OUTPUT).wms : $(OUTPUT).elf
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
%.o: %.def
|
||||||
|
$(SILENTMSG) $(notdir $<)
|
||||||
|
$(SILENTCMD)rplimportgen $< $*.s $*.ld $(ERROR_FILTER)
|
||||||
|
$(SILENTCMD)$(CC) -x assembler-with-cpp $(ASFLAGS) -c $*.s -o $@ $(ERROR_FILTER)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%_bin.h %.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.o: %.s
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#-------------------------------------------------------------------------------
|
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[![CI-Release](https://github.com/wiiu-env/WUHBUtilsModule/actions/workflows/ci.yml/badge.svg)](https://github.com/wiiu-env/WUHBUtilsModule/actions/workflows/ci.yml)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
(`[ENVIRONMENT]` is a placeholder for the actual environment name.)
|
||||||
|
|
||||||
|
1. Copy the file `WUHBUtils.wms` into `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||||
|
2. Requires the [WUMSLoader](https://github.com/wiiu-env/WUMSLoader) in `sd:/wiiu/environments/[ENVIRONMENT]/modules/setup`.
|
||||||
|
3. Use [libwuhbutils](https://github.com/wiiu-env/libwuhbutils).
|
||||||
|
|
||||||
|
## 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 wuhbutils-builder
|
||||||
|
|
||||||
|
# make
|
||||||
|
docker run -it --rm -v ${PWD}:/project wuhbutils-builder make
|
||||||
|
|
||||||
|
# make clean
|
||||||
|
docker run -it --rm -v ${PWD}:/project wuhbutils-builder make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
## Format the code via docker
|
||||||
|
|
||||||
|
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src -i`
|
79
src/FileUtils.cpp
Normal file
79
src/FileUtils.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include "FileUtils.h"
|
||||||
|
#include "export.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <wuhb_utils/utils.h>
|
||||||
|
|
||||||
|
int32_t CheckFile(const char *filepath) {
|
||||||
|
if (!filepath) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat filestat {};
|
||||||
|
|
||||||
|
char dirnoslash[strlen(filepath) + 2];
|
||||||
|
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
|
||||||
|
|
||||||
|
while (dirnoslash[strlen(dirnoslash) - 1] == '/') {
|
||||||
|
dirnoslash[strlen(dirnoslash) - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
char *notRoot = strrchr(dirnoslash, '/');
|
||||||
|
if (!notRoot) {
|
||||||
|
strcat(dirnoslash, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(dirnoslash, &filestat) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBRPXInfoResultCode getRPXInfoForPath(const std::string &path, BundleSource source, WUHBRPXInfo *outFileInfo) {
|
||||||
|
auto realSource = RomfsSource_FileDescriptor;
|
||||||
|
switch (source) {
|
||||||
|
case BundleSource_FileDescriptor:
|
||||||
|
realSource = RomfsSource_FileDescriptor;
|
||||||
|
break;
|
||||||
|
case BundleSource_FileDescriptor_CafeOS:
|
||||||
|
realSource = RomfsSource_FileDescriptor_CafeOS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (romfsMount("wuu_rpxinfo", path.c_str(), realSource) < 0) {
|
||||||
|
return WUHB_UTILS_RPX_INFO_MOUNT_FAILED;
|
||||||
|
}
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
|
||||||
|
if (!(dir = opendir("wuu_rpxinfo:/code/"))) {
|
||||||
|
romfsUnmount("wuu_rpxinfo");
|
||||||
|
return WUHB_UTILS_RPX_INFO_OPENDIR_FAILED;
|
||||||
|
}
|
||||||
|
bool found = false;
|
||||||
|
WUHBRPXInfoResultCode res;
|
||||||
|
while ((entry = readdir(dir)) != nullptr) {
|
||||||
|
if (std::string_view(entry->d_name).ends_with(".rpx")) {
|
||||||
|
romfs_fileInfo info;
|
||||||
|
if (romfsGetFileInfoPerPath("wuu_rpxinfo", (std::string("code/") + entry->d_name).c_str(), &info) >= 0) {
|
||||||
|
found = true;
|
||||||
|
res = WUHB_UTILS_RPX_INFO_SUCCESS;
|
||||||
|
outFileInfo->length = info.length;
|
||||||
|
outFileInfo->offset = info.offset;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to get info for %s", entry->d_name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
romfsUnmount("wuu_rpxinfo");
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return WUHB_UTILS_RPX_INFO_NO_RPX_FOUND;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
11
src/FileUtils.h
Normal file
11
src/FileUtils.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "export.h"
|
||||||
|
#include <coreinit/filesystem.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <romfs_dev.h>
|
||||||
|
#include <string>
|
||||||
|
#include <wuhb_utils/utils.h>
|
||||||
|
|
||||||
|
WUHBRPXInfoResultCode getRPXInfoForPath(const std::string &path, BundleSource source, WUHBRPXInfo *outFileInfo);
|
||||||
|
|
||||||
|
int32_t CheckFile(const char *filepath);
|
172
src/export.cpp
Normal file
172
src/export.cpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#include "FileUtils.h"
|
||||||
|
#include "utils/FileReader.h"
|
||||||
|
#include "utils/FileReaderCompressed.h"
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
#include <wuhb_utils/utils.h>
|
||||||
|
#include <wums/exports.h>
|
||||||
|
|
||||||
|
std::vector<FileReader *> openFiles;
|
||||||
|
std::map<std::string, std::string> mountedWUHB;
|
||||||
|
std::mutex mutex;
|
||||||
|
|
||||||
|
void WUHBUtils_CleanUp() {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
for (auto &file : openFiles) {
|
||||||
|
delete file;
|
||||||
|
}
|
||||||
|
openFiles.clear();
|
||||||
|
|
||||||
|
for (const auto &[name, path] : mountedWUHB) {
|
||||||
|
romfsUnmount(name.c_str());
|
||||||
|
}
|
||||||
|
mountedWUHB.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBUtilsApiErrorType WUU_MountBundle(const char *name, const char *path, BundleSource source, int32_t *outRes) {
|
||||||
|
if (!name || !path || (source != BundleSource_FileDescriptor && source != BundleSource_FileDescriptor_CafeOS)) {
|
||||||
|
return WUHB_UTILS_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
for (const auto &[key, value] : mountedWUHB) {
|
||||||
|
if (key == name) {
|
||||||
|
if (value == path) {
|
||||||
|
*outRes = 0;
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
return WUHB_UTILS_API_ERROR_MOUNT_NAME_TAKEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = romfsMount(name, path, (RomfsSource) source);
|
||||||
|
if (res == 0) {
|
||||||
|
mountedWUHB[name] = path;
|
||||||
|
*outRes = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBUtilsApiErrorType WUU_UnmountBundle(const char *name, int32_t *outRes) {
|
||||||
|
if (!name) {
|
||||||
|
return WUHB_UTILS_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
if (mountedWUHB.count(name) > 0) {
|
||||||
|
auto res = romfsUnmount(name);
|
||||||
|
if (outRes) {
|
||||||
|
*outRes = res;
|
||||||
|
}
|
||||||
|
mountedWUHB.erase(name);
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
return WUHB_UTILS_API_ERROR_MOUNT_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBUtilsApiErrorType WUU_FileOpen(const char *name, uint32_t *outHandle) {
|
||||||
|
if (!outHandle || !name) {
|
||||||
|
return WUHB_UTILS_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
FileReader *reader;
|
||||||
|
std::string path = std::string(name);
|
||||||
|
std::string pathGZ = path + ".gz";
|
||||||
|
|
||||||
|
if (CheckFile(path.c_str())) {
|
||||||
|
reader = new (std::nothrow) FileReader(path);
|
||||||
|
} else if (CheckFile(pathGZ.c_str())) {
|
||||||
|
reader = new (std::nothrow) FileReaderCompressed(pathGZ);
|
||||||
|
} else {
|
||||||
|
return WUHB_UTILS_API_ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
if (reader == nullptr) {
|
||||||
|
return WUHB_UTILS_API_ERROR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
openFiles.push_back(reader);
|
||||||
|
*outHandle = (uint32_t) reader;
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBUtilsApiErrorType WUU_FileRead(uint32_t handle, uint8_t *buffer, uint32_t size, int32_t *outRes) {
|
||||||
|
if (!buffer | !outRes) {
|
||||||
|
return WUHB_UTILS_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
auto found = false;
|
||||||
|
FileReader *reader;
|
||||||
|
for (auto &cur : openFiles) {
|
||||||
|
if ((uint32_t) cur == handle) {
|
||||||
|
found = true;
|
||||||
|
reader = cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
return WUHB_UTILS_API_ERROR_FILE_HANDLE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outRes = (int32_t) reader->read(buffer, size);
|
||||||
|
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBUtilsApiErrorType WUU_FileClose(uint32_t handle) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
auto count = 0;
|
||||||
|
auto found = false;
|
||||||
|
FileReader *reader;
|
||||||
|
for (auto &cur : openFiles) {
|
||||||
|
if ((uint32_t) cur == handle) {
|
||||||
|
found = true;
|
||||||
|
reader = cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
return WUHB_UTILS_API_ERROR_FILE_HANDLE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
openFiles.erase(openFiles.begin() + count);
|
||||||
|
delete reader;
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBUtilsApiErrorType WUU_FileExists(const char *name, int32_t *outRes) {
|
||||||
|
if (!outRes || !name) {
|
||||||
|
return WUHB_UTILS_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
std::string checkgz = std::string(name) + ".gz";
|
||||||
|
*outRes = CheckFile(name) || CheckFile(checkgz.c_str());
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUHBUtilsApiErrorType WUU_GetRPXInfo(const char *path, BundleSource source, WUHBRPXInfo *outFileInfo) {
|
||||||
|
if (!outFileInfo || !path || (source != BundleSource_FileDescriptor && source != BundleSource_FileDescriptor_CafeOS)) {
|
||||||
|
return WUHB_UTILS_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|
||||||
|
auto res = getRPXInfoForPath(path, source, outFileInfo);
|
||||||
|
|
||||||
|
if (res == WUHB_UTILS_RPX_INFO_MOUNT_FAILED) {
|
||||||
|
return WUHB_UTILS_API_ERROR_MOUNT_FAILED;
|
||||||
|
} else if (res == WUHB_UTILS_RPX_INFO_NO_RPX_FOUND || res == WUHB_UTILS_RPX_INFO_OPENDIR_FAILED) {
|
||||||
|
return WUHB_UTILS_API_ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WUHB_UTILS_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t WUU_GetVersion() {
|
||||||
|
return WUHB_UTILS_MODULE_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_MountBundle);
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_UnmountBundle);
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_FileOpen);
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_FileRead);
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_FileClose);
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_FileExists);
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_GetRPXInfo);
|
||||||
|
WUMS_EXPORT_FUNCTION(WUU_GetVersion);
|
10
src/export.h
Normal file
10
src/export.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum WUHBRPXInfoResultCode {
|
||||||
|
WUHB_UTILS_RPX_INFO_SUCCESS = 0,
|
||||||
|
WUHB_UTILS_RPX_INFO_MOUNT_FAILED = -1,
|
||||||
|
WUHB_UTILS_RPX_INFO_OPENDIR_FAILED = -2,
|
||||||
|
WUHB_UTILS_RPX_INFO_NO_RPX_FOUND = -3,
|
||||||
|
} WUHBRPXInfoResultCode;
|
||||||
|
|
||||||
|
void WUHBUtils_CleanUp();
|
16
src/main.cpp
Normal file
16
src/main.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include "export.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <wums.h>
|
||||||
|
|
||||||
|
WUMS_MODULE_EXPORT_NAME("homebrew_wuhb_utils");
|
||||||
|
|
||||||
|
WUMS_USE_WUT_DEVOPTAB();
|
||||||
|
|
||||||
|
WUMS_APPLICATION_STARTS() {
|
||||||
|
initLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
WUMS_APPLICATION_ENDS() {
|
||||||
|
WUHBUtils_CleanUp();
|
||||||
|
deinitLogging();
|
||||||
|
}
|
50
src/utils/FileReader.cpp
Normal file
50
src/utils/FileReader.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "FileReader.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
int64_t FileReader::read(uint8_t *buffer, uint32_t size) {
|
||||||
|
if (isReadFromBuffer) {
|
||||||
|
if (input_buffer == nullptr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uint32_t toRead = size;
|
||||||
|
if (toRead > input_size - input_pos) {
|
||||||
|
toRead = input_size - input_pos;
|
||||||
|
}
|
||||||
|
if (toRead == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(buffer, &input_buffer[input_pos], toRead);
|
||||||
|
input_pos += toRead;
|
||||||
|
return toRead;
|
||||||
|
} else if (isReadFromFile) {
|
||||||
|
int res = ::read(file_fd, buffer, size);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader::FileReader(std::string &path) {
|
||||||
|
int fd;
|
||||||
|
if ((fd = open(path.c_str(), O_RDONLY)) >= 0) {
|
||||||
|
this->isReadFromFile = true;
|
||||||
|
this->isReadFromBuffer = false;
|
||||||
|
this->file_fd = fd;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("## INFO ## Failed to open file %s", path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader::~FileReader() {
|
||||||
|
if (isReadFromFile) {
|
||||||
|
::close(this->file_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader::FileReader(uint8_t *buffer, uint32_t size) {
|
||||||
|
this->input_buffer = buffer;
|
||||||
|
this->input_size = size;
|
||||||
|
this->input_pos = 0;
|
||||||
|
this->isReadFromBuffer = true;
|
||||||
|
this->isReadFromFile = false;
|
||||||
|
}
|
28
src/utils/FileReader.h
Normal file
28
src/utils/FileReader.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
class FileReader {
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileReader(uint8_t *buffer, uint32_t size);
|
||||||
|
|
||||||
|
explicit FileReader(std::string &path);
|
||||||
|
|
||||||
|
virtual ~FileReader();
|
||||||
|
|
||||||
|
virtual int64_t read(uint8_t *buffer, uint32_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isReadFromBuffer = false;
|
||||||
|
uint8_t *input_buffer = nullptr;
|
||||||
|
uint32_t input_size = 0;
|
||||||
|
uint32_t input_pos = 0;
|
||||||
|
|
||||||
|
bool isReadFromFile = false;
|
||||||
|
int file_fd = 0;
|
||||||
|
};
|
89
src/utils/FileReaderCompressed.cpp
Normal file
89
src/utils/FileReaderCompressed.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "FileReaderCompressed.h"
|
||||||
|
|
||||||
|
int64_t FileReaderCompressed::read(uint8_t *buffer, uint32_t size) {
|
||||||
|
if (!initDone) {
|
||||||
|
return -11;
|
||||||
|
}
|
||||||
|
uint32_t startValue = this->strm.total_out;
|
||||||
|
uint32_t newSize = 0;
|
||||||
|
int ret;
|
||||||
|
do {
|
||||||
|
uint32_t nextOut = BUFFER_SIZE;
|
||||||
|
if (nextOut > size) {
|
||||||
|
nextOut = size;
|
||||||
|
}
|
||||||
|
if (this->strm.avail_in == 0) {
|
||||||
|
auto read_res = FileReader::read(this->zlib_in_buf, BUFFER_SIZE);
|
||||||
|
if (read_res <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->strm.avail_in = read_res;
|
||||||
|
this->strm.next_in = this->zlib_in_buf;
|
||||||
|
}
|
||||||
|
/* run inflate() on input until output buffer not full */
|
||||||
|
do {
|
||||||
|
if (nextOut > size - newSize) {
|
||||||
|
nextOut = size - newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->strm.avail_out = nextOut;
|
||||||
|
this->strm.next_out = buffer + newSize;
|
||||||
|
ret = inflate(&this->strm, Z_NO_FLUSH);
|
||||||
|
|
||||||
|
if (ret == Z_STREAM_ERROR) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Z_STREAM_ERROR");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case Z_NEED_DICT:
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Z_NEED_DICT");
|
||||||
|
ret = Z_DATA_ERROR;
|
||||||
|
[[fallthrough]]; /* and fall through */
|
||||||
|
case Z_DATA_ERROR:
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Z_MEM_ERROR or Z_DATA_ERROR");
|
||||||
|
(void) inflateEnd(&this->strm);
|
||||||
|
return ret;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSize = this->strm.total_out - startValue;
|
||||||
|
if (newSize == size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nextOut = BUFFER_SIZE;
|
||||||
|
if (newSize + nextOut >= (size)) {
|
||||||
|
nextOut = (size) -newSize;
|
||||||
|
}
|
||||||
|
} while (this->strm.avail_out == 0 && newSize < (size));
|
||||||
|
|
||||||
|
/* done when inflate() says it's done */
|
||||||
|
} while (ret != Z_STREAM_END && newSize < size);
|
||||||
|
|
||||||
|
return newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReaderCompressed::FileReaderCompressed(std::string &file) : FileReader(file) {
|
||||||
|
this->initCompressedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReaderCompressed::initCompressedData() {
|
||||||
|
/* allocate inflate state */
|
||||||
|
this->strm.zalloc = Z_NULL;
|
||||||
|
this->strm.zfree = Z_NULL;
|
||||||
|
this->strm.opaque = Z_NULL;
|
||||||
|
this->strm.avail_in = 0;
|
||||||
|
this->strm.next_in = Z_NULL;
|
||||||
|
int ret = inflateInit2(&this->strm, MAX_WBITS | 16); //gzip
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("inflateInit2 failed: %d", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] FileReaderCompressed::FileReaderCompressed(uint8_t *buffer, uint32_t size) : FileReader(buffer, size) {
|
||||||
|
this->initCompressedData();
|
||||||
|
}
|
25
src/utils/FileReaderCompressed.h
Normal file
25
src/utils/FileReaderCompressed.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "FileReader.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 0x20000
|
||||||
|
|
||||||
|
class FileReaderCompressed : public FileReader {
|
||||||
|
public:
|
||||||
|
[[maybe_unused]] FileReaderCompressed(uint8_t *buffer, uint32_t size);
|
||||||
|
|
||||||
|
explicit FileReaderCompressed(std::string &file);
|
||||||
|
|
||||||
|
~FileReaderCompressed() override = default;
|
||||||
|
|
||||||
|
int64_t read(uint8_t *buffer, uint32_t size) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool initDone = false;
|
||||||
|
alignas(0x40) uint8_t zlib_in_buf[BUFFER_SIZE]{};
|
||||||
|
z_stream strm{};
|
||||||
|
|
||||||
|
void initCompressedData();
|
||||||
|
};
|
36
src/utils/logger.c
Normal file
36
src/utils/logger.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifdef DEBUG
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <whb/log_cafe.h>
|
||||||
|
#include <whb/log_module.h>
|
||||||
|
#include <whb/log_udp.h>
|
||||||
|
|
||||||
|
uint32_t moduleLogInit = false;
|
||||||
|
uint32_t cafeLogInit = false;
|
||||||
|
uint32_t udpLogInit = false;
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
void initLogging() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!(moduleLogInit = WHBLogModuleInit())) {
|
||||||
|
cafeLogInit = WHBLogCafeInit();
|
||||||
|
udpLogInit = WHBLogUdpInit();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
void deinitLogging() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (moduleLogInit) {
|
||||||
|
WHBLogModuleDeinit();
|
||||||
|
moduleLogInit = false;
|
||||||
|
}
|
||||||
|
if (cafeLogInit) {
|
||||||
|
WHBLogCafeDeinit();
|
||||||
|
cafeLogInit = false;
|
||||||
|
}
|
||||||
|
if (udpLogInit) {
|
||||||
|
WHBLogUdpDeinit();
|
||||||
|
udpLogInit = false;
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
58
src/utils/logger.h
Normal file
58
src/utils/logger.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <coreinit/debug.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||||
|
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||||
|
|
||||||
|
// #define VERBOSE_DEBUG
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
#ifdef VERBOSE_DEBUG
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) \
|
||||||
|
do { \
|
||||||
|
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) \
|
||||||
|
do { \
|
||||||
|
OSReport("## ERROR ## [%23s]%30s@L%04d: ##ERROR## " FMT "\n", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void initLogging();
|
||||||
|
|
||||||
|
void deinitLogging();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user