First commit

This commit is contained in:
Maschell 2019-11-24 14:35:38 +01:00
commit 9ba9e5ca1b
32 changed files with 3931 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
build/*
*.mod
sysapp.layout
sysapp.cbp
sysapp.cscope_file_list

272
Makefile Normal file
View File

@ -0,0 +1,272 @@
# You probably never need to adjust this Makefile.
# All changes can be done in the makefile.mk
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
endif
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPRO")
endif
export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH)
export PORTLIBS := $(DEVKITPRO)/portlibs/ppc
export WUPSDIR := $(DEVKITPRO)/wups
export GCC_VER := $(shell $(DEVKITPPC)/bin/powerpc-eabi-gcc -dumpversion)
PREFIX := powerpc-eabi-
export AS := $(PREFIX)as
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export LD := $(PREFIX)ld
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
#---------------------------------------------------------------------------------
# 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
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
ifeq ($(notdir $(CURDIR)),$(BUILD))
include ../makefile.mk
else
include makefile.mk
endif
include $(WUPSDIR)/plugin_makefile.mk
#MAP ?= $(TARGET:.mod=.map)
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
MACHDEP = -DESPRESSO -mcpu=750 -meabi -mhard-float
# -Os: optimise size
# -Wall: generate lots of warnings
# -D__wiiu__: define the symbol __wiiu__ (used in some headers)
# -mcpu=750: enable processor specific compilation
# -meabi: enable eabi specific compilation
# -mhard-float: enable hardware floating point instructions
# -nostartfiles: Do not use the standard system startup files when linking
# -ffunction-sections: split up functions so linker can garbage collect
# -fdata-sections: split up data so linker can garbage collect
COMMON_CFLAGS := -O0 -Wall $(MACHDEP) -meabi -ffunction-sections -fdata-sections -Wl,-q $(COMMON_CFLAGS)
CFLAGS += -D__WIIU__ -D__WUT__
# -x c: compile as c code
# -std=c11: use the c11 standard
CFLAGS := $(COMMON_CFLAGS) -x c -std=gnu11 $(CFLAGS)
# -x c++: compile as c++ code
# -std=gnu++11: use the c++11 standard
CXXFLAGS := $(COMMON_CFLAGS) -x c++ -std=gnu++11 $(CXXFLAGS)
#---------------------------------------------------------------------------------
# any extra ld flags
#--------------------------------------------------------------------------------
# --gc-sections: remove unneeded symbols
# -Map: generate a map file
LDFLAGS += $(ARCH) -Wl,-Map,$(notdir $@).map,--gc-sections,-wrap,__gxx_personality_v0
#---------------------------------------------------------------------------------
Q := @
MAKEFLAGS += --no-print-directory
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS +=
#
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS +=
#---------------------------------------------------------------------------------
# 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 PROJECTDIR := $(CURDIR)
export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
TTFFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.ttf)))
PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
export REAL_LD := $(CC)
else
export REAL_LD := $(CXX)
endif
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
$(sFILES:.s=.o) $(SFILES:.S=.o) \
$(PNGFILES:.png=.png.o) $(addsuffix .o,$(BINFILES))
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE_FULL += $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(EXTERNAL_INCLUDE)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS_FULL += $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
$(EXTERNAL_LIBPATHS)
export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean install
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).mod $(OUTPUT)
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
THIS_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
###############################################################################
# Rule to make everything.
PHONY += all
all : $(OUTPUT)
###############################################################################
# Special build rules
# Rule to make the module file.
$(OUTPUT) : $(OFILES)
@echo "linking ... " $@
@$(REAL_LD) $(OFILES) $(LDFLAGS) $(LIBS) $(LIBPATHS_FULL) -o $@
###############################################################################
# Standard build rules
#---------------------------------------------------------------------------------
%.a:
#---------------------------------------------------------------------------------
@echo $(notdir $@)
@rm -f $@
@$(AR) -rc $@ $^
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<)
@$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.png.o : %.png
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.jpg.o : %.jpg
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.ttf.o : %.ttf
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.wav.o : %.wav
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.mp3.o : %.mp3
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.ogg.o : %.ogg
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
###############################################################################
# Assembly listing rules
# Rule to make assembly listing.
PHONY += list
list : $(LIST)
# Rule to make the listing file.
%.list : $(TARGET)
$(LOG)
-$Qmkdir -p $(dir $@)
$Q$(OBJDUMP) -d $< > $@
###############################################################################
# Clean rule
# Rule to clean files.
PHONY += clean
clean :
$Qrm -rf $(wildcard $(BUILD) $(BIN))
###############################################################################
# Phony targets
.PHONY : $(PHONY)
-include $(DEPENDS)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------

50
makefile.mk Normal file
View File

@ -0,0 +1,50 @@
# Compiling the projects with libutils logging code?
DO_LOGGING := 1
# Target filename
TARGET := $(notdir $(CURDIR)).mod
# Source directories
SOURCES := src src/utils src/fs src/plugin
# Data directories
DATA :=
# Include directories
INCLUDES := src
#---------------------------------------------------------------------------------
# options for code generation and linking
#---------------------------------------------------------------------------------
# Extra C AND C++ compiler flags
COMMON_CFLAGS :=
# Extra C compiler flags
CFLAGS :=
# Extra C++ compiler flags
CXXFLAGS :=
# Extra linking flags for all linking steps
LDFLAGS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(WUPSDIR) $(WUT_ROOT) $(PORTLIBS)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lwups -lwut
#---------------------------------------------------------------------------------
# Will be added to the final lib paths
# example:
# -L$C:/library1/lib
#---------------------------------------------------------------------------------
EXTERNAL_LIBPATHS :=
#---------------------------------------------------------------------------------
# Will be added to the final include paths
# -IC:/library1/include
#---------------------------------------------------------------------------------
EXTERNAL_INCLUDE :=

175
src/fs/CFile.cpp Normal file
View File

@ -0,0 +1,175 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <fs/CFile.hpp>
CFile::CFile() {
iFd = -1;
mem_file = NULL;
filesize = 0;
pos = 0;
}
CFile::CFile(const std::string & filepath, eOpenTypes mode) {
iFd = -1;
this->open(filepath, mode);
}
CFile::CFile(const uint8_t * mem, int32_t size) {
iFd = -1;
this->open(mem, size);
}
CFile::~CFile() {
this->close();
}
int32_t CFile::open(const std::string & filepath, eOpenTypes mode) {
this->close();
int32_t openMode = 0;
// This depend on the devoptab implementation.
// see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference
switch(mode) {
default:
case ReadOnly: // file must exist
openMode = O_RDONLY;
break;
case WriteOnly: // file will be created / zerod
openMode = O_TRUNC | O_CREAT | O_WRONLY;
break;
case ReadWrite: // file must exist
openMode = O_RDWR;
break;
case Append: // append to file, file will be created if missing. write only
openMode = O_CREAT | O_APPEND | O_WRONLY;
break;
}
//! Using fopen works only on the first launch as expected
//! on the second launch it causes issues because we don't overwrite
//! the .data sections which is needed for a normal application to re-init
//! this will be added with launching as RPX
iFd = ::open(filepath.c_str(), openMode);
if(iFd < 0)
return iFd;
filesize = ::lseek(iFd, 0, SEEK_END);
::lseek(iFd, 0, SEEK_SET);
return 0;
}
int32_t CFile::open(const uint8_t * mem, int32_t size) {
this->close();
mem_file = mem;
filesize = size;
return 0;
}
void CFile::close() {
if(iFd >= 0)
::close(iFd);
iFd = -1;
mem_file = NULL;
filesize = 0;
pos = 0;
}
int32_t CFile::read(uint8_t * ptr, size_t size) {
if(iFd >= 0) {
int32_t ret = ::read(iFd, ptr,size);
if(ret > 0)
pos += ret;
return ret;
}
int32_t readsize = size;
if(readsize > (int64_t) (filesize-pos))
readsize = filesize-pos;
if(readsize <= 0)
return readsize;
if(mem_file != NULL) {
memcpy(ptr, mem_file+pos, readsize);
pos += readsize;
return readsize;
}
return -1;
}
int32_t CFile::write(const uint8_t * ptr, size_t size) {
if(iFd >= 0) {
size_t done = 0;
while(done < size) {
int32_t ret = ::write(iFd, ptr, size - done);
if(ret <= 0)
return ret;
ptr += ret;
done += ret;
pos += ret;
}
return done;
}
return -1;
}
int32_t CFile::seek(long int offset, int32_t origin) {
int32_t ret = 0;
int64_t newPos = pos;
if(origin == SEEK_SET) {
newPos = offset;
} else if(origin == SEEK_CUR) {
newPos += offset;
} else if(origin == SEEK_END) {
newPos = filesize+offset;
}
if(newPos < 0) {
pos = 0;
} else {
pos = newPos;
}
if(iFd >= 0)
ret = ::lseek(iFd, pos, SEEK_SET);
if(mem_file != NULL) {
if(pos > filesize) {
pos = filesize;
}
}
return ret;
}
int32_t CFile::fwrite(const char *format, ...) {
char tmp[512];
tmp[0] = 0;
int32_t result = -1;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
result = this->write((uint8_t *)tmp, strlen(tmp));
}
va_end(va);
return result;
}

61
src/fs/CFile.hpp Normal file
View File

@ -0,0 +1,61 @@
#ifndef CFILE_HPP_
#define CFILE_HPP_
#include <stdio.h>
#include <string>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <wut_types.h>
class CFile {
public:
enum eOpenTypes {
ReadOnly,
WriteOnly,
ReadWrite,
Append
};
CFile();
CFile(const std::string & filepath, eOpenTypes mode);
CFile(const uint8_t * memory, int32_t memsize);
virtual ~CFile();
int32_t open(const std::string & filepath, eOpenTypes mode);
int32_t open(const uint8_t * memory, int32_t memsize);
BOOL isOpen() const {
if(iFd >= 0)
return true;
if(mem_file)
return true;
return false;
}
void close();
int32_t read(uint8_t * ptr, size_t size);
int32_t write(const uint8_t * ptr, size_t size);
int32_t fwrite(const char *format, ...);
int32_t seek(long int offset, int32_t origin);
uint64_t tell() {
return pos;
};
uint64_t size() {
return filesize;
};
void rewind() {
this->seek(0, SEEK_SET);
};
protected:
int32_t iFd;
const uint8_t * mem_file;
uint64_t filesize;
uint64_t pos;
};
#endif

213
src/fs/DirList.cpp Normal file
View 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;
}

103
src/fs/DirList.h Normal file
View File

@ -0,0 +1,103 @@
/****************************************************************************
* 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

142
src/fs/FSUtils.cpp Normal file
View File

@ -0,0 +1,142 @@
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <fs/FSUtils.h>
#include <fs/CFile.hpp>
#include <utils/logger.h>
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
//! always initialze input
*inbuffer = NULL;
if(size)
*size = 0;
int32_t iFd = open(filepath, O_RDONLY);
if (iFd < 0)
return -1;
uint32_t filesize = lseek(iFd, 0, SEEK_END);
lseek(iFd, 0, SEEK_SET);
uint8_t *buffer = (uint8_t *) malloc(filesize);
if (buffer == NULL) {
close(iFd);
return -2;
}
uint32_t blocksize = 0x4000;
uint32_t done = 0;
int32_t readBytes = 0;
while(done < filesize) {
if(done + blocksize > filesize) {
blocksize = filesize - done;
}
readBytes = read(iFd, buffer + done, blocksize);
if(readBytes <= 0)
break;
done += readBytes;
}
close(iFd);
if (done != filesize) {
free(buffer);
buffer = NULL;
return -3;
}
*inbuffer = buffer;
//! sign is optional input
if(size) {
*size = filesize;
}
return filesize;
}
int32_t FSUtils::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;
}
int32_t FSUtils::CreateSubfolder(const char * fullpath) {
if(!fullpath)
return 0;
int32_t result = 0;
char dirnoslash[strlen(fullpath)+1];
strcpy(dirnoslash, fullpath);
int32_t pos = strlen(dirnoslash)-1;
while(dirnoslash[pos] == '/') {
dirnoslash[pos] = '\0';
pos--;
}
if(CheckFile(dirnoslash)) {
return 1;
} else {
char parentpath[strlen(dirnoslash)+2];
strcpy(parentpath, dirnoslash);
char * ptr = strrchr(parentpath, '/');
if(!ptr) {
//!Device root directory (must be with '/')
strcat(parentpath, "/");
struct stat filestat;
if (stat(parentpath, &filestat) == 0)
return 1;
return 0;
}
ptr++;
ptr[0] = '\0';
result = CreateSubfolder(parentpath);
}
if(!result)
return 0;
if (mkdir(dirnoslash, 0777) == -1) {
return 0;
}
return 1;
}
BOOL FSUtils::saveBufferToFile(const char * path, void * buffer, uint32_t size) {
CFile file(path, CFile::WriteOnly);
if (!file.isOpen()) {
DEBUG_FUNCTION_LINE("Failed to open %s\n",path);
return false;
}
file.write((const uint8_t*) buffer,size);
file.close();
return true;
}

16
src/fs/FSUtils.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __FS_UTILS_H_
#define __FS_UTILS_H_
#include <wut_types.h>
class FSUtils {
public:
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
//! todo: C++ class
static int32_t CreateSubfolder(const char * fullpath);
static int32_t CheckFile(const char * filepath);
static BOOL saveBufferToFile(const char * path, void * buffer, uint32_t size);
};
#endif // __FS_UTILS_H_

39
src/main.cpp Normal file
View File

@ -0,0 +1,39 @@
#include <wups.h>
#include "utils/TcpReceiver.h"
#include <whb/libmanager.h>
WUPS_PLUGIN_NAME("Wiiload");
WUPS_PLUGIN_DESCRIPTION("Wiiload Server");
WUPS_PLUGIN_VERSION("0.1");
WUPS_PLUGIN_AUTHOR("Maschell");
WUPS_PLUGIN_LICENSE("GPL");
WUPS_USE_WUT_CRT()
TcpReceiver * thread = NULL;
/* Entry point */
ON_APPLICATION_START(args) {
WHBInitializeSocketLibrary();
log_init();
DEBUG_FUNCTION_LINE("Started wiiload thread\n");
thread = new TcpReceiver(4299);
}
void stopThread(){
if(thread != NULL){
delete thread;
thread = NULL;
}
}
ON_APPLICATION_END(){
DEBUG_FUNCTION_LINE("Kill thread\n");
stopThread();
DEBUG_FUNCTION_LINE("Unmount SD\n");
}

