Merge branch 'port/3ds'
Jeffrey Pfau jeffrey@endrift.com
Tue, 25 Aug 2015 21:12:11 -0700
11 files changed,
623 insertions(+),
4 deletions(-)
M
CMakeLists.txt
→
CMakeLists.txt
@@ -28,7 +28,6 @@ file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c)
file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c) file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c) file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c) -file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/gui/*.c) file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs]) file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/util/gui/*.c) file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c)@@ -176,6 +175,21 @@ include_directories(${CMAKE_BINARY_DIR})
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/*.c) list(APPEND OS_LIB wiiuse bte fat ogc) source_group("Wii-specific code" FILES ${OS_SRC}) +elseif(3DS) + set(M_LIBRARY m) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format") + add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) + execute_process(COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw) + include_directories(${CMAKE_BINARY_DIR}) + list(APPEND OS_LIB sf2d ctru) + file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/3ds/*.c ${CMAKE_BINARY_DIR}/font.c) + if(USE_VFS_3DS) + add_definitions(-DUSE_VFS_3DS) + else() + add_definitions(-DUSE_VFS_FILE) + list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) + endif() + source_group("3DS-specific code" FILES ${OS_SRC}) endif() if(APPLE)@@ -459,6 +473,12 @@ endif()
if(PSP2) add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp2 ${CMAKE_BINARY_DIR}/psp2) +endif() + +if(3DS) + add_executable(${BINARY_NAME}.elf ${GUI_SRC}) + target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} m ${OS_LIB}) + add_custom_command(TARGET ${BINARY_NAME}.elf POST_BUILD COMMAND ${3DSXTOOL} ${BINARY_NAME}.elf ${BINARY_NAME}.3dsx) endif() if(BUILD_PERF)
M
src/gba/serialize.c
→
src/gba/serialize.c
@@ -187,11 +187,13 @@ }
return true; } +#ifndef _3DS struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write) { char suffix[5] = { '\0' }; snprintf(suffix, sizeof(suffix), ".ss%d", slot); return VDirOptionalOpenFile(dir, gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); } +#endif #ifdef USE_PNG static bool _savePNGState(struct GBA* gba, struct VFile* vf) {@@ -268,6 +270,7 @@ return success;
} #endif +#ifndef _3DS bool GBASaveState(struct GBAThread* threadContext, struct VDir* dir, int slot, bool screenshot) { struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, true); if (!vf) {@@ -298,6 +301,7 @@ GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to load", slot);
} return success; } +#endif bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot) { if (!screenshot) {
A
src/platform/3ds/3ds-memory.c
@@ -0,0 +1,19 @@
+/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "util/memory.h" + +#define asm __asm__ + +#include <3ds.h> + +void* anonymousMemoryMap(size_t size) { + return linearAlloc(size); +} + +void mappedMemoryFree(void* memory, size_t size) { + UNUSED(size); + linearFree(memory); +}
A
src/platform/3ds/3ds-vfs.c
@@ -0,0 +1,248 @@
+/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "3ds-vfs.h" + +#ifdef USE_VFS_3DS +#include "util/memory.h" +#include "util/string.h" + +struct VFile3DS { + struct VFile d; + + Handle handle; + u64 offset; +}; + +struct VDirEntry3DS { + struct VDirEntry d; + FS_dirent ent; + char* utf8Name; +}; + +struct VDir3DS { + struct VDir d; + + char* path; + Handle handle; + struct VDirEntry3DS vde; +}; + +static bool _vf3dClose(struct VFile* vf); +static off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence); +static ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size); +static ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size); +static void* _vf3dMap(struct VFile* vf, size_t size, int flags); +static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size); +static void _vf3dTruncate(struct VFile* vf, size_t size); +static ssize_t _vf3dSize(struct VFile* vf); +static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size); + +static bool _vd3dClose(struct VDir* vd); +static void _vd3dRewind(struct VDir* vd); +static struct VDirEntry* _vd3dListNext(struct VDir* vd); +static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode); + +static const char* _vd3deName(struct VDirEntry* vde); + +struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags) { + struct VFile3DS* vf3d = malloc(sizeof(struct VFile3DS)); + if (!vf3d) { + return 0; + } + + FS_path newPath = FS_makePath(PATH_CHAR, path); + Result res = FSUSER_OpenFile(0, &vf3d->handle, *archive, newPath, flags, FS_ATTRIBUTE_NONE); + if (res & 0xFFFC03FF) { + free(vf3d); + return 0; + } + + vf3d->offset = 0; + + vf3d->d.close = _vf3dClose; + vf3d->d.seek = _vf3dSeek; + vf3d->d.read = _vf3dRead; + vf3d->d.readline = 0; + vf3d->d.write = _vf3dWrite; + vf3d->d.map = _vf3dMap; + vf3d->d.unmap = _vf3dUnmap; + vf3d->d.truncate = _vf3dTruncate; + vf3d->d.size = _vf3dSize; + vf3d->d.sync = _vf3dSync; + + return &vf3d->d; +} + +bool _vf3dClose(struct VFile* vf) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + + FSFILE_Close(vf3d->handle); + svcCloseHandle(vf3d->handle); + return true; +} + +off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + u64 size; + switch (whence) { + case SEEK_SET: + vf3d->offset = offset; + break; + case SEEK_END: + FSFILE_GetSize(vf3d->handle, &size); + vf3d->offset = size; + // Fall through + case SEEK_CUR: + vf3d->offset += offset; + break; + } + return vf3d->offset; +} + +ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + u32 sizeRead; + Result res = FSFILE_Read(vf3d->handle, &sizeRead, vf3d->offset, buffer, size); + if (res) { + return -1; + } + vf3d->offset += sizeRead; + return sizeRead; +} + +ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + u32 sizeWritten; + Result res = FSFILE_Write(vf3d->handle, &sizeWritten, vf3d->offset, buffer, size, FS_WRITE_FLUSH); + if (res) { + return -1; + } + vf3d->offset += sizeWritten; + return sizeWritten; +} + +static void* _vf3dMap(struct VFile* vf, size_t size, int flags) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + UNUSED(flags); + void* buffer = anonymousMemoryMap(size); + if (buffer) { + u32 sizeRead; + FSFILE_Read(vf3d->handle, &sizeRead, 0, buffer, size); + } + return buffer; +} + +static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size) { + UNUSED(vf); + mappedMemoryFree(memory, size); +} + +static void _vf3dTruncate(struct VFile* vf, size_t size) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + FSFILE_SetSize(vf3d->handle, size); +} + +ssize_t _vf3dSize(struct VFile* vf) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + u64 size; + FSFILE_GetSize(vf3d->handle, &size); + return size; +} + +static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size) { + struct VFile3DS* vf3d = (struct VFile3DS*) vf; + if (buffer) { + u32 sizeWritten; + Result res = FSFILE_Write(vf3d->handle, &sizeWritten, 0, buffer, size, FS_WRITE_FLUSH); + if (res) { + return false; + } + } + FSFILE_Flush(vf3d->handle); + return true; +} + +struct VDir* VDirOpen(const char* path) { + struct VDir3DS* vd3d = malloc(sizeof(struct VDir3DS)); + if (!vd3d) { + return 0; + } + + FS_path newPath = FS_makePath(PATH_CHAR, path); + Result res = FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath); + if (res & 0xFFFC03FF) { + free(vd3d); + return 0; + } + + vd3d->path = strdup(path); + + vd3d->d.close = _vd3dClose; + vd3d->d.rewind = _vd3dRewind; + vd3d->d.listNext = _vd3dListNext; //// Crashes here for no good reason + vd3d->d.openFile = _vd3dOpenFile; + + vd3d->vde.d.name = _vd3deName; + vd3d->vde.utf8Name = 0; + + return &vd3d->d; +} + +static bool _vd3dClose(struct VDir* vd) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + FSDIR_Close(vd3d->handle); + free(vd3d->path); + if (vd3d->vde.utf8Name) { + free(vd3d->vde.utf8Name); + } + free(vd3d); + return true; +} + +static void _vd3dRewind(struct VDir* vd) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + FSDIR_Close(vd3d->handle); + FS_path newPath = FS_makePath(PATH_CHAR, vd3d->path); + FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath); +} + +static struct VDirEntry* _vd3dListNext(struct VDir* vd) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + u32 n = 0; + memset(&vd3d->vde.ent, 0, sizeof(vd3d->vde.ent)); + if (vd3d->vde.utf8Name) { + free(vd3d->vde.utf8Name); + vd3d->vde.utf8Name = 0; + }; + FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent); + if (!n) { + return 0; + } + return &vd3d->vde.d; +} + +static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + if (!path) { + return 0; + } + const char* dir = vd3d->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); + sprintf(combined, "%s/%s", dir, path); + + struct VFile* file = VFileOpen(combined, mode); + free(combined); + return file; +} + +static const char* _vd3deName(struct VDirEntry* vde) { + struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde; + if (!vd3de->utf8Name) { + vd3de->utf8Name = utf16to8(vd3de->ent.name, sizeof(vd3de->ent.name) / 2); + } + return vd3de->utf8Name; +} +#endif
A
src/platform/3ds/3ds-vfs.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef N3DS_VFS_H +#define N3DS_VFS_H + +#include "util/vfs.h" + +#define asm __asm__ + +#include <3ds.h> + +extern FS_archive sdmcArchive; + +struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags); + +#endif
A
src/platform/3ds/CMakeToolchain.txt
@@ -0,0 +1,40 @@
+if(DEFINED ENV{DEVKITPRO}) + set(DEVKITPRO $ENV{DEVKITPRO}) +else() + message(FATAL_ERROR "Could not find DEVKITPRO in environment") +endif() + +if(DEFINED ENV{DEVKITARM}) + set(DEVKITARM $ENV{DEVKITARM}) +else() + set(DEVKITARM ${DEVKITPRO}/devkitARM) +endif() + +set(toolchain_bin_dir ${DEVKITARM}/bin) +set(cross_prefix ${toolchain_bin_dir}/arm-none-eabi-) +set(inc_flags -I${DEVKITPRO}/libctru/include) +set(arch_flags "-march=armv6k -mtune=mpcore -mfpu=vfp -mfloat-abi=hard") +set(link_flags "-L${DEVKITPRO}/libctru/lib -lctru -lm -specs=3dsx.specs ${arch_flags}") + +set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name") +set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor") +set(CMAKE_LIBRARY_ARCHITECTURE arm-none-eabi CACHE INTERNAL "abi") +set(CMAKE_AR ${cross_prefix}ar CACHE INTERNAL "archiver") +set(CMAKE_C_COMPILER ${cross_prefix}gcc CACHE INTERNAL "c compiler") +set(CMAKE_CXX_COMPILER ${cross_prefix}g++ CACHE INTERNAL "cxx compiler") +set(CMAKE_ASM_COMPILER ${cross_prefix}gcc CACHE INTERNAL "assembler") +set(common_flags "${arch_flags} -mword-relocations ${inc_flags}") +set(CMAKE_C_FLAGS ${common_flags} CACHE INTERNAL "c compiler flags") +set(CMAKE_ASM_FLAGS ${common_flags} CACHE INTERNAL "c compiler flags") +set(CMAKE_CXX_FLAGS ${common_flags} CACHE INTERNAL "cxx compiler flags") +set(CMAKE_LINKER ${cross_prefix}ld CACHE INTERNAL "linker") + +set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags") +set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags") +set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags") + +set(3DSXTOOL ${toolchain_bin_dir}/3dsxtool) +set(RAW2C ${toolchain_bin_dir}/raw2c) + +set(3DS ON) +add_definitions(-D_3DS -DARM11)
A
src/platform/3ds/gui-font.c
@@ -0,0 +1,67 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "util/gui/font.h" +#include "util/gui/font-metrics.h" +#include "util/png-io.h" +#include "util/vfs.h" +#include "font.h" + +#include <sf2d.h> + +#define CELL_HEIGHT 16 +#define CELL_WIDTH 16 +#define GLYPH_HEIGHT 12 + +struct GUIFont { + sf2d_texture* tex; +}; + +struct GUIFont* GUIFontCreate(void) { + struct GUIFont* guiFont = malloc(sizeof(struct GUIFont)); + if (!guiFont) { + return 0; + } + guiFont->tex = sf2d_create_texture(256, 128, TEXFMT_RGB5A1, SF2D_PLACE_RAM); + memcpy(guiFont->tex->data, font, font_size); + guiFont->tex->tiled = 1; + return guiFont; +} + +void GUIFontDestroy(struct GUIFont* font) { + sf2d_free_texture(font->tex); + free(font); +} + +int GUIFontHeight(const struct GUIFont* font) { + UNUSED(font); + return GLYPH_HEIGHT; +} + +void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUITextAlignment align, uint32_t color, const char* text, ...) { + UNUSED(align); // TODO + char buffer[256]; + va_list args; + va_start(args, text); + int len = vsnprintf(buffer, sizeof(buffer), text, args); + va_end(args); + int i; + for (i = 0; i < len; ++i) { + char c = buffer[i]; + if (c > 0x7F) { + c = 0; + } + struct GUIFontGlyphMetric metric = defaultFontMetrics[c]; + sf2d_draw_texture_part_blend(font->tex, + x - metric.padding.left, + y - GLYPH_HEIGHT, + (c & 15) * CELL_WIDTH, + (c >> 4) * CELL_HEIGHT, + CELL_WIDTH, + CELL_HEIGHT, + color); + x += metric.width; + } +}
A
src/platform/3ds/main.c
@@ -0,0 +1,171 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gba/renderers/video-software.h" +#include "gba/supervisor/context.h" +#include "gba/video.h" +#include "util/gui.h" +#include "util/gui/file-select.h" +#include "util/gui/font.h" +#include "util/memory.h" + +#include "3ds-vfs.h" + +#include <3ds.h> +#include <sf2d.h> + +FS_archive sdmcArchive; + +static void GBA3DSLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args); +static Handle logFile; + +static void _drawStart(void) { + sf2d_start_frame(GFX_BOTTOM, GFX_LEFT); +} +static void _drawEnd(void) { + sf2d_end_frame(); + sf2d_swapbuffers(); +} + +static int _pollInput(void) { + hidScanInput(); + int keys = 0; + int activeKeys = hidKeysHeld(); + if (activeKeys & KEY_X) { + keys |= 1 << GUI_INPUT_CANCEL; + } + if (activeKeys & KEY_B) { + keys |= 1 << GUI_INPUT_BACK; + } + if (activeKeys & KEY_A) { + keys |= 1 << GUI_INPUT_SELECT; + } + if (activeKeys & KEY_LEFT) { + keys |= 1 << GUI_INPUT_LEFT; + } + if (activeKeys & KEY_RIGHT) { + keys |= 1 << GUI_INPUT_RIGHT; + } + if (activeKeys & KEY_UP) { + keys |= 1 << GUI_INPUT_UP; + } + if (activeKeys & KEY_DOWN) { + keys |= 1 << GUI_INPUT_DOWN; + } + return keys; +} + +int main() { + struct GBAContext context; + srvInit(); + aptInit(); + hidInit(0); + fsInit(); + sdmcInit(); + + sf2d_init(); + sf2d_set_clear_color(0); + sf2d_texture* tex = sf2d_create_texture(256, 256, TEXFMT_RGB565, SF2D_PLACE_RAM); + memset(tex->data, 0, 256 * 256 * 2); + + sdmcArchive = (FS_archive) { + ARCH_SDMC, + (FS_path) { PATH_EMPTY, 1, (const u8*)"" }, + 0, 0 + }; + FSUSER_OpenArchive(0, &sdmcArchive); + FSUSER_OpenFile(0, &logFile, sdmcArchive, FS_makePath(PATH_CHAR, "/mgba.log"), FS_OPEN_WRITE | FS_OPEN_CREATE, FS_ATTRIBUTE_NONE); + + struct GUIFont* font = GUIFontCreate(); + + GBAContextInit(&context, 0); + struct GBAOptions opts = { + .useBios = true, + .logLevel = 0, + .idleOptimization = IDLE_LOOP_REMOVE + }; + GBAConfigLoadDefaults(&context.config, &opts); + context.gba->logHandler = GBA3DSLog; + context.gba->logLevel = 0; + + struct GBAVideoSoftwareRenderer renderer; + GBAVideoSoftwareRendererCreate(&renderer); + renderer.outputBuffer = anonymousMemoryMap(256 * VIDEO_VERTICAL_PIXELS * 2); + renderer.outputBufferStride = 256; + GBAVideoAssociateRenderer(&context.gba->video, &renderer.d); + + if (!font) { + goto cleanup; + } + + struct GUIParams params = { + 320, 240, + font, _drawStart, _drawEnd, _pollInput + }; + + while (aptMainLoop()) { + char path[256]; + if (!selectFile(¶ms, "/", path, sizeof(path), "gba")) { + break; + } + _drawStart(); + GUIFontPrintf(font, 130, (GUIFontHeight(font) + 240) / 2, GUI_TEXT_LEFT, 0xFFFFFFFF, "Loading..."); + _drawEnd(); + if (!GBAContextLoadROM(&context, path, true)) { + continue; + } + if (!GBAContextStart(&context)) { + continue; + } + while (aptMainLoop()) { + hidScanInput(); + int activeKeys = hidKeysHeld() & 0x3FF; + if (hidKeysDown() & KEY_X) { + break; + } + GBAContextFrame(&context, activeKeys); + GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202); + GSPGPU_FlushDataCache(0, tex->data, 256 * VIDEO_VERTICAL_PIXELS * 2); + gspWaitForPPF(); + _drawStart(); + sf2d_draw_texture_scale(tex, 40, 296, 1, -1); + _drawEnd(); + } + GBAContextStop(&context); + } + GBAContextDeinit(&context); + +cleanup: + mappedMemoryFree(renderer.outputBuffer, 0); + + FSFILE_Close(logFile); + + sf2d_free_texture(tex); + sf2d_fini(); + + sdmcExit(); + fsExit(); + gfxExit(); + hidExit(); + aptExit(); + srvExit(); + return 0; +} + +static void GBA3DSLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) { + UNUSED(thread); + UNUSED(level); + char out[256]; + u64 size; + u32 written; + size_t len = vsnprintf(out, sizeof(out), format, args); + if (len >= 256) { + len = 255; + } + out[len] = '\n'; + FSFILE_GetSize(logFile, &size); + FSFILE_Write(logFile, &written, size, out, len + 1, FS_WRITE_FLUSH); +}
M
src/util/gui/file-select.c
→
src/util/gui/file-select.c
@@ -12,7 +12,7 @@
DECLARE_VECTOR(FileList, char*); DEFINE_VECTOR(FileList, char*); -void _cleanFiles(struct FileList* currentFiles) { +static void _cleanFiles(struct FileList* currentFiles) { size_t size = FileListSize(currentFiles); size_t i; for (i = 0; i < size; ++i) {@@ -21,7 +21,7 @@ }
FileListClear(currentFiles); } -void _upDirectory(char* currentPath) { +static void _upDirectory(char* currentPath) { char* end = strrchr(currentPath, '/'); if (!end) { return;@@ -37,7 +37,7 @@ }
// TODO: What if there was a trailing slash? } -bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) { +static bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) { _cleanFiles(currentFiles); struct VDir* dir = VDirOpen(currentPath);
M
src/util/vfs.c
→
src/util/vfs.c
@@ -8,6 +8,9 @@
#ifdef PSP2 #include "platform/psp2/sce-vfs.h" #endif +#ifdef _3DS +#include "platform/3ds/3ds-vfs.h" +#endif struct VFile* VFileOpen(const char* path, int flags) { #ifdef USE_VFS_FILE@@ -58,6 +61,34 @@ if (flags & O_CREAT) {
sceFlags |= PSP2_O_CREAT; } return VFileOpenSce(path, sceFlags, 0666); +#elif defined(USE_VFS_3DS) + int ctrFlags = FS_OPEN_READ; + switch (flags & O_ACCMODE) { + case O_WRONLY: + ctrFlags = FS_OPEN_WRITE; + break; + case O_RDWR: + ctrFlags = FS_OPEN_READ | FS_OPEN_WRITE; + break; + case O_RDONLY: + ctrFlags = FS_OPEN_READ; + break; + } + + if (flags & O_CREAT) { + ctrFlags |= FS_OPEN_CREATE; + } + struct VFile* vf = VFileOpen3DS(&sdmcArchive, path, ctrFlags); + if (!vf) { + return 0; + } + if (flags & O_TRUNC) { + vf->truncate(vf, 0); + } + if (flags & O_APPEND) { + vf->seek(vf, vf->size(vf), SEEK_SET); + } + return vf; #else return VFileOpenFD(path, flags); #endif