diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..756d82d --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,26 @@ +SUBDIRS:= $(shell ls | egrep -v '^(CVS)$$') + +DATESTRING := $(shell date +%Y)$(shell date +%m)$(shell date +%d) + +#--------------------------------------------------------------------------------- +all: examples +#--------------------------------------------------------------------------------- + @rm -fr bin + @mkdir -p bin + @find . -name "*.3dsx" -exec cp -fv {} bin \; + +examples: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i || { exit 1;} fi; done; + +#--------------------------------------------------------------------------------- +clean: +#--------------------------------------------------------------------------------- + @rm -fr bin + @rm -f *.bz2 + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i clean || { exit 1;} fi; done; + +#--------------------------------------------------------------------------------- +dist: clean +#--------------------------------------------------------------------------------- + @rm -fr bin + @tar --exclude=.svn --exclude=*CVS* -cvjf 3ds-examples-$(DATESTRING).tar.bz2 * diff --git a/examples/app_launch/Makefile b/examples/app_launch/Makefile index c4c758e..8dce08d 100644 --- a/examples/app_launch/Makefile +++ b/examples/app_launch/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -120,7 +120,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/app_launch/source/main.c b/examples/app_launch/source/main.c index 807cb39..73cecb6 100644 --- a/examples/app_launch/source/main.c +++ b/examples/app_launch/source/main.c @@ -6,10 +6,7 @@ int main() { - srvInit(); // Needed - aptInit(); // Needed - gfxInit(); // Init graphic stuff - hidInit(NULL); // For input (buttons, touchscreen...) + gfxInitDefault(); // Init graphic stuff // We need these 2 buffers for APT_DoAppJump() later. They can be smaller too @@ -46,11 +43,7 @@ int main() } - // Deinit everything before the app process get's terminated - hidExit(); gfxExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/audio/mic/Makefile b/examples/audio/mic/Makefile new file mode 100644 index 0000000..8dce08d --- /dev/null +++ b/examples/audio/mic/Makefile @@ -0,0 +1,170 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/3ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# +# NO_SMDH: if set to anything, no SMDH file is generated. +# APP_TITLE is the name of the app stored in the SMDH file (Optional) +# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) +# APP_AUTHOR is the author of the app stored in the SMDH file (Optional) +# ICON is the filename of the icon (.png), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .png +# - icon.png +# - /default_icon.png +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard + +CFLAGS := -g -Wall -O2 -mword-relocations \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM11 -D_3DS + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lctru -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CTRULIB) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.png) + ifneq (,$(findstring $(TARGET).png,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).png + else + ifneq (,$(findstring icon.png,$(icons))) + export APP_ICON := $(TOPDIR)/icon.png + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +.PHONY: all +all : $(OUTPUT).3dsx $(OUTPUT).smdh +endif +$(OUTPUT).3dsx : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +# WARNING: This is not the right way to do this! TODO: Do it right! +#--------------------------------------------------------------------------------- +%.vsh.o : %.vsh +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin + @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h + @rm ../$(notdir $<).shbin + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/examples/mic/README.md b/examples/audio/mic/README.md similarity index 100% rename from examples/mic/README.md rename to examples/audio/mic/README.md diff --git a/examples/mic/source/main.c b/examples/audio/mic/source/main.c similarity index 95% rename from examples/mic/source/main.c rename to examples/audio/mic/source/main.c index 89ece51..2726a75 100644 --- a/examples/mic/source/main.c +++ b/examples/audio/mic/source/main.c @@ -13,11 +13,8 @@ int main() u8 control=0x40; u32 audio_initialized = 0; - srvInit(); - aptInit(); - gfxInit(); - hidInit(NULL); - + gfxInitDefault(); + if(CSND_initialize(NULL)==0)audio_initialized = 1; sharedmem = (u32*)memalign(0x1000, sharedmem_size); @@ -85,10 +82,7 @@ int main() free(sharedmem); linearFree(audiobuf); - hidExit(); gfxExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/get_system_language/Makefile b/examples/get_system_language/Makefile index 1ed1097..e6815d1 100644 --- a/examples/get_system_language/Makefile +++ b/examples/get_system_language/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -124,7 +124,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/get_system_language/source/main.c b/examples/get_system_language/source/main.c index d0fa815..4cbb874 100644 --- a/examples/get_system_language/source/main.c +++ b/examples/get_system_language/source/main.c @@ -6,7 +6,7 @@ int main(int argc, char** argv) { // Initialize services - gfxInit(); + gfxInitDefault(); initCfgu(); diff --git a/examples/gpu/Makefile b/examples/gpu/Makefile index c4c758e..f0728dc 100644 --- a/examples/gpu/Makefile +++ b/examples/gpu/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -120,7 +120,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: @@ -153,7 +153,7 @@ $(OUTPUT).elf : $(OFILES) # WARNING: This is not the right way to do this! TODO: Do it right! #--------------------------------------------------------------------------------- -%.vsh.o : %.vsh +%_vsh.h %.vsh.o : %.vsh #--------------------------------------------------------------------------------- @echo $(notdir $<) @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin diff --git a/examples/gpu/README.md b/examples/gpu/README.md index 5c9c899..7d7ecf7 100644 --- a/examples/gpu/README.md +++ b/examples/gpu/README.md @@ -1,5 +1,11 @@ gpu ======= -example of how to use the GPU with ctrulib -before trying to compile, make sure to download aemstro ( https://github.com/smealum/aemstro ) and update Makefile's AEMSTROPATH definition with the proper path +example of how to use the GPU with libctru + +before trying to compile, make sure to download aemstro +( https://github.com/smealum/aemstro reflog: 55bf5056d199e0e9ec3d136dc830ac45a49da074 ) +and update Makefile's AEMSTROPATH definition with the proper path + +You'll also need to install Python 3 and have that in your path. + diff --git a/examples/gpu/source/main.c b/examples/gpu/source/main.c index 5747637..3662ccd 100644 --- a/examples/gpu/source/main.c +++ b/examples/gpu/source/main.c @@ -114,13 +114,13 @@ const vertex_s modelVboData[]= //stolen from staplebutt void GPU_SetDummyTexEnv(u8 num) { - GPU_SetTexEnv(num, - GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), - GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), - GPU_TEVOPERANDS(0,0,0), - GPU_TEVOPERANDS(0,0,0), - GPU_REPLACE, - GPU_REPLACE, + GPU_SetTexEnv(num, + GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), + GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), + GPU_TEVOPERANDS(0,0,0), + GPU_TEVOPERANDS(0,0,0), + GPU_REPLACE, + GPU_REPLACE, 0xFFFFFFFF); } @@ -128,31 +128,31 @@ void GPU_SetDummyTexEnv(u8 num) void renderFrame() { GPU_SetViewport((u32*)osConvertVirtToPhys((u32)gpuDOut),(u32*)osConvertVirtToPhys((u32)gpuOut),0,0,240*2,400); - + GPU_DepthRange(-1.0f, 0.0f); GPU_SetFaceCulling(GPU_CULL_BACK_CCW); GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00); GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP); GPU_SetBlendingColor(0,0,0,0); GPU_SetDepthTestAndWriteMask(true, GPU_GREATER, GPU_WRITE_ALL); - - GPUCMD_AddSingleParam(0x00010062, 0); + + GPUCMD_AddSingleParam(0x00010062, 0); GPUCMD_AddSingleParam(0x000F0118, 0); - + //setup shader SHDR_UseProgram(shader, 0); - + GPU_SetAlphaBlending(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00); - + GPU_SetTextureEnable(GPU_TEXUNIT0); - - GPU_SetTexEnv(0, - GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR), + + GPU_SetTexEnv(0, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR), - GPU_TEVOPERANDS(0,0,0), - GPU_TEVOPERANDS(0,0,0), - GPU_MODULATE, GPU_MODULATE, + GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR), + GPU_TEVOPERANDS(0,0,0), + GPU_TEVOPERANDS(0,0,0), + GPU_MODULATE, GPU_MODULATE, 0xFFFFFFFF); GPU_SetDummyTexEnv(1); GPU_SetDummyTexEnv(2); @@ -189,11 +189,8 @@ void renderFrame() int main(int argc, char** argv) { - //setup services - srvInit(); - aptInit(); - gfxInit(); - hidInit(NULL); + + gfxInitDefault(); //initialize GPU GPU_Init(NULL); @@ -321,9 +318,6 @@ int main(int argc, char** argv) } gsExit(); - hidExit(); gfxExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/graphics/Makefile b/examples/graphics/Makefile new file mode 100644 index 0000000..bce05ec --- /dev/null +++ b/examples/graphics/Makefile @@ -0,0 +1,7 @@ +SUBDIRS:= `ls | egrep -v '^(CVS)$$'` +all: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i || { exit 1;} fi; done; +clean: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i clean || { exit 1;} fi; done; +install: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i install || { exit 1;} fi; done; diff --git a/examples/graphics/bitmap/24bit-color/Makefile b/examples/graphics/bitmap/24bit-color/Makefile new file mode 100755 index 0000000..acbfaf4 --- /dev/null +++ b/examples/graphics/bitmap/24bit-color/Makefile @@ -0,0 +1,190 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/3ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# +# NO_SMDH: if set to anything, no SMDH file is generated. +# APP_TITLE is the name of the app stored in the SMDH file (Optional) +# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) +# APP_AUTHOR is the author of the app stored in the SMDH file (Optional) +# ICON is the filename of the icon (.png), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .png +# - icon.png +# - /default_icon.png +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := +INCLUDES := include +GRAPHICS := gfx + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard + +CFLAGS := -g -Wall -O2 -mword-relocations \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM11 -D_3DS + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lctru -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CTRULIB) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(PNGFILES:.png=.bgr.o) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) \ + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.png) + ifneq (,$(findstring $(TARGET).png,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).png + else + ifneq (,$(findstring icon.png,$(icons))) + export APP_ICON := $(TOPDIR)/icon.png + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +IMAGEMAGICK := $(shell which convert) + + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +ifeq ($(strip $(IMAGEMAGICK)),) + +all: + @echo "Image Magick not found!" + @echo + @echo "Please install Image Magick from http://www.imagemagick.org/ to build this example" + +else + +all: $(BUILD) + +endif + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +.PHONY: all +all : $(OUTPUT).3dsx $(OUTPUT).smdh +endif +$(OUTPUT).3dsx : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + + +#--------------------------------------------------------------------------------- +%.bgr.o: %.bgr +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.bgr: %.png +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @convert $< -rotate 90 $@ + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/examples/graphics/bitmap/24bit-color/README.md b/examples/graphics/bitmap/24bit-color/README.md new file mode 100644 index 0000000..50fff6d --- /dev/null +++ b/examples/graphics/bitmap/24bit-color/README.md @@ -0,0 +1,16 @@ +24bit Bitmap Example +======= + +This example shows on bottom screen an upscaled version of the nds examples Drunken Coders logo that can be found in devkitPro. + +If you want to try with your own image follow these steps: + +1. Download & install: http://www.imagemagick.org/ (If you get an option to add the application to the path make sure to check it!). +2. convert fileIn.png -channel B -separate fileIn.png -channel G -separate fileIn.png -channel R -separate -channel RGB -combine -rotate 90 fileOut.rgb +3. Rename fileOut.rgb in fileOut.bin +4. Copy fileOut.bin in the data folder of your project +5. Replace any reference of drunkenlogo_bin in main.cpp with fileOut_bin (or however you named it) +6. Re-Build the project + + +As you can see from the previos steps the image is clockwise rotated by 90 degrees and its B and R channels are swapped. The first operation is done because the 3DS screens are actually portrait screens rotated by 90 degrees (in a counter-clockwise direction), while the second one is done because the 3DS screens' framebuffers have a BGR888 color format, by default. \ No newline at end of file diff --git a/examples/graphics/bitmap/24bit-color/gfx/brew.png b/examples/graphics/bitmap/24bit-color/gfx/brew.png new file mode 100644 index 0000000..6ac625b Binary files /dev/null and b/examples/graphics/bitmap/24bit-color/gfx/brew.png differ diff --git a/examples/graphics/bitmap/24bit-color/source/main.c b/examples/graphics/bitmap/24bit-color/source/main.c new file mode 100644 index 0000000..a6ac76e --- /dev/null +++ b/examples/graphics/bitmap/24bit-color/source/main.c @@ -0,0 +1,64 @@ +/* + Hello World example made by Aurelio Mannara for ctrulib + This code was modified for the last time on: 12/13/2014 01:00 UTC+1 + + This wouldn't be possible without the amazing work done by: + -Smealum + -fincs + -WinterMute + -yellows8 + -plutoo + -mtheall + -Many others who worked on 3DS and I'm surely forgetting about +*/ + +#include <3ds.h> +#include +#include + +//This include a header containing definitions of our image +#include "brew_bgr.h" + +int main(int argc, char **argv) +{ + gfxInitDefault(); + + //Initialize console on top screen. Using NULL as the second argument tells the console library to use the internal console structure as current one + consoleInit(GFX_TOP, NULL); + + printf("Why so sad Smealum? We can haz 3DS homebrew!"); + + printf("\x1b[20;15HPress Start to exit."); + + //We don't need double buffering in this example. In this way we can draw our image only once on screen. + gfxSetDoubleBuffering(GFX_BOTTOM, false); + + //Get the bottom screen's frame buffer + u8* fb = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + + //Copy our image in the bottom screen's frame buffer + memcpy(fb, brew_bgr, brew_bgr_size); + + // Main loop + while (aptMainLoop()) + { + //Scan all the inputs. This should be done once for each frame + hidScanInput(); + + //hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame) + u32 kDown = hidKeysDown(); + + if (kDown & KEY_START) break; // break in order to return to hbmenu + + // Flush and swap framebuffers + gfxFlushBuffers(); + gfxSwapBuffers(); + + //Wait for VBlank + gspWaitForVBlank(); + } + + // Exit services + gfxExit(); + return 0; +} diff --git a/examples/graphics/printing/Makefile b/examples/graphics/printing/Makefile new file mode 100644 index 0000000..bce05ec --- /dev/null +++ b/examples/graphics/printing/Makefile @@ -0,0 +1,7 @@ +SUBDIRS:= `ls | egrep -v '^(CVS)$$'` +all: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i || { exit 1;} fi; done; +clean: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i clean || { exit 1;} fi; done; +install: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i install || { exit 1;} fi; done; diff --git a/examples/graphics/printing/hello-world/Makefile b/examples/graphics/printing/hello-world/Makefile index c4c758e..8dce08d 100755 --- a/examples/graphics/printing/hello-world/Makefile +++ b/examples/graphics/printing/hello-world/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -120,7 +120,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/graphics/printing/hello-world/source/main.c b/examples/graphics/printing/hello-world/source/main.c index a954290..260b017 100644 --- a/examples/graphics/printing/hello-world/source/main.c +++ b/examples/graphics/printing/hello-world/source/main.c @@ -17,17 +17,13 @@ int main(int argc, char **argv) { - // Initialize services - srvInit(); - aptInit(); - gfxInit(); - hidInit(NULL); + gfxInitDefault(); //Initialize console on top screen. Using NULL as the second argument tells the console library to use the internal console structure as current one consoleInit(GFX_TOP, NULL); - //Move the cursor to row 15 and column 19 and then prints "Hello World!" - //To move the cursor you have tu print "\x1b[r;cH", where r and c are respectively + //Move the cursor to row 15 and column 19 and then prints "Hello World!" + //To move the cursor you have to print "\x1b[r;cH", where r and c are respectively //the row and column where you want your cursor to move //The top screen has 30 rows and 50 columns //The bottom screen has 30 rows and 40 columns @@ -54,10 +50,6 @@ int main(int argc, char **argv) gspWaitForVBlank(); } - // Exit services gfxExit(); - hidExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/http/Makefile b/examples/http/Makefile index c4c758e..8dce08d 100644 --- a/examples/http/Makefile +++ b/examples/http/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -120,7 +120,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/http/source/main.c b/examples/http/source/main.c index bb93652..2ef2bbe 100644 --- a/examples/http/source/main.c +++ b/examples/http/source/main.c @@ -1,27 +1,18 @@ #include #include +#include +#include #include <3ds.h> Result http_download(httpcContext *context)//This error handling needs updated with proper text printing once ctrulib itself supports that. { Result ret=0; - u8* framebuf_top, *framebuf_bottom; + u8* framebuf_top; u32 statuscode=0; u32 size=0, contentsize=0; u8 *buf; - framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); - memset(framebuf_bottom, 0x40, 240*320*3); - gfxFlushBuffers(); - gfxSwapBuffers(); - - framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); - memset(framebuf_bottom, 0x40, 240*320*3); - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank(); - ret = httpcBeginRequest(context); if(ret!=0)return ret; @@ -33,23 +24,13 @@ Result http_download(httpcContext *context)//This error handling needs updated w ret=httpcGetDownloadSizeState(context, NULL, &contentsize); if(ret!=0)return ret; + printf("size: %"PRId32"\n",contentsize); + gfxFlushBuffers(); + buf = (u8*)malloc(contentsize); if(buf==NULL)return -1; memset(buf, 0, contentsize); - framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); - memset(framebuf_bottom, 0xc0, 240*320*3); - gfxFlushBuffers(); - gfxSwapBuffers(); - - framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); - memset(framebuf_bottom, 0xc0, 240*320*3); - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank(); - - framebuf_top = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); - framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); ret = httpcDownloadData(context, buf, contentsize, NULL); if(ret!=0) @@ -59,18 +40,15 @@ Result http_download(httpcContext *context)//This error handling needs updated w } size = contentsize; - if(size>(240*400*3))size = 240*400*3; + if(size>(240*400*3*2))size = 240*400*3*2; - memset(framebuf_bottom, 0xff, 240*320*3); + framebuf_top = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); memcpy(framebuf_top, buf, size); gfxFlushBuffers(); gfxSwapBuffers(); framebuf_top = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); - framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); - - memset(framebuf_bottom, 0xff, 240*320*3); memcpy(framebuf_top, buf, size); gfxFlushBuffers(); @@ -87,19 +65,26 @@ int main() Result ret=0; httpcContext context; - // Initialize services - srvInit(); - aptInit(); - hidInit(NULL); - gfxInit(); - //gfxSet3D(true); // uncomment if using stereoscopic 3D + gfxInitDefault(); httpcInit(); - ret = httpcOpenContext(&context, "http://10.0.0.3/httpexample_rawimg.bin", 0);//Change this to your own URL. + consoleInit(GFX_BOTTOM,NULL); + + //Change this to your own URL. + char *url = "http://devkitpro.org/misc/httpexample_rawimg.rgb"; + + printf("Downloading %s\n",url); + gfxFlushBuffers(); + + ret = httpcOpenContext(&context, url , 0); + printf("return from httpcOpenContext: %"PRId32"\n",ret); + gfxFlushBuffers(); if(ret==0) { ret=http_download(&context); + printf("return from http_download: %"PRId32"\n",ret); + gfxFlushBuffers(); httpcCloseContext(&context); } @@ -123,9 +108,6 @@ int main() // Exit services httpcExit(); gfxExit(); - hidExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/mic/Makefile b/examples/input/read-controls/Makefile old mode 100644 new mode 100755 similarity index 99% rename from examples/mic/Makefile rename to examples/input/read-controls/Makefile index c4c758e..c21562a --- a/examples/mic/Makefile +++ b/examples/input/read-controls/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ diff --git a/examples/input/read-controls/source/main.c b/examples/input/read-controls/source/main.c new file mode 100644 index 0000000..bb9c2b3 --- /dev/null +++ b/examples/input/read-controls/source/main.c @@ -0,0 +1,105 @@ +/* + Circle Pad example made by Aurelio Mannara for ctrulib + Please refer to https://github.com/smealum/ctrulib/blob/master/libctru/include/3ds/services/hid.h for more information + This code was modified for the last time on: 12/13/2014 2:20 UTC+1 + + This wouldn't be possible without the amazing work done by: + -Smealum + -fincs + -WinterMute + -yellows8 + -plutoo + -mtheall + -Many others who worked on 3DS and I'm surely forgetting about +*/ + +#include <3ds.h> +#include + +int main(int argc, char **argv) +{ + //Matrix containing the name of each key. Useful for printing when a key is pressed + char keysNames[32][32] = { + "KEY_A", "KEY_B", "KEY_SELECT", "KEY_START", + "KEY_DRIGHT", "KEY_DLEFT", "KEY_DUP", "KEY_DDOWN", + "KEY_R", "KEY_L", "KEY_X", "KEY_Y", + "", "", "KEY_ZL", "KEY_ZR", + "", "", "", "", + "KEY_TOUCH", "", "", "", + "KEY_CSTICK_RIGHT", "KEY_CSTICK_LEFT", "KEY_CSTICK_UP", "KEY_CSTICK_DOWN", + "KEY_CPAD_RIGHT", "KEY_CPAD_LEFT", "KEY_CPAD_UP", "KEY_CPAD_DOWN" + }; + + // Initialize services + gfxInitDefault(); + + //Initialize console on top screen. Using NULL as the second argument tells the console library to use the internal console structure as current one + consoleInit(GFX_TOP, NULL); + + u32 kDownOld = 0, kHeldOld = 0, kUpOld = 0; //In these variables there will be information about keys detected in the previous frame + + printf("\x1b[0;0HPress Start to exit."); + printf("\x1b[1;0HCirclePad position:"); + + // Main loop + while (aptMainLoop()) + { + //Scan all the inputs. This should be done once for each frame + hidScanInput(); + + //hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame) + u32 kDown = hidKeysDown(); + //hidKeysHeld returns information about which buttons have are held down in this frame + u32 kHeld = hidKeysHeld(); + //hidKeysUp returns information about which buttons have been just released + u32 kUp = hidKeysUp(); + + if (kDown & KEY_START) break; // break in order to return to hbmenu + + //Do the keys printing only if keys have changed + if (kDown != kDownOld || kHeld != kHeldOld || kUp != kUpOld) + { + //Clear console + consoleClear(); + + //These two lines must be rewritten because we cleared the whole console + printf("\x1b[0;0HPress Start to exit."); + printf("\x1b[1;0HCirclePad position:"); + + printf("\x1b[3;0H"); //Move the cursor to the fourth row because on the third one we'll write the circle pad position + + //Check if some of the keys are down, held or up + int i; + for (i = 0; i < 32; i++) + { + if (kDown & BIT(i)) printf("%s down\n", keysNames[i]); + if (kHeld & BIT(i)) printf("%s held\n", keysNames[i]); + if (kUp & BIT(i)) printf("%s up\n", keysNames[i]); + } + } + + //Set keys old values for the next frame + kDownOld = kDown; + kHeldOld = kHeld; + kUpOld = kUp; + + circlePosition pos; + + //Read the CirclePad position + hidCircleRead(&pos); + + //Print the CirclePad position + printf("\x1b[2;0H%04d; %04d", pos.dx, pos.dy); + + // Flush and swap framebuffers + gfxFlushBuffers(); + gfxSwapBuffers(); + + //Wait for VBlank + gspWaitForVBlank(); + } + + // Exit services + gfxExit(); + return 0; +} diff --git a/examples/libapplet_launch/Makefile b/examples/libapplet_launch/Makefile index c4c758e..8dce08d 100644 --- a/examples/libapplet_launch/Makefile +++ b/examples/libapplet_launch/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -120,7 +120,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/libapplet_launch/source/main.c b/examples/libapplet_launch/source/main.c index d4244a3..0e03373 100644 --- a/examples/libapplet_launch/source/main.c +++ b/examples/libapplet_launch/source/main.c @@ -4,11 +4,7 @@ int main() { u32 val, i; - // Initialize services - srvInit(); - aptInit(); - hidInit(NULL); - gfxInit(); + gfxInitDefault(); //gfxSet3D(true); // uncomment if using stereoscopic 3D val = 0x22447899; @@ -42,9 +38,6 @@ int main() // Exit services gfxExit(); - hidExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/mvd/Makefile b/examples/mvd/Makefile index c4c758e..8dce08d 100644 --- a/examples/mvd/Makefile +++ b/examples/mvd/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -120,7 +120,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/mvd/source/main.c b/examples/mvd/source/main.c index 3908a18..7e8aec4 100644 --- a/examples/mvd/source/main.c +++ b/examples/mvd/source/main.c @@ -106,13 +106,7 @@ void draw_startup() int main() { - // Initialize services - srvInit(); - aptInit(); - hidInit(NULL); - gfxInit(); - fsInit(); - sdmcInit(); + gfxInitDefault(); //gfxSet3D(true); // uncomment if using stereoscopic 3D memset(logstring, 0, 256); @@ -143,13 +137,7 @@ int main() if(inaddr)linearFree(inaddr); if(outaddr)linearFree(outaddr); - // Exit services - sdmcExit(); - fsExit(); gfxExit(); - hidExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/qtm/Makefile b/examples/qtm/Makefile index 1ed1097..e6815d1 100644 --- a/examples/qtm/Makefile +++ b/examples/qtm/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -124,7 +124,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/qtm/source/main.c b/examples/qtm/source/main.c index 5464a42..252e352 100644 --- a/examples/qtm/source/main.c +++ b/examples/qtm/source/main.c @@ -11,11 +11,7 @@ int main() qtmHeadtrackingInfo qtminfo; u32 colors[4] = {0x0000FF, 0x00FF00, 0xFF0000, 0xFFFFFF}; - // Initialize services - srvInit(); - aptInit(); - hidInit(NULL); - gfxInit(); + gfxInitDefault(); //gfxSet3D(true); // uncomment if using stereoscopic 3D qtmInit(); @@ -84,9 +80,6 @@ int main() // Exit services qtmExit(); gfxExit(); - hidExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/sdmc/Makefile b/examples/sdmc/Makefile index c4c758e..8dce08d 100644 --- a/examples/sdmc/Makefile +++ b/examples/sdmc/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -120,7 +120,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/sdmc/source/main.c b/examples/sdmc/source/main.c index b946f0a..7c91ab4 100644 --- a/examples/sdmc/source/main.c +++ b/examples/sdmc/source/main.c @@ -45,7 +45,7 @@ void renderEffect() int main(int argc, char** argv) { - gfxInit(); //makes displaying to screen easier + gfxInitDefault(); //makes displaying to screen easier FILE *file = fopen("test.bin","rb"); if (file == NULL) goto exit; diff --git a/examples/templates/Makefile b/examples/templates/Makefile new file mode 100644 index 0000000..bce05ec --- /dev/null +++ b/examples/templates/Makefile @@ -0,0 +1,7 @@ +SUBDIRS:= `ls | egrep -v '^(CVS)$$'` +all: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i || { exit 1;} fi; done; +clean: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i clean || { exit 1;} fi; done; +install: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i install || { exit 1;} fi; done; diff --git a/examples/templates/application/Makefile b/examples/templates/application/Makefile index 1ed1097..e6815d1 100644 --- a/examples/templates/application/Makefile +++ b/examples/templates/application/Makefile @@ -35,7 +35,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ @@ -124,7 +124,7 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: diff --git a/examples/templates/application/source/main.c b/examples/templates/application/source/main.c index df717a6..633c7ff 100644 --- a/examples/templates/application/source/main.c +++ b/examples/templates/application/source/main.c @@ -4,11 +4,7 @@ int main() { - // Initialize services - srvInit(); - aptInit(); - hidInit(NULL); - gfxInit(); + gfxInitDefault(); //gfxSet3D(true); // uncomment if using stereoscopic 3D // Main loop @@ -36,10 +32,6 @@ int main() gfxSwapBuffers(); } - // Exit services gfxExit(); - hidExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/templates/library/Makefile b/examples/templates/library/Makefile index 2e8b155..887909f 100644 --- a/examples/templates/library/Makefile +++ b/examples/templates/library/Makefile @@ -24,7 +24,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2\ $(ARCH) diff --git a/libctru/Makefile b/libctru/Makefile index 5ee809b..8a5c00c 100644 --- a/libctru/Makefile +++ b/libctru/Makefile @@ -9,7 +9,7 @@ endif include $(DEVKITARM)/base_rules export LIBCTRU_MAJOR := 0 -export LIBCTRU_MINOR := 2 +export LIBCTRU_MINOR := 4 export LIBCTRU_PATCH := 0 @@ -29,7 +29,8 @@ SOURCES := source \ source/gpu \ source/services \ source/services/soc \ - source/util \ + source/util/rbtree \ + source/util/utf \ source/system DATA := data @@ -38,7 +39,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard CFLAGS := -g -Wall -O2 -mword-relocations \ -fomit-frame-pointer -ffast-math \ diff --git a/libctru/data/default_font.bin b/libctru/data/default_font.bin index 73436fc..e3ae20b 100644 Binary files a/libctru/data/default_font.bin and b/libctru/data/default_font.bin differ diff --git a/libctru/include/3ds/console.h b/libctru/include/3ds/console.h index 48c7224..7901084 100644 --- a/libctru/include/3ds/console.h +++ b/libctru/include/3ds/console.h @@ -18,12 +18,13 @@ consoleInit() #define CONSOLE_H #include <3ds/types.h> +#include <3ds/gfx.h> #ifdef __cplusplus extern "C" { #endif -typedef bool(* ConsolePrint)(void* con, char c); +typedef bool(* ConsolePrint)(void* con, int c); //! a font struct for the console. typedef struct ConsoleFont diff --git a/libctru/include/3ds/gfx.h b/libctru/include/3ds/gfx.h index 9cfcae0..1d0e545 100644 --- a/libctru/include/3ds/gfx.h +++ b/libctru/include/3ds/gfx.h @@ -19,7 +19,8 @@ typedef enum }gfx3dSide_t; //system stuff -void gfxInit(); +void gfxInitDefault(); +void gfxInit(GSP_FramebufferFormats topFormat, GSP_FramebufferFormats bottomFormat, bool vrambuffers); void gfxExit(); //control stuff diff --git a/libctru/include/3ds/services/csnd.h b/libctru/include/3ds/services/csnd.h index f607955..5deac20 100644 --- a/libctru/include/3ds/services/csnd.h +++ b/libctru/include/3ds/services/csnd.h @@ -1,30 +1,106 @@ #pragma once +#include <3ds/types.h> +#define CSND_NUM_CHANNELS 32 #define CSND_SHAREDMEM_DEFAULT 0x10004000 -typedef enum{ - CSND_LOOP_DISABLE, - CSND_LOOP_ENABLE -} CSND_LOOPING; +#define CSND_TIMER(n) (0x3FEC3FC / ((u32)(n))) -typedef enum{ - CSND_ENCODING_PCM8, - CSND_ENCODING_PCM16, - CSND_ENCODING_IMA_ADPCM, - CSND_ENCODING_PSG//"3 = PSG, similar to DS?" -} CSND_ENCODING; +enum +{ + CSND_ENCODING_PCM8 = 0, + CSND_ENCODING_PCM16, + CSND_ENCODING_ADPCM, // IMA-ADPCM + CSND_ENCODING_PSG, // Similar to DS? +}; +enum +{ + CSND_LOOPMODE_MANUAL = 0, + CSND_LOOPMODE_NORMAL, + CSND_LOOPMODE_ONESHOT, + CSND_LOOPMODE_NORELOAD, +}; -//See here regarding CSND shared-mem commands, etc: http://3dbrew.org/wiki/CSND_Shared_Memory +#define SOUND_CHANNEL(n) ((u32)(n) & 0x1F) +#define SOUND_FORMAT(n) ((u32)(n) << 12) +#define SOUND_LOOPMODE(n) ((u32)(n) << 10) -Result CSND_initialize(u32* sharedMem); -Result CSND_shutdown(); +enum +{ + SOUND_LINEAR_INTERP = BIT(6), + SOUND_REPEAT = SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL), + SOUND_ONE_SHOT = SOUND_LOOPMODE(CSND_LOOPMODE_ONESHOT), + SOUND_FORMAT_8BIT = SOUND_FORMAT(CSND_ENCODING_PCM8), + SOUND_FORMAT_16BIT = SOUND_FORMAT(CSND_ENCODING_PCM16), + SOUND_FORMAT_ADPCM = SOUND_FORMAT(CSND_ENCODING_ADPCM), + SOUND_FORMAT_PSG = SOUND_FORMAT(CSND_ENCODING_PSG), + SOUND_ENABLE = BIT(14), +}; -Result CSND_playsound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u32 *vaddr0, u32 *vaddr1, u32 totalbytesize, u32 unk0, u32 unk1); -void CSND_setchannel_playbackstate(u32 channel, u32 value); -void CSND_sharedmemtype0_cmd0(u32 channel, u32 value); -void CSND_writesharedmem_cmdtype0(u16 cmdid, u8 *cmdparams); -Result CSND_sharedmemtype0_cmdupdatestate(int waitdone); +// Duty cycles for a PSG channel +enum +{ + DutyCycle_0 = 7, /*!< 0.0% duty cycle */ + DutyCycle_12 = 0, /*!< 12.5% duty cycle */ + DutyCycle_25 = 1, /*!< 25.0% duty cycle */ + DutyCycle_37 = 2, /*!< 37.5% duty cycle */ + DutyCycle_50 = 3, /*!< 50.0% duty cycle */ + DutyCycle_62 = 4, /*!< 62.5% duty cycle */ + DutyCycle_75 = 5, /*!< 75.0% duty cycle */ + DutyCycle_87 = 6 /*!< 87.5% duty cycle */ +}; -Result CSND_getchannelstate(u32 entryindex, u32 *out); -Result CSND_getchannelstate_isplaying(u32 entryindex, u8 *status); +typedef union +{ + u32 value[3]; + struct + { + u8 active; + u8 _pad1; + u16 _pad2; + s16 adpcmSample; + u8 adpcmIndex; + u8 _pad3; + u32 samplePAddr; + }; +} CSND_ChnInfo; + +// See here regarding CSND shared-mem commands, etc: http://3dbrew.org/wiki/CSND_Shared_Memory + +extern vu32* csndSharedMem; +extern u32 csndSharedMemSize; +extern u32 csndChannels; // Bitmask of channels that are allowed for usage + +Result CSND_AcquireCapUnit(u32* capUnit); +Result CSND_ReleaseCapUnit(u32 capUnit); + +Result csndInit(void); +Result csndExit(void); + +void csndWriteCmd(int cmdid, u8 *cmdparams); +Result csndExecCmds(bool waitDone); + +void CSND_SetPlayStateR(u32 channel, u32 value); +void CSND_SetPlayState(u32 channel, u32 value); +void CSND_SetBlock(u32 channel, int block, u32 physaddr, u32 size); +void CSND_SetVol(u32 channel, u16 left, u16 right); +void CSND_SetTimer(u32 channel, u32 timer); +void CSND_SetDuty(u32 channel, u32 duty); +void CSND_SetAdpcmState(u32 channel, int block, int sample, int index); +void CSND_SetAdpcmReload(u32 channel, bool reload); +void CSND_SetChnRegs(u32 flags, u32 physaddr0, u32 physaddr1, u32 totalbytesize); + +void CSND_CapEnable(u32 capUnit, bool enable); +void CSND_CapSetBit(u32 capUnit, int bit, bool state); // Sets bit0..2 in the CNT register, purpose currently unknown +void CSND_CapSetTimer(u32 capUnit, u32 timer); +void CSND_CapSetBuffer(u32 capUnit, u32 paddr, u32 size); + +Result CSND_UpdateInfo(bool waitDone); + +Result csndPlaySound(int chn, u32 flags, u32 sampleRate, void* data0, void* data1, u32 size); + +CSND_ChnInfo* csndGetChnInfo(u32 channel); // Requires previous CSND_UpdateInfo() + +Result csndGetState(u32 channel, CSND_ChnInfo* out); +Result csndIsPlaying(u32 channel, u8* status); diff --git a/libctru/include/3ds/services/soc.h b/libctru/include/3ds/services/soc.h index 55ff21e..3ec99b7 100644 --- a/libctru/include/3ds/services/soc.h +++ b/libctru/include/3ds/services/soc.h @@ -1,11 +1,8 @@ #pragma once Result SOC_Initialize(u32 *context_addr, u32 context_size);//Example context_size: 0x48000. The specified context buffer can no longer be accessed by the process which called this function, since the userland permissions for this block are set to no-access. -Result SOC_Shutdown(); -int SOC_GetErrno(); Result SOC_Shutdown(void); -int SOC_GetErrno(void); /* this is supposed to be in unistd.h but newlib only puts it for cygwin */ long gethostid(void); diff --git a/libctru/include/3ds/types.h b/libctru/include/3ds/types.h index 2f7d01a..88d09fc 100644 --- a/libctru/include/3ds/types.h +++ b/libctru/include/3ds/types.h @@ -39,6 +39,12 @@ typedef volatile s64 vs64; typedef u32 Handle; typedef s32 Result; -typedef void (*ThreadFunc)(u32); +typedef void (*ThreadFunc)(void *); #define BIT(n) (1U<<(n)) + +//! aligns a struct (and other types?) to m, making sure that the size of the struct is a multiple of m. +#define ALIGN(m) __attribute__((aligned (m))) + +//! packs a struct (and other types?) so it won't include padding bytes. +#define PACKED __attribute__ ((packed)) diff --git a/libctru/include/3ds/util/utf.h b/libctru/include/3ds/util/utf.h new file mode 100644 index 0000000..eaaae25 --- /dev/null +++ b/libctru/include/3ds/util/utf.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include + +/*! Convert a UTF-8 sequence into a UTF-32 codepoint + * + * @param[out] out Output codepoint + * @param[in] in Input sequence + * + * @returns number of input code units consumed + * @returns -1 for error + */ +ssize_t decode_utf8 (uint32_t *out, const uint8_t *in); + +/*! Convert a UTF-16 sequence into a UTF-32 codepoint + * + * @param[out] out Output codepoint + * @param[in] in Input sequence + * + * @returns number of input code units consumed + * @returns -1 for error + */ +ssize_t decode_utf16(uint32_t *out, const uint16_t *in); + +/*! Convert a UTF-32 codepoint into a UTF-8 sequence + * + * @param[out] out Output sequence + * @param[in] in Input codepoint + * + * @returns number of output code units produced + * @returns -1 for error + * + * @note \a out must be able to store 4 code units + */ +ssize_t encode_utf8 (uint8_t *out, uint32_t in); + +/*! Convert a UTF-32 codepoint into a UTF-16 sequence + * + * @param[out] out Output sequence + * @param[in] in Input codepoint + * + * @returns number of output code units produced + * @returns -1 for error + * + * @note \a out must be able to store 2 code units + */ +ssize_t encode_utf16(uint16_t *out, uint32_t in); + +/*! Convert a UTF-8 sequence into a UTF-16 sequence + * + * @param[out] out Output sequence + * @param[in] in Input sequence + * + * @returns number of output code units produced + * @returns -1 for error + */ +size_t utf8_to_utf16(uint16_t *out, const uint8_t *in, size_t len); + +/*! Convert a UTF-8 sequence into a UTF-32 sequence + * + * @param[out] out Output sequence + * @param[in] in Input sequence + * + * @returns number of output code units produced + * @returns -1 for error + */ +size_t utf8_to_utf32(uint32_t *out, const uint8_t *in, size_t len); + +/*! Convert a UTF-16 sequence into a UTF-8 sequence + * + * @param[out] out Output sequence + * @param[in] in Input sequence + * + * @returns number of output code units produced + * @returns -1 for error + */ +size_t utf16_to_utf8(uint8_t *out, const uint16_t *in, size_t len); + +/*! Convert a UTF-16 sequence into a UTF-32 sequence + * + * @param[out] out Output sequence + * @param[in] in Input sequence + * + * @returns number of output code units produced + * @returns -1 for error + */ +size_t utf16_to_utf32(uint32_t *out, const uint16_t *in, size_t len); + +/*! Convert a UTF-32 sequence into a UTF-8 sequence + * + * @param[out] out Output sequence + * @param[in] in Input sequence + * + * @returns number of output code units produced + * @returns -1 for error + */ +size_t utf32_to_utf8(uint8_t *out, const uint32_t *in, size_t len); + +/*! Convert a UTF-32 sequence into a UTF-16 sequence + * + * @param[out] out Output sequence + * @param[in] in Input sequence + * + * @returns number of output code units produced + * @returns -1 for error + */ +size_t utf32_to_utf16(uint16_t *out, const uint32_t *in, size_t len); diff --git a/libctru/include/netdb.h b/libctru/include/netdb.h index 7f769a4..b3fac81 100644 --- a/libctru/include/netdb.h +++ b/libctru/include/netdb.h @@ -22,6 +22,8 @@ extern "C" { extern int h_errno; struct hostent* gethostbyname(const char *name); + void herror(const char *s); + const char* hstrerror(int err); #ifdef __cplusplus } diff --git a/libctru/libctru.cfg b/libctru/libctru.cfg new file mode 100644 index 0000000..a9fcc28 --- /dev/null +++ b/libctru/libctru.cfg @@ -0,0 +1,2586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + linearAlloc + linearMemAlign + linearFree + + + vramAlloc + vramMemAlign + vramFree + + + + + + false + + + + false + + + + + false + + + + + false + + + + false + + + + false + + + + + + false + + + + + false + + + + + false + + + + + + false + + + + false + + + + + false + + + + + false + + + + false + + + + + + + + + + + false + + + + + false + + + + + + false + + + + + false + + + + + + + false + + + + + false + + + + + + false + + + + + false + + + + + + + false + + + + false + + + + false + + + + + + + + false + + + + false + + + + false + + + + + + false + + + + false + + + + + + + false + + + + + false + + + + + + + false + + + + + + false + + + + + false + + + + + false + + + + + + + false + + + + + + false + + + + false + + + + + + + false + + + + + + + false + + + + false + + + + + false + + + + + + + + + + false + + + + + + + + + false + + + + + + false + + + + + + + false + + + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + + + + false + + + + + false + + + + + + + + false + + + + + false + + + + + + + + + + false + + + + + + + + + + + + + false + + + + + false + + + + + false + + + + + + + + + + + + false + + + + + + false + + + + + + + false + + + + + false + + + + + + false + + + + + + + false + + + + + false + + + + + false + + + + + false + + + + + false + + + + + false + + + + + + + false + + + + + false + + + + + false + + + + false + + + + false + + + false + + + + + + + false + + + + false + + + + false + + + + + + false + + + + + + + false + + + + + + false + + + + + + false + + + + false + + + + false + + + + + + false + + + + + + + false + + + + + false + + + + + + false + + + + + false + + + + + false + + + + + false + + + + + + false + + + + + + false + + + + + + + + false + + + + false + + + + + false + + + + false + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + false + + + + + false + + + + false + + + + false + + + + false + + + + + + + false + + + + + + + false + + + + + false + + + + + + false + + + + + + + + + + false + + + + + false + + + + + + + false + + + + + false + + + + + + + + false + + + + + + false + + + + + + + + + + + false + + + + + + + + + + false + + + + + + + + + + false + + + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + false + + + + + + false + + + + + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + + + + false + + + + + + + + + false + + + + + + false + + + + + + + + + false + + + + + + + + + + false + + + + + false + + + + false + + + + + + + false + + + + + + + false + + + + + + false + + + + + + + + false + + + + false + + + + false + + + + + false + + + + + + false + + + + + false + + + + + false + + + + + false + + + + + + false + + + + + + false + + + + + + + false + + + + + + + false + + + + false + + + + false + + + + + false + + + + false + + + + + false + + + + + false + + + + false + + + + false + + + + + false + + + + + + false + + + + + false + + + + + + false + + + + + + false + + + + + + + + false + + + + + + + false + + + + + + false + + + + + + false + + + + + + + + false + + + + + + false + + + + + + + + false + + + + + false + + + + + + false + + + + + + + false + + + + + + false + + + + + + + false + + + + + + + + + + false + + + + + false + + + + + + false + + + + + + + + false + + + + + + false + + + + false + + + + false + + + + false + + + + + + + + + false + + + + + + + + + + false + + + + + + + false + + + + + + + + + false + + + + + + + false + + + + false + + + + + + + + false + + + + + + + false + + + + + + + + + false + + + + + + + false + + + + + false + + + + + false + + + + + + + + + false + + + + + + false + + + + + + false + + + + + false + + + + + false + + + + + + + + + false + + + + + + + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + false + + + + + + + + false + + + + + + + false + + + + false + + + + false + + + + + + + false + + + + false + + + + + + false + + + + false + + + + + + + + false + + + + + + + + + + false + + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + false + + + + + false + + + + + + + + + false + + + + + false + + + + + + false + + + + + false + + + + + + false + + + + + false + + + + + false + + + + + + + + false + + + + + + + + false + + + + + + + + false + + + + + + + + + + + + false + + + + + + + + + + false + + + + + + + + + + + false + + + + + + + + + + + + + false + + + + false + + + + false + + + + false + + + + + + false + + + + + + + + + + false + + + + + false + + + + false + + + + + + false + + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + + false + + + + + false + + + + + + + + + + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + + + + false + + + + false + + + + false + + + + + + false + + + + + false + + + + + + + false + + + + + false + + + + + + + false + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + + false + + + + + false + + + + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + + + + false + + + + + + false + + + + + + + + false + + + + + + + false + + + + + + + + false + + + + + + + + + false + + + + false + + + + false + + + + + + false + + + + false + + + + + + false + + + + + false + + + + + false + + + + + false + + + + + false + + + + + false + + + + + + false + + + + false + + + + false + + + + + false + + + + + + + + + + + false + + + + + false + + + + false + + + + + false + + + + + + false + + + + false + + + + false + + + + + false + + + + + + false + + + + false + + + + + + false + + + + + + + + + + + false + + + + false + + + + false + + + + + + + false + + + + + + false + + + + false + + + + + + + + + false + + + + false + + + + + false + + + + + false + + + + + false + + + + + false + + + + false + + + + + + + false + + + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + + + + + + + + + false + + + + + + + + false + + + + false + + + + + + + + + + false + + + + false + + + + false + + + + + + + false + + + + + + + + false + + + + false + + + + false + + + + + + + false + + + + + + + false + + + + + + false + + + + + + false + + + + + + + + + false + + + + false + + + + false + + + + + + + + + + false + + + + + + + + + + + + + + false + + + + + false + + + + + + + false + + + + false + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + + false + + + + + + + + false + + + + false + + + + false + + + + false + + + + + + false + + + + + false + + + + + + + + + + + false + + + + + + false + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + + false + + + + false + + + + + + + false + + + + + + + false + + + + + + false + + + + + + false + + + + + + true + + + + + + + false + + + + + + false + + + + + false + + + + + + + + false + + + + + + + false + + + + + + false + + + + + + + + false + + + + + + false + + + + + + + + false + + + + + false + + + + + + + false + + + + + false + + + + + + false + + + + + + + + + false + + + + + + + + + false + + + \ No newline at end of file diff --git a/libctru/libctru.cppcheck b/libctru/libctru.cppcheck new file mode 100644 index 0000000..caa2d77 --- /dev/null +++ b/libctru/libctru.cppcheck @@ -0,0 +1,2 @@ + + diff --git a/libctru/source/console.c b/libctru/source/console.c index c6469f2..6346d25 100644 --- a/libctru/source/console.c +++ b/libctru/source/console.c @@ -43,7 +43,7 @@ PrintConsole defaultConsole = { (u8*)default_font_bin, //font gfx 0, //first ascii character in the set - 128 //number of characters in the font set + 256 //number of characters in the font set }, (u16*)NULL, 0,0, //cursorX cursorY @@ -68,7 +68,7 @@ PrintConsole* currentConsole = ¤tCopy; PrintConsole* consoleGetDefault(void){return &defaultConsole;} -void consolePrintChar(char c); +void consolePrintChar(int c); void consoleDrawChar(int c); //--------------------------------------------------------------------------------- @@ -121,6 +121,7 @@ static void consoleCls(char mode) { break; } } + gfxFlushBuffers(); } //--------------------------------------------------------------------------------- static void consoleClearLine(char mode) { @@ -173,6 +174,7 @@ static void consoleClearLine(char mode) { break; } } + gfxFlushBuffers(); } @@ -605,6 +607,7 @@ static void newRow() { } consoleClearLine('2'); + gfxFlushBuffers(); } } //--------------------------------------------------------------------------------- @@ -672,7 +675,7 @@ void consoleDrawChar(int c) { } //--------------------------------------------------------------------------------- -void consolePrintChar(char c) { +void consolePrintChar(int c) { //--------------------------------------------------------------------------------- if (c==0) return; @@ -718,6 +721,7 @@ void consolePrintChar(char c) { newRow(); case 13: currentConsole->cursorX = 0; + gfxFlushBuffers(); break; default: consoleDrawChar(c); diff --git a/libctru/source/gfx.c b/libctru/source/gfx.c index 9c9aded..0688804 100644 --- a/libctru/source/gfx.c +++ b/libctru/source/gfx.c @@ -5,6 +5,7 @@ #include <3ds/gfx.h> #include <3ds/svc.h> #include <3ds/linear.h> +#include <3ds/vram.h> GSP_FramebufferInfo topFramebufferInfo, bottomFramebufferInfo; @@ -96,8 +97,23 @@ void gfxWriteFramebufferInfo(gfxScreen_t screen) framebufferInfoHeader[0x1]=1; } -void gfxInit() +void (*screenFree)(void *) = NULL; + +void gfxInit(GSP_FramebufferFormats topFormat, GSP_FramebufferFormats bottomFormat, bool vrambuffers) { + void *(*screenAlloc)(size_t); + + if (vrambuffers) + { + screenAlloc=vramAlloc; + screenFree=vramFree; + + } else { + + screenAlloc=linearAlloc; + screenFree=linearFree; + } + gspInit(); gfxSharedMemory=(u8*)0x10002000; @@ -117,15 +133,22 @@ void gfxInit() // if 3d enabled : // topright1 0x000FD200-0x00143700 // topright2 0x00143700-0x00189C00 + u32 topSize = 400 * 240 * __get_bytes_per_pixel(topFormat); + u32 bottomSize = 320 * 240 * __get_bytes_per_pixel(bottomFormat); + + gfxTopLeftFramebuffers[0]=screenAlloc(topSize); + gfxTopLeftFramebuffers[1]=screenAlloc(topSize); + gfxBottomFramebuffers[0]=screenAlloc(bottomSize); + gfxBottomFramebuffers[1]=screenAlloc(bottomSize); + gfxTopRightFramebuffers[0]=screenAlloc(topSize); + gfxTopRightFramebuffers[1]=screenAlloc(topSize); - gfxTopLeftFramebuffers[0]=linearAlloc(0x46500); - gfxTopLeftFramebuffers[1]=linearAlloc(0x46500); - gfxBottomFramebuffers[0]=linearAlloc(0x38400); - gfxBottomFramebuffers[1]=linearAlloc(0x38400); - gfxTopRightFramebuffers[0]=linearAlloc(0x46500); - gfxTopRightFramebuffers[1]=linearAlloc(0x46500); enable3d=false; + //set requested modes + gfxSetScreenFormat(GFX_TOP,topFormat); + gfxSetScreenFormat(GFX_BOTTOM,bottomFormat); + //initialize framebuffer info structures gfxSetFramebufferInfo(GFX_TOP, 0); gfxSetFramebufferInfo(GFX_BOTTOM, 0); @@ -143,18 +166,24 @@ void gfxInit() GSPGPU_SetLcdForceBlack(NULL, 0x0); } +void gfxInitDefault() { + gfxInit(GSP_BGR8_OES,GSP_BGR8_OES,false); +} + void gfxExit() { + if (screenFree == NULL ) return; + // Exit event handler gspExitEventHandler(); // Free framebuffers - linearFree(gfxTopRightFramebuffers[1]); - linearFree(gfxTopRightFramebuffers[0]); - linearFree(gfxBottomFramebuffers[1]); - linearFree(gfxBottomFramebuffers[0]); - linearFree(gfxTopLeftFramebuffers[1]); - linearFree(gfxTopLeftFramebuffers[0]); + screenFree(gfxTopRightFramebuffers[1]); + screenFree(gfxTopRightFramebuffers[0]); + screenFree(gfxBottomFramebuffers[1]); + screenFree(gfxBottomFramebuffers[0]); + screenFree(gfxTopLeftFramebuffers[1]); + screenFree(gfxTopLeftFramebuffers[0]); //unmap GSP shared mem svcUnmapMemoryBlock(gspSharedMemHandle, 0x10002000); @@ -167,6 +196,8 @@ void gfxExit() GSPGPU_ReleaseRight(NULL); gspExit(); + + screenFree = NULL; } u8* gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16* width, u16* height) @@ -185,9 +216,12 @@ u8* gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16* width, u16* hei void gfxFlushBuffers() { - GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x46500); - if(enable3d)GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), 0x46500); - GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), 0x38400); + u32 topSize = 400 * 240 * __get_bytes_per_pixel(gfxGetScreenFormat(GFX_TOP)); + u32 bottomSize = 320 * 240 * __get_bytes_per_pixel(gfxGetScreenFormat(GFX_BOTTOM)); + + GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), topSize); + if(enable3d)GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), topSize); + GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), bottomSize); } void gfxSwapBuffers() diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index d02c962..36d75fa 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -1,15 +1,17 @@ -#include #include -#include +#include #include +#include +#include +#include #include #include +#include -#include #include <3ds/types.h> #include <3ds/sdmc.h> #include <3ds/services/fs.h> - +#include <3ds/util/utf.h> /*! @internal @@ -19,6 +21,8 @@ * SDMC Device */ +static int sdmc_translate_error(Result error); + static int sdmc_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); static int sdmc_close(struct _reent *r, int fd); static ssize_t sdmc_write(struct _reent *r, int fd, const char *ptr, size_t len); @@ -40,6 +44,7 @@ static int sdmc_ftruncate(struct _reent *r, int fd, off_t len); static int sdmc_fsync(struct _reent *r, int fd); static int sdmc_chmod(struct _reent *r, const char *path, mode_t mode); static int sdmc_fchmod(struct _reent *r, int fd, mode_t mode); +static int sdmc_rmdir(struct _reent *r, const char *name); /*! @cond INTERNAL */ @@ -87,6 +92,7 @@ sdmc_devoptab = .deviceData = NULL, .chmod_r = sdmc_chmod, .fchmod_r = sdmc_fchmod, + .rmdir_r = sdmc_rmdir, }; /*! SDMC archive handle */ @@ -103,28 +109,106 @@ static FS_archive sdmcArchive = /*! @endcond */ -static char __cwd[PATH_MAX+1] = "/"; -static char __fixedpath[PATH_MAX+1]; +static char __cwd[PATH_MAX+1] = "/"; +static char __fixedpath[PATH_MAX+1]; +static uint16_t __utf16path[PATH_MAX+1]; -static const char *sdmc_fixpath(const char *path) +static const char* +sdmc_fixpath(struct _reent *r, + const char *path) { + size_t units; + uint32_t code; + const uint8_t *p = (const uint8_t*)path; + // Move the path pointer to the start of the actual path - if (strchr (path, ':') != NULL) + do { - path = strchr (path, ':') + 1; + units = decode_utf8(&code, p); + if(units == (size_t)-1) + { + r->_errno = EILSEQ; + return NULL; + } + + p += units; + } while(code != ':' && code != 0); + + // We found a colon; p points to the actual path + if(code == ':') + path = (const char*)p; + + // Make sure there are no more colons and that the + // remainder of the filename is valid UTF-8 + p = (const uint8_t*)path; + do + { + units = decode_utf8(&code, p); + if(units == (size_t)-1) + { + r->_errno = EILSEQ; + return NULL; + } + + if(code == ':') + { + r->_errno = EINVAL; + return NULL; + } + + p += units; + } while(code != 0); + + if(path[0] == '/') + strncpy(__fixedpath, path, PATH_MAX+1); + else + { + strncpy(__fixedpath, __cwd, PATH_MAX+1); + strncat(__fixedpath, path, PATH_MAX+1); } - if (strchr (path, ':') != NULL) return NULL; - - - if (path[0]=='/') return path; - - strncpy(__fixedpath,__cwd,PATH_MAX); - strncat(__fixedpath,path,PATH_MAX); - __fixedpath[PATH_MAX] = 0; + if(__fixedpath[PATH_MAX] != 0) + { + __fixedpath[PATH_MAX] = 0; + r->_errno = ENAMETOOLONG; + return NULL; + } return __fixedpath; +} +static const FS_path +sdmc_utf16path(struct _reent *r, + const char *path) +{ + size_t units; + FS_path fspath; + + fspath.data = NULL; + + if(sdmc_fixpath(r, path) == NULL) + return fspath; + + units = utf8_to_utf16(__utf16path, (const uint8_t*)__fixedpath, PATH_MAX+1); + if(units == (size_t)-1) + { + r->_errno = EILSEQ; + return fspath; + } + + if(__utf16path[PATH_MAX] != 0) + { + r->_errno = ENAMETOOLONG; + return fspath; + } + + __utf16path[units] = 0; + + fspath.type = PATH_WCHAR; + fspath.size = (units+1)*sizeof(uint16_t); + fspath.data = (const u8*)__utf16path; + + return fspath; } extern int __system_argc; @@ -135,29 +219,56 @@ static bool sdmcInitialised = false; /*! Initialize SDMC device */ Result sdmcInit(void) { - Result rc = 0; + size_t units; + uint32_t code; + char *p; + Result rc = 0; - if (sdmcInitialised) return rc; + if(sdmcInitialised) + return rc; rc = FSUSER_OpenArchive(NULL, &sdmcArchive); - - if(rc == 0) { int dev = AddDevice(&sdmc_devoptab); - if (dev != -1) { + if(dev != -1) + { setDefaultDevice(dev); - if (__system_argc != 0 && __system_argv[0] != NULL) + if(__system_argc != 0 && __system_argv[0] != NULL) { - if (FindDevice(__system_argv[0]) == dev) + if(FindDevice(__system_argv[0]) == dev) { strncpy(__fixedpath,__system_argv[0],PATH_MAX); - char *last_slash = strrchr(__fixedpath,'/'); - if (last_slash != NULL) { - last_slash[0] = 0; - chdir(__fixedpath); + if(__fixedpath[PATH_MAX] != 0) + { + __fixedpath[PATH_MAX] = 0; + } + else + { + char *last_slash = NULL; + p = __fixedpath; + do + { + units = decode_utf8(&code, (const uint8_t*)p); + if(units == (size_t)-1) + { + last_slash = NULL; + break; + } + + if(code == '/') + last_slash = p; + + p += units; + } while(code != 0); + + if(last_slash != NULL) + { + last_slash[0] = 0; + chdir(__fixedpath); + } } } } @@ -174,13 +285,14 @@ Result sdmcExit(void) { Result rc = 0; - if (!sdmcInitialised) return rc; + if(!sdmcInitialised) return rc; rc = FSUSER_CloseArchive(NULL, &sdmcArchive); if(rc == 0) + { RemoveDevice("sdmc"); - - sdmcInitialised = false; + sdmcInitialised = false; + } return rc; } @@ -207,15 +319,11 @@ sdmc_open(struct _reent *r, Result rc; u32 sdmc_flags = 0; u32 attributes = FS_ATTRIBUTE_NONE; - const char *pathptr = NULL; + FS_path fs_path; - pathptr = sdmc_fixpath(path); - - if(pathptr==NULL) - { - r->_errno=EINVAL; + fs_path = sdmc_utf16path(r, path); + if(fs_path.data == NULL) return -1; - } /* get pointer to our data */ sdmc_file_t *file = (sdmc_file_t*)fileStruct; @@ -256,14 +364,10 @@ sdmc_open(struct _reent *r, /* Test O_EXCL. */ if((flags & O_CREAT) && (flags & O_EXCL)) { - rc = FSUSER_CreateFile(NULL, sdmcArchive, FS_makePath(PATH_CHAR, pathptr), 0); + rc = FSUSER_CreateFile(NULL, sdmcArchive, fs_path, 0); if(rc != 0) { - r->_errno = rc; - if(rc == 0x82044BE) - r->_errno = EEXIST; - if(rc == 0x86044D2) - r->_errno = ENOSPC; + r->_errno = sdmc_translate_error(rc); return -1; } } @@ -273,7 +377,7 @@ sdmc_open(struct _reent *r, attributes |= FS_ATTRIBUTE_READONLY;*/ /* open the file */ - rc = FSUSER_OpenFile(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, pathptr), + rc = FSUSER_OpenFile(NULL, &fd, sdmcArchive, fs_path, sdmc_flags, attributes); if(rc == 0) { @@ -283,17 +387,18 @@ sdmc_open(struct _reent *r, if(rc != 0) { FSFILE_Close(fd); - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } } + file->fd = fd; file->flags = (flags & (O_ACCMODE|O_APPEND|O_SYNC)); file->offset = 0; return 0; } - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -318,7 +423,7 @@ sdmc_close(struct _reent *r, if(rc == 0) return 0; - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -339,9 +444,8 @@ sdmc_write(struct _reent *r, size_t len) { Result rc; - u32 bytes; + u32 bytes, bytesWritten = 0; u32 sync = 0; - u64 offset; /* get pointer to our data */ sdmc_file_t *file = (sdmc_file_t*)fd; @@ -355,38 +459,52 @@ sdmc_write(struct _reent *r, /* check if this is synchronous or not */ if(file->flags & O_SYNC) - sync = 0x10001; + sync = FS_WRITE_FLUSH; - /* initialize offset */ - offset = file->offset; if(file->flags & O_APPEND) { /* append means write from the end of the file */ - rc = FSFILE_GetSize(file->fd, &offset); + rc = FSFILE_GetSize(file->fd, &file->offset); if(rc != 0) { - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } } - /* TODO: Copy to internal buffer and write in chunks. - * You cannot write from read-only memory. + /* Copy to internal buffer and write in chunks. + * You cannot write from read-only memory. */ - - /* write the data */ - rc = FSFILE_Write(file->fd, &bytes, offset, (u32*)ptr, (u32)len, sync); - if(rc == 0) + static char tmp_buffer[8192]; + while(len > 0) { - /* update current file offset; if O_APPEND, this moves it to the - * new end-of-file - */ - file->offset = offset + bytes; - return (ssize_t)bytes; + size_t toWrite = len; + if(toWrite > sizeof(tmp_buffer)) + toWrite = sizeof(tmp_buffer); + + /* copy to internal buffer */ + memcpy(tmp_buffer, ptr, toWrite); + + /* write the data */ + rc = FSFILE_Write(file->fd, &bytes, file->offset, + (u32*)tmp_buffer, (u32)toWrite, sync); + if(rc != 0) + { + /* return partial transfer */ + if(bytesWritten > 0) + return bytesWritten; + + r->_errno = sdmc_translate_error(rc); + return -1; + } + + file->offset += bytes; + bytesWritten += bytes; + ptr += bytes; + len -= bytes; } - r->_errno = rc; - return -1; + return bytesWritten; } /*! Read from an open file @@ -427,7 +545,7 @@ sdmc_read(struct _reent *r, return (ssize_t)bytes; } - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -471,7 +589,7 @@ sdmc_seek(struct _reent *r, rc = FSFILE_GetSize(file->fd, &offset); if(rc != 0) { - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } break; @@ -509,7 +627,21 @@ sdmc_fstat(struct _reent *r, int fd, struct stat *st) { - r->_errno = ENOSYS; + Result rc; + u64 size; + sdmc_file_t *file = (sdmc_file_t*)fd; + + rc = FSFILE_GetSize(file->fd, &size); + if(rc == 0) + { + memset(st, 0, sizeof(struct stat)); + st->st_size = (off_t)size; + st->st_nlink = 1; + st->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + return 0; + } + + r->_errno = sdmc_translate_error(rc); return -1; } @@ -527,48 +659,33 @@ sdmc_stat(struct _reent *r, const char *file, struct stat *st) { - Handle fd; - Result rc; - const char *pathptr = NULL; + Handle fd; + Result rc; + FS_path fs_path; - pathptr = sdmc_fixpath(file); - - if(pathptr==NULL) - { - r->_errno=EINVAL; + fs_path = sdmc_utf16path(r, file); + if(fs_path.data == NULL) return -1; - } - if( (rc = FSUSER_OpenFile(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, pathptr), - FS_OPEN_READ, FS_ATTRIBUTE_NONE))==0) + if((rc = FSUSER_OpenFile(NULL, &fd, sdmcArchive, fs_path, + FS_OPEN_READ, FS_ATTRIBUTE_NONE)) == 0) { - u64 tmpsize = 0; - rc = FSFILE_GetSize(fd, &tmpsize); - + sdmc_file_t tmpfd = { .fd = fd }; + rc = sdmc_fstat(r, (int)&tmpfd, st); FSFILE_Close(fd); - if(rc==0) - { - memset(st, 0, sizeof(struct stat)); - st->st_size = (off_t)tmpsize; - st->st_nlink = 1; - st->st_uid = 1; - st->st_gid = 2; - st->st_mode = S_IFREG | S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH; - return 0; - } + return rc; + } + else if((rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, fs_path)) == 0) + { + memset(st, 0, sizeof(struct stat)); + st->st_nlink = 1; + st->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; + FSDIR_Close(fd); + return 0; } - if( (rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, pathptr))) == 0 ) - { - memset(st, 0, sizeof(struct stat)); - st->st_nlink = 1; - st->st_uid = 1; - st->st_gid = 2; - st->st_mode = S_IFDIR | S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH; - return 0; - } - r->_errno = EBADF; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -602,7 +719,18 @@ static int sdmc_unlink(struct _reent *r, const char *name) { - r->_errno = ENOSYS; + Result rc; + FS_path fs_path; + + fs_path = sdmc_utf16path(r, name); + if(fs_path.data == NULL) + return -1; + + rc = FSUSER_DeleteFile(NULL, sdmcArchive, fs_path); + if(rc == 0) + return 0; + + r->_errno = sdmc_translate_error(rc); return -1; } @@ -618,32 +746,24 @@ static int sdmc_chdir(struct _reent *r, const char *name) { - Handle fd; - Result rc; - const char *pathptr = NULL; + Handle fd; + Result rc; + FS_path fs_path; - pathptr = sdmc_fixpath(name); - - if(pathptr==NULL) - { - r->_errno=EINVAL; + fs_path = sdmc_utf16path(r, name); + if(fs_path.data == NULL) return -1; - } - rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, pathptr)); + rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, fs_path); if(rc == 0) { FSDIR_Close(fd); - strncpy(__cwd,pathptr,PATH_MAX); - } - else - { - r->_errno=EINVAL; - return -1; + strncpy(__cwd, __fixedpath, PATH_MAX); + return 0; } - return 0; - + r->_errno = sdmc_translate_error(rc); + return -1; } /*! Rename a file @@ -660,7 +780,30 @@ sdmc_rename(struct _reent *r, const char *oldName, const char *newName) { - r->_errno = ENOSYS; + Result rc; + FS_path fs_path_old, fs_path_new; + static uint16_t __utf16path_old[PATH_MAX+1]; + + fs_path_old = sdmc_utf16path(r, oldName); + if(fs_path_old.data == NULL) + return -1; + + memcpy(__utf16path_old, __utf16path, sizeof(__utf16path)); + fs_path_old.data = (const u8*)__utf16path_old; + + fs_path_new = sdmc_utf16path(r, newName); + if(fs_path_new.data == NULL) + return -1; + + rc = FSUSER_RenameFile(NULL, sdmcArchive, fs_path_old, sdmcArchive, fs_path_new); + if(rc == 0) + return 0; + + rc = FSUSER_RenameDirectory(NULL, sdmcArchive, fs_path_old, sdmcArchive, fs_path_new); + if(rc == 0) + return 0; + + r->_errno = sdmc_translate_error(rc); return -1; } @@ -679,23 +822,19 @@ sdmc_mkdir(struct _reent *r, int mode) { Result rc; - const char *pathptr = NULL; + FS_path fs_path; - pathptr = sdmc_fixpath(path); - - if(pathptr==NULL) - { - r->_errno=EINVAL; + fs_path = sdmc_utf16path(r, path); + if(fs_path.data == NULL) return -1; - } /* TODO: Use mode to set directory attributes. */ - rc = FSUSER_CreateDirectory(NULL, sdmcArchive, FS_makePath(PATH_CHAR, pathptr)); + rc = FSUSER_CreateDirectory(NULL, sdmcArchive, fs_path); if(rc == 0) return 0; - r->_errno = ENOSYS; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -713,23 +852,20 @@ sdmc_diropen(struct _reent *r, DIR_ITER *dirState, const char *path) { - Handle fd; - Result rc; - const char *pathptr = NULL; + Handle fd; + Result rc; + FS_path fs_path; - pathptr = sdmc_fixpath(path); + fs_path = sdmc_utf16path(r, path); - if(pathptr==NULL) - { - r->_errno=EINVAL; + if(fs_path.data == NULL) return NULL; - } /* get pointer to our data */ sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct); /* open the directory */ - rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, pathptr)); + rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, fs_path); if(rc == 0) { dir->fd = fd; @@ -737,7 +873,7 @@ sdmc_diropen(struct _reent *r, return dirState; } - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return NULL; } @@ -773,14 +909,15 @@ sdmc_dirnext(struct _reent *r, char *filename, struct stat *filestat) { - Result rc; - u32 entries; - u16 *name; + Result rc; + u32 entries; + size_t units; /* get pointer to our data */ sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct); /* fetch the next entry */ + memset(&dir->entry_data, 0, sizeof(dir->entry_data)); rc = FSDIR_Read(dir->fd, &entries, 1, &dir->entry_data); if(rc == 0) { @@ -798,16 +935,25 @@ sdmc_dirnext(struct _reent *r, else filestat->st_mode = S_IFREG; - /* copy the name */ - name = dir->entry_data.name; - while(*name) - *filename++ = *name++; - *filename = 0; + /* convert name from UTF-16 to UTF-8 */ + memset(filename, 0, NAME_MAX); + units = utf16_to_utf8((uint8_t*)filename, dir->entry_data.name, NAME_MAX); + if(units == (size_t)-1) + { + r->_errno = EILSEQ; + return -1; + } + + if(filename[NAME_MAX-1] != 0) + { + r->_errno = ENAMETOOLONG; + return -1; + } return 0; } - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -833,7 +979,7 @@ sdmc_dirclose(struct _reent *r, if(rc == 0) return 0; - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -882,7 +1028,7 @@ sdmc_statvfs(struct _reent *r, return 0; } - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -917,7 +1063,7 @@ sdmc_ftruncate(struct _reent *r, if(rc == 0) return 0; - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -942,7 +1088,7 @@ sdmc_fsync(struct _reent *r, if(rc == 0) return 0; - r->_errno = rc; + r->_errno = sdmc_translate_error(rc); return -1; } @@ -981,3 +1127,91 @@ sdmc_fchmod(struct _reent *r, r->_errno = ENOSYS; return -1; } + +/*! Remove a directory + * + * @param[in,out] r newlib reentrancy struct + * @param[in] name Path of directory to remove + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_rmdir(struct _reent *r, + const char *name) +{ + Result rc; + FS_path fs_path; + + fs_path = sdmc_utf16path(r, name); + if(fs_path.data == NULL) + return -1; + + rc = FSUSER_DeleteDirectory(NULL, sdmcArchive, fs_path); + if(rc == 0) + return 0; + + r->_errno = sdmc_translate_error(rc); + return -1; +} + +/*! Error map */ +typedef struct +{ + Result fs_error; //!< Error from FS service + int error; //!< POSIX errno +} error_map_t; + +/*! Error table */ +static const error_map_t error_table[] = +{ + /* keep this list sorted! */ + { 0x082044BE, EEXIST, }, + { 0x086044D2, ENOSPC, }, + { 0xC8804478, ENOENT, }, + { 0xC92044FA, ENOENT, }, + { 0xE0E046BE, EINVAL, }, + { 0xE0E046BF, ENAMETOOLONG, }, +}; +static const size_t num_errors = sizeof(error_table)/sizeof(error_table[0]); + +/*! Comparison function for bsearch on error_table + * + * @param[in] p1 Left side of comparison + * @param[in] p2 Right side of comparison + * + * @returns <0 if lhs < rhs + * @returns >0 if lhs > rhs + * @returns 0 if lhs == rhs + */ +static int +error_cmp(const void *p1, const void *p2) +{ + const error_map_t *lhs = (const error_map_t*)p1; + const error_map_t *rhs = (const error_map_t*)p2; + + if((u32)lhs->fs_error < (u32)rhs->fs_error) + return -1; + else if((u32)lhs->fs_error > (u32)rhs->fs_error) + return 1; + return 0; +} + +/*! Translate FS service error to errno + * + * @param[in] error FS service error + * + * @returns errno + */ +static int +sdmc_translate_error(Result error) +{ + error_map_t key = { .fs_error = error }; + const error_map_t *rc = bsearch(&key, error_table, num_errors, + sizeof(error_map_t), error_cmp); + + if(rc != NULL) + return rc->error; + + return (int)error; +} diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index 1d9bc48..9560c79 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -380,7 +380,7 @@ static bool __handle_incoming_parameter() { return true; } -void aptEventHandler(u32 arg) +void aptEventHandler(void *arg) { bool runThread = true; diff --git a/libctru/source/services/cfgu.c b/libctru/source/services/cfgu.c index a8bbc49..6b89bba 100644 --- a/libctru/source/services/cfgu.c +++ b/libctru/source/services/cfgu.c @@ -38,7 +38,7 @@ Result CFGU_GenHashConsoleUnique(u32 appIDSalt, u64* hash) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = 0x00030000; + cmdbuf[0] = 0x00030040; cmdbuf[1] = appIDSalt; if((ret = svcSendSyncRequest(CFGU_handle))!=0)return ret; diff --git a/libctru/source/services/csnd.c b/libctru/source/services/csnd.c index 52f95ec..994443f 100644 --- a/libctru/source/services/csnd.c +++ b/libctru/source/services/csnd.c @@ -6,102 +6,160 @@ #include <3ds/os.h> #include <3ds/services/csnd.h> -//See here regarding CSND shared-mem commands, etc: http://3dbrew.org/wiki/CSND_Shared_Memory +// See here regarding CSND shared-mem commands, etc: http://3dbrew.org/wiki/CSND_Shared_Memory -Handle CSND_handle = 0; -Handle CSND_mutexhandle = 0; -Handle CSND_sharedmemhandle = 0; -u32 *CSND_sharedmem = NULL; -static u32 CSND_bitmask=0; +vu32* csndSharedMem = NULL; +u32 csndSharedMemSize; +u32 csndChannels = 0; +u32 csndOffsets[4]; -static u32 CSND_sharedmem_cmdblocksize = 0x2000; -static u32 CSND_sharedmem_startcmdoff = 0; -static u32 CSND_sharedmem_currentcmdoff = 0; +static Handle csndHandle = 0; +static Handle csndMutex = 0; +static Handle csndSharedMemBlock = 0; -Result CSND_cmd1(Handle *mutexhandle, Handle *sharedmemhandle, u32 sharedmem_size, u32 off0, u32 off1, u32 off2, u32 off3) +static u8 csndChnIdx[CSND_NUM_CHANNELS]; +static u32 csndCmdBlockSize = 0x2000; +static u32 csndCmdStartOff = 0; +static u32 csndCmdCurOff = 0; + +static Result CSND_Initialize(void) { Result ret=0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = 0x00010140; - cmdbuf[1] = sharedmem_size; - cmdbuf[2] = off0; - cmdbuf[3] = off1; - cmdbuf[4] = off2; - cmdbuf[5] = off3; + cmdbuf[1] = csndSharedMemSize; + memcpy(&cmdbuf[2], &csndOffsets[0], 4*sizeof(u32)); - if((ret = svcSendSyncRequest(CSND_handle))!=0)return ret; + if((ret = svcSendSyncRequest(csndHandle))!=0)return ret; - *mutexhandle = cmdbuf[3]; - *sharedmemhandle = cmdbuf[4]; + csndMutex = cmdbuf[3]; + csndSharedMemBlock = cmdbuf[4]; return (Result)cmdbuf[1]; } -Result CSND_cmd2() +static Result CSND_Shutdown() { Result ret=0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = 0x00020000; - if((ret = svcSendSyncRequest(CSND_handle))!=0)return ret; + if((ret = svcSendSyncRequest(csndHandle))!=0)return ret; return (Result)cmdbuf[1]; } -Result CSND_cmd5(u32 *bitmask) +static Result CSND_AcquireSoundChannels(u32* channelMask) { Result ret=0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = 0x00050000; - if((ret = svcSendSyncRequest(CSND_handle))!=0)return ret; + if((ret = svcSendSyncRequest(csndHandle))!=0)return ret; - *bitmask = cmdbuf[2]; + *channelMask = cmdbuf[2]; return (Result)cmdbuf[1]; } -Result CSND_initialize(u32* sharedMem) +static Result CSND_ReleaseSoundChannels(void) { Result ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); - if(sharedMem==NULL)sharedMem = (u32*)CSND_SHAREDMEM_DEFAULT; - CSND_sharedmem = sharedMem; + cmdbuf[0] = 0x00060000; - ret = srvGetServiceHandle(&CSND_handle, "csnd:SND"); - if(ret!=0)return ret; + if((ret = svcSendSyncRequest(csndHandle))!=0)return ret; - ret = CSND_cmd1(&CSND_mutexhandle, &CSND_sharedmemhandle, CSND_sharedmem_cmdblocksize+0x114, CSND_sharedmem_cmdblocksize, CSND_sharedmem_cmdblocksize+8, CSND_sharedmem_cmdblocksize+0xc8, CSND_sharedmem_cmdblocksize+0xd8); - if(ret!=0)return ret; + return (Result)cmdbuf[1]; +} - ret = svcMapMemoryBlock(CSND_sharedmemhandle, (u32)CSND_sharedmem, 3, 0x10000000); - if(ret!=0)return ret; +Result CSND_AcquireCapUnit(u32* capUnit) +{ + Result ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); - memset(CSND_sharedmem, 0, 0x2114); + cmdbuf[0] = 0x00070000; - ret = CSND_cmd5(&CSND_bitmask); - if(ret!=0)return ret; + if((ret = svcSendSyncRequest(csndHandle))!=0)return ret; + + *capUnit = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result CSND_ReleaseCapUnit(u32 capUnit) +{ + Result ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00080040; + cmdbuf[1] = capUnit; + + if((ret = svcSendSyncRequest(csndHandle))!=0)return ret; + + return (Result)cmdbuf[1]; +} + +Result csndInit(void) +{ + Result ret=0; + csndSharedMem = (vu32*)CSND_SHAREDMEM_DEFAULT; + + // TODO: proper error handling! + + ret = srvGetServiceHandle(&csndHandle, "csnd:SND"); + if (ret != 0) return ret; + + // Calculate offsets and sizes required by the CSND module + csndOffsets[0] = csndCmdBlockSize; // Offset to some unknown DSP status flags + csndOffsets[1] = csndOffsets[0] + 8; // Offset to sound channel information + csndOffsets[2] = csndOffsets[1] + 32*sizeof(CSND_ChnInfo); // Offset to information for an 'unknown' sort of channels + csndOffsets[3] = csndOffsets[2] + 2*8; // Offset to more unknown information + csndSharedMemSize = csndOffsets[3] + 0x3C; // Total size of the CSND shared memory + + ret = CSND_Initialize(); + if (ret != 0) return ret; + + ret = svcMapMemoryBlock(csndSharedMemBlock, (u32)csndSharedMem, 3, 0x10000000); + if (ret != 0) return ret; + + memset((void*)csndSharedMem, 0, csndSharedMemSize); + + ret = CSND_AcquireSoundChannels(&csndChannels); + if (ret != 0) return ret; + + // Build channel indices for the sound channel information table + int i, j = 0; + for (i = 0; i < CSND_NUM_CHANNELS; i ++) + { + csndChnIdx[i] = j; + if (csndChannels & BIT(i)) + j ++; + } return 0; } -Result CSND_shutdown() +Result csndExit(void) { Result ret; - svcUnmapMemoryBlock(CSND_sharedmemhandle, (u32)CSND_sharedmem); - svcCloseHandle(CSND_sharedmemhandle); + ret = CSND_ReleaseSoundChannels(); + if (ret != 0) return ret; - ret = CSND_cmd2(); - if(ret!=0)return ret; + svcUnmapMemoryBlock(csndSharedMemBlock, (u32)csndSharedMem); + svcCloseHandle(csndSharedMemBlock); - return svcCloseHandle(CSND_handle); + ret = CSND_Shutdown(); + svcCloseHandle(csndHandle); + return ret; } -Result CSND_cmd3(u32 offset) +static Result CSND_ExecCmd0(u32 offset) { Result ret=0; u32 *cmdbuf = getThreadCommandBuffer(); @@ -109,66 +167,66 @@ Result CSND_cmd3(u32 offset) cmdbuf[0] = 0x00030040; cmdbuf[1] = offset; - if((ret = svcSendSyncRequest(CSND_handle))!=0)return ret; + if((ret = svcSendSyncRequest(csndHandle))!=0)return ret; return (Result)cmdbuf[1]; } -void CSND_writesharedmem_cmdtype0(u16 cmdid, u8 *cmdparams) +void csndWriteCmd(int cmdid, u8 *cmdparams) { - u16 *ptr; + vu16* ptr; u32 prevoff; s32 outindex=0; - svcWaitSynchronizationN(&outindex, &CSND_mutexhandle, 1, 0, ~0); + svcWaitSynchronizationN(&outindex, &csndMutex, 1, 0, ~0); - if(CSND_sharedmem_startcmdoff != CSND_sharedmem_currentcmdoff) + if (csndCmdStartOff != csndCmdCurOff) { - if(CSND_sharedmem_currentcmdoff>=0x20) - { - prevoff = CSND_sharedmem_currentcmdoff-0x20; - } + if (csndCmdCurOff>=0x20) + prevoff = csndCmdCurOff-0x20; else - { - prevoff = CSND_sharedmem_cmdblocksize-0x20; - } + prevoff = csndCmdBlockSize-0x20; - ptr = (u16*)&CSND_sharedmem[prevoff>>2]; - *ptr = CSND_sharedmem_currentcmdoff; + ptr = (vu16*)&csndSharedMem[prevoff>>2]; + *ptr = csndCmdCurOff; } - ptr = (u16*)&CSND_sharedmem[CSND_sharedmem_currentcmdoff>>2]; + ptr = (vu16*)&csndSharedMem[csndCmdCurOff>>2]; - ptr[0] = 0xffff; + ptr[0] = 0xFFFF; ptr[1] = cmdid; ptr[2] = 0; ptr[3] = 0; - memcpy(&ptr[8>>1], cmdparams, 0x18); + memcpy((void*)&ptr[4], cmdparams, 0x18); - CSND_sharedmem_currentcmdoff+= 0x20; - if(CSND_sharedmem_currentcmdoff >= CSND_sharedmem_cmdblocksize)CSND_sharedmem_currentcmdoff = 0; + csndCmdCurOff += 0x20; + if (csndCmdCurOff >= csndCmdBlockSize) + csndCmdCurOff = 0; - svcReleaseMutex(CSND_mutexhandle); + svcReleaseMutex(csndMutex); } -Result CSND_processtype0cmds() +Result csndExecCmds(bool waitDone) { Result ret=0; - if(CSND_sharedmem_startcmdoff == CSND_sharedmem_currentcmdoff)return 0; + // Check we actually wrote commands + if (csndCmdStartOff == csndCmdCurOff) + return 0; - ret = CSND_cmd3(CSND_sharedmem_startcmdoff); - CSND_sharedmem_startcmdoff = CSND_sharedmem_currentcmdoff; + vu8* flag = (vu8*)&csndSharedMem[(csndCmdStartOff + 4) >> 2]; + + ret = CSND_ExecCmd0(csndCmdStartOff); + csndCmdStartOff = csndCmdCurOff; + if (ret != 0) return ret; + + // FIXME: This is a really ugly busy waiting loop! + while (waitDone && *flag == 0); return ret; } -u32 CSND_convertsamplerate(u32 samplerate) -{ - return (u32)(6.7027964E+07f / ((float)samplerate)); -} - -void CSND_sharedmemtype0_cmd0(u32 channel, u32 value) +void CSND_SetPlayStateR(u32 channel, u32 value) { u32 cmdparams[0x18>>2]; @@ -177,10 +235,10 @@ void CSND_sharedmemtype0_cmd0(u32 channel, u32 value) cmdparams[0] = channel & 0x1f; cmdparams[1] = value; - CSND_writesharedmem_cmdtype0(0x0, (u8*)&cmdparams); + csndWriteCmd(0x0, (u8*)&cmdparams); } -void CSND_setchannel_playbackstate(u32 channel, u32 value) +void CSND_SetPlayState(u32 channel, u32 value) { u32 cmdparams[0x18>>2]; @@ -189,10 +247,10 @@ void CSND_setchannel_playbackstate(u32 channel, u32 value) cmdparams[0] = channel & 0x1f; cmdparams[1] = value; - CSND_writesharedmem_cmdtype0(0x1, (u8*)&cmdparams); + csndWriteCmd(0x1, (u8*)&cmdparams); } -void CSND_sharedmemtype0_cmd3(u32 channel, u32 physaddr, u32 size) +void CSND_SetBlock(u32 channel, int block, u32 physaddr, u32 size) { u32 cmdparams[0x18>>2]; @@ -202,127 +260,210 @@ void CSND_sharedmemtype0_cmd3(u32 channel, u32 physaddr, u32 size) cmdparams[1] = physaddr; cmdparams[2] = size; - CSND_writesharedmem_cmdtype0(0x3, (u8*)&cmdparams); + csndWriteCmd(block ? 0x3 : 0xA, (u8*)&cmdparams); } -void CSND_sharedmemtype0_cmd9(u32 channel, u16 value) +void CSND_SetVol(u32 channel, u16 left, u16 right) { u32 cmdparams[0x18>>2]; memset(cmdparams, 0, 0x18); cmdparams[0] = channel & 0x1f; - cmdparams[1] = value | (value<<16); + cmdparams[1] = left | (right<<16); - CSND_writesharedmem_cmdtype0(0x9, (u8*)&cmdparams); + csndWriteCmd(0x9, (u8*)&cmdparams); } -void CSND_sharedmemtype0_cmd8(u32 channel, u32 samplerate) +void CSND_SetTimer(u32 channel, u32 timer) { u32 cmdparams[0x18>>2]; memset(cmdparams, 0, 0x18); cmdparams[0] = channel & 0x1f; - cmdparams[1] = CSND_convertsamplerate(samplerate); + cmdparams[1] = timer; - CSND_writesharedmem_cmdtype0(0x8, (u8*)&cmdparams); + csndWriteCmd(0x8, (u8*)&cmdparams); } -void CSND_sharedmemtype0_cmde(u32 channel, u32 looping, u32 encoding, u32 samplerate, u32 unk0, u32 unk1, u32 physaddr0, u32 physaddr1, u32 totalbytesize) +void CSND_SetDuty(u32 channel, u32 duty) { - u32 val; u32 cmdparams[0x18>>2]; memset(cmdparams, 0, 0x18); cmdparams[0] = channel & 0x1f; - cmdparams[0] |= (unk0 & 0xf) << 6; - if(!looping)cmdparams[0] |= 2 << 10; - if(looping)cmdparams[0] |= 1 << 10; - cmdparams[0] |= (encoding & 3) << 12; - cmdparams[0] |= (unk1 & 3) << 14; + cmdparams[1] = duty; - val = CSND_convertsamplerate(samplerate); - if(val<0x42)val = 0x42; - if(val>0xffff)val = 0xffff; - cmdparams[0] |= val<<16; + csndWriteCmd(0x7, (u8*)&cmdparams); +} +void CSND_SetAdpcmState(u32 channel, int block, int sample, int index) +{ + u32 cmdparams[0x18>>2]; + + memset(cmdparams, 0, 0x18); + + cmdparams[0] = channel & 0x1f; + cmdparams[1] = sample & 0xFFFF; + cmdparams[2] = index & 0x7F; + + csndWriteCmd(block ? 0xC : 0xB, (u8*)&cmdparams); +} + +void CSND_SetAdpcmReload(u32 channel, bool reload) +{ + u32 cmdparams[0x18>>2]; + + memset(cmdparams, 0, 0x18); + + cmdparams[0] = channel & 0x1f; + cmdparams[1] = reload ? 1 : 0; + + csndWriteCmd(0xD, (u8*)&cmdparams); +} + +void CSND_SetChnRegs(u32 flags, u32 physaddr0, u32 physaddr1, u32 totalbytesize) +{ + u32 cmdparams[0x18>>2]; + + memset(cmdparams, 0, 0x18); + + cmdparams[0] = flags; + cmdparams[1] = 0x7FFF7FFF; // Volume + cmdparams[2] = 0; // Unknown cmdparams[3] = physaddr0; cmdparams[4] = physaddr1; cmdparams[5] = totalbytesize; - CSND_writesharedmem_cmdtype0(0xe, (u8*)&cmdparams); + csndWriteCmd(0xe, (u8*)&cmdparams); } -Result CSND_sharedmemtype0_cmdupdatestate(int waitdone) +Result CSND_UpdateInfo(bool waitDone) { - u8 *ptr; - int ret=0; - u32 cmdparams[0x18>>2]; memset(cmdparams, 0, 0x18); - ptr = (u8*)&CSND_sharedmem[CSND_sharedmem_startcmdoff>>2]; + csndWriteCmd(0x300, (u8*)&cmdparams); + return csndExecCmds(waitDone); +} - CSND_writesharedmem_cmdtype0(0x300, (u8*)&cmdparams); +void CSND_CapEnable(u32 capUnit, bool enable) +{ + u32 cmdparams[0x18>>2]; + memset(cmdparams, 0, 0x18); - ret = CSND_processtype0cmds(); - if(ret!=0)return ret; + cmdparams[0] = capUnit; + cmdparams[1] = enable ? 1 : 0; - if(waitdone) + csndWriteCmd(0x100, (u8*)&cmdparams); +} + +void CSND_CapSetBit(u32 capUnit, int bit, bool state) +{ + u32 cmdparams[0x18>>2]; + memset(cmdparams, 0, 0x18); + + cmdparams[0] = capUnit; + cmdparams[1] = state ? 1 : 0; + + csndWriteCmd(0x101 + bit, (u8*)&cmdparams); +} + +void CSND_CapSetTimer(u32 capUnit, u32 timer) +{ + u32 cmdparams[0x18>>2]; + memset(cmdparams, 0, 0x18); + + cmdparams[0] = capUnit; + cmdparams[1] = timer & 0xFFFF; + + csndWriteCmd(0x104, (u8*)&cmdparams); +} + +void CSND_CapSetBuffer(u32 capUnit, u32 paddr, u32 size) +{ + u32 cmdparams[0x18>>2]; + memset(cmdparams, 0, 0x18); + + cmdparams[0] = capUnit; + cmdparams[1] = paddr; + cmdparams[2] = size; + + csndWriteCmd(0x105, (u8*)&cmdparams); +} + +Result csndPlaySound(int chn, u32 flags, u32 sampleRate, void* data0, void* data1, u32 size) +{ + if (!(csndChannels & BIT(chn))) + return 1; + + u32 paddr0 = 0, paddr1 = 0; + + int encoding = (flags >> 12) & 3; + int loopMode = (flags >> 10) & 3; + + if (encoding != CSND_ENCODING_PSG) { - while(*ptr == 0); + if (data0) paddr0 = osConvertVirtToPhys((u32)data0); + if (data1) paddr1 = osConvertVirtToPhys((u32)data1); + + if (data0 && encoding == CSND_ENCODING_ADPCM) + { + int adpcmSample = ((s16*)data0)[-2]; + int adpcmIndex = ((u8*)data0)[-2]; + CSND_SetAdpcmState(chn, 0, adpcmSample, adpcmIndex); + } } + u32 timer = CSND_TIMER(sampleRate); + if (timer < 0x0042) timer = 0x0042; + else if (timer > 0xFFFF) timer = 0xFFFF; + flags &= ~0xFFFF001F; + flags |= SOUND_ENABLE | SOUND_CHANNEL(chn) | (timer << 16); + + CSND_SetChnRegs(flags, paddr0, paddr1, size); + + if (loopMode == CSND_LOOPMODE_NORMAL && paddr1 > paddr0) + { + // Now that the first block is playing, configure the size of the subsequent blocks + size -= paddr1 - paddr0; + CSND_SetBlock(chn, 1, paddr1, size); + } + + return csndExecCmds(true); +} + +CSND_ChnInfo* csndGetChnInfo(u32 channel) +{ + channel = csndChnIdx[channel]; + return (CSND_ChnInfo*)(&csndSharedMem[(csndOffsets[1] + channel*0xc) >> 2]); +} + +Result csndGetState(u32 channel, CSND_ChnInfo* out) +{ + Result ret = 0; + channel = csndChnIdx[channel]; + + if ((ret = CSND_UpdateInfo(true)) != 0)return ret; + + memcpy(out, (const void*)&csndSharedMem[(csndOffsets[1] + channel*0xc) >> 2], 0xc); + //out[2] -= 0x0c000000; + return 0; } -Result CSND_playsound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u32 *vaddr0, u32 *vaddr1, u32 totalbytesize, u32 unk0, u32 unk1) -{ - u32 physaddr0 = 0; - u32 physaddr1 = 0; - - physaddr0 = osConvertVirtToPhys((u32)vaddr0); - physaddr1 = osConvertVirtToPhys((u32)vaddr1); - - CSND_sharedmemtype0_cmde(channel, looping, encoding, samplerate, unk0, unk1, physaddr0, physaddr1, totalbytesize); - CSND_sharedmemtype0_cmd8(channel, samplerate); - if(looping) - { - if(physaddr1>physaddr0)totalbytesize-= (u32)physaddr1 - (u32)physaddr0; - CSND_sharedmemtype0_cmd3(channel, physaddr1, totalbytesize); - } - CSND_sharedmemtype0_cmd8(channel, samplerate); - CSND_sharedmemtype0_cmd9(channel, 0xffff); - CSND_setchannel_playbackstate(channel, 1); - - return CSND_sharedmemtype0_cmdupdatestate(0); -} - -Result CSND_getchannelstate(u32 entryindex, u32 *out) -{ - Result ret=0; - - if((ret = CSND_sharedmemtype0_cmdupdatestate(1))!=0)return ret; - - memcpy(out, &CSND_sharedmem[(CSND_sharedmem_cmdblocksize+8 + entryindex*0xc) >> 2], 0xc); - out[2] -= 0x0c000000; - - return 0; -} - -Result CSND_getchannelstate_isplaying(u32 entryindex, u8 *status) +Result csndIsPlaying(u32 channel, u8* status) { Result ret; - u32 entry[0xc>>2]; + CSND_ChnInfo entry; - ret = CSND_getchannelstate(entryindex, entry); + ret = csndGetState(channel, &entry); if(ret!=0)return ret; - *status = entry[0] & 0xff; + *status = entry.active; return 0; } - diff --git a/libctru/source/services/gsp.c b/libctru/source/services/gsp.c index 9a88c3a..0234712 100644 --- a/libctru/source/services/gsp.c +++ b/libctru/source/services/gsp.c @@ -21,7 +21,7 @@ Handle gspEventThread; static Handle gspEvent; static vu8* gspEventData; -static void gspEventThreadMain(u32 arg); +static void gspEventThreadMain(void *arg); Result gspInit() @@ -82,7 +82,7 @@ void gspWaitForEvent(GSP_Event id, bool nextEvent) svcClearEvent(gspEvents[id]); } -void gspEventThreadMain(u32 arg) +void gspEventThreadMain(void *arg) { while (gspRunEvents) { @@ -114,7 +114,7 @@ void gspEventThreadMain(u32 arg) Result GSPGPU_WriteHWRegs(Handle* handle, u32 regAddr, u32* data, u8 size) { if(!handle)handle=&gspGpuHandle; - + if(size>0x80 || !data)return -1; u32* cmdbuf=getThreadCommandBuffer(); @@ -133,7 +133,7 @@ Result GSPGPU_WriteHWRegs(Handle* handle, u32 regAddr, u32* data, u8 size) Result GSPGPU_WriteHWRegsWithMask(Handle* handle, u32 regAddr, u32* data, u8 datasize, u32* maskdata, u8 masksize) { if(!handle)handle=&gspGpuHandle; - + if(datasize>0x80 || !data)return -1; u32* cmdbuf=getThreadCommandBuffer(); @@ -154,7 +154,7 @@ Result GSPGPU_WriteHWRegsWithMask(Handle* handle, u32 regAddr, u32* data, u8 dat Result GSPGPU_ReadHWRegs(Handle* handle, u32 regAddr, u32* data, u8 size) { if(!handle)handle=&gspGpuHandle; - + if(size>0x80 || !data)return -1; u32* cmdbuf=getThreadCommandBuffer(); @@ -180,7 +180,7 @@ Result GSPGPU_SetBufferSwap(Handle* handle, u32 screenid, GSP_FramebufferInfo *f cmdbuf[0] = 0x00050200; cmdbuf[1] = screenid; memcpy(&cmdbuf[2], framebufinfo, sizeof(GSP_FramebufferInfo)); - + if((ret=svcSendSyncRequest(*handle)))return ret; return cmdbuf[1]; @@ -189,7 +189,7 @@ Result GSPGPU_SetBufferSwap(Handle* handle, u32 screenid, GSP_FramebufferInfo *f Result GSPGPU_FlushDataCache(Handle* handle, u8* adr, u32 size) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x00080082; //request header code cmdbuf[1]=(u32)adr; @@ -224,7 +224,7 @@ Result GSPGPU_InvalidateDataCache(Handle* handle, u8* adr, u32 size) Result GSPGPU_SetLcdForceBlack(Handle* handle, u8 flags) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x000B0040; //request header code cmdbuf[1]=flags; @@ -238,7 +238,7 @@ Result GSPGPU_SetLcdForceBlack(Handle* handle, u8 flags) Result GSPGPU_TriggerCmdReqQueue(Handle* handle) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x000C0000; //request header code @@ -251,7 +251,7 @@ Result GSPGPU_TriggerCmdReqQueue(Handle* handle) Result GSPGPU_RegisterInterruptRelayQueue(Handle* handle, Handle eventHandle, u32 flags, Handle* outMemHandle, u8* threadID) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x00130042; //request header code cmdbuf[1]=flags; @@ -263,27 +263,27 @@ Result GSPGPU_RegisterInterruptRelayQueue(Handle* handle, Handle eventHandle, u3 if(threadID)*threadID=cmdbuf[2]; if(outMemHandle)*outMemHandle=cmdbuf[4]; - + return cmdbuf[1]; } Result GSPGPU_UnregisterInterruptRelayQueue(Handle* handle) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x00140000; //request header code Result ret=0; if((ret=svcSendSyncRequest(*handle)))return ret; - + return cmdbuf[1]; } Result GSPGPU_AcquireRight(Handle* handle, u8 flags) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x160042; //request header code cmdbuf[1]=flags; @@ -299,7 +299,7 @@ Result GSPGPU_AcquireRight(Handle* handle, u8 flags) Result GSPGPU_ReleaseRight(Handle* handle) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x170000; //request header code @@ -312,7 +312,7 @@ Result GSPGPU_ReleaseRight(Handle* handle) Result GSPGPU_ImportDisplayCaptureInfo(Handle* handle, GSP_CaptureInfo *captureinfo) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x00180000; //request header code @@ -332,7 +332,7 @@ Result GSPGPU_ImportDisplayCaptureInfo(Handle* handle, GSP_CaptureInfo *capturei Result GSPGPU_SaveVramSysArea(Handle* handle) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x00190000; //request header code @@ -345,7 +345,7 @@ Result GSPGPU_SaveVramSysArea(Handle* handle) Result GSPGPU_RestoreVramSysArea(Handle* handle) { if(!handle)handle=&gspGpuHandle; - + u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x001A0000; //request header code @@ -361,7 +361,7 @@ Result GSPGPU_RestoreVramSysArea(Handle* handle) Result GSPGPU_SubmitGxCommand(u32* sharedGspCmdBuf, u32 gxCommand[0x8], Handle* handle) { if(!sharedGspCmdBuf || !gxCommand)return -1; - + u32 cmdBufHeader; __asm__ __volatile__ ("ldrex %[result], [%[adr]]" : [result] "=r" (cmdBufHeader) : [adr] "r" (sharedGspCmdBuf)); diff --git a/libctru/source/services/httpc.c b/libctru/source/services/httpc.c index a9f1eb9..8b839e8 100644 --- a/libctru/source/services/httpc.c +++ b/libctru/source/services/httpc.c @@ -43,8 +43,8 @@ Result httpcOpenContext(httpcContext *context, char* url, u32 use_defaultproxy) ret = HTTPC_InitializeConnectionSession(context->servhandle, context->httphandle); if(ret!=0) { - HTTPC_CloseContext(__httpc_servhandle, context->httphandle); svcCloseHandle(context->servhandle); + HTTPC_CloseContext(__httpc_servhandle, context->httphandle); return ret; } @@ -52,8 +52,8 @@ Result httpcOpenContext(httpcContext *context, char* url, u32 use_defaultproxy) ret = HTTPC_SetProxyDefault(context->servhandle, context->httphandle); if(ret!=0) { - HTTPC_CloseContext(__httpc_servhandle, context->httphandle); svcCloseHandle(context->servhandle); + HTTPC_CloseContext(__httpc_servhandle, context->httphandle); return ret; } @@ -64,8 +64,8 @@ Result httpcCloseContext(httpcContext *context) { Result ret=0; - ret = HTTPC_CloseContext(context->servhandle, context->httphandle); svcCloseHandle(context->servhandle); + ret = HTTPC_CloseContext(__httpc_servhandle, context->httphandle); return ret; } @@ -216,16 +216,16 @@ Result HTTPC_AddRequestHeaderField(Handle handle, Handle contextHandle, char* na { u32* cmdbuf=getThreadCommandBuffer(); - int l1=strlen(name)+1; - int l2=strlen(value)+1; + int name_len=strlen(name)+1; + int value_len=strlen(value)+1; cmdbuf[0]=0x1100c4; //request header code cmdbuf[1]=contextHandle; - cmdbuf[2]=l1; - cmdbuf[3]=l2; - cmdbuf[4]=(l1<<14)|0xC02; + cmdbuf[2]=name_len; + cmdbuf[3]=value_len; + cmdbuf[4]=(name_len<<14)|0xC02; cmdbuf[5]=(u32)name; - cmdbuf[6]=(l1<<4)|0xA; + cmdbuf[6]=(value_len<<4)|0xA; cmdbuf[7]=(u32)value; Result ret=0; diff --git a/libctru/source/services/soc/soc_accept.c b/libctru/source/services/soc/soc_accept.c index 355a744..71ce790 100644 --- a/libctru/source/services/soc/soc_accept.c +++ b/libctru/source/services/soc/soc_accept.c @@ -1,14 +1,39 @@ #include "soc_common.h" +#include #include int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - int ret=0; - int tmp_addrlen=0x1c; + int ret = 0; + int tmp_addrlen = 0x1c; + int fd, dev; + __handle *handle; u32 *cmdbuf = getThreadCommandBuffer(); u8 tmpaddr[0x1c]; u32 saved_threadstorage[2]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + + dev = FindDevice("soc:"); + if(dev < 0) { + errno = ENODEV; + return -1; + } + + fd = __alloc_handle(sizeof(__handle) + sizeof(Handle)); + if(fd < 0) { + errno = ENOMEM; + return -1; + } + + handle = __get_handle(fd); + handle->device = dev; + handle->fileStruct = ((void *)handle) + sizeof(__handle); + memset(tmpaddr, 0, 0x1c); cmdbuf[0] = 0x00040082; @@ -22,22 +47,36 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) cmdbuf[0x100>>2] = (tmp_addrlen<<14) | 2; cmdbuf[0x104>>2] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + __release_handle(fd); + errno = SYNC_ERROR; + return ret; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret>=0 && addr!=NULL) - { + if(ret < 0) + errno = -ret; + + if(ret >= 0 && addr != NULL) { addr->sa_family = tmpaddr[1]; - if(*addrlen > tmpaddr[0])*addrlen = tmpaddr[0]; + if(*addrlen > tmpaddr[0]) + *addrlen = tmpaddr[0]; memcpy(addr->sa_data, &tmpaddr[2], *addrlen - 2); } - if(ret<0)return -1; - return ret; + if(ret < 0) { + __release_handle(fd); + return -1; + } + else + *(Handle*)handle->fileStruct = ret; + + return fd; } diff --git a/libctru/source/services/soc/soc_bind.c b/libctru/source/services/soc/soc_bind.c index dba52e5..610cdf6 100644 --- a/libctru/source/services/soc/soc_bind.c +++ b/libctru/source/services/soc/soc_bind.c @@ -4,25 +4,26 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - int ret=0; - int tmp_addrlen=0; + int ret = 0; + int tmp_addrlen = 0; u32 *cmdbuf = getThreadCommandBuffer(); u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + memset(tmpaddr, 0, 0x1c); if(addr->sa_family == AF_INET) - { tmp_addrlen = 8; - } else - { tmp_addrlen = 0x1c; - } - if(addrlen < tmp_addrlen) - { - SOCU_errno = EINVAL; + if(addrlen < tmp_addrlen) { + errno = EINVAL; return -1; } @@ -37,12 +38,20 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) cmdbuf[5] = (((u32)tmp_addrlen)<<14) | 2; cmdbuf[6] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret<0)return -1; return 0; } diff --git a/libctru/source/services/soc/soc_closesocket.c b/libctru/source/services/soc/soc_closesocket.c index 85dcd52..9a3c93b 100644 --- a/libctru/source/services/soc/soc_closesocket.c +++ b/libctru/source/services/soc/soc_closesocket.c @@ -1,21 +1,15 @@ #include "soc_common.h" +#include #include +#include int closesocket(int sockfd) { - int ret=0; - u32 *cmdbuf = getThreadCommandBuffer(); + int fd = soc_get_fd(sockfd); + if(fd < 0) { + errno = -fd; + return -1; + } - cmdbuf[0] = 0x000B0042; - cmdbuf[1] = (u32)sockfd; - cmdbuf[2] = 0x20; - - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; - - ret = (int)cmdbuf[1]; - if(ret==0)ret =_net_convert_error(cmdbuf[2]); - SOCU_errno = ret; - - if(ret!=0)return -1; - return 0; + return close(sockfd); } diff --git a/libctru/source/services/soc/soc_common.c b/libctru/source/services/soc/soc_common.c index 8814453..a610919 100644 --- a/libctru/source/services/soc/soc_common.c +++ b/libctru/source/services/soc/soc_common.c @@ -1,8 +1,8 @@ #include "soc_common.h" #include +#include Handle SOCU_handle = 0; -int SOCU_errno = 0; Handle socMemhandle = 0; //This is based on the array from libogc network_wii.c. @@ -91,14 +91,11 @@ static u8 _net_error_code_map[] = { //This is based on the function from libogc network_wii.c. s32 _net_convert_error(s32 sock_retval) { - if (sock_retval >= 0) return sock_retval; - if (sock_retval < -sizeof(_net_error_code_map) - || !_net_error_code_map[-sock_retval]) - return NET_UNKNOWN_ERROR_OFFSET + sock_retval; + if(sock_retval >= 0) + return sock_retval; + + if(sock_retval < -sizeof(_net_error_code_map) + || !_net_error_code_map[-sock_retval]) + return NET_UNKNOWN_ERROR_OFFSET + sock_retval; return -_net_error_code_map[-sock_retval]; } - -int SOC_GetErrno(void) -{ - return SOCU_errno; -} diff --git a/libctru/source/services/soc/soc_common.h b/libctru/source/services/soc/soc_common.h index 5cf5dee..a9fd779 100644 --- a/libctru/source/services/soc/soc_common.h +++ b/libctru/source/services/soc/soc_common.h @@ -1,13 +1,36 @@ #pragma once +#include #include +#include +#include #include <3ds/types.h> #include <3ds/svc.h> #include <3ds/srv.h> #include <3ds/services/soc.h> +#define SYNC_ERROR ENODEV + +int __alloc_handle(size_t size); +__handle *__get_handle(int fd); +void __release_handle(int fd); + extern Handle SOCU_handle; -extern int SOCU_errno; extern Handle socMemhandle; +static inline int +soc_get_fd(int fd) +{ + __handle *handle = __get_handle(fd); + if(handle == NULL) + return -ENODEV; + if(strcmp(devoptab_list[handle->device]->name, "soc") != 0) + return -ENOTSOCK; + return *(Handle*)handle->fileStruct; +} + s32 _net_convert_error(s32 sock_retval); + +ssize_t soc_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); + +ssize_t soc_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); diff --git a/libctru/source/services/soc/soc_connect.c b/libctru/source/services/soc/soc_connect.c index 9577c77..4cab7cc 100644 --- a/libctru/source/services/soc/soc_connect.c +++ b/libctru/source/services/soc/soc_connect.c @@ -4,25 +4,26 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - int ret=0; - int tmp_addrlen=0; + int ret = 0; + int tmp_addrlen = 0; u32 *cmdbuf = getThreadCommandBuffer(); u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + memset(tmpaddr, 0, 0x1c); if(addr->sa_family == AF_INET) - { tmp_addrlen = 8; - } else - { tmp_addrlen = 0x1c; - } - if(addrlen < tmp_addrlen) - { - SOCU_errno = -EINVAL; + if(addrlen < tmp_addrlen) { + errno = EINVAL; return -1; } @@ -37,12 +38,20 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) cmdbuf[5] = (((u32)tmp_addrlen)<<14) | 2; cmdbuf[6] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret<0)return -1; return 0; } diff --git a/libctru/source/services/soc/soc_fcntl.c b/libctru/source/services/soc/soc_fcntl.c index fcc873b..f14a0e0 100644 --- a/libctru/source/services/soc/soc_fcntl.c +++ b/libctru/source/services/soc/soc_fcntl.c @@ -12,7 +12,8 @@ static int from_3ds(int flags) { int newflags = 0; - if(flags & O_NONBLOCK_3DS) newflags |= O_NONBLOCK; + if(flags & O_NONBLOCK_3DS) + newflags |= O_NONBLOCK; /* add other flag translations here, but I have only seen O_NONBLOCK */ return newflags; @@ -22,13 +23,14 @@ static int to_3ds(int flags) { int newflags = 0; - if(flags & O_NONBLOCK) newflags |= O_NONBLOCK_3DS; + if(flags & O_NONBLOCK) + newflags |= O_NONBLOCK_3DS; /* add other flag translations here, but I have only seen O_NONBLOCK */ return newflags; } -int fcntl(int fd, int cmd, ...) +int fcntl(int sockfd, int cmd, ...) { int ret = 0; int arg = 0; @@ -36,49 +38,53 @@ int fcntl(int fd, int cmd, ...) va_list args; - if(cmd != F_GETFL && cmd != F_SETFL) - { - SOCU_errno = -EINVAL; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; return -1; } - va_start(args, cmd); - if(cmd == F_SETFL) - { + if(cmd != F_GETFL && cmd != F_SETFL) { + errno = EINVAL; + return -1; + } + + if(cmd == F_SETFL) { + va_start(args, cmd); arg = va_arg(args, int); + va_end(args); /* make sure they only used known flags */ - if(arg & ~ALL_FLAGS) - { - SOCU_errno = -EINVAL; - va_end(args); + if(arg & ~ALL_FLAGS) { + errno = EINVAL; return -1; } arg = to_3ds(arg); } - va_end(args); cmdbuf[0] = 0x001300C2; - cmdbuf[1] = (u32)fd; + cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)cmd; cmdbuf[3] = (u32)arg; cmdbuf[4] = 0x20; - if((ret = svcSendSyncRequest(SOCU_handle)) != 0) + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; return ret; + } ret = (int)cmdbuf[1]; if(ret == 0) ret = _net_convert_error(cmdbuf[2]); - if(ret < 0) - SOCU_errno = ret; - if(ret < 0) + if(ret < 0) { + errno = ret; return -1; + } - if(ret & ~ALL_3DS) - { + if(ret & ~ALL_3DS) { /* somehow report unknown flags */ } diff --git a/libctru/source/services/soc/soc_gethostbyname.c b/libctru/source/services/soc/soc_gethostbyname.c index 4932378..ed712db 100644 --- a/libctru/source/services/soc/soc_gethostbyname.c +++ b/libctru/source/services/soc/soc_gethostbyname.c @@ -10,11 +10,13 @@ int h_errno = 0; struct hostent* gethostbyname(const char *name) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; static u8 outbuf[0x1A88]; + h_errno = 0; + cmdbuf[0] = 0x000D0082; cmdbuf[1] = strlen(name)+1; cmdbuf[2] = sizeof(outbuf); @@ -27,17 +29,25 @@ struct hostent* gethostbyname(const char *name) cmdbuf[0x100>>2] = (sizeof(outbuf) << 14) | 2; cmdbuf[0x104>>2] = (u32)outbuf; - if(( ret = svcSendSyncRequest(SOCU_handle))!=0)return NULL; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + h_errno = NO_RECOVERY; + return NULL; + } + cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; - /* TODO: set h_errno based on SOCU_errno */ + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret<0)return NULL; + if(ret < 0) { + /* TODO: set h_errno based on ret */ + h_errno = HOST_NOT_FOUND; + return NULL; + } u32 num_results, i; memcpy(&num_results, (char*)outbuf+4, sizeof(num_results)); diff --git a/libctru/source/services/soc/soc_gethostid.c b/libctru/source/services/soc/soc_gethostid.c index fb747c3..7a254aa 100644 --- a/libctru/source/services/soc/soc_gethostid.c +++ b/libctru/source/services/soc/soc_gethostid.c @@ -1,16 +1,22 @@ #include "soc_common.h" +#include long gethostid(void) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = 0x00160000; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return -1; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = cmdbuf[2]; + if(ret == 0) + ret = cmdbuf[2]; return ret; } diff --git a/libctru/source/services/soc/soc_getpeername.c b/libctru/source/services/soc/soc_getpeername.c index f20be86..977b14b 100644 --- a/libctru/source/services/soc/soc_getpeername.c +++ b/libctru/source/services/soc/soc_getpeername.c @@ -1,13 +1,20 @@ #include "soc_common.h" +#include #include int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + cmdbuf[0] = 0x00180082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = 0x1c; @@ -19,23 +26,29 @@ int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) cmdbuf[0x100>>2] = (0x1c<<14) | 2; cmdbuf[0x104>>2] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret==0) - { - if(*addrlen > tmpaddr[0])*addrlen = tmpaddr[0]; - memset(addr, 0, sizeof(struct sockaddr)); - addr->sa_family = tmpaddr[1]; - memcpy(addr->sa_data, &tmpaddr[2], *addrlen - 2); + if(ret < 0) { + errno = -ret; + return -1; } - if(ret<0)return -1; + if(*addrlen > tmpaddr[0]) + *addrlen = tmpaddr[0]; + memset(addr, 0, sizeof(struct sockaddr)); + addr->sa_family = tmpaddr[1]; + memcpy(addr->sa_data, &tmpaddr[2], *addrlen - 2); + return ret; } diff --git a/libctru/source/services/soc/soc_getsockname.c b/libctru/source/services/soc/soc_getsockname.c index 80812af..2fd16b3 100644 --- a/libctru/source/services/soc/soc_getsockname.c +++ b/libctru/source/services/soc/soc_getsockname.c @@ -1,13 +1,20 @@ #include "soc_common.h" +#include #include int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + cmdbuf[0] = 0x00170082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = 0x1c; @@ -19,23 +26,29 @@ int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) cmdbuf[0x100>>2] = (0x1c<<14) | 2; cmdbuf[0x104>>2] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret==0) - { - if(*addrlen > tmpaddr[0])*addrlen = tmpaddr[0]; - memset(addr, 0, sizeof(struct sockaddr)); - addr->sa_family = tmpaddr[1]; - memcpy(addr->sa_data, &tmpaddr[2], *addrlen - 2); + if(ret < 0) { + errno = -ret; + return -1; } - if(ret<0)return -1; + if(*addrlen > tmpaddr[0]) + *addrlen = tmpaddr[0]; + memset(addr, 0, sizeof(struct sockaddr)); + addr->sa_family = tmpaddr[1]; + memcpy(addr->sa_data, &tmpaddr[2], *addrlen - 2); + return ret; } diff --git a/libctru/source/services/soc/soc_getsockopt.c b/libctru/source/services/soc/soc_getsockopt.c index 20bf148..8b48994 100644 --- a/libctru/source/services/soc/soc_getsockopt.c +++ b/libctru/source/services/soc/soc_getsockopt.c @@ -1,12 +1,19 @@ #include "soc_common.h" +#include #include int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + cmdbuf[0] = 0x00110102; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)level; @@ -20,17 +27,25 @@ int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optl cmdbuf[0x100>>2] = ((*optlen)<<14) | 2; cmdbuf[0x104>>2] = (u32)optval; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret==0)*optlen = cmdbuf[3]; + if(ret < 0) { + errno = -ret; + return -1; + } + + *optlen = cmdbuf[3]; - if(ret<0)return -1; return ret; } diff --git a/libctru/source/services/soc/soc_herror.c b/libctru/source/services/soc/soc_herror.c new file mode 100644 index 0000000..04a7e24 --- /dev/null +++ b/libctru/source/services/soc/soc_herror.c @@ -0,0 +1,10 @@ +#include "soc_common.h" +#include +#include + +void herror(const char *s) { + if(s) + fiprintf(stderr, "%s\n", hstrerror(h_errno)); + else + fiprintf(stderr, "%s: %s\n", s, hstrerror(h_errno)); +} diff --git a/libctru/source/services/soc/soc_hstrerror.c b/libctru/source/services/soc/soc_hstrerror.c new file mode 100644 index 0000000..cb1660c --- /dev/null +++ b/libctru/source/services/soc/soc_hstrerror.c @@ -0,0 +1,26 @@ +#include "soc_common.h" +#include + +static const struct +{ + int err; + const char *str; +} error_strings[] = +{ + { 0, "Resolver Error 0 (no error)", }, + { HOST_NOT_FOUND, "Unknown host", }, + { NO_DATA, "No address associated with name", }, + { NO_RECOVERY, "Unknown server error", }, + { TRY_AGAIN, "Host name lookup failure", }, +}; +static const size_t num_error_strings = sizeof(error_strings)/sizeof(error_strings[0]); + +const char* hstrerror(int err) { + size_t i; + for(i = 0; i < num_error_strings; ++i) { + if(error_strings[i].err == err) + return error_strings[i].str; + } + + return "Unknown resolver error"; +} diff --git a/libctru/source/services/soc/soc_init.c b/libctru/source/services/soc/soc_init.c index 2b961fa..9f5a88f 100644 --- a/libctru/source/services/soc/soc_init.c +++ b/libctru/source/services/soc/soc_init.c @@ -1,8 +1,46 @@ #include "soc_common.h" +#include +#include + +static int soc_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); +static int soc_close(struct _reent *r, int fd); +static ssize_t soc_write(struct _reent *r, int fd, const char *ptr, size_t len); +static ssize_t soc_read(struct _reent *r, int fd, char *ptr, size_t len); + +static devoptab_t +soc_devoptab = +{ + .name = "soc", + .structSize = sizeof(Handle), + .open_r = soc_open, + .close_r = soc_close, + .write_r = soc_write, + .read_r = soc_read, + .seek_r = NULL, + .fstat_r = NULL, + .stat_r = NULL, + .link_r = NULL, + .unlink_r = NULL, + .chdir_r = NULL, + .rename_r = NULL, + .mkdir_r = NULL, + .dirStateSize = 0, + .diropen_r = NULL, + .dirreset_r = NULL, + .dirnext_r = NULL, + .dirclose_r = NULL, + .statvfs_r = NULL, + .ftruncate_r = NULL, + .fsync_r = NULL, + .deviceData = NULL, + .chmod_r = NULL, + .fchmod_r = NULL, +}; + static Result socu_cmd1(Handle memhandle, u32 memsize) { - Result ret=0; + Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = 0x00010044; @@ -11,34 +49,132 @@ static Result socu_cmd1(Handle memhandle, u32 memsize) cmdbuf[4] = 0; cmdbuf[5] = memhandle; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } return cmdbuf[1]; } Result SOC_Initialize(u32 *context_addr, u32 context_size) { - Result ret=0; + Result ret = 0; + + /* check that the "soc" device doesn't already exist */ + int dev = FindDevice("soc:"); + if(dev >= 0) + return -1; + + /* add the "soc" device */ + dev = AddDevice(&soc_devoptab); + if(dev < 0) + return dev; ret = svcCreateMemoryBlock(&socMemhandle, (u32)context_addr, context_size, 0, 3); - if(ret!=0)return ret; + if(ret != 0) { + RemoveDevice("soc"); + return ret; + } - if((ret = srvGetServiceHandle(&SOCU_handle, "soc:U"))!=0)return ret; + ret = srvGetServiceHandle(&SOCU_handle, "soc:U"); + if(ret != 0) { + RemoveDevice("soc"); + return ret; + } - return socu_cmd1(socMemhandle, context_size); + ret = socu_cmd1(socMemhandle, context_size); + if(ret != 0) { + RemoveDevice("soc"); + return ret; + } + + return 0; } Result SOC_Shutdown(void) { - Result ret=0; + Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + int dev; cmdbuf[0] = 0x00190000; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } svcCloseHandle(SOCU_handle); svcCloseHandle(socMemhandle); + dev = FindDevice("soc:"); + if(dev >= 0) + RemoveDevice("soc"); + return cmdbuf[1]; } + +static int +soc_open(struct _reent *r, + void *fileStruct, + const char *path, + int flags, + int mode) +{ + r->_errno = ENOSYS; + return -1; +} + +static int +soc_close(struct _reent *r, + int fd) +{ + Handle sockfd = *(Handle*)fd; + + int ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x000B0042; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = 0x20; + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret =_net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } + + return 0; +} + +static ssize_t +soc_write(struct _reent *r, + int fd, + const char *ptr, + size_t len) +{ + Handle sockfd = *(Handle*)fd; + return soc_sendto(sockfd, ptr, len, 0, NULL, 0); +} + +static ssize_t +soc_read(struct _reent *r, + int fd, + char *ptr, + size_t len) +{ + Handle sockfd = *(Handle*)fd; + return soc_recvfrom(sockfd, ptr, len, 0, NULL, 0); +} diff --git a/libctru/source/services/soc/soc_ioctl.c b/libctru/source/services/soc/soc_ioctl.c index 4125646..ba43a8c 100644 --- a/libctru/source/services/soc/soc_ioctl.c +++ b/libctru/source/services/soc/soc_ioctl.c @@ -4,35 +4,38 @@ #include #include -int ioctl(int fd, int request, ...) +int ioctl(int sockfd, int request, ...) { int ret; int flags; int *value; va_list ap; - va_start(ap, request); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } switch(request) { case FIONBIO: + va_start(ap, request); value = va_arg(ap, int*); + va_end(ap); + if(value == NULL) { errno = EFAULT; - ret = -1; - } - - flags = fcntl(fd, F_GETFL, 0); - if(flags == -1) { - errno = SOC_GetErrno(); - va_end(ap); return -1; } - if(*value) ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - else ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + flags = fcntl(sockfd, F_GETFL, 0); + if(flags == -1) + return -1; - if(ret != 0) - errno = SOC_GetErrno(); + if(*value) + ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + else + ret = fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK); break; @@ -42,7 +45,5 @@ int ioctl(int fd, int request, ...) break; } - va_end(ap); - return ret; } diff --git a/libctru/source/services/soc/soc_listen.c b/libctru/source/services/soc/soc_listen.c index ce7ff05..53257d2 100644 --- a/libctru/source/services/soc/soc_listen.c +++ b/libctru/source/services/soc/soc_listen.c @@ -1,22 +1,37 @@ #include "soc_common.h" +#include #include int listen(int sockfd, int max_connections) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + cmdbuf[0] = 0x00030082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)max_connections; cmdbuf[3] = 0x20; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret!=0)return -1; return 0; } diff --git a/libctru/source/services/soc/soc_poll.c b/libctru/source/services/soc/soc_poll.c index 8cf5b34..324612c 100644 --- a/libctru/source/services/soc/soc_poll.c +++ b/libctru/source/services/soc/soc_poll.c @@ -1,35 +1,77 @@ #include "soc_common.h" +#include #include +#include +#include -int poll(struct pollfd *fds, nfds_t nfsd, int timeout) +int poll(struct pollfd *fds, nfds_t nfds, int timeout) { int ret = 0; - u32 size = sizeof(struct pollfd)*nfsd; + nfds_t i; + u32 size = sizeof(struct pollfd)*nfds; u32 *cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; + if(nfds == 0) { + errno = EINVAL; + return -1; + } + + struct pollfd *tmp_fds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds); + if(tmp_fds == NULL) { + errno = ENOMEM; + return -1; + } + + memcpy(tmp_fds, fds, sizeof(struct pollfd) * nfds); + + for(i = 0; i < nfds; ++i) { + tmp_fds[i].fd = soc_get_fd(fds[i].fd); + if(tmp_fds[i].fd < 0) { + errno = -tmp_fds[i].fd; + free(tmp_fds); + return -1; + } + tmp_fds[i].revents = 0; + } + cmdbuf[0] = 0x00140084; - cmdbuf[1] = (u32)nfsd; + cmdbuf[1] = (u32)nfds; cmdbuf[2] = (u32)timeout; cmdbuf[3] = 0x20; cmdbuf[5] = (size<<14) | 0x2802; - cmdbuf[6] = (u32)fds; + cmdbuf[6] = (u32)tmp_fds; saved_threadstorage[0] = cmdbuf[0x100>>2]; saved_threadstorage[1] = cmdbuf[0x104>>2]; cmdbuf[0x100>>2] = (size<<14) | 2; - cmdbuf[0x104>>2] = (u32)fds; + cmdbuf[0x104>>2] = (u32)tmp_fds; - if((ret = svcSendSyncRequest(SOCU_handle)) != 0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + free(tmp_fds); + errno = SYNC_ERROR; + return ret; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + free(tmp_fds); + errno = -ret; + return -1; + } + + for(i = 0; i < nfds; ++i) + fds[i].revents = tmp_fds[i].revents; + + free(tmp_fds); - if(ret<0)return -1; return ret; } diff --git a/libctru/source/services/soc/soc_recvfrom.c b/libctru/source/services/soc/soc_recvfrom.c index df5c56c..f9b206a 100644 --- a/libctru/source/services/soc/soc_recvfrom.c +++ b/libctru/source/services/soc/soc_recvfrom.c @@ -1,17 +1,19 @@ #include "soc_common.h" +#include #include ssize_t socuipc_cmd7(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - u32 tmp_addrlen=0; + u32 tmp_addrlen = 0; u8 tmpaddr[0x1c]; u32 saved_threadstorage[2]; memset(tmpaddr, 0, 0x1c); - if(src_addr)tmp_addrlen = 0x1c; + if(src_addr) + tmp_addrlen = 0x1c; cmdbuf[0] = 0x00070104; cmdbuf[1] = (u32)sockfd; @@ -28,35 +30,44 @@ ssize_t socuipc_cmd7(int sockfd, void *buf, size_t len, int flags, struct sockad cmdbuf[0x100>>2] = (tmp_addrlen<<14) | 2; cmdbuf[0x104>>2] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return -1; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret>0 && src_addr!=NULL) - { + if(ret < 0) { + errno = -ret; + return -1; + } + + if(src_addr != NULL) { src_addr->sa_family = tmpaddr[1]; - if(*addrlen > tmpaddr[0])*addrlen = tmpaddr[0]; + if(*addrlen > tmpaddr[0]) + *addrlen = tmpaddr[0]; memcpy(src_addr->sa_data, &tmpaddr[2], *addrlen - 2); } - if(ret<0)return -1; return ret; } ssize_t socuipc_cmd8(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - u32 tmp_addrlen=0; + u32 tmp_addrlen = 0; u8 tmpaddr[0x1c]; u32 saved_threadstorage[4]; - if(src_addr)tmp_addrlen = 0x1c; + if(src_addr) + tmp_addrlen = 0x1c; memset(tmpaddr, 0, 0x1c); @@ -77,7 +88,11 @@ ssize_t socuipc_cmd8(int sockfd, void *buf, size_t len, int flags, struct sockad cmdbuf[0x108>>2] = (tmp_addrlen<<14) | 2; cmdbuf[0x10c>>2] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; @@ -85,23 +100,38 @@ ssize_t socuipc_cmd8(int sockfd, void *buf, size_t len, int flags, struct sockad cmdbuf[0x10c>>2] = saved_threadstorage[3]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret>0 && src_addr!=NULL) - { + if(ret < 0) { + errno = -ret; + return -1; + } + + if(src_addr != NULL) { src_addr->sa_family = tmpaddr[1]; - if(*addrlen > tmpaddr[0])*addrlen = tmpaddr[0]; + if(*addrlen > tmpaddr[0]) + *addrlen = tmpaddr[0]; memcpy(src_addr->sa_data, &tmpaddr[2], *addrlen - 2); } - if(ret<0)return -1; return ret; } +ssize_t soc_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) +{ + if(len < 0x2000) + return socuipc_cmd8(sockfd, buf, len, flags, src_addr, addrlen); + return socuipc_cmd7(sockfd, buf, len, flags, src_addr, addrlen); +} ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { - if(len<0x2000)return socuipc_cmd8(sockfd, buf, len, flags, src_addr, addrlen); - return socuipc_cmd7(sockfd, buf, len, flags, src_addr, addrlen); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + + return soc_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); } diff --git a/libctru/source/services/soc/soc_select.c b/libctru/source/services/soc/soc_select.c index d2cd911..7e47827 100644 --- a/libctru/source/services/soc/soc_select.c +++ b/libctru/source/services/soc/soc_select.c @@ -20,7 +20,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struc pollinfo = (struct pollfd*)calloc(numfds, sizeof(struct pollfd)); if(pollinfo == NULL) { - SOCU_errno = ENOMEM; + errno = ENOMEM; return -1; } @@ -79,7 +79,8 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struc FD_CLR(i, exceptfds); } - if(found) ++rc; + if(found) + ++rc; ++j; } } diff --git a/libctru/source/services/soc/soc_sendto.c b/libctru/source/services/soc/soc_sendto.c index 9afd36a..4b84749 100644 --- a/libctru/source/services/soc/soc_sendto.c +++ b/libctru/source/services/soc/soc_sendto.c @@ -4,27 +4,21 @@ ssize_t socuipc_cmd9(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - u32 tmp_addrlen=0; + u32 tmp_addrlen = 0; u8 tmpaddr[0x1c]; memset(tmpaddr, 0, 0x1c); - if(dest_addr) - { + if(dest_addr) { if(dest_addr->sa_family == AF_INET) - { tmp_addrlen = 8; - } else - { tmp_addrlen = 0x1c; - } - if(addrlen < tmp_addrlen) - { - SOCU_errno = -EINVAL; + if(addrlen < tmp_addrlen) { + errno = EINVAL; return -1; } @@ -44,39 +38,41 @@ ssize_t socuipc_cmd9(int sockfd, const void *buf, size_t len, int flags, const s cmdbuf[9] = (((u32)len)<<4) | 10; cmdbuf[10] = (u32)buf; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret<0)return -1; return ret; } ssize_t socuipc_cmda(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - u32 tmp_addrlen=0; + u32 tmp_addrlen = 0; u8 tmpaddr[0x1c]; memset(tmpaddr, 0, 0x1c); - if(dest_addr) - { + if(dest_addr) { if(dest_addr->sa_family == AF_INET) - { tmp_addrlen = 8; - } else - { tmp_addrlen = 0x1c; - } - if(addrlen < tmp_addrlen) - { - SOCU_errno = -EINVAL; + if(addrlen < tmp_addrlen) { + errno = EINVAL; return -1; } @@ -96,18 +92,38 @@ ssize_t socuipc_cmda(int sockfd, const void *buf, size_t len, int flags, const s cmdbuf[9] = (tmp_addrlen<<14) | 0x402; cmdbuf[10] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret<0)return -1; return ret; } +ssize_t soc_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) +{ + if(len < 0x2000) + return socuipc_cmda(sockfd, buf, len, flags, dest_addr, addrlen); + return socuipc_cmd9(sockfd, buf, len, flags, dest_addr, addrlen); +} + ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - if(len<0x2000)return socuipc_cmda(sockfd, buf, len, flags, dest_addr, addrlen); - return socuipc_cmd9(sockfd, buf, len, flags, (struct sockaddr*)dest_addr, addrlen); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + + return soc_sendto(sockfd, buf, len, flags, dest_addr, addrlen); } diff --git a/libctru/source/services/soc/soc_setsockopt.c b/libctru/source/services/soc/soc_setsockopt.c index ff142b2..600d8cf 100644 --- a/libctru/source/services/soc/soc_setsockopt.c +++ b/libctru/source/services/soc/soc_setsockopt.c @@ -1,11 +1,18 @@ #include "soc_common.h" +#include #include int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + cmdbuf[0] = 0x00120104; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)level; @@ -15,12 +22,20 @@ int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t cmdbuf[7] = (optlen<<14) | 0x2402; cmdbuf[8] = (u32)optval; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret<0)return -1; return ret; } diff --git a/libctru/source/services/soc/soc_shutdown.c b/libctru/source/services/soc/soc_shutdown.c index be86293..89b2db6 100644 --- a/libctru/source/services/soc/soc_shutdown.c +++ b/libctru/source/services/soc/soc_shutdown.c @@ -1,22 +1,37 @@ #include "soc_common.h" +#include #include int shutdown(int sockfd, int shutdown_type) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + cmdbuf[0] = 0x000C0082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)shutdown_type; cmdbuf[3] = 0x20; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret!=0)return -1; return 0; } diff --git a/libctru/source/services/soc/soc_sockatmark.c b/libctru/source/services/soc/soc_sockatmark.c index d445fb8..f774389 100644 --- a/libctru/source/services/soc/soc_sockatmark.c +++ b/libctru/source/services/soc/soc_sockatmark.c @@ -1,21 +1,36 @@ #include "soc_common.h" +#include #include int sockatmark(int sockfd) { - int ret=0; + int ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) { + errno = -sockfd; + return -1; + } + cmdbuf[0] = 0x00150042; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = 0x20; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + errno = SYNC_ERROR; + return -1; + } ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } - if(ret<0)return -1; return ret; } diff --git a/libctru/source/services/soc/soc_socket.c b/libctru/source/services/soc/soc_socket.c index 628138b..5072275 100644 --- a/libctru/source/services/soc/soc_socket.c +++ b/libctru/source/services/soc/soc_socket.c @@ -1,9 +1,13 @@ #include "soc_common.h" +#include +#include #include int socket(int domain, int type, int protocol) { - int ret=0; + int ret = 0; + int fd, dev; + __handle *handle; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = 0x000200C2; @@ -12,11 +16,37 @@ int socket(int domain, int type, int protocol) cmdbuf[3] = protocol; cmdbuf[4] = 0x20; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + dev = FindDevice("soc:"); + if(dev < 0) { + errno = ENODEV; + return -1; + } + + fd = __alloc_handle(sizeof(__handle) + sizeof(Handle)); + if(fd < 0) { + errno = ENOMEM; + return -1; + } + + handle = __get_handle(fd); + handle->device = dev; + handle->fileStruct = ((void *)handle) + sizeof(__handle); + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) + { + __release_handle(fd); + errno = SYNC_ERROR; + return ret; + } ret = (int)cmdbuf[1]; - SOCU_errno = ret; + if(ret != 0) { + __release_handle(fd); + errno = _net_convert_error(cmdbuf[2]); + return -1; + } - if(ret!=0)return -1; - return _net_convert_error(cmdbuf[2]); + *(Handle*)handle->fileStruct = cmdbuf[2]; + return fd; } diff --git a/libctru/source/system/ctru_exit.c b/libctru/source/system/ctru_exit.c index f4c99f1..6cd4a38 100644 --- a/libctru/source/system/ctru_exit.c +++ b/libctru/source/system/ctru_exit.c @@ -15,9 +15,6 @@ void __attribute__((weak)) __attribute__((noreturn)) __libctru_exit(int rc) { u32 tmp=0; - // Run the global destructors - __libc_fini_array(); - __appExit(); // Unmap the linear heap diff --git a/libctru/source/system/initSystem.c b/libctru/source/system/initSystem.c index 501cfaa..c14c455 100644 --- a/libctru/source/system/initSystem.c +++ b/libctru/source/system/initSystem.c @@ -12,9 +12,6 @@ void __system_allocateHeaps(); void __system_initArgv(); void __appInit(); -// newlib definitions we need -void __libc_init_array(void); - void __ctru_exit(int rc); @@ -32,6 +29,4 @@ void __attribute__((weak)) __libctru_init(void (*retAddr)(void)) __appInit(); - // Run the global constructors - __libc_init_array(); } diff --git a/libctru/source/system/stack_adjust.s b/libctru/source/system/stack_adjust.s index 7c780fb..03513f0 100644 --- a/libctru/source/system/stack_adjust.s +++ b/libctru/source/system/stack_adjust.s @@ -16,12 +16,14 @@ initSystem: ldr sp, [r2] ldr r3, =__stacksize__ - ldr r3, [r3] + ldr r3, [r3] add sp, sp, r3 add sp, sp, #7 bics sp, sp, #7 str sp, [r2] + bl __libc_init_array + ldr r2, =saved_stack ldr lr, [r2,#4] bx lr @@ -31,6 +33,8 @@ initSystem: .type __ctru_exit, %function __ctru_exit: + bl __libc_fini_array + ldr r2, =saved_stack ldr sp, [r2] b __libctru_exit diff --git a/libctru/source/util/rbtree_clear.c b/libctru/source/util/rbtree/rbtree_clear.c similarity index 100% rename from libctru/source/util/rbtree_clear.c rename to libctru/source/util/rbtree/rbtree_clear.c diff --git a/libctru/source/util/rbtree_empty.c b/libctru/source/util/rbtree/rbtree_empty.c similarity index 100% rename from libctru/source/util/rbtree_empty.c rename to libctru/source/util/rbtree/rbtree_empty.c diff --git a/libctru/source/util/rbtree_find.c b/libctru/source/util/rbtree/rbtree_find.c similarity index 100% rename from libctru/source/util/rbtree_find.c rename to libctru/source/util/rbtree/rbtree_find.c diff --git a/libctru/source/util/rbtree_init.c b/libctru/source/util/rbtree/rbtree_init.c similarity index 100% rename from libctru/source/util/rbtree_init.c rename to libctru/source/util/rbtree/rbtree_init.c diff --git a/libctru/source/util/rbtree_insert.c b/libctru/source/util/rbtree/rbtree_insert.c similarity index 100% rename from libctru/source/util/rbtree_insert.c rename to libctru/source/util/rbtree/rbtree_insert.c diff --git a/libctru/source/util/rbtree_internal.h b/libctru/source/util/rbtree/rbtree_internal.h similarity index 100% rename from libctru/source/util/rbtree_internal.h rename to libctru/source/util/rbtree/rbtree_internal.h diff --git a/libctru/source/util/rbtree_iterator.c b/libctru/source/util/rbtree/rbtree_iterator.c similarity index 100% rename from libctru/source/util/rbtree_iterator.c rename to libctru/source/util/rbtree/rbtree_iterator.c diff --git a/libctru/source/util/rbtree_minmax.c b/libctru/source/util/rbtree/rbtree_minmax.c similarity index 100% rename from libctru/source/util/rbtree_minmax.c rename to libctru/source/util/rbtree/rbtree_minmax.c diff --git a/libctru/source/util/rbtree_remove.c b/libctru/source/util/rbtree/rbtree_remove.c similarity index 100% rename from libctru/source/util/rbtree_remove.c rename to libctru/source/util/rbtree/rbtree_remove.c diff --git a/libctru/source/util/rbtree_rotate.c b/libctru/source/util/rbtree/rbtree_rotate.c similarity index 100% rename from libctru/source/util/rbtree_rotate.c rename to libctru/source/util/rbtree/rbtree_rotate.c diff --git a/libctru/source/util/rbtree_size.c b/libctru/source/util/rbtree/rbtree_size.c similarity index 100% rename from libctru/source/util/rbtree_size.c rename to libctru/source/util/rbtree/rbtree_size.c diff --git a/libctru/source/util/utf/decode_utf16.c b/libctru/source/util/utf/decode_utf16.c new file mode 100644 index 0000000..dc82588 --- /dev/null +++ b/libctru/source/util/utf/decode_utf16.c @@ -0,0 +1,25 @@ +#include "3ds/util/utf.h" + +ssize_t +decode_utf16(uint32_t *out, + const uint16_t *in) +{ + uint16_t code1, code2; + + code1 = *in++; + if(code1 >= 0xD800 && code1 < 0xDC00) + { + /* surrogate pair */ + code2 = *in++; + if(code2 >= 0xDC00 && code2 < 0xE000) + { + *out = (code1 << 10) + code2 - 0x35FDC00; + return 2; + } + + return -1; + } + + *out = code1; + return 1; +} diff --git a/libctru/source/util/utf/decode_utf8.c b/libctru/source/util/utf/decode_utf8.c new file mode 100644 index 0000000..d2c86d4 --- /dev/null +++ b/libctru/source/util/utf/decode_utf8.c @@ -0,0 +1,88 @@ +#include "3ds/util/utf.h" + +ssize_t +decode_utf8(uint32_t *out, + const uint8_t *in) +{ + uint8_t code1, code2, code3, code4; + + code1 = *in++; + if(code1 < 0x80) + { + /* 1-byte sequence */ + *out = code1; + return 1; + } + else if(code1 < 0xC2) + { + return -1; + } + else if(code1 < 0xE0) + { + /* 2-byte sequence */ + code2 = *in++; + if((code2 & 0xC0) != 0x80) + { + return -1; + } + + *out = (code1 << 6) + code2 - 0x3080; + return 2; + } + else if(code1 < 0xF0) + { + /* 3-byte sequence */ + code2 = *in++; + if((code2 & 0xC0) != 0x80) + { + return -1; + } + if(code1 == 0xE0 && code2 < 0xA0) + { + return -1; + } + + code3 = *in++; + if((code3 & 0xC0) != 0x80) + { + return -1; + } + + *out = (code1 << 12) + (code2 << 6) + code3 - 0xE2080; + return 3; + } + else if(code1 < 0xF5) + { + /* 4-byte sequence */ + code2 = *in++; + if((code2 & 0xC0) != 0x80) + { + return -1; + } + if(code1 == 0xF0 && code2 < 0x90) + { + return -1; + } + if(code1 == 0xF4 && code2 >= 0x90) + { + return -1; + } + + code3 = *in++; + if((code3 & 0xC0) != 0x80) + { + return -1; + } + + code4 = *in++; + if((code4 & 0xC0) != 0x80) + { + return -1; + } + + *out = (code1 << 18) + (code2 << 12) + (code3 << 6) + code4 - 0x3C82080; + return 4; + } + + return -1; +} diff --git a/libctru/source/util/utf/encode_utf16.c b/libctru/source/util/utf/encode_utf16.c new file mode 100644 index 0000000..e7f2ba1 --- /dev/null +++ b/libctru/source/util/utf/encode_utf16.c @@ -0,0 +1,24 @@ +#include "3ds/util/utf.h" + +ssize_t +encode_utf16(uint16_t *out, + uint32_t in) +{ + if(in < 0x10000) + { + if(out != NULL) + *out++ = in; + return 1; + } + else if(in < 0x110000) + { + if(out != NULL) + { + *out++ = (in >> 10) + 0xD7C0; + *out++ = (in & 0x3FF) + 0xDC00; + } + return 2; + } + + return -1; +} diff --git a/libctru/source/util/utf/encode_utf8.c b/libctru/source/util/utf/encode_utf8.c new file mode 100644 index 0000000..18d028c --- /dev/null +++ b/libctru/source/util/utf/encode_utf8.c @@ -0,0 +1,45 @@ +#include "3ds/util/utf.h" + +ssize_t +encode_utf8(uint8_t *out, + uint32_t in) +{ + if(in < 0x80) + { + if(out != NULL) + *out++ = in; + return 1; + } + else if(in < 0x800) + { + if(out != NULL) + { + *out++ = (in >> 6) + 0xC0; + *out++ = (in & 0x3F) + 0x80; + } + return 2; + } + else if(in < 0x10000) + { + if(out != NULL) + { + *out++ = (in >> 12) + 0xE0; + *out++ = ((in >> 6) & 0x3F) + 0x80; + *out++ = (in & 0x3F) + 0x80; + } + return 3; + } + else if(in < 0x110000) + { + if(out != NULL) + { + *out++ = (in >> 18) + 0xF0; + *out++ = ((in >> 12) & 0x3F) + 0x80; + *out++ = ((in >> 6) & 0x3F) + 0x80; + *out++ = (in & 0x3F) + 0x80; + } + return 4; + } + + return -1; +} diff --git a/libctru/source/util/utf/utf16_to_utf32.c b/libctru/source/util/utf/utf16_to_utf32.c new file mode 100644 index 0000000..9ed21ac --- /dev/null +++ b/libctru/source/util/utf/utf16_to_utf32.c @@ -0,0 +1,35 @@ +#include "3ds/util/utf.h" + +size_t +utf16_to_utf32(uint32_t *out, + const uint16_t *in, + size_t len) +{ + size_t rc = 0; + ssize_t units; + uint32_t code; + + do + { + units = decode_utf16(&code, in); + if(units == -1) + return (size_t)-1; + + if(code > 0) + { + in += units; + + if(out != NULL) + { + if(rc < len) + *out++ = code; + else + return rc; + } + + ++rc; + } + } while(code > 0); + + return rc; +} diff --git a/libctru/source/util/utf/utf16_to_utf8.c b/libctru/source/util/utf/utf16_to_utf8.c new file mode 100644 index 0000000..3567e63 --- /dev/null +++ b/libctru/source/util/utf/utf16_to_utf8.c @@ -0,0 +1,48 @@ +#include "3ds/util/utf.h" + +size_t +utf16_to_utf8(uint8_t *out, + const uint16_t *in, + size_t len) +{ + size_t rc = 0; + ssize_t units; + uint32_t code; + uint8_t encoded[4]; + + do + { + units = decode_utf16(&code, in); + if(units == -1) + return (size_t)-1; + + if(code > 0) + { + in += units; + + units = encode_utf8(encoded, code); + if(units == -1) + return (size_t)-1; + + if(out != NULL) + { + if(rc + units <= len) + { + *out++ = encoded[0]; + if(units > 1) + *out++ = encoded[1]; + if(units > 2) + *out++ = encoded[2]; + if(units > 3) + *out++ = encoded[3]; + } + else + return rc; + } + + rc += units; + } + } while(code > 0); + + return rc; +} diff --git a/libctru/source/util/utf/utf32_to_utf16.c b/libctru/source/util/utf/utf32_to_utf16.c new file mode 100644 index 0000000..81ce203 --- /dev/null +++ b/libctru/source/util/utf/utf32_to_utf16.c @@ -0,0 +1,34 @@ +#include "3ds/util/utf.h" + +size_t +utf32_to_utf16(uint16_t *out, + const uint32_t *in, + size_t len) +{ + size_t rc = 0; + ssize_t units; + uint16_t encoded[2]; + + while(*in > 0) + { + units = encode_utf16(encoded, *in++); + if(units == -1) + return (size_t)-1; + + if(out != NULL) + { + if(rc + units <= len) + { + *out++ = encoded[0]; + if(units > 1) + *out++ = encoded[1]; + } + else + return rc; + } + + rc += units; + } + + return rc; +} diff --git a/libctru/source/util/utf/utf32_to_utf8.c b/libctru/source/util/utf/utf32_to_utf8.c new file mode 100644 index 0000000..80fc7c5 --- /dev/null +++ b/libctru/source/util/utf/utf32_to_utf8.c @@ -0,0 +1,38 @@ +#include "3ds/util/utf.h" + +size_t +utf32_to_utf8(uint8_t *out, + const uint32_t *in, + size_t len) +{ + size_t rc = 0; + ssize_t units; + uint8_t encoded[4]; + + while(*in > 0) + { + units = encode_utf8(encoded, *in++); + if(units == -1) + return (size_t)-1; + + if(out != NULL) + { + if(rc + units <= len) + { + *out++ = encoded[0]; + if(units > 1) + *out++ = encoded[1]; + if(units > 2) + *out++ = encoded[2]; + if(units > 3) + *out++ = encoded[3]; + } + else + return rc; + } + + rc += units; + } + + return rc; +} diff --git a/libctru/source/util/utf/utf8_to_utf16.c b/libctru/source/util/utf/utf8_to_utf16.c new file mode 100644 index 0000000..6991b3f --- /dev/null +++ b/libctru/source/util/utf/utf8_to_utf16.c @@ -0,0 +1,44 @@ +#include "3ds/util/utf.h" + +size_t +utf8_to_utf16(uint16_t *out, + const uint8_t *in, + size_t len) +{ + size_t rc = 0; + ssize_t units; + uint32_t code; + uint16_t encoded[2]; + + do + { + units = decode_utf8(&code, in); + if(units == -1) + return (size_t)-1; + + if(code > 0) + { + in += units; + + units = encode_utf16(encoded, code); + if(units == -1) + return (size_t)-1; + + if(out != NULL) + { + if(rc + units <= len) + { + *out++ = encoded[0]; + if(units > 1) + *out++ = encoded[1]; + } + else + return rc; + } + + rc += units; + } + } while(code > 0); + + return rc; +} diff --git a/libctru/source/util/utf/utf8_to_utf32.c b/libctru/source/util/utf/utf8_to_utf32.c new file mode 100644 index 0000000..fac6acd --- /dev/null +++ b/libctru/source/util/utf/utf8_to_utf32.c @@ -0,0 +1,35 @@ +#include "3ds/util/utf.h" + +size_t +utf8_to_utf32(uint32_t *out, + const uint8_t *in, + size_t len) +{ + size_t rc = 0; + ssize_t units; + uint32_t code; + + do + { + units = decode_utf8(&code, in); + if(units == -1) + return (size_t)-1; + + if(code > 0) + { + in += units; + + if(out != NULL) + { + if(rc < len) + *out++ = code; + else + return rc; + } + + ++rc; + } + } while(code > 0); + + return rc; +}