32
src/main.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef _MAIN_H_
#define _MAIN_H_
/* Main */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <nsysnet/socket.h>
#define MAXPATHLEN 256
#define WIIU_EAGAIN EWOULDBLOCK
#define ENODATA 1
#define EISCONN 3
#define EWOULDBLOCK 6
#define EALREADY 10
#define EAGAIN EWOULDBLOCK
#define EINVAL 11
#define ENOMEM 18
#define EINPROGRESS 22
#define wiiu_geterrno() (socketlasterr())
//! C wrapper for our C++ functions
int Menu_Main(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,117 @@
/* based on module.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018, Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _PLUGIN_INFORMATION_H_
#define _PLUGIN_INFORMATION_H_
#include <string>
#include <vector>
#include "utils/logger.h"
#include "utils/ipcclient.h"
class PluginInformation {
public:
PluginInformation(plugin_information_handle handle, const char * path, const char * name, const char * author) {
this->handle = handle;
this->path = path;
this->name = name;
this->author = author;
}
~PluginInformation() {
IPC_Delete_Plugin_Information(this->handle);
}
std::string getName() {
return this->name;
}
std::string getAuthor() {
return this->author;
}
std::string getVersion() {
return this->version;
}
std::string getLicense() {
return this->license;
}
std::string getBuildTimestamp() {
return this->buildtimestamp;
}
std::string getDescription() {
return this->description;
}
std::string getPath() {
return path;
}
size_t getSize() {
return this->size;
}
plugin_information_handle getHandle() {
return this->handle;
}
private:
void setVersion(const char * version) {
this->version = version;
}
void setLicense(const char * license) {
this->license = license;
}
void setBuildTimestamp(const char * buildtimestamp) {
this->buildtimestamp = buildtimestamp;
}
void setDescription(const char * description) {
this->description = description;
}
void setSize(size_t size) {
this->size = size;
}
plugin_information_handle handle;
std::string path;
std::string name;
std::string author;
std::string version;
std::string license;
std::string buildtimestamp;
std::string description;
size_t size = 0;
};
#endif

View File

@ -0,0 +1,121 @@
#include <string>
#include "PluginInformationUtils.h"
#include "utils/ipcclient.h"
std::vector<PluginInformation *> PluginInformationUtils::getPluginInformationByStruct(plugin_information_handle * handleList, uint32_t handleListSize) {
std::vector<PluginInformation *> result;
if(handleListSize > 0) {
DEBUG_FUNCTION_LINE("Getting details for handles\n");
plugin_information * informationList = NULL;
uint32_t informationListSize = 0;
uint32_t res = IPC_Get_Plugin_Information_Details(handleList, handleListSize, &informationList, &informationListSize);
if(res == 0) {
for(uint32_t i = 0; i<informationListSize; i++) {
DEBUG_FUNCTION_LINE("Adding %08X %s\n", informationList[i].handle, informationList[i].path);
result.push_back(new PluginInformation(informationList[i].handle,informationList[i].path,informationList[i].name,informationList[i].author));
}
} else {
DEBUG_FUNCTION_LINE("IPC_Get_Plugin_Information_Details failed\n");
}
if(informationList != NULL) {
free(informationList);
}
} else {
DEBUG_FUNCTION_LINE("List is empty.\n");
}
return result;
}
void PluginInformationUtils::clearPluginInformation(std::vector<PluginInformation *> pluginInformation) {
for(size_t i = 0; i < pluginInformation.size(); i++) {
PluginInformation * curPluginInformation = pluginInformation[i];
if(curPluginInformation != NULL) {
delete curPluginInformation;
}
}
}
std::vector<PluginInformation *> PluginInformationUtils::getPluginsByPath(std::string path) {
std::vector<PluginInformation *> result;
plugin_information_handle * handleList = NULL;
uint32_t handleListSize = 0;
uint32_t res = IPC_Get_Plugin_Information(path.c_str(), &handleList, &handleListSize);
if(res == 0) {
DEBUG_FUNCTION_LINE("SUCCESS reading plugins from %s. handleListSize %d, handlelist %08X \n",path, handleListSize, handleList);
result = getPluginInformationByStruct(handleList, handleListSize);
}
if(handleList != NULL) {
free(handleList);
}
return result;
}
PluginInformation * PluginInformationUtils::loadPluginInformation(std::string path) {
std::vector<PluginInformation *> result;
plugin_information_handle handle = NULL;
uint32_t res = IPC_Get_Plugin_Information_For_Filepath(path.c_str(), &handle);
if(res == 0 && handle != NULL) {
DEBUG_FUNCTION_LINE("SUCCESS reading plugins from %s. handle %08X \n",path.c_str(), &handle);
result = getPluginInformationByStruct(&handle, 1);
}
if(result.size() > 0){
return result.at(0);
}
return NULL;
}
bool PluginInformationUtils::loadAndLinkPluginsOnRestart(std::vector<PluginInformation *> pluginInformation) {
uint32_t handleListSize = pluginInformation.size();
DEBUG_FUNCTION_LINE("Convert PluginInformation* to plugin_information_handle *\n");
plugin_information_handle * handleList = (plugin_information_handle *) malloc(handleListSize * sizeof(plugin_information_handle));
if(handleList == NULL) {
return false;
}
DEBUG_FUNCTION_LINE("Allocation was okay %08X\n", handleList);
uint32_t cur = 0;
for (std::vector<PluginInformation *>::iterator it = pluginInformation.begin() ; it != pluginInformation.end(); ++it) {
PluginInformation * curPlugin = *it;
handleList[cur] = curPlugin->getHandle();
DEBUG_FUNCTION_LINE("Adding to List %08X\n", handleList[cur]);
cur++;
}
bool result = false;
int32_t res = IPC_Link_Plugin_Information_On_Restart(handleList, handleListSize);
if(res >= 0) {
DEBUG_FUNCTION_LINE("result was %d\n", res);
result = true;
}
free(handleList);
return result;
}
std::vector<PluginInformation *> PluginInformationUtils::getPluginsLoadedInMemory() {
std::vector<PluginInformation *> result;
plugin_information_handle * handleList = NULL;
uint32_t handleListSize = 0;
uint32_t res = IPC_Get_Plugin_Information_Loaded(&handleList, &handleListSize);
if(res == 0) {
result = getPluginInformationByStruct(handleList, handleListSize);
}
if(handleList != NULL) {
free(handleList);
}
return result;
}

View File

@ -0,0 +1,70 @@
/* based on module.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018,2019 Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _PLUGIN_INFORMATION_UTILS_H_
#define _PLUGIN_INFORMATION_UTILS_H_
#include <string>
#include <vector>
#include "PluginInformation.h"
#include "utils/logger.h"
#include "utils/ipcclient.h"
class PluginInformationUtils {
public:
static PluginInformation * loadPluginInformation(std::string path);
/**
\brief Parses the meta data of all plugins in the given directory.
\param path the path of the directory which should be scanned.
\return a list of PluginInformation objects, one for each valid plugin.
**/
static std::vector<PluginInformation *> getPluginsByPath(std::string path);
/**
\brief Gets plugin information from the global struct.
\return a list of MetaInformation objects for all plugins currently loaded and linked (relocated). Will only contain
plugin which are still on the sd card.
**/
static std::vector<PluginInformation *> getPluginsLoadedInMemory();
static void clearPluginInformation(std::vector<PluginInformation *> pluginInformation) ;
static bool loadAndLinkPluginsOnRestart(std::vector<PluginInformation *> pluginInformation);
static std::vector<PluginInformation *> getPluginInformationByStruct(plugin_information_handle * handleList, uint32_t handleListSize);
};
#endif

