mirror of
https://github.com/wiiu-env/wiiload_plugin.git
synced 2024-11-25 12:06:52 +01:00
First commit
This commit is contained in:
commit
9ba9e5ca1b
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
build/*
|
||||
*.mod
|
||||
sysapp.layout
|
||||
sysapp.cbp
|
||||
sysapp.cscope_file_list
|
272
Makefile
Normal file
272
Makefile
Normal 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
50
makefile.mk
Normal 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
175
src/fs/CFile.cpp
Normal 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
61
src/fs/CFile.hpp
Normal 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
213
src/fs/DirList.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* DirList Class
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <algorithm>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/dirent.h>
|
||||
|
||||
#include <fs/DirList.h>
|
||||
#include <utils/StringTools.h>
|
||||
|
||||
DirList::DirList() {
|
||||
Flags = 0;
|
||||
Filter = 0;
|
||||
Depth = 0;
|
||||
}
|
||||
|
||||
DirList::DirList(const std::string & path, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||
this->LoadPath(path, filter, flags, maxDepth);
|
||||
this->SortList();
|
||||
}
|
||||
|
||||
DirList::~DirList() {
|
||||
ClearList();
|
||||
}
|
||||
|
||||
BOOL DirList::LoadPath(const std::string & folder, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||
if(folder.empty()) return false;
|
||||
|
||||
Flags = flags;
|
||||
Filter = filter;
|
||||
Depth = maxDepth;
|
||||
|
||||
std::string folderpath(folder);
|
||||
uint32_t length = folderpath.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
StringTools::RemoveDoubleSlashs(folderpath);
|
||||
|
||||
//! remove last slash if exists
|
||||
if(length > 0 && folderpath[length-1] == '/')
|
||||
folderpath.erase(length-1);
|
||||
|
||||
//! add root slash if missing
|
||||
if(folderpath.find('/') == std::string::npos) {
|
||||
folderpath += '/';
|
||||
}
|
||||
|
||||
return InternalLoadPath(folderpath);
|
||||
}
|
||||
|
||||
BOOL DirList::InternalLoadPath(std::string &folderpath) {
|
||||
if(folderpath.size() < 3)
|
||||
return false;
|
||||
|
||||
struct dirent *dirent = NULL;
|
||||
DIR *dir = NULL;
|
||||
|
||||
dir = opendir(folderpath.c_str());
|
||||
if (dir == NULL)
|
||||
return false;
|
||||
|
||||
while ((dirent = readdir(dir)) != 0) {
|
||||
BOOL isDir = dirent->d_type & DT_DIR;
|
||||
const char *filename = dirent->d_name;
|
||||
|
||||
if(isDir) {
|
||||
if(strcmp(filename,".") == 0 || strcmp(filename,"..") == 0)
|
||||
continue;
|
||||
|
||||
if((Flags & CheckSubfolders) && (Depth > 0)) {
|
||||
int32_t length = folderpath.size();
|
||||
if(length > 2 && folderpath[length-1] != '/') {
|
||||
folderpath += '/';
|
||||
}
|
||||
folderpath += filename;
|
||||
|
||||
Depth--;
|
||||
InternalLoadPath(folderpath);
|
||||
folderpath.erase(length);
|
||||
Depth++;
|
||||
}
|
||||
|
||||
if(!(Flags & Dirs))
|
||||
continue;
|
||||
} else if(!(Flags & Files)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(Filter) {
|
||||
char * fileext = strrchr(filename, '.');
|
||||
if(!fileext)
|
||||
continue;
|
||||
|
||||
if(StringTools::strtokcmp(fileext, Filter, ",") == 0)
|
||||
AddEntrie(folderpath, filename, isDir);
|
||||
} else {
|
||||
AddEntrie(folderpath, filename, isDir);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DirList::AddEntrie(const std::string &filepath, const char * filename, BOOL isDir) {
|
||||
if(!filename)
|
||||
return;
|
||||
|
||||
int32_t pos = FileInfo.size();
|
||||
|
||||
FileInfo.resize(pos+1);
|
||||
|
||||
FileInfo[pos].FilePath = (char *) malloc(filepath.size()+strlen(filename)+2);
|
||||
if(!FileInfo[pos].FilePath) {
|
||||
FileInfo.resize(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(FileInfo[pos].FilePath, "%s/%s", filepath.c_str(), filename);
|
||||
FileInfo[pos].isDir = isDir;
|
||||
}
|
||||
|
||||
void DirList::ClearList() {
|
||||
for(uint32_t i = 0; i < FileInfo.size(); ++i) {
|
||||
if(FileInfo[i].FilePath) {
|
||||
free(FileInfo[i].FilePath);
|
||||
FileInfo[i].FilePath = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo.clear();
|
||||
std::vector<DirEntry>().swap(FileInfo);
|
||||
}
|
||||
|
||||
const char * DirList::GetFilename(int32_t ind) const {
|
||||
if (!valid(ind))
|
||||
return "";
|
||||
|
||||
return StringTools::FullpathToFilename(FileInfo[ind].FilePath);
|
||||
}
|
||||
|
||||
static BOOL SortCallback(const DirEntry & f1, const DirEntry & f2) {
|
||||
if(f1.isDir && !(f2.isDir)) return true;
|
||||
if(!(f1.isDir) && f2.isDir) return false;
|
||||
|
||||
if(f1.FilePath && !f2.FilePath) return true;
|
||||
if(!f1.FilePath) return false;
|
||||
|
||||
if(strcasecmp(f1.FilePath, f2.FilePath) > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DirList::SortList() {
|
||||
if(FileInfo.size() > 1)
|
||||
std::sort(FileInfo.begin(), FileInfo.end(), SortCallback);
|
||||
}
|
||||
|
||||
void DirList::SortList(BOOL (*SortFunc)(const DirEntry &a, const DirEntry &b)) {
|
||||
if(FileInfo.size() > 1)
|
||||
std::sort(FileInfo.begin(), FileInfo.end(), SortFunc);
|
||||
}
|
||||
|
||||
uint64_t DirList::GetFilesize(int32_t index) const {
|
||||
struct stat st;
|
||||
const char *path = GetFilepath(index);
|
||||
|
||||
if(!path || stat(path, &st) != 0)
|
||||
return 0;
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
int32_t DirList::GetFileIndex(const char *filename) const {
|
||||
if(!filename)
|
||||
return -1;
|
||||
|
||||
for (uint32_t i = 0; i < FileInfo.size(); ++i) {
|
||||
if (strcasecmp(GetFilename(i), filename) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
103
src/fs/DirList.h
Normal file
103
src/fs/DirList.h
Normal 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
142
src/fs/FSUtils.cpp
Normal 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
16
src/fs/FSUtils.h
Normal 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
39
src/main.cpp
Normal 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
32
src/main.h
Normal 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
|
117
src/plugin/PluginInformation.h
Normal file
117
src/plugin/PluginInformation.h
Normal 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
|
121
src/plugin/PluginInformationUtils.cpp
Normal file
121
src/plugin/PluginInformationUtils.cpp
Normal 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;
|
||||
}
|
70
src/plugin/PluginInformationUtils.h
Normal file
70
src/plugin/PluginInformationUtils.h
Normal 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
|
60
src/plugin/PluginLoader.cpp
Normal file
60
src/plugin/PluginLoader.cpp
Normal 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
78
src/plugin/PluginLoader.h
Normal 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
69
src/utils/CMutex.h
Normal 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
134
src/utils/CThread.h
Normal 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
210
src/utils/StringTools.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <strings.h>
|
||||
#include <wut_types.h>
|
||||
#include <stdio.h>
|
||||
#include <utils/StringTools.h>
|
||||
|
||||
|
||||
BOOL StringTools::EndsWith(const std::string& a, const std::string& b) {
|
||||
if (b.size() > a.size()) return false;
|
||||
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
||||
}
|
||||
|
||||
const char * StringTools::byte_to_binary(int32_t x) {
|
||||
static char b[9];
|
||||
b[0] = '\0';
|
||||
|
||||
int32_t z;
|
||||
for (z = 128; z > 0; z >>= 1) {
|
||||
strcat(b, ((x & z) == z) ? "1" : "0");
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
std::string StringTools::removeCharFromString(std::string& input,char toBeRemoved) {
|
||||
std::string output = input;
|
||||
size_t position;
|
||||
while(1) {
|
||||
position = output.find(toBeRemoved);
|
||||
if(position == std::string::npos)
|
||||
break;
|
||||
output.erase(position, 1);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
const char * StringTools::fmt(const char * format, ...) {
|
||||
static char strChar[512];
|
||||
strChar[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if((vsprintf(strChar, format, va) >= 0)) {
|
||||
va_end(va);
|
||||
return (const char *) strChar;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const wchar_t * StringTools::wfmt(const char * format, ...) {
|
||||
static char tmp[512];
|
||||
static wchar_t strWChar[512];
|
||||
strWChar[0] = 0;
|
||||
tmp[0] = 0;
|
||||
|
||||
if(!format)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
if(strcmp(format, "") == 0)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if((vsprintf(tmp, format, va) >= 0)) {
|
||||
int bt;
|
||||
int32_t strlength = strlen(tmp);
|
||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512 );
|
||||
|
||||
if(bt > 0) {
|
||||
strWChar[bt] = 0;
|
||||
return (const wchar_t *) strWChar;
|
||||
}
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t StringTools::strprintf(std::string &str, const char * format, ...) {
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
int32_t result = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
result = str.size();
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string StringTools::strfmt(const char * format, ...) {
|
||||
std::string str;
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
BOOL StringTools::char2wchar_t(const char * strChar, wchar_t * dest) {
|
||||
if(!strChar || !dest)
|
||||
return false;
|
||||
|
||||
int bt;
|
||||
bt = mbstowcs(dest, strChar, strlen(strChar));
|
||||
if (bt > 0) {
|
||||
dest[bt] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t StringTools::strtokcmp(const char * string, const char * compare, const char * separator) {
|
||||
if(!string || !compare)
|
||||
return -1;
|
||||
|
||||
char TokCopy[512];
|
||||
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||
TokCopy[511] = '\0';
|
||||
|
||||
char * strTok = strtok(TokCopy, separator);
|
||||
|
||||
while (strTok != NULL) {
|
||||
if (strcasecmp(string, strTok) == 0) {
|
||||
return 0;
|
||||
}
|
||||
strTok = strtok(NULL,separator);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t StringTools::strextcmp(const char * string, const char * extension, char seperator) {
|
||||
if(!string || !extension)
|
||||
return -1;
|
||||
|
||||
char *ptr = strrchr(string, seperator);
|
||||
if(!ptr)
|
||||
return -1;
|
||||
|
||||
return strcasecmp(ptr + 1, extension);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> StringTools::stringSplit(const std::string & inValue, const std::string & splitter) {
|
||||
std::string value = inValue;
|
||||
std::vector<std::string> result;
|
||||
while (true) {
|
||||
uint32_t index = value.find(splitter);
|
||||
if (index == std::string::npos) {
|
||||
result.push_back(value);
|
||||
break;
|
||||
}
|
||||
std::string first = value.substr(0, index);
|
||||
result.push_back(first);
|
||||
if (index + splitter.size() == value.length()) {
|
||||
result.push_back("");
|
||||
break;
|
||||
}
|
||||
if(index + splitter.size() > value.length()) {
|
||||
break;
|
||||
}
|
||||
value = value.substr(index + splitter.size(), value.length());
|
||||
}
|
||||
return result;
|
||||
}
|
82
src/utils/StringTools.h
Normal file
82
src/utils/StringTools.h
Normal 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
336
src/utils/TcpReceiver.cpp
Normal 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
38
src/utils/TcpReceiver.h
Normal 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
294
src/utils/ipcclient.cpp
Normal 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
71
src/utils/ipcclient.h
Normal 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
82
src/utils/logger.c
Normal 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
38
src/utils/logger.h
Normal 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
84
src/utils/net.c
Normal 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
20
src/utils/net.h
Normal 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
702
src/utils/romfs_dev.c
Normal 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
90
src/utils/romfs_dev.h
Normal 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
88
src/utils/utils.c
Normal 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
39
src/utils/utils.h
Normal 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_
|
Loading…
Reference in New Issue
Block a user