View File

@ -0,0 +1,60 @@
#include <string>
#include "PluginLoader.h"
#include "utils/ipcclient.h"
PluginLoader * PluginLoader::createInstance(uint32_t startAddress, uint32_t endAddress) {
plugin_loader_handle handle = IPC_Open_Plugin_Loader(startAddress, endAddress);
if(handle != 0) {
return new PluginLoader(handle, startAddress,endAddress);
}
return NULL;
}
void PluginLoader::destroyInstance(PluginLoader * loader) {
if(loader != NULL) {
delete loader;
}
}
PluginLoader::PluginLoader(plugin_information_handle handle,uint32_t startAddress, uint32_t endAddress) {
this->handle = handle;
this->startAddress = startAddress;
this->endAddress = endAddress;
}
PluginLoader::~PluginLoader() {
IPC_Close_Plugin_Loader(this->handle);
}
bool PluginLoader::loadAndLinkPlugins(std::vector<PluginInformation *> pluginInformation) {
uint32_t handleListSize = pluginInformation.size();
DEBUG_FUNCTION_LINE("Convert PluginInformation* to plugin_information_handle *\n");
plugin_information_handle * handleList = (plugin_information_handle *) malloc(handleListSize * sizeof(plugin_information_handle));
if(handleList == NULL) {
return false;
}
DEBUG_FUNCTION_LINE("Allocation was okay %08X\n", handleList);
uint32_t cur = 0;
for (std::vector<PluginInformation *>::iterator it = pluginInformation.begin() ; it != pluginInformation.end(); ++it) {
PluginInformation * curPlugin = *it;
handleList[cur] = curPlugin->getHandle();
DEBUG_FUNCTION_LINE("Adding to List %08X\n", handleList[cur]);
cur++;
}
bool result = false;
int32_t res = IPC_Link_Plugin_Information(this->handle, handleList, handleListSize);
if(res >= 0) {
DEBUG_FUNCTION_LINE("result was %d\n", res);
result = true;
}
free(handleList);
return result;
}

78
src/plugin/PluginLoader.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef _PLUGIN_LOADER_H_
#define _PLUGIN_LOADER_H_
#include <vector>
#include "PluginInformation.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <utils/utils.h>
#ifdef __cplusplus
}
#endif
class PluginLoader {
public:
static PluginLoader * createInstance(uint32_t startAddress, uint32_t endAddress);
static void destroyInstance(PluginLoader * loader);
~PluginLoader();
/**
\brief Takes a list of plugins that should be linked (relocated) loaded into the memory.
The function that should be replaced will be replaced in the order of the given plugin list.
So two plugin will override the same function, the plugin first in this list will override the function first.
Also the hooks of the plugins will be called in the order their plugin where passed to this method.
\param A list of plugin that should be linked (relocated) an loaded into memory
\return Returns true if all plugins were linked successfully. Returns false if at least one plugin failed while linking.
**/
bool loadAndLinkPlugins(std::vector<PluginInformation *> pluginInformation);
/**
\brief Load
\param pluginInformation a PluginInformation object of the plugin that should be linked (relocated) and loaded.
**/
bool loadAndLinkPlugin(PluginInformation * pluginInformation);
/*
size_t getTotalSpace() {
return ((uint32_t) this->endAddress - (uint32_t) this->startAddress);
}
size_t getAvailableSpace() {
return ((uint32_t) this->endAddress - (uint32_t) this->currentStoreAddress);
}
size_t getUsedSpace() {
return getTotalSpace() - getAvailableSpace();
}
void resetPluginLoader() {
this->currentStoreAddress = ROUNDUP((uint32_t)startAddress, 0x10000);
}*/
private:
PluginLoader(plugin_loader_handle handle, uint32_t startAddress, uint32_t endAddress);
static std::vector<PluginInformation *> getPluginInformationByStruct(plugin_information_handle * handleList, uint32_t handleListSize);
plugin_loader_handle handle = 0;
uint32_t startAddress = 0;
uint32_t endAddress = 0;
uint32_t currentStoreAddress = 0;
};
#endif

69
src/utils/CMutex.h Normal file
View File

@ -0,0 +1,69 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _CMUTEX_H_
#define _CMUTEX_H_
#include <malloc.h>
#include <coreinit/mutex.h>
class CMutex
{
public:
CMutex() {
pMutex = (OSMutex*) malloc(sizeof(OSMutex));
if(!pMutex)
return;
OSInitMutex(pMutex);
}
virtual ~CMutex() {
if(pMutex)
free(pMutex);
}
void lock(void) {
if(pMutex)
OSLockMutex(pMutex);
}
void unlock(void) {
if(pMutex)
OSUnlockMutex(pMutex);
}
BOOL tryLock(void) {
if(!pMutex)
return false;
return (OSTryLockMutex(pMutex) != 0);
}
private:
OSMutex *pMutex;
};
class CMutexLock
{
public:
CMutexLock() {
mutex.lock();
}
virtual ~CMutexLock() {
mutex.unlock();
}
private:
CMutex mutex;
};
#endif // _CMUTEX_H_

134
src/utils/CThread.h Normal file
View File

@ -0,0 +1,134 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef CTHREAD_H_
#define CTHREAD_H_
#include <malloc.h>
#include <unistd.h>
#include <coreinit/systeminfo.h>
#include <coreinit/thread.h>
#include "utils/logger.h"
class CThread {
public:
typedef void (* Callback)(CThread *thread, void *arg);
//! constructor
CThread(int32_t iAttr, int32_t iPriority = 16, int32_t iStackSize = 0x8000, CThread::Callback callback = NULL, void *callbackArg = NULL)
: pThread(NULL)
, pThreadStack(NULL)
, pCallback(callback)
, pCallbackArg(callbackArg) {
//! save attribute assignment
iAttributes = iAttr;
//! allocate the thread
pThread = (OSThread*)memalign(8, sizeof(OSThread));
//! allocate the stack
pThreadStack = (uint8_t *) memalign(0x20, iStackSize);
//! create the thread
if(pThread && pThreadStack)
OSCreateThread(pThread, &CThread::threadCallback, 1, (char*)this, pThreadStack+iStackSize, iStackSize, iPriority, iAttributes);
}
//! destructor
virtual ~CThread() {
shutdownThread();
DEBUG_FUNCTION_LINE("END\n");
}
static CThread *create(CThread::Callback callback, void *callbackArg, int32_t iAttr = eAttributeNone, int32_t iPriority = 16, int32_t iStackSize = 0x8000) {
return ( new CThread(iAttr, iPriority, iStackSize, callback, callbackArg) );
}
//! Get thread ID
virtual void* getThread() const {
return pThread;
}
//! Thread entry function
virtual void executeThread(void) {
if(pCallback)
pCallback(this, pCallbackArg);
}
//! Suspend thread
virtual void suspendThread(void) {
if(isThreadSuspended()) return;
if(pThread) OSSuspendThread(pThread);
}
//! Resume thread
virtual void resumeThread(void) {
if(!isThreadSuspended()) return;
if(pThread) OSResumeThread(pThread);
}
//! Set thread priority
virtual void setThreadPriority(int prio) {
if(pThread) OSSetThreadPriority(pThread, prio);
}
//! Check if thread is suspended
virtual BOOL isThreadSuspended(void) const {
if(pThread) return OSIsThreadSuspended(pThread);
return false;
}
//! Check if thread is terminated
virtual BOOL isThreadTerminated(void) const {
if(pThread) return OSIsThreadTerminated(pThread);
return false;
}
//! Check if thread is running
virtual BOOL isThreadRunning(void) const {
return !isThreadSuspended() && !isThreadRunning();
}
//! Shutdown thread
virtual void shutdownThread(void) {
//! wait for thread to finish
if(pThread && !(iAttributes & eAttributeDetach)) {
if(isThreadSuspended())
resumeThread();
OSJoinThread(pThread, NULL);
}
//! free the thread stack buffer
if(pThreadStack)
free(pThreadStack);
if(pThread)
free(pThread);
pThread = NULL;
pThreadStack = NULL;
}
//! Thread attributes
enum eCThreadAttributes {
eAttributeNone = 0x07,
eAttributeAffCore0 = 0x01,
eAttributeAffCore1 = 0x02,
eAttributeAffCore2 = 0x04,
eAttributeDetach = 0x08,
eAttributePinnedAff = 0x10
};
private:
static int threadCallback(int argc, const char **argv) {
//! After call to start() continue with the internal function
((CThread *) argv)->executeThread();
return 0;
}
int iAttributes;
OSThread *pThread;
uint8_t *pThreadStack;
Callback pCallback;
void *pCallbackArg;
};
#endif

210
src/utils/StringTools.cpp Normal file
View 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;
}

82
src/utils/StringTools.h Normal file
View File

@ -0,0 +1,82 @@
/***************************************************************************
* 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 */

336
src/utils/TcpReceiver.cpp Normal file
View File

@ -0,0 +1,336 @@
#include <algorithm>
#include <string>
#include <vector>
#include <string.h>
#include <zlib.h>
#include <libgen.h>
#include <sysapp/launch.h>
#include <coreinit/messagequeue.h>
#include <coreinit/ios.h>
#include "TcpReceiver.h"
#include "fs/CFile.hpp"
#include "fs/FSUtils.h"
#include "utils/logger.h"
#include "utils/StringTools.h"
#include "utils/net.h"
#include "utils/utils.h"
#include "plugin/PluginInformationUtils.h"
#define WUPS_TEMP_PLUGIN_PATH "fs:/vol/external01/wiiu/plugins/temp/"
#define WUPS_TEMP_PLUGIN_FILE "fs:/vol/external01/wiiu/plugins/temp/temp.mod"
#define RPX_TEMP_PATH "fs:/vol/external01/wiiu/apps/"
#define RPX_TEMP_FILE "fs:/vol/external01/wiiu/apps/temp.rpx"
#define RPX_TEMP_FILE_EX "wiiu/apps/temp.rpx"
extern "C"{
uint64_t _SYSGetSystemApplicationTitleId(int32_t);
void _SYSLaunchTitleWithStdArgsInNoSplash(uint64_t, uint32_t);
}
TcpReceiver::TcpReceiver(int32_t port)
: CThread(CThread::eAttributeAffCore0)
, exitRequested(false)
, serverPort(port)
, serverSocket(-1) {
resumeThread();
}
TcpReceiver::~TcpReceiver() {
exitRequested = true;
if(serverSocket >= 0) {
shutdown(serverSocket, SHUT_RDWR);
}
}
#define wiiu_geterrno() (socketlasterr())
void TcpReceiver::executeThread() {
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (serverSocket < 0)
return;
DEBUG_FUNCTION_LINE("\n");
uint32_t enable = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
struct sockaddr_in bindAddress;
memset(&bindAddress, 0, sizeof(bindAddress));
bindAddress.sin_family = AF_INET;
bindAddress.sin_port = serverPort;
bindAddress.sin_addr.s_addr = INADDR_ANY;
DEBUG_FUNCTION_LINE("\n");
socklen_t len;
int32_t ret;
if ((ret = bind(serverSocket, (struct sockaddr *)&bindAddress, 16)) < 0) {
socketclose(serverSocket);
return;
}
DEBUG_FUNCTION_LINE("\n");
if ((ret = listen(serverSocket, 1)) < 0) {
socketclose(serverSocket);
return;
}
DEBUG_FUNCTION_LINE("\n");
struct sockaddr_in clientAddr;
memset(&clientAddr, 0, sizeof(clientAddr));
int32_t addrlen = sizeof(struct sockaddr);
while(!exitRequested) {
DEBUG_FUNCTION_LINE("\n");
len = 16;
int32_t clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &len);
if(clientSocket >= 0) {
DEBUG_FUNCTION_LINE("\n");
uint32_t ipAddress = clientAddr.sin_addr.s_addr;
//serverReceiveStart(this, ipAddress);
int32_t result = loadToMemory(clientSocket, ipAddress);
//serverReceiveFinished(this, ipAddress, result);
socketclose(clientSocket);
if(result > 0)
break;
} else {
DEBUG_FUNCTION_LINE("Server socket accept failed %i %d\n", clientSocket,wiiu_geterrno());
OSSleepTicks(OSMicrosecondsToTicks(100000));
}
}
socketclose(serverSocket);
}
typedef struct __attribute((packed)) {
uint32_t command;
uint32_t target;
uint32_t filesize;
uint32_t fileoffset;
char path[256];
}LOAD_REQUEST;
int32_t TcpReceiver::loadToMemory(int32_t clientSocket, uint32_t ipAddress) {
DEBUG_FUNCTION_LINE("Loading file from ip %08X\n", ipAddress);
uint32_t fileSize = 0;
uint32_t fileSizeUnc = 0;
unsigned char haxx[8];
memset(haxx, 0, sizeof(haxx));
//skip haxx
recvwait(clientSocket, haxx, sizeof(haxx));
recvwait(clientSocket, (unsigned char*)&fileSize, sizeof(fileSize));
if (haxx[4] > 0 || haxx[5] > 4) {
recvwait(clientSocket, (unsigned char*)&fileSizeUnc, sizeof(fileSizeUnc)); // Compressed protocol, read another 4 bytes
}
struct in_addr in;
uint32_t bytesRead = 0;
in.s_addr = ipAddress;
DEBUG_FUNCTION_LINE("transfer start\n");
unsigned char* loadAddress = (unsigned char*)memalign(0x40, fileSize);
if(!loadAddress) {
OSSleepTicks(OSSecondsToTicks(1));
return NOT_ENOUGH_MEMORY;
}
// Copy rpl in memory
while(bytesRead < fileSize) {
uint32_t blockSize = 0x1000;
if(blockSize > (fileSize - bytesRead))
blockSize = fileSize - bytesRead;
int32_t ret = recv(clientSocket, loadAddress + bytesRead, blockSize, 0);
if(ret <= 0) {
DEBUG_FUNCTION_LINE("Failure on reading file\n");
break;
}
bytesRead += ret;
}
if(bytesRead != fileSize) {
free(loadAddress);
DEBUG_FUNCTION_LINE("File loading not finished, %i of %i bytes received\n", bytesRead, fileSize);
return FILE_READ_ERROR;
}
bool res = false;
bool loadedRPX = false;
// Do we need to unzip this thing?
if (haxx[4] > 0 || haxx[5] > 4) {
unsigned char* inflatedData = NULL;
// We need to unzip...
if (loadAddress[0] == 'P' && loadAddress[1] == 'K' && loadAddress[2] == 0x03 && loadAddress[3] == 0x04) {
//! TODO:
//! mhmm this is incorrect, it has to parse the zip
// Section is compressed, inflate
inflatedData = (unsigned char*)malloc(fileSizeUnc);
if(!inflatedData) {
free(loadAddress);
return NOT_ENOUGH_MEMORY;
}
int32_t ret = 0;
z_stream s;
memset(&s, 0, sizeof(s));
s.zalloc = Z_NULL;
s.zfree = Z_NULL;
s.opaque = Z_NULL;
ret = inflateInit(&s);
if (ret != Z_OK) {
free(loadAddress);
free(inflatedData);
return FILE_READ_ERROR;
}
s.avail_in = fileSize;
s.next_in = (Bytef *)(&loadAddress[0]);
s.avail_out = fileSizeUnc;
s.next_out = (Bytef *)&inflatedData[0];
ret = inflate(&s, Z_FINISH);
if (ret != Z_OK && ret != Z_STREAM_END) {
free(loadAddress);
free(inflatedData);
return FILE_READ_ERROR;
}
inflateEnd(&s);
fileSize = fileSizeUnc;
} else {
// Section is compressed, inflate
inflatedData = (unsigned char*)malloc(fileSizeUnc);
if(!inflatedData) {
free(loadAddress);
return NOT_ENOUGH_MEMORY;
}
uLongf f = fileSizeUnc;
int32_t result = uncompress((Bytef*)&inflatedData[0], &f, (Bytef*)loadAddress, fileSize);
if(result != Z_OK) {
DEBUG_FUNCTION_LINE("uncompress failed %i\n", result);
return FILE_READ_ERROR;
}
fileSizeUnc = f;
fileSize = fileSizeUnc;
}
if(inflatedData[0x7] == 0xCA && inflatedData[0x8] == 0xFE){
DEBUG_FUNCTION_LINE("Try to load a rpx\n");
FSUtils::CreateSubfolder(RPX_TEMP_PATH);
res = FSUtils::saveBufferToFile(RPX_TEMP_FILE,inflatedData, fileSize);
free(inflatedData);
loadedRPX = true;
}else{
FSUtils::CreateSubfolder(WUPS_TEMP_PLUGIN_PATH);
res = FSUtils::saveBufferToFile(WUPS_TEMP_PLUGIN_FILE,inflatedData, fileSize);
free(inflatedData);
}
} else {
if(loadAddress[0x7] == 0xCA && loadAddress[0x8] == 0xFE){
DEBUG_FUNCTION_LINE("Try to load a rpx\n");
FSUtils::CreateSubfolder(RPX_TEMP_PATH);
res = FSUtils::saveBufferToFile(RPX_TEMP_FILE,loadAddress, fileSize);
free(loadAddress);
loadedRPX = true;
}else{
FSUtils::CreateSubfolder(WUPS_TEMP_PLUGIN_PATH);
res = FSUtils::saveBufferToFile(WUPS_TEMP_PLUGIN_FILE,loadAddress, fileSize);
free(loadAddress);
}
}
if(!res) {
return NOT_ENOUGH_MEMORY;
}
if(loadedRPX){
LOAD_REQUEST request;
memset(&request, 0, sizeof(request));
log_printf("Loading file %s\n", RPX_TEMP_FILE_EX);
request.command = 0xFC; // IPC_CUSTOM_LOAD_CUSTOM_RPX;
request.target = 0; // LOAD_FILE_TARGET_SD_CARD
request.filesize = 0; // unknown
request.fileoffset = 0; //
strncpy(request.path, RPX_TEMP_FILE_EX, 255);
int mcpFd = IOS_Open("/dev/mcp", (IOSOpenMode)0);
if(mcpFd >= 0) {
int out = 0;
IOS_Ioctl(mcpFd, 100, &request, sizeof(request), &out, sizeof(out));
IOS_Close(mcpFd);
if(out == 2) {
}
}
uint64_t titleID = _SYSGetSystemApplicationTitleId(8);
_SYSLaunchTitleWithStdArgsInNoSplash(titleID, 0);
return fileSize;
}
PluginInformation * newFile = PluginInformationUtils::loadPluginInformation("sd:/wiiu/plugins/temp/temp.mod");
if(newFile == NULL){
return -1;
}
std::vector<PluginInformation *> alreadyLoaded = PluginInformationUtils::getPluginsLoadedInMemory();
std::vector<PluginInformation *> newList;
newList.push_back(newFile);
for (std::vector<PluginInformation *>::iterator it = alreadyLoaded.begin() ; it != alreadyLoaded.end(); ++it) {
PluginInformation * curPlugin = *it;
if(curPlugin->getPath().compare(newFile->getPath()) != 0){
if(curPlugin->getName().compare(newFile->getName()) == 0 &&
curPlugin->getAuthor().compare(newFile->getAuthor()) == 0
){
DEBUG_FUNCTION_LINE("Name and Author of the new plugin are identical to an old one. Loading the new one! %s %s\n",newFile->getName().c_str(),newFile->getAuthor().c_str());
continue;
}
newList.push_back(curPlugin);
}else{
DEBUG_FUNCTION_LINE("%s was overridden\n",newFile->getPath().c_str());
}
}
PluginInformationUtils::loadAndLinkPluginsOnRestart(newList);
alreadyLoaded.push_back(newFile);
PluginInformationUtils::clearPluginInformation(alreadyLoaded);
SYSRelaunchTitle(NULL,NULL);
return fileSize;
}

38
src/utils/TcpReceiver.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef TCP_RECEIVER_H_
#define TCP_RECEIVER_H_
#include <vector>
#include <string>
#include "CThread.h"
class TcpReceiver : public CThread {
public:
enum eLoadResults {
SUCCESS = 0,
INVALID_INPUT = -1,
FILE_OPEN_FAILURE = -2,
FILE_READ_ERROR = -3,
NOT_ENOUGH_MEMORY = -4,
NOT_A_VALID_PLUGIN = -5,
};
TcpReceiver(int32_t port);
~TcpReceiver();
//sigslot::signal2<GuiElement *, uint32_t> serverReceiveStart;
//sigslot::signal3<GuiElement *, uint32_t, int32_t> serverReceiveFinished;
private:
void executeThread();
int32_t loadToMemory(int32_t clientSocket, uint32_t ipAddress);
bool saveFileToSDCard(const char * path, void * buffer,uint32_t size);
bool exitRequested;
int32_t serverPort;
int32_t serverSocket;
};
#endif

294
src/utils/ipcclient.cpp Normal file
View File

@ -0,0 +1,294 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "utils/logger.h"
#include "utils/utils.h"
#include "ipcclient.h"
int (*ipc_ioctl)(ipcmessage *message) = (int (*)(ipcmessage*)) *(uint32_t*)0x80800000;
#define ALIGN(align) __attribute__((aligned(align)))
int32_t doIOCTL(int32_t command, uint32_t *in_buf, uint32_t in_length, uint32_t *io_buf, uint32_t io_length) {
ALIGN(0x20) ipcmessage message;
memset(&message,0,sizeof(message));
message.command = command;
message.ioctl.buffer_in = in_buf;
message.ioctl.length_in = in_length;
message.ioctl.buffer_io = io_buf;
message.ioctl.length_io = io_length;
DEBUG_FUNCTION_LINE("command: %d in_buf %08X size: %d io_buf %08X size: %d \n",command, in_buf,in_length,io_buf,io_length);
//DCFlushRange(&message, sizeof(ipcmessage));
//ICInvalidatRange(&message, sizeof(ipcmessage));
return ((int (*)(ipcmessage *))((uint32_t*)*((uint32_t*)0x80800000)) )(&message);
}
plugin_loader_handle IPC_Open_Plugin_Loader(uint32_t startAddress, uint32_t endAddress) {
uint32_t *io_buf = (uint32_t*)memalign(0x20, ROUNDUP(8,0x20));
if(!io_buf) {
return (plugin_loader_handle) NULL;
}
io_buf[0] = startAddress;
io_buf[1] = endAddress;
int32_t ret = doIOCTL(IOCTL_OPEN_PLUGIN_LOADER, io_buf, 8, io_buf, 4);
if(ret < 0) {
free(io_buf);
return (plugin_loader_handle) NULL;
}
plugin_information_handle result = (plugin_loader_handle) io_buf[0];
free(io_buf);
return result;
}
bool IPC_Close_Plugin_Loader(plugin_loader_handle handle) {
uint32_t *io_buf = (uint32_t*)memalign(0x20, ROUNDUP(4,0x20));
if(!io_buf) {
return false;
}
io_buf[0] = handle;
int32_t ret = doIOCTL(IOCTL_CLOSE_PLUGIN_LOADER, io_buf, 4, NULL, 0);
if(ret < 0) {
free(io_buf);
return false;
}
free(io_buf);
return true;
}
int32_t IPC_Get_Plugin_Information(const char * path, plugin_information_handle ** handleList, uint32_t * handleListSize) {
uint32_t buffersize = ROUNDUP((128 * sizeof(plugin_information_handle)) + 4,0x20);
uint32_t *io_buf = (uint32_t*)memalign(0x20, buffersize);
if(!io_buf) {
return -1;
}
io_buf[0] = (uint32_t) path;
int32_t ret = doIOCTL(IOCTL_PLUGIN_LOADER_GET_INFORMATION_FOR_PATH, io_buf, 4, io_buf, buffersize);
if(ret < 0) {
free(io_buf);
return ret;
}
uint32_t length = io_buf[0];
if(handleListSize != NULL) {
*handleListSize = length;
}
uint32_t result = -1;
if(handleList != NULL) {
// we create a new buffer so the caller can free it properly
uint32_t outbuffersize = ROUNDUP((length * sizeof(plugin_information_handle)),0x20);
*handleList = (uint32_t*)memalign(0x20, outbuffersize);
if(*handleList != NULL) {
result = 0;
memcpy(*handleList, &(io_buf[1]), length * sizeof(plugin_information_handle));
}
}
free(io_buf);
return result;
}
int32_t IPC_Get_Plugin_Information_Loaded(plugin_information_handle ** handleList, uint32_t * handleListSize) {
uint32_t buffersize = ROUNDUP((128 * sizeof(plugin_information_handle)),0x20);
uint32_t *io_buf = (uint32_t*)memalign(0x20, buffersize);
if(!io_buf) {
return -1;
}
int32_t ret = doIOCTL(IOCTL_PLUGIN_LOADER_GET_INFORMATION_LOADED, io_buf, 0, io_buf, buffersize);
if(ret < 0) {
free(io_buf);
return ret;
}
// DEBUG_FUNCTION_LINE("IPC_Get_Plugin_Information_Loaded was fine\n");
uint32_t length = io_buf[0];
if(handleListSize != NULL) {
// DEBUG_FUNCTION_LINE("length set to %d\n", length);
*handleListSize = length;
}
uint32_t result = -1;
if(handleList != NULL && length > 0) {
// we create a new buffer so the caller can free it properly
uint32_t outbuffersize = ROUNDUP((length * sizeof(plugin_information_handle)),0x20);
*handleList = (uint32_t*)memalign(0x20, outbuffersize);
if(*handleList != NULL) {
result = 0;
memcpy(*handleList, &(io_buf[1]), length * sizeof(plugin_information_handle));
}
}
free(io_buf);
return result;
}
int32_t IPC_Get_Plugin_Information_Details(plugin_information_handle * handles, uint32_t handlesize, plugin_information ** informationList, uint32_t * informationListSize) {
uint32_t buffersize = ROUNDUP((handlesize * sizeof(plugin_information)),0x20);
if(buffersize < 8){
buffersize = 8;
}
uint32_t *io_buf = (uint32_t*)memalign(0x20, buffersize);
if(!io_buf) {
if(io_buf != NULL) {
free(io_buf);
}
return -1;
}
io_buf[0] = (uint32_t) handles;
io_buf[1] = handlesize;
int32_t ret = doIOCTL(IOCTL_PLUGIN_LOADER_GET_INFORMATION_DETAILS, io_buf, 8, io_buf, buffersize);
if(ret < 0) {
free(io_buf);
return ret;
}
uint32_t result = -1;
if(informationListSize != NULL) {
*informationListSize = handlesize;
}
if(informationList != NULL) {
// we create a new buffer so the caller can free it properly
uint32_t outbuffersize = ROUNDUP((handlesize * sizeof(plugin_information)),0x20);
*informationList = (plugin_information*)memalign(0x20, outbuffersize);
if(*informationList != NULL) {
result = 0;
memcpy(*informationList, &(io_buf[0]), handlesize * sizeof(plugin_information));
}
}
free(io_buf);
return result;
}
int32_t IPC_Delete_Plugin_Information(plugin_information_handle handle) {
uint32_t *io_buf = (uint32_t*)memalign(0x20, ROUNDUP(4,0x20));
if(!io_buf) {
if(io_buf != NULL) {
free(io_buf);
}
return -1;
}
io_buf[0] = (uint32_t) handle;
int32_t ret = doIOCTL(IOCTL_PLUGIN_LOADER_DELETE_INFORMATION, io_buf, 4, NULL, 0);
if(ret < 0) {
free(io_buf);
return ret;
}
free(io_buf);
return 0;
}
int32_t IPC_Link_Plugin_Information(plugin_loader_handle handle, plugin_information_handle * handleList, uint32_t listSize) {
uint32_t buffersize = ROUNDUP((listSize * sizeof(plugin_information_handle)),0x20);
uint32_t io_buffersize = ROUNDUP(12,0x20);
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buffersize);
uint32_t * buf = (uint32_t*)memalign(0x20, buffersize);
if(!io_buf || !buf) {
if(buf != NULL) {
free(buf);
}
if(io_buf != NULL) {
free(io_buf);
}
return -1;
}
memcpy(buf, handleList, listSize * sizeof(plugin_information_handle*));
io_buf[0] = handle;
io_buf[1] = (uint32_t) buf;
io_buf[2] = listSize;
int32_t ret = doIOCTL(IOCTL_PLUGIN_LOADER_LINK_VIA_INFORMATION, io_buf, 12, io_buf, io_buffersize);
if(ret < 0) {
free(io_buf);
free(buf);
return ret;
}
int32_t result = (int32_t) io_buf[0];
free(io_buf);
free(buf);
return result;
}
int32_t IPC_Link_Plugin_Information_On_Restart(plugin_information_handle * handleList, uint32_t listSize) {
uint32_t buffersize = ROUNDUP((listSize * sizeof(plugin_information_handle)),0x20);
uint32_t io_buffersize = ROUNDUP(8,0x20);
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buffersize);
uint32_t * buf = (uint32_t*)memalign(0x20, buffersize);
if(!io_buf || !buf) {
if(buf != NULL) {
free(buf);
}
if(io_buf != NULL) {
free(io_buf);
}
return -1;
}
memcpy(buf, handleList, listSize * sizeof(plugin_information_handle*));
io_buf[0] = (uint32_t) buf;
io_buf[1] = listSize;
int32_t ret = doIOCTL(IOCTL_PLUGIN_LOADER_LINK_VIA_INFORMATION_ON_RESTART, io_buf, 8, io_buf, io_buffersize);
if(ret < 0) {
free(io_buf);
free(buf);
return ret;
}
int32_t result = (int32_t) io_buf[0];
free(io_buf);
free(buf);
return result;
}
int32_t IPC_Get_Plugin_Information_For_Filepath(const char * path, plugin_information_handle * handle) {
uint32_t buffersize = ROUNDUP((sizeof(plugin_information_handle)),0x20);
uint32_t *io_buf = (uint32_t*)memalign(0x20, buffersize);
if(!io_buf) {
return -1;
}
io_buf[0] = (uint32_t) path;
int32_t ret = doIOCTL(IOCTL_PLUGIN_INFORMATION_GET_INFORMATION_FOR_FILEPATH, io_buf, 4, io_buf, 4);
if(ret < 0) {
free(io_buf);
return ret;
}
*handle = io_buf[0];
free(io_buf);
return 0;
}

71
src/utils/ipcclient.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef __IPC_UTILS_H_
#define __IPC_UTILS_H_
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
#define IPC_ERROR_INVALID_NONE 0
#define IPC_ERROR_INVALID_SIZE 0xFFFFFFFF
#define IPC_ERROR_INVALID_ARG 0xFFFFFFFE
#define IPC_ERROR_FAILED_ALLOC 0xFFFFFFFD
#define IOCTL_OPEN_PLUGIN_LOADER 0x01
#define IOCTL_CLOSE_PLUGIN_LOADER 0x02
#define IOCTL_PLUGIN_LOADER_GET_INFORMATION_FOR_PATH 0x03
#define IOCTL_PLUGIN_LOADER_GET_INFORMATION_LOADED 0x04
#define IOCTL_PLUGIN_LOADER_GET_INFORMATION_DETAILS 0x05
#define IOCTL_PLUGIN_LOADER_DELETE_INFORMATION 0x06
#define IOCTL_PLUGIN_LOADER_LINK_VIA_INFORMATION 0x07
#define IOCTL_PLUGIN_LOADER_LINK_VIA_INFORMATION_ON_RESTART 0x08
#define IOCTL_PLUGIN_INFORMATION_GET_INFORMATION_FOR_FILEPATH 0x09
/* IPC message */
typedef struct ipcmessage {
uint32_t command;
union {
struct {
uint32_t *buffer_in;
uint32_t length_in;
uint32_t *buffer_io;
uint32_t length_io;
} ioctl;
};
} __attribute__((packed)) ipcmessage;
typedef uint32_t plugin_information_handle;
typedef uint32_t plugin_loader_handle;
/* plugin_information message */
typedef struct plugin_information {
plugin_information_handle handle;
char path[256];
char name[256];
char author[256];
} plugin_information;
extern int (*ipc_ioctl)(ipcmessage *message);
plugin_loader_handle IPC_Open_Plugin_Loader(uint32_t startAddress, uint32_t endAddress);
bool IPC_Close_Plugin_Loader(plugin_loader_handle handle);
int32_t IPC_Get_Plugin_Information(const char * path, plugin_information_handle ** handleList, uint32_t * handleListSize);
int32_t IPC_Get_Plugin_Information_For_Filepath(const char * path, plugin_information_handle * handle);
int32_t IPC_Get_Plugin_Information_Loaded(plugin_information_handle ** handleList, uint32_t * handleListSize);
int32_t IPC_Get_Plugin_Information_Details(plugin_information_handle * handles, uint32_t handlesize, plugin_information ** informationList, uint32_t * informationListSize);
int32_t IPC_Delete_Plugin_Information(plugin_information_handle handle);
int32_t IPC_Link_Plugin_Information(plugin_loader_handle handle, plugin_information_handle * handleList, uint32_t listSize);
int32_t IPC_Link_Plugin_Information_On_Restart(plugin_information_handle * handleList, uint32_t listSize);
#ifdef __cplusplus
}
#endif
#endif

82
src/utils/logger.c Normal file
View File

@ -0,0 +1,82 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <utils/logger.h>
#include <nsysnet/socket.h>
#include <coreinit/debug.h>
#include <coreinit/systeminfo.h>
#include <coreinit/thread.h>
static int log_socket __attribute__((section(".data")))= -1;
static struct sockaddr_in connect_addr __attribute__((section(".data")));
static volatile int log_lock __attribute__((section(".data"))) = 0;
void log_init_() {
int broadcastEnable = 1;
log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (log_socket < 0)
return;
setsockopt(log_socket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
memset(&connect_addr, 0, sizeof(struct sockaddr_in));
connect_addr.sin_family = AF_INET;
connect_addr.sin_port = 4405;
connect_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
}
void log_print_(const char *str) {
// socket is always 0 initially as it is in the BSS
if(log_socket < 0) {
return;
}
while(log_lock)
OSSleepTicks(OSMicrosecondsToTicks(1000));
log_lock = 1;
int len = strlen(str);
int ret;
while (len > 0) {
int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet
ret = sendto(log_socket, str, block, 0, (struct sockaddr *)&connect_addr, sizeof(struct sockaddr_in));
if(ret < 0)
break;
len -= ret;
str += ret;
}
log_lock = 0;
}
void OSFatal_printf(const char *format, ...) {
char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
OSFatal(tmp);
}
va_end(va);
}
void log_printf_(const char *format, ...) {
if(log_socket < 0) {
return;
}
char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
log_print_(tmp);
}
va_end(va);
}

38
src/utils/logger.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef __LOGGER_H_
#define __LOGGER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
void log_init_();
//void log_deinit_(void);
void log_print_(const char *str);
void log_printf_(const char *format, ...);
void OSFatal_printf(const char *format, ...);
#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 log_init() log_init_()
//#define log_deinit() log_deinit_()
#define log_print(str) log_print_(str)
#define log_printf(FMT, ARGS...) log_printf_(FMT, ## ARGS);
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
log_printf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0)
#ifdef __cplusplus
}
#endif
#endif

84
src/utils/net.c Normal file
View File

@ -0,0 +1,84 @@
#include "net.h"
#include <unistd.h>
static volatile int socket_lock __attribute__((section(".data"))) = 0;
int32_t recvwait(int32_t sock, void *buffer, int32_t len) {
while(socket_lock) {
usleep(1000);
}
int32_t ret;
while (len > 0) {
ret = recv(sock, buffer, len, 0);
if(ret < 0) {
socket_lock = 0;
return ret;
}
len -= ret;
buffer = (void *)(((char *) buffer) + ret);
}
socket_lock = 0;
return 0;
}
uint8_t recvbyte(int32_t sock) {
unsigned char buffer[1];
int32_t ret;
ret = recvwait(sock, buffer, 1);
if (ret < 0)
return ret;
return buffer[0];
}
uint32_t recvword(int32_t sock) {
uint32_t result;
int32_t ret;
ret = recvwait(sock, &result, 4);
if (ret < 0)
return ret;
return result;
}
int32_t checkbyte(int32_t sock) {
while(socket_lock) {
usleep(1000);
}
unsigned char buffer[1];
int32_t ret;
ret = recv(sock, buffer, 1, MSG_DONTWAIT);
socket_lock = 0;
if (ret < 0)
return ret;
if (ret == 0)
return -1;
return buffer[0];
}
int32_t sendwait(int32_t sock, const void *buffer, int32_t len) {
while(socket_lock) {
usleep(1000);
}
int32_t ret;
while (len > 0) {
// For some reason the send blocks/crashes if the buffer is too big..
int cur_length = len <= 0x30 ? len : 0x30;
ret = send(sock, buffer, cur_length, 0);
if(ret < 0) {
socket_lock = 0;
return ret;
}
len -= ret;
buffer = (void *)(((char *) buffer) + ret);
}
socket_lock = 0;
return 0;
}
int32_t sendbyte(int32_t sock, unsigned char byte) {
unsigned char buffer[1];
buffer[0] = byte;
return sendwait(sock, buffer, 1);
}

20
src/utils/net.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _UTILS_NET_H_
#define _UTILS_NET_H_
#include <stdint.h>
#include <nsysnet/socket.h>
#ifdef __cplusplus
extern "C" {
#endif
int32_t recvwait(int32_t sock, void *buffer, int32_t len);
uint8_t recvbyte(int32_t sock);
uint32_t recvword(int32_t sock);
int32_t checkbyte(int32_t sock);
int32_t sendwait(int32_t sock, const void *buffer, int32_t len);
int32_t sendbyte(int32_t sock, unsigned char byte);
#ifdef __cplusplus
}
#endif
#endif

702
src/utils/romfs_dev.c Normal file
View File

@ -0,0 +1,702 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/dirent.h>
#include <sys/iosupport.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdbool.h>
#include "romfs_dev.h"
typedef enum {
RomfsSource_FileDescriptor,
} RomfsSource;
typedef struct romfs_mount {
devoptab_t device;
bool setup;
RomfsSource fd_type;
int32_t id;
int32_t fd;
time_t mtime;
uint64_t offset;
romfs_header header;
romfs_dir *cwd;
uint32_t *dirHashTable, *fileHashTable;
void *dirTable, *fileTable;
char name[32];
} romfs_mount;
extern int __system_argc;
extern char** __system_argv;
//static char __thread __component[PATH_MAX+1];
static char __component[PATH_MAX+1];
#define romFS_root(m) ((romfs_dir*)(m)->dirTable)
#define romFS_dir(m,x) ((romfs_dir*) ((uint8_t*)(m)->dirTable + (x)))
#define romFS_file(m,x) ((romfs_file*)((uint8_t*)(m)->fileTable + (x)))
#define romFS_none ((uint32_t)~0)
#define romFS_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH)
#define romFS_file_mode (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH)
uint64_t swapLong(uint64_t X) {
uint64_t x = (uint64_t) X;
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#define REVERSE_SHORT(n) ((unsigned short) (((n & 0xFF) << 8) | \
((n & 0xFF00) >> 8)))
#define REVERSE_INT(n) ((unsigned int) (((n & 0xFF) << 24) | \
((n & 0xFF00) << 8) | \
((n & 0xFF0000) >> 8) | \
((n & 0xFF000000) >> 24)))
static ssize_t _romfs_read(romfs_mount *mount, uint64_t offset, void* buffer, uint64_t size) {
uint64_t pos = mount->offset + offset;
size_t _read = 0;
if(mount->fd_type == RomfsSource_FileDescriptor) {
off_t seek_offset = lseek(mount->fd, pos, SEEK_SET);
if(pos != seek_offset) {
return -1;
}
_read = read(mount->fd, buffer, size);
}
return _read;
}
static bool _romfs_read_chk(romfs_mount *mount, uint64_t offset, void* buffer, uint64_t size) {
return _romfs_read(mount, offset, buffer, size) == size;
}
//-----------------------------------------------------------------------------
static int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
static int romfs_close(struct _reent *r, void *fd);
static ssize_t romfs_read(struct _reent *r, void *fd, char *ptr, size_t len);
static off_t romfs_seek(struct _reent *r, void *fd, off_t pos, int dir);
static int romfs_fstat(struct _reent *r, void *fd, struct stat *st);
static int romfs_stat(struct _reent *r, const char *path, struct stat *st);
static int romfs_chdir(struct _reent *r, const char *path);
static DIR_ITER* romfs_diropen(struct _reent *r, DIR_ITER *dirState, const char *path);
static int romfs_dirreset(struct _reent *r, DIR_ITER *dirState);
static int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
static int romfs_dirclose(struct _reent *r, DIR_ITER *dirState);
typedef struct {
romfs_mount *mount;
romfs_file *file;
uint64_t offset, pos;
} romfs_fileobj;
typedef struct {
romfs_mount *mount;
romfs_dir* dir;
uint32_t state;
uint32_t childDir;
uint32_t childFile;
} romfs_diriter;
static devoptab_t romFS_devoptab = {
.structSize = sizeof(romfs_fileobj),
.open_r = romfs_open,
.close_r = romfs_close,
.read_r = romfs_read,
.seek_r = romfs_seek,
.fstat_r = romfs_fstat,
.stat_r = romfs_stat,
.chdir_r = romfs_chdir,
.dirStateSize = sizeof(romfs_diriter),
.diropen_r = romfs_diropen,
.dirreset_r = romfs_dirreset,
.dirnext_r = romfs_dirnext,
.dirclose_r = romfs_dirclose,
};
static bool romfs_initialised = false;
static romfs_mount romfs_mounts[32];
//-----------------------------------------------------------------------------
static int32_t romfsMountCommon(const char *name, romfs_mount *mount);
static void romfsInitMtime(romfs_mount *mount);
static void _romfsResetMount(romfs_mount *mount, int32_t id) {
memset(mount, 0, sizeof(*mount));
memcpy(&mount->device, &romFS_devoptab, sizeof(romFS_devoptab));
mount->device.name = mount->name;
mount->device.deviceData = mount;
mount->id = id;
}
static void _romfsInit(void) {
uint32_t i;
uint32_t total = sizeof(romfs_mounts) / sizeof(romfs_mount);
if(!romfs_initialised) {
for(i = 0; i < total; i++) {
_romfsResetMount(&romfs_mounts[i], i);
}
romfs_initialised = true;
}
}
static romfs_mount *romfsFindMount(const char *name) {
uint32_t i;
uint32_t total = sizeof(romfs_mounts) / sizeof(romfs_mount);
romfs_mount *mount = NULL;
_romfsInit();
for(i=0; i<total; i++) {
mount = &romfs_mounts[i];
if(name==NULL) { //Find an unused mount entry.
if(!mount->setup)
return mount;
} else if(mount->setup) { //Find the mount with the input name.
if(strncmp(mount->name, name, sizeof(mount->name))==0)
return mount;
}
}
return NULL;
}
__attribute__((weak)) const char* __romfs_path = NULL;
static romfs_mount* romfs_alloc(void) {
return romfsFindMount(NULL);
}
static void romfs_free(romfs_mount *mount) {
free(mount->fileTable);
free(mount->fileHashTable);
free(mount->dirTable);
free(mount->dirHashTable);
_romfsResetMount(mount, mount->id);
}
static void romfs_mountclose(romfs_mount *mount) {
if(mount->fd_type == RomfsSource_FileDescriptor) {
close(mount->fd);
}
romfs_free(mount);
}
int32_t romfsMount(const char *name, const char * filepath) {
romfs_mount *mount = romfs_alloc();
if(mount == NULL)
return 99;
// Regular RomFS
mount->fd_type = RomfsSource_FileDescriptor;
mount->fd = open(filepath, 0);
if (mount->fd == -1) {
romfs_free(mount);
return -1;
}
romfsInitMtime(mount);
return romfsMountCommon(name, mount);
_fail0:
romfs_mountclose(mount);
return 10;
}
int32_t romfsMountCommon(const char *name, romfs_mount *mount) {
memset(mount->name, 0, sizeof(mount->name));
strncpy(mount->name, name, sizeof(mount->name)-1);
if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header))
goto fail;
mount->dirHashTable = (uint32_t*)malloc(swapLong(mount->header.dirHashTableSize));
if (!mount->dirHashTable)
goto fail;
if (!_romfs_read_chk(mount, swapLong(mount->header.dirHashTableOff), mount->dirHashTable, swapLong(mount->header.dirHashTableSize)))
goto fail;
mount->dirTable = malloc(swapLong(mount->header.dirTableSize));
if (!mount->dirTable)
goto fail;
if (!_romfs_read_chk(mount, swapLong(mount->header.dirTableOff), mount->dirTable, swapLong(mount->header.dirTableSize)))
goto fail;
mount->fileHashTable = (uint32_t*)malloc(swapLong(mount->header.fileHashTableSize));
if (!mount->fileHashTable)
goto fail;
if (!_romfs_read_chk(mount, swapLong(mount->header.fileHashTableOff), mount->fileHashTable, swapLong(mount->header.fileHashTableSize)))
goto fail;
mount->fileTable = malloc(swapLong(mount->header.fileTableSize));
if (!mount->fileTable)
goto fail;
if (!_romfs_read_chk(mount, swapLong(mount->header.fileTableOff), mount->fileTable, swapLong(mount->header.fileTableSize)))
goto fail;
mount->cwd = romFS_root(mount);
// add device if this is the first one
if(AddDevice(&mount->device) < 0)
goto fail;
mount->setup = true;
return 0;
fail:
romfs_mountclose(mount);
return 10;
}
static void romfsInitMtime(romfs_mount *mount) {
mount->mtime = time(NULL);
}
int32_t romfsUnmount(const char *name) {
romfs_mount *mount;
char tmpname[34];
mount = romfsFindMount(name);
if (mount == NULL)
return -1;
// Remove device
memset(tmpname, 0, sizeof(tmpname));
strncpy(tmpname, mount->name, sizeof(tmpname)-2);
strncat(tmpname, ":", sizeof(tmpname)-strlen(tmpname)-1);
RemoveDevice(tmpname);
romfs_mountclose(mount);
return 0;
}
//-----------------------------------------------------------------------------
static uint32_t calcHash(uint32_t parent, const uint8_t* name, uint32_t namelen, uint32_t total) {
uint32_t hash = parent ^ 123456789;
uint32_t i;
for (i = 0; i < namelen; i ++) {
hash = (hash >> 5) | (hash << 27);
hash ^= name[i];
}
return hash % total;
}
static romfs_dir* searchForDir(romfs_mount *mount, romfs_dir* parent, const uint8_t* name, uint32_t namelen) {
uint64_t parentOff = (uintptr_t)parent - (uintptr_t)mount->dirTable;
uint32_t hash = calcHash(parentOff, name, namelen, swapLong(mount->header.dirHashTableSize)/4);
romfs_dir* curDir = NULL;
uint32_t curOff;
for (curOff = REVERSE_INT(mount->dirHashTable[hash]); curOff != romFS_none; curOff = REVERSE_INT(curDir->nextHash)) {
curDir = romFS_dir(mount, curOff);
if (REVERSE_INT(curDir->parent) != parentOff)
continue;
if (REVERSE_INT(curDir->nameLen) != namelen)
continue;
if (memcmp(curDir->name, name, namelen) != 0)
continue;
return curDir;
}
return NULL;
}
static romfs_file* searchForFile(romfs_mount *mount, romfs_dir* parent, const uint8_t* name, uint32_t namelen) {
uint64_t parentOff = (uintptr_t)parent - (uintptr_t)mount->dirTable;
uint32_t hash = calcHash(parentOff, name, namelen, swapLong(mount->header.fileHashTableSize)/4);
romfs_file* curFile = NULL;
uint32_t curOff;
for (curOff = REVERSE_INT(mount->fileHashTable[hash]); curOff != romFS_none; curOff = REVERSE_INT(curFile->nextHash)) {
curFile = romFS_file(mount, curOff);
if (REVERSE_INT(curFile->parent) != parentOff)
continue;
if (REVERSE_INT(curFile->nameLen) != namelen)
continue;
if (memcmp(curFile->name, name, namelen) != 0)
continue;
return curFile;
}
return NULL;
}
static int navigateToDir(romfs_mount *mount, romfs_dir** ppDir, const char** pPath, bool isDir) {
char* colonPos = strchr(*pPath, ':');
if (colonPos)
*pPath = colonPos+1;
if (!**pPath)
return EILSEQ;
*ppDir = mount->cwd;
if (**pPath == '/') {
*ppDir = romFS_root(mount);
(*pPath)++;
}
while (**pPath) {
char* slashPos = strchr(*pPath, '/');
char* component = __component;
if (slashPos) {
uint32_t len = slashPos - *pPath;
if (!len)
return EILSEQ;
if (len > PATH_MAX)
return ENAMETOOLONG;
memcpy(component, *pPath, len);
component[len] = 0;
*pPath = slashPos+1;
} else if (isDir) {
component = (char*)*pPath;
*pPath += strlen(component);
} else
return 0;
if (component[0]=='.') {
if (!component[1])
continue;
if (component[1]=='.' && !component[2]) {
*ppDir = romFS_dir(mount, REVERSE_INT((*ppDir)->parent));
continue;
}
}
*ppDir = searchForDir(mount, *ppDir, (uint8_t*)component, strlen(component));
if (!*ppDir)
return EEXIST;
}
if (!isDir && !**pPath)
return EILSEQ;
return 0;
}
static ino_t dir_inode(romfs_mount *mount, romfs_dir *dir) {
return (uint32_t*)dir - (uint32_t*)mount->dirTable;
}
static off_t dir_size(romfs_dir *dir) {
return sizeof(romfs_dir) + (REVERSE_INT(dir->nameLen)+3)/4;
}
static nlink_t dir_nlink(romfs_mount *mount, romfs_dir *dir) {
nlink_t count = 2; // one for self, one for parent
uint32_t offset = REVERSE_INT(dir->childDir);
while(offset != romFS_none) {
romfs_dir *tmp = romFS_dir(mount, offset);
++count;
offset = REVERSE_INT(tmp->sibling);
}
offset = REVERSE_INT(dir->childFile);
while(offset != romFS_none) {
romfs_file *tmp = romFS_file(mount, offset);
++count;
offset = REVERSE_INT(tmp->sibling);
}
return count;
}
static ino_t file_inode(romfs_mount *mount, romfs_file *file) {
return ((uint32_t*)file - (uint32_t*)mount->fileTable) + swapLong(mount->header.dirTableSize)/4;
}
int romfs_GetFileInfoPerPath(const char* romfs, const char *path, romfs_fileInfo* out) {
if(out == NULL){
return -1;
}
romfs_mount* mount = (romfs_mount*)romfsFindMount(romfs);
if(mount == NULL){
return -2;
}
romfs_dir* curDir = NULL;
int errno2 = navigateToDir(mount, &curDir, &path, false);
if (errno2 != 0){
return -3;
}
romfs_file* file = searchForFile(mount, curDir, (uint8_t*)path, strlen(path));
if (!file) {
return -4;
}
out->length = swapLong(file->dataSize);
out->offset = swapLong(mount->header.fileDataOff) + swapLong(file->dataOff);
return 0;
}
//-----------------------------------------------------------------------------
int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) {
romfs_fileobj* fileobj = (romfs_fileobj*)fileStruct;
fileobj->mount = (romfs_mount*)r->deviceData;
if ((flags & O_ACCMODE) != O_RDONLY) {
r->_errno = EROFS;
return -1;
}
romfs_dir* curDir = NULL;
r->_errno = navigateToDir(fileobj->mount, &curDir, &path, false);
if (r->_errno != 0)
return -1;
romfs_file* file = searchForFile(fileobj->mount, curDir, (uint8_t*)path, strlen(path));
if (!file) {
if(flags & O_CREAT)
r->_errno = EROFS;
else
r->_errno = ENOENT;
return -1;
} else if((flags & O_CREAT) && (flags & O_EXCL)) {
r->_errno = EEXIST;
return -1;
}
fileobj->file = file;
fileobj->offset = swapLong(fileobj->mount->header.fileDataOff) + swapLong(file->dataOff);
fileobj->pos = 0;
return 0;
}
int romfs_close(struct _reent *r, void *fd) {
return 0;
}
ssize_t romfs_read(struct _reent *r, void *fd, char *ptr, size_t len) {
romfs_fileobj* file = (romfs_fileobj*)fd;
uint64_t endPos = file->pos + len;
/* check if past end-of-file */
if(file->pos >= swapLong(file->file->dataSize))
return 0;
/* truncate the read to end-of-file */
if(endPos > swapLong(file->file->dataSize))
endPos = swapLong(file->file->dataSize);
len = endPos - file->pos;
ssize_t adv = _romfs_read(file->mount, file->offset + file->pos, ptr, len);
if(adv >= 0) {
file->pos += adv;
return adv;
}
r->_errno = EIO;
return -1;
}
off_t romfs_seek(struct _reent *r, void *fd, off_t pos, int dir) {
romfs_fileobj* file = (romfs_fileobj*)fd;
off_t start;
switch (dir) {
case SEEK_SET:
start = 0;
break;
case SEEK_CUR:
start = file->pos;
break;
case SEEK_END:
start = swapLong(file->file->dataSize);
break;
default:
r->_errno = EINVAL;
return -1;
}
/* don't allow negative position */
if(pos < 0) {
if(start + pos < 0) {
r->_errno = EINVAL;
return -1;
}
}
/* check for overflow */
else if(INT64_MAX - pos < start) {
r->_errno = EOVERFLOW;
return -1;
}
file->pos = start + pos;
return file->pos;
}
int romfs_fstat(struct _reent *r, void *fd, struct stat *st) {
romfs_fileobj* file = (romfs_fileobj*)fd;
memset(st, 0, sizeof(struct stat));
st->st_ino = file_inode(file->mount, file->file);
st->st_mode = romFS_file_mode;
st->st_nlink = 1;
st->st_size = (off_t)swapLong(file->file->dataSize);
st->st_blksize = 512;
st->st_blocks = (st->st_blksize + 511) / 512;
st->st_atime = st->st_mtime = st->st_ctime = file->mount->mtime;
return 0;
}
int romfs_stat(struct _reent *r, const char *path, struct stat *st) {
romfs_mount* mount = (romfs_mount*)r->deviceData;
romfs_dir* curDir = NULL;
r->_errno = navigateToDir(mount, &curDir, &path, false);
if(r->_errno != 0)
return -1;
romfs_dir* dir = searchForDir(mount, curDir, (uint8_t*)path, strlen(path));
if(dir) {
memset(st, 0, sizeof(*st));
st->st_ino = dir_inode(mount, dir);
st->st_mode = romFS_dir_mode;
st->st_nlink = dir_nlink(mount, dir);
st->st_size = dir_size(dir);
st->st_blksize = 512;
st->st_blocks = (st->st_blksize + 511) / 512;
st->st_atime = st->st_mtime = st->st_ctime = mount->mtime;
return 0;
}
romfs_file* file = searchForFile(mount, curDir, (uint8_t*)path, strlen(path));
if(file) {
memset(st, 0, sizeof(*st));
st->st_ino = file_inode(mount, file);
st->st_mode = romFS_file_mode;
st->st_nlink = 1;
st->st_size = swapLong(file->dataSize);
st->st_blksize = 512;
st->st_blocks = (st->st_blksize + 511) / 512;
st->st_atime = st->st_mtime = st->st_ctime = mount->mtime;
return 0;
}
r->_errno = ENOENT;
return 1;
}
int romfs_chdir(struct _reent *r, const char *path) {
romfs_mount* mount = (romfs_mount*)r->deviceData;
romfs_dir* curDir = NULL;
r->_errno = navigateToDir(mount, &curDir, &path, false);
if (r->_errno != 0)
return -1;
mount->cwd = curDir;
return 0;
}
DIR_ITER* romfs_diropen(struct _reent *r, DIR_ITER *dirState, const char *path) {
romfs_diriter* iter = (romfs_diriter*)(dirState->dirStruct);
romfs_dir* curDir = NULL;
iter->mount = (romfs_mount*)r->deviceData;
r->_errno = navigateToDir(iter->mount, &curDir, &path, true);
if(r->_errno != 0)
return NULL;
iter->dir = curDir;
iter->state = 0;
iter->childDir = REVERSE_INT(curDir->childDir);
iter->childFile = REVERSE_INT(curDir->childFile);
return dirState;
}
int romfs_dirreset(struct _reent *r, DIR_ITER *dirState) {
romfs_diriter* iter = (romfs_diriter*)(dirState->dirStruct);
iter->state = 0;
iter->childDir = REVERSE_INT(iter->dir->childDir);
iter->childFile = REVERSE_INT(iter->dir->childFile);
return 0;
}
int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) {
romfs_diriter* iter = (romfs_diriter*)(dirState->dirStruct);
if(iter->state == 0) {
/* '.' entry */
memset(filestat, 0, sizeof(*filestat));
filestat->st_ino = dir_inode(iter->mount, iter->dir);
filestat->st_mode = romFS_dir_mode;
strcpy(filename, ".");
iter->state = 1;
return 0;
} else if(iter->state == 1) {
/* '..' entry */
romfs_dir* dir = romFS_dir(iter->mount, REVERSE_INT(iter->dir->parent));
memset(filestat, 0, sizeof(*filestat));
filestat->st_ino = dir_inode(iter->mount, dir);
filestat->st_mode = romFS_dir_mode;
strcpy(filename, "..");
iter->state = 2;
return 0;
}
if(iter->childDir != romFS_none) {
romfs_dir* dir = romFS_dir(iter->mount, iter->childDir);
iter->childDir = REVERSE_INT(dir->sibling);
memset(filestat, 0, sizeof(*filestat));
filestat->st_ino = dir_inode(iter->mount, dir);
filestat->st_mode = romFS_dir_mode;
memset(filename, 0, NAME_MAX);
if(REVERSE_INT(dir->nameLen) >= NAME_MAX) {
r->_errno = ENAMETOOLONG;
return -1;
}
strncpy(filename, (char*)dir->name, REVERSE_INT(dir->nameLen));
return 0;
} else if(iter->childFile != romFS_none) {
romfs_file* file = romFS_file(iter->mount, iter->childFile);
iter->childFile = REVERSE_INT(file->sibling);
memset(filestat, 0, sizeof(*filestat));
filestat->st_ino = file_inode(iter->mount, file);
filestat->st_mode = romFS_file_mode;
memset(filename, 0, NAME_MAX);
if(REVERSE_INT(file->nameLen) >= NAME_MAX) {
r->_errno = ENAMETOOLONG;
return -1;
}
strncpy(filename, (char*)file->name, REVERSE_INT(file->nameLen));
return 0;
}
r->_errno = ENOENT;
return -1;
}
int romfs_dirclose(struct _reent *r, DIR_ITER *dirState) {
return 0;
}

90
src/utils/romfs_dev.h Normal file
View File

@ -0,0 +1,90 @@
/**
* @file romfs_dev.h
* @brief RomFS driver.
* @author yellows8
* @author mtheall
* @author fincs
* @copyright libnx Authors
*/
#pragma once
#include <wut.h>
/// RomFS header.
typedef struct {
uint64_t headerSize; ///< Size of the header.
uint64_t dirHashTableOff; ///< Offset of the directory hash table.
uint64_t dirHashTableSize; ///< Size of the directory hash table.
uint64_t dirTableOff; ///< Offset of the directory table.
uint64_t dirTableSize; ///< Size of the directory table.
uint64_t fileHashTableOff; ///< Offset of the file hash table.
uint64_t fileHashTableSize; ///< Size of the file hash table.
uint64_t fileTableOff; ///< Offset of the file table.
uint64_t fileTableSize; ///< Size of the file table.
uint64_t fileDataOff; ///< Offset of the file data.
} romfs_header;
/// RomFS directory.
typedef struct {
uint32_t parent; ///< Offset of the parent directory.
uint32_t sibling; ///< Offset of the next sibling directory.
uint32_t childDir; ///< Offset of the first child directory.
uint32_t childFile; ///< Offset of the first file.
uint32_t nextHash; ///< Directory hash table pointer.
uint32_t nameLen; ///< Name length.
uint8_t name[]; ///< Name. (UTF-8)
} romfs_dir;
/// RomFS file.
typedef struct {
uint32_t parent; ///< Offset of the parent directory.
uint32_t sibling; ///< Offset of the next sibling file.
uint64_t dataOff; ///< Offset of the file's data.
uint64_t dataSize; ///< Length of the file's data.
uint32_t nextHash; ///< File hash table pointer.
uint32_t nameLen; ///< Name length.
uint8_t name[]; ///< Name. (UTF-8)
} romfs_file;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Mounts the Application's RomFS.
* @param name Device mount name.
*/
int32_t romfsMount(const char *name, const char * path);
/**
* @brief Mounts RomFS from an open file.
* @param file FsFile of the RomFS image.
* @param offset Offset of the RomFS within the file.
* @param name Device mount name.
bool romfsMountFromFile(FsFile file, uint64_t offset, const char *name);
*/
/*
static inline bool romfsInitFromFile(int32_t fd, uint64_t offset) {
return romfsMountFromFile(fd, offset, "romfs");
}*/
/// Unmounts the RomFS device.
int32_t romfsUnmount(const char *name);
/*
static inline bool romfsExit(void) {
return romfsUnmount("romfs");
}*/
/// RomFS file.
typedef struct {
uint64_t length; ///< Offset of the file's data.
uint64_t offset; ///< Length of the file's data.
} romfs_fileInfo;
int romfs_GetFileInfoPerPath(const char* romfs, const char *path, romfs_fileInfo* out);
#ifdef __cplusplus
}
#endif

88
src/utils/utils.c Normal file
View File

@ -0,0 +1,88 @@
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <malloc.h>
#include <utils/logger.h>
// https://gist.github.com/ccbrown/9722406
void dumpHex(const void* data, size_t size) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data);
for (i = 0; i < size; ++i) {
log_printf("%02X ", ((unsigned char*)data)[i]);
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char*)data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
log_printf(" ");
if ((i+1) % 16 == 0) {
log_printf("| %s \n", ascii);
if(i + 1 < size) {
DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", data + i + 1,i+1);
}
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
log_printf(" ");
}
for (j = (i+1) % 16; j < 16; ++j) {
log_printf(" ");
}
log_printf("| %s \n", ascii);
}
}
}
}
// You must free the result if result is non-NULL.
char *str_replace(char *orig, char *rep, char *with) {
char *result; // the return string
char *ins; // the next insert point
char *tmp; // varies
int len_rep; // length of rep (the string to remove)
int len_with; // length of with (the string to replace rep with)
int len_front; // distance between rep and end of last rep
int count; // number of replacements
// sanity checks and initialization
if (!orig || !rep)
return NULL;
len_rep = strlen(rep);
if (len_rep == 0)
return NULL; // empty rep causes infinite loop during count
if (!with)
with = "";
len_with = strlen(with);
// count the number of replacements needed
ins = orig;
for (count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + len_rep;
}
tmp = result = (char*)malloc(strlen(orig) + (len_with - len_rep) * count + 1);
if (!result)
return NULL;
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
while (count--) {
ins = strstr(orig, rep);
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
}
strcpy(tmp, orig);
return result;
}

39
src/utils/utils.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef __UTILS_H_
#define __UTILS_H_
#include <malloc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LIMIT(x, min, max) \
({ \
typeof( x ) _x = x; \
typeof( min ) _min = min; \
typeof( max ) _max = max; \
( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \
})
#define DegToRad(a) ( (a) * 0.01745329252f )
#define RadToDeg(a) ( (a) * 57.29577951f )
#define ALIGN4(x) (((x) + 3) & ~3)
#define ALIGN32(x) (((x) + 31) & ~31)
#define ROUNDUP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
#define le16(i) ((((uint16_t) ((i) & 0xFF)) << 8) | ((uint16_t) (((i) & 0xFF00) >> 8)))
#define le32(i) ((((uint32_t)le16((i) & 0xFFFF)) << 16) | ((uint32_t)le16(((i) & 0xFFFF0000) >> 16)))
#define le64(i) ((((uint64_t)le32((i) & 0xFFFFFFFFLL)) << 32) | ((uint64_t)le32(((i) & 0xFFFFFFFF00000000LL) >> 32)))
//Needs to have log_init() called beforehand.
void dumpHex(const void* data, size_t size);
char *str_replace(char *orig, char *rep, char *with);
#ifdef __cplusplus
}
#endif
#endif // __UTILS_H_