draft transfer implementation

This commit is contained in:
2024-08-25 00:02:59 +03:00
parent 31953464e7
commit 7d2da74466
105 changed files with 2311 additions and 4151 deletions

BIN
.DS_Store vendored

Binary file not shown.

34
.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
server
client

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

18
.idea/misc.xml generated
View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MakefileSettings">
<option name="linkedExternalProjectsSettings">
<MakefileProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="version" value="2" />
</MakefileProjectSettings>
</option>
</component>
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

7
.idea/vcs.xml generated
View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib" vcs="Git" />
</component>
</project>

View File

@@ -1,23 +1,30 @@
{
"configurations": [
{
"name": "DKP aarch64",
"includePath": [
"${env:DEVKITPRO}/devkitA64/aarch64-none-elf/include/**",
"${env:DEVKITPRO}/devkitARM/arm-none-eabi/include/**",
"${env:DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/13.2.0/include/**",
"${env:DEVKITPRO}/libnx/include/**",
"${env:DEVKITPRO}/portlibs/switch/include/**",
"${workspaceFolder}/include/**",
"${workspaceFolder}/lib/Plutonium/include/**",
"/opt/homebrew/opt/lz4/include/**"
],
"defines": ["SWITCH", "__SWITCH__", "DEBUG", "__BSD_VISIBLE"],
"compilerPath": "${env:DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++",
"cStandard": "c17",
"cppStandard": "c++14",
"intelliSenseMode": "linux-gcc-arm64"
}
],
"version": 4
"configurations": [
{
"name": "DKP aarch64",
"includePath": [
"${env:DEVKITPRO}/devkitA64/aarch64-none-elf/include/**",
"${env:DEVKITPRO}/devkitARM/arm-none-eabi/include/**",
"${env:DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/13.2.0/include/**",
"${env:DEVKITPRO}/libnx/include/**",
"${env:DEVKITPRO}/portlibs/switch/include/**",
"${workspaceFolder}/include/**",
"${workspaceFolder}/lib/Plutonium/include/**",
"/usr/local/include/**",
"/opt/homebrew/opt/lz4/include/**",
"/opt/devkitpro/devkitA64/aarch64-none-elf/include/machine"
],
"defines": [
"SWITCH",
"__SWITCH__",
"DEBUG",
"__BSD_VISIBLE"
],
"compilerPath": "${env:DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++",
"cStandard": "c17",
"cppStandard": "c++14",
"intelliSenseMode": "linux-gcc-arm64"
}
],
"version": 4
}

53
.vscode/settings.json vendored
View File

@@ -3,30 +3,23 @@
"string.h": "c",
"stdlib.h": "c",
"switch.h": "c",
"psm.h": "c",
"vector": "cpp",
"any": "cpp",
"optional": "cpp",
"array": "cpp",
"mutex": "cpp",
"any": "cpp",
"atomic": "cpp",
"barrier": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"cfenv": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"csetjmp": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
@@ -34,7 +27,6 @@
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cuchar": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
@@ -44,20 +36,16 @@
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"expected": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
@@ -65,37 +53,48 @@
"utility": "cpp",
"format": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"latch": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"scoped_allocator": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"spanstream": "cpp",
"sstream": "cpp",
"stacktrace": "cpp",
"stdexcept": "cpp",
"stdfloat": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"syncstream": "cpp",
"thread": "cpp",
"typeindex": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"filesystem": "cpp",
"plutonium": "cpp"
"plutonium": "cpp",
"barrier": "cpp",
"cfenv": "cpp",
"complex": "cpp",
"coroutine": "cpp",
"csetjmp": "cpp",
"csignal": "cpp",
"cuchar": "cpp",
"unordered_set": "cpp",
"expected": "cpp",
"regex": "cpp",
"source_location": "cpp",
"future": "cpp",
"latch": "cpp",
"scoped_allocator": "cpp",
"shared_mutex": "cpp",
"spanstream": "cpp",
"stacktrace": "cpp",
"stdfloat": "cpp",
"syncstream": "cpp",
"typeindex": "cpp"
}
}

View File

@@ -49,7 +49,7 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS += -g -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__
CFLAGS += $(INCLUDE) -D__SWITCH__ -D_GNU_SOURCE=1
CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17

View File

@@ -1,428 +0,0 @@
[
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/Main.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/Main.cpp",
"-o",
"Main.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/Main.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/MainApplication.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/MainApplication.cpp",
"-o",
"MainApplication.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/MainApplication.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/TitlesLayout.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/TitlesLayout.cpp",
"-o",
"TitlesLayout.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/TitlesLayout.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/UsersLayout.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/UsersLayout.cpp",
"-o",
"UsersLayout.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/UsersLayout.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/data.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/data.cpp",
"-o",
"data.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/data.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/fs.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/fs.cpp",
"-o",
"fs.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/fs.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/ldn.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/ldn.cpp",
"-o",
"ldn.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/ldn.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/threads.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/threads.cpp",
"-o",
"threads.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/threads.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/util.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/util.cpp",
"-o",
"util.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/util.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/dir.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/fs/dir.cpp",
"-o",
"dir.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/fs/dir.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/file.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/fs/file.cpp",
"-o",
"file.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/fs/file.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-g++",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/zip.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-fno-rtti",
"-fno-exceptions",
"-std=gnu++17",
"-c",
"/Users/n.fedorov/dev/NXST/source/fs/zip.cpp",
"-o",
"zip.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/fs/zip.cpp"
},
{
"directory": "/Users/n.fedorov/dev/NXST",
"arguments": [
"aarch64-none-elf-gcc",
"-MMD",
"-MP",
"-MF",
"/Users/n.fedorov/dev/NXST/build/fsfile.d",
"-g",
"-O2",
"-ffunction-sections",
"-march=armv8-a+crc+crypto",
"-mtune=cortex-a57",
"-mtp=soft",
"-fPIE",
"-I/Users/n.fedorov/dev/NXST/include",
"-I/Users/n.fedorov/dev/NXST/include/fs",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/opt/devkitpro/portlibs/switch/include",
"-I/opt/devkitpro/libnx/include",
"-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include",
"-I/Users/n.fedorov/dev/NXST/build",
"-D__SWITCH__",
"-c",
"/Users/n.fedorov/dev/NXST/source/fs/fsfile.c",
"-o",
"fsfile.o"
],
"file": "/Users/n.fedorov/dev/NXST/source/fs/fsfile.c"
}
]

37
deps/asprintf/asprintf.c vendored Normal file
View File

@@ -0,0 +1,37 @@
#include <stdio.h>
#include <stdlib.h>
#include "asprintf.h"
int vasprintf(char **strp, const char *fmt, va_list ap) {
int size, res;
va_list cp;
va_copy(cp, ap);
size = vsnprintf(NULL, 0, fmt, cp);
va_end(cp);
if (size < 0)
return -1;
*strp = (char *)malloc(size + 1);
if (*strp == NULL)
return -1;
res = vsnprintf(*strp, size + 1, fmt, ap);
if (res < 0) {
free(*strp);
return -1;
}
return res;
}
int asprintf(char **s, const char *fmt, ...) {
int ret;
va_list ap;
va_start(ap, fmt);
ret = vasprintf(s, fmt, ap);
va_end(ap);
return ret;
}

10
deps/asprintf/asprintf.h vendored Normal file
View File

@@ -0,0 +1,10 @@
#ifndef HAVE_ASPRINTF
#define HAVE_ASPRINTF 1
#include <stdarg.h>
int vasprintf(char **strp, const char *fmt, va_list ap);
int asprintf(char **s, const char *fmt, ...);
#endif

9
deps/asprintf/clib.json vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"name": "asprintf",
"version": "1.0.0",
"repo": "Neved4/asprintf",
"description": "asprintf, vasprintf - print to allocated string",
"license": "MIT",
"keywords": ["asprintf", "sprintf", "alloc", "string"],
"src": ["asprintf.c", "asprintf.h"]
}

View File

@@ -1,6 +1,6 @@
#include <pu/Plutonium>
#include <const.h>
#include <data.h>
#include <title.hpp>
namespace ui {
class TitlesLayout : public pu::ui::Layout {

74
include/account.hpp Normal file
View File

@@ -0,0 +1,74 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef ACCOUNT_HPP
#define ACCOUNT_HPP
#include <map>
#include <string.h>
#include <string>
#include <switch.h>
#include <vector>
#define USER_ICON_SIZE 64
namespace std {
template <>
struct hash<AccountUid> {
size_t operator()(const AccountUid& a) const { return ((hash<u64>()(a.uid[0]) ^ (hash<u64>()(a.uid[1]) << 1)) >> 1); }
};
}
inline bool operator==(const AccountUid& x, const AccountUid& y)
{
return x.uid[0] == y.uid[0] && x.uid[1] == y.uid[1];
}
inline bool operator==(const AccountUid& x, u64 y)
{
return x.uid[0] == y && x.uid[1] == y;
}
inline bool operator<(const AccountUid& x, const AccountUid& y)
{
return x.uid[0] < y.uid[0] && x.uid[1] == y.uid[1];
}
struct User {
AccountUid id;
std::string name;
};
namespace Account {
Result init(void);
void exit(void);
std::vector<AccountUid> ids(void);
AccountUid selectAccount(void);
std::string username(AccountUid id);
}
#endif

7
include/client.hpp Normal file
View File

@@ -0,0 +1,7 @@
#ifdef __SWITCH__
namespace fs = std::filesystem;
#else
namespace fs = std::__fs::filesystem;
#endif
int transfer_files(fs::path directory, char** filenames, int file_count);

65
include/common.hpp Normal file
View File

@@ -0,0 +1,65 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef COMMON_HPP
#define COMMON_HPP
#include <algorithm>
#include <arpa/inet.h>
#include <codecvt>
#include <cstdio>
#include <locale>
#include <memory>
#include <netinet/in.h>
#include <stdarg.h>
#include <string.h>
#include <string>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
#define ATEXIT(func) atexit((void (*)())func)
namespace DateTime {
std::string timeStr(void);
std::string dateTimeStr(void);
std::string logDateTime(void);
}
namespace StringUtils {
bool containsInvalidChar(const std::string& str);
std::string escapeJson(const std::string& s);
std::string format(const std::string fmt_str, ...);
std::string removeForbiddenCharacters(std::string src);
std::string UTF16toUTF8(const std::u16string& src);
void ltrim(std::string& s);
void rtrim(std::string& s);
void trim(std::string& s);
}
char* getConsoleIP(void);
#endif

View File

@@ -1,91 +0,0 @@
#pragma once
#include <switch.h>
#include <vector>
#include <string>
#include <unordered_map>
#define BLD_MON 02
#define BLD_DAY 23
#define BLD_YEAR 2023
namespace data
{
//Loads user + title info
void init();
void exit();
bool loadUsersTitles(bool clearUsers);
void sortUserTitles();
//Draws some stats to the upper left corner
void dispStats();
//Global stuff for all titles/saves
typedef struct
{
NacpStruct nacp;
std::string title, safeTitle, author;//Shortcuts sorta.
bool fav;
} titleInfo;
//Holds stuff specific to user's titles/saves
typedef struct
{
//Makes it easier to grab id
uint64_t tid;
FsSaveDataInfo saveInfo;
PdmPlayStatistics playStats;
} userTitleInfo;
//Class to store user info + titles
class user
{
public:
user() = default;
user(const AccountUid& _id, const std::string& _backupName, const std::string& _safeBackupName);
//Sets ID
void setUID(const AccountUid& _id);
//Returns user ID
AccountUid getUID() const { return userID; }
u128 getUID128() const { return uID128; }
//Returns username
std::string getUsername() const { return username; }
std::string getUsernameSafe() const { return userSafe; }
std::vector<data::userTitleInfo> titleInfo;
void addUserTitleInfo(const uint64_t& _tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats);
private:
AccountUid userID;
u128 uID128;
std::string username, userSafe;
//User icon
};
//User vector
extern std::vector<user> users;
//Title data/info map
extern std::unordered_map<uint64_t, data::titleInfo> titles;
//Sets/Retrieves current user/title
void setUserIndex(unsigned _sUser);
data::user *getCurrentUser();
unsigned getCurrentUserIndex();
void setTitleIndex(unsigned _sTitle);
data::userTitleInfo *getCurrentUserTitleInfo();
unsigned getCurrentUserTitleInfoIndex();
//Gets pointer to info that also has title + nacp
data::titleInfo *getTitleInfoByTID(const uint64_t& tid);
//More shortcut functions
std::string getTitleNameByTID(const uint64_t& tid);
std::string getTitleSafeNameByTID(const uint64_t& tid);
int getTitleIndexInUser(const data::user& u, const uint64_t& tid);
extern SetLanguage sysLang;
}

58
include/directory.hpp Normal file
View File

@@ -0,0 +1,58 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef DIRECTORY_HPP
#define DIRECTORY_HPP
#include <dirent.h>
#include <errno.h>
#include <string>
#include <switch.h>
#include <vector>
struct DirectoryEntry {
std::string name;
bool directory;
};
class Directory {
public:
Directory(const std::string& root);
~Directory() = default;
Result error(void);
std::string entry(size_t index);
bool folder(size_t index);
bool good(void);
size_t size(void);
private:
std::vector<struct DirectoryEntry> mList;
Result mError;
bool mGood;
};
#endif

39
include/filesystem.hpp Normal file
View File

@@ -0,0 +1,39 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef FILESYSTEM_HPP
#define FILESYSTEM_HPP
#include "account.hpp"
#include <switch.h>
namespace FileSystem {
Result mount(FsFileSystem* fileSystem, u64 titleID, AccountUid userID);
int mount(FsFileSystem fs);
void unmount(void);
}
#endif

View File

@@ -1,54 +0,0 @@
#pragma once
#include <cstring>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#include "fs/fstype.h"
#include "fs/file.h"
#include "fs/dir.h"
#include "fs/fsfile.h"
#include "fs/zip.h"
#define BUFF_SIZE 0x4000
#define ZIP_BUFF_SIZE 0x20000
#define TRANSFER_BUFFER_LIMIT 0xC00000
namespace fs
{
copyArgs *copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces);
void copyArgsDestroy(copyArgs *c);
void init();
bool mountSave(const FsSaveDataInfo& _m);
inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; }
bool commitToDevice(const std::string& dev);
std::string getWorkDir();
void setWorkDir(const std::string& _w);
//Loads paths to filter from backup/deletion
void loadPathFilters(const uint64_t& tid);
bool pathIsFiltered(const std::string& _path);
void freePathFilters();
void createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t);
void createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid);
bool extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t);
void extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize);
uint64_t getJournalSize(const data::userTitleInfo *tinfo);
uint64_t getJournalSizeMax(const data::userTitleInfo *tinfo);
//Always threaded
void wipeSave();
void createNewBackup(void *a);
void overwriteBackup(void *a);
void restoreBackup(void *a);
void deleteBackup(void *a);
void dumpAllUserSaves(void *a);
void dumpAllUsersAllSaves(void *a);
void logOpen();
void logWrite(const char *fmt, ...);
}

View File

@@ -1,54 +0,0 @@
#pragma once
#include <string>
#include "type.h"
namespace fs
{
void mkDir(const std::string& _p);
void mkDirRec(const std::string& _p);
void delDir(const std::string& _p);
bool dirNotEmpty(const std::string& _dir);
bool isDir(const std::string& _path);
//threadInfo is optional. Only for updating task status.
void copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t);
void copyDirToDirThreaded(const std::string& src, const std::string& dst);
void copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t);
void copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev);
void getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize);
class dirItem
{
public:
dirItem(const std::string& pathTo, const std::string& sItem);
std::string getItm() const { return itm; }
std::string getName() const;
std::string getExt() const;
bool isDir() const { return dir; }
private:
std::string itm;
bool dir = false;
};
//Just retrieves a listing for _path and stores it in item vector
class dirList
{
public:
dirList() = default;
dirList(const std::string& _path);
void reassign(const std::string& _path);
void rescan();
std::string getItem(int index) const { return item[index].getItm(); }
std::string getItemExt(int index) const { return item[index].getExt(); }
bool isDir(int index) const { return item[index].isDir(); }
unsigned getCount() const { return item.size(); }
fs::dirItem *getDirItemAt(unsigned int _ind) { return &item[_ind]; }
private:
std::string path;
std::vector<dirItem> item;
};
}

View File

@@ -1,64 +0,0 @@
#pragma once
#include <string>
#include <cstdio>
#include <vector>
#include <switch.h>
#include <dirent.h>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#include "fs.h"
#include "data.h"
namespace fs
{
//Copy args are optional and only used if passed and threaded
void copyFile(const std::string& src, const std::string& dst, threadInfo *t);
void copyFileThreaded(const std::string& src, const std::string& dst);
void copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t);
void copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev);
void fileDrawFunc(void *a);
//deletes file
void delfile(const std::string& _p);
//Dumps all titles for current user
void dumpAllUserSaves();
void getShowFileProps(const std::string& _path);
void getShowDirProps(const std::string& _path);
bool fileExists(const std::string& _path);
//Returns file size
size_t fsize(const std::string& _f);
class dataFile
{
public:
dataFile(const std::string& _path);
~dataFile();
void close(){ fclose(f); }
bool isOpen() const { return opened; }
bool readNextLine(bool proc);
//Finds where variable name ends. When a '(' or '=' is hit. Strips spaces
void procLine();
std::string getLine() const { return line; }
std::string getName() const { return name; }
//Reads until ';', ',', or '\n' is hit and returns as string.
std::string getNextValueStr();
int getNextValueInt();
private:
FILE *f;
std::string line, name;
size_t lPos = 0;
bool opened = false;
};
void logOpen();
void logWrite(const char *fmt, ...);
void logClose();
}

View File

@@ -1,100 +0,0 @@
#pragma once
#include <switch.h>
#include <stdint.h>
//Bare minimum wrapper around switch fs for JKSV
#define FS_SEEK_SET 0
#define FS_SEEK_CUR 1
#define FS_SEEK_END 2
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
FsFile _f;
Result error;
s64 offset, fsize;
} FSFILE;
int fsremove(const char *_p);
Result fsDelDirRec(const char *_p);
char *getDeviceFromPath(char *dev, size_t _max, const char *path);
char *getFilePath(char *pathOut, size_t _max, const char *path);
bool fsMkDir(const char *_p);
/*Opens file. Device is fetched from path. Libnx romfs doesn't work with this.
Mode needs to be:
FsOpenMode_Read
FsOpenMode_Write
FsOpenMode_Append
*/
bool fsfcreate(const char *_p, int64_t crSize);
FSFILE *fsfopen(const char *_p, uint32_t mode);
/*Same as above, but FsFileSystem _s is used. Path cannot have device in it*/
FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode);
//Closes _f
inline void fsfclose(FSFILE *_f)
{
if(_f != NULL)
{
fsFileClose(&_f->_f);
free(_f);
}
}
//Seeks like stdio
inline void fsfseek(FSFILE *_f, int offset, int origin)
{
switch(origin)
{
case FS_SEEK_SET:
_f->offset = offset;
break;
case FS_SEEK_CUR:
_f->offset += offset;
break;
case FS_SEEK_END:
_f->offset = offset + _f->fsize;
break;
}
}
//Returns offset
inline size_t fsftell(FSFILE *_f) { return _f->offset; }
//Writes buf to file. Automatically resizes _f to fit buf
size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f);
//Reads to buff
inline size_t fsfread(void *buf, size_t sz, size_t count, FSFILE *_f)
{
uint64_t read = 0;
_f->error = fsFileRead(&_f->_f, _f->offset, buf, sz * count, 0, &read);
_f->offset += read;
return read;
}
//Gets byte from file
inline char fsfgetc(FSFILE *_f)
{
char ret = 0;
uint64_t read = 0;
_f->error = fsFileRead(&_f->_f, _f->offset++, &ret, 1, 0, &read);
return ret;
}
//Writes byte to file
inline void fsfputc(int ch, FSFILE *_f) { fsfwrite(&ch, 1, 1, _f); }
#ifdef __cplusplus
}
#endif

View File

@@ -1,46 +0,0 @@
#pragma once
#include "data.h"
#include "type.h"
#include "ldn.h"
namespace fs
{
typedef struct
{
std::string src, dst, dev;
zipFile z;
unzFile unz;
LDN::LDNCommunicate *comm;
bool cleanup = false, trimZipPath = false;
uint8_t trimZipPlaces = 0;
uint64_t offset = 0;
threadStatus *thrdStatus;
Mutex arglck = 0;
void argLock() { mutexLock(&arglck); }
void argUnlock() { mutexUnlock(&arglck); }
} copyArgs;
typedef struct
{
FsSaveDataType type;
uint64_t tid;
AccountUid account;
uint16_t index;
} svCreateArgs;
typedef struct
{
const data::userTitleInfo *tinfo;
uint64_t extSize;
} svExtendArgs;
typedef struct
{
std::string path;
bool origin = false;
unsigned dirCount = 0;
unsigned fileCount = 0;
uint64_t totalSize = 0;
} dirCountArgs;
}

View File

@@ -1,94 +0,0 @@
#pragma once
#include <switch.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string>
#include <vector>
#include <lz4.h>
#include <lz4frame.h>
#include <lz4frame_static.h>
#include <mutex>
#include "type.h"
#define SAVE_DATA_SERVER_PORT 25789
#define SOCKET_BUFFER_SIZE 4096
#define LENGTH_OF_LISTEN_QUEUE 20
enum LDN_COMMUNICATE_TYPE {
UPDATE_FILE,
UPDATE_ABORT,
UPDATE_OK,
UPDATE_DONE,
};
struct LZ4_readFile_s {
LZ4F_dctx *dctxPtr;
int socket;
LZ4_byte *srcBuf;
size_t srcBufNext;
size_t srcBufSize;
size_t srcBufMaxSize;
};
struct LZ4_writeFile_s {
LZ4F_cctx *cctxPtr;
int socket;
LZ4_byte *dstBuf;
size_t maxWriteSize;
size_t dstBufMaxSize;
LZ4F_errorCode_t errCode;
};
namespace LDN {
typedef struct {
// point to server's socket fd;
int serverFD;
// point to communicate socket fd, send meta data
int commFD;
// for client to bind with server, communicate create file socket fd
struct sockaddr_in serverAddr;
} LDNCommunicate;
typedef struct {
LDNCommunicate *comm;
unsigned int filesize = 0, writeLimit = 0;
std::string fullPath;
std::mutex bufferLock;
std::condition_variable cond;
std::vector<uint8_t> sharedBuffer;
bool bufferIsFull = false;
std::string dst, dev;
LZ4_writeFile_s* lz4fWrite;
} LDNfcopyArgs;
typedef struct {
u32 type;
size_t fsz;
} commMeta;
void destroyLDN();
LDN::LDNCommunicate *createCommunicate(void);
void destroyCommunicate(LDNCommunicate *comm);
Result createLDNServer(LDNCommunicate *comm);
Result createLDNClient(LDNCommunicate *comm);
int bindClient(int serverFD);
int bindServer(sockaddr_in *serverAddr);
bool waitForOK(int socketfd);
bool waitForDONE(int socketfd);
void sendOK(int socket_fd);
void sendDONE(int socket_fd);
void sendAbort(int socket_fd);
void reciveMeta(commMeta *meta, int socketfd);
void sendMeta(commMeta *meta, int socketfd);
void copySaveFileToRemote(const std::string &local, threadInfo *t);
void copyRemoteSaveFile(threadInfo *t);
};

View File

@@ -1,18 +0,0 @@
#pragma once
#include <string>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#include "type.h"
namespace fs
{
//threadInfo is optional and only used when threaded versions are used
void copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t);
void copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces);
void copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t);
void copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev);
uint64_t getZipTotalSize(unzFile unz);
bool zipNotEmpty(unzFile unz);
}

55
include/io.hpp Normal file
View File

@@ -0,0 +1,55 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef IO_HPP
#define IO_HPP
#include "account.hpp"
#include "directory.hpp"
#include "title.hpp"
#include "util.hpp"
#include <dirent.h>
#include <switch.h>
#include <sys/stat.h>
#include <tuple>
#include <unistd.h>
#include <utility>
#define BUFFER_SIZE 0x80000
namespace io {
std::tuple<bool, Result, std::string> backup(size_t index, AccountUid uid);
std::tuple<bool, Result, std::string> restore(size_t index, AccountUid uid, size_t cellIndex, const std::string& nameFromCell);
Result copyDirectory(const std::string& srcPath, const std::string& dstPath);
void copyFile(const std::string& srcPath, const std::string& dstPath);
Result createDirectory(const std::string& path);
Result deleteFolderRecursively(const std::string& path);
bool directoryExists(const std::string& path);
bool fileExists(const std::string& path);
}
#endif

84
include/logger.hpp Normal file
View File

@@ -0,0 +1,84 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include "common.hpp"
#include <stdio.h>
#include <string>
class Logger {
public:
static Logger& getInstance(void)
{
static Logger mLogger;
return mLogger;
}
inline static const std::string INFO = "[ INFO]";
inline static const std::string DEBUG = "[DEBUG]";
inline static const std::string ERROR = "[ERROR]";
inline static const std::string WARN = "[ WARN]";
template <typename... Args>
void log(const std::string& level, const std::string& format = {}, Args... args)
{
// xcbuffer += StringUtils::format(("[" + DateTime::logDateTime() + "] " + level + " " + format + "\n").c_str(), args...);
printf("%s\n", format.c_str());
// printf("%s\n",StringUtils::format("[" + DateTime::logDateTime() + "] " + level + " " + format + "\n").c_str(), args...);
}
void flush(void)
{
mFile = fopen(mPath.c_str(), "a");
if (mFile != NULL) {
fprintf(mFile, buffer.c_str());
fprintf(stderr, buffer.c_str());
fclose(mFile);
}
}
private:
Logger(void) { buffer = ""; }
~Logger(void) {}
Logger(Logger const&) = delete;
void operator=(Logger const&) = delete;
#if defined(__SWITCH__)
const std::string mPath = "/switch/NXST/log.log";
#else
const std::string mPath = "log.log";
#endif
FILE* mFile;
std::string buffer;
};
#endif

26
include/main.hpp Normal file
View File

@@ -0,0 +1,26 @@
#ifndef MAIN_HPP
#define MAIN_HPP
#include <const.h>
#include "account.hpp"
#include "title.hpp"
#include "util.hpp"
#include <memory>
#include <switch.h>
#include "logger.hpp"
typedef enum { SORT_ALPHA, SORT_LAST_PLAYED, SORT_PLAY_TIME, SORT_MODES_COUNT } sort_t;
inline float g_currentTime = 0;
inline AccountUid g_currentUId;
inline bool g_backupScrollEnabled = 0;
inline bool g_notificationLedAvailable = false;
inline bool g_shouldExitNetworkLoop = false;
inline std::string g_selectedCheatKey;
inline std::vector<std::string> g_selectedCheatCodes;
inline u32 g_username_dotsize;
inline sort_t g_sortMode = SORT_ALPHA;
inline std::string g_currentFile = "";
inline bool g_isTransferringFile = false;
inline const std::string g_emptySave = "New...";
#endif

View File

@@ -1,44 +0,0 @@
#include <switch.h>
#include "type.h"
namespace threads {
//pad data cause i don't know where else to put it
extern PadState pad;
extern HidTouchScreenState touchState;
static inline void updateInput() {
touchState = {0};
padUpdate(&pad);
hidGetTouchScreenStates(&touchState, 1);
}
inline uint64_t padKeysDown() { return padGetButtonsDown(&pad); }
inline uint64_t padKeysHeld() { return padGetButtons(&pad); }
inline uint64_t padKeysUp() { return padGetButtonsUp(&pad); }
threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc);
class threadProcMngr {
public:
~threadProcMngr();
//Draw function is used and called to draw on overlay
threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc);
void update();
void draw();
bool empty() { return threads.empty(); }
private:
std::vector<threadInfo *> threads;
uint8_t lgFrame = 0, clrShft = 0;
bool clrAdd = true;
unsigned frameCount = 0;
Mutex threadLock = 0;
};
}

90
include/title.hpp Normal file
View File

@@ -0,0 +1,90 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef TITLE_HPP
#define TITLE_HPP
#include "account.hpp"
#include "filesystem.hpp"
#include "io.hpp"
#include <algorithm>
#include <stdlib.h>
#include <string>
#include <switch.h>
#include <unordered_map>
#include <utility>
#include <vector>
class Title {
public:
void init(u8 saveDataType, u64 titleid, AccountUid userID, const std::string& name, const std::string& author);
~Title() = default;
std::string author(void);
std::pair<std::string, std::string> displayName(void);
u64 id(void);
std::string name(void);
std::string path(void);
u64 playTimeNanoseconds(void);
std::string playTime(void);
void playTimeNanoseconds(u64 playTimeNanoseconds);
u32 lastPlayedTimestamp(void);
void lastPlayedTimestamp(u32 lastPlayedTimestamp);
std::string fullPath(size_t index);
void refreshDirectories(void);
u64 saveId();
void saveId(u64 id);
std::vector<std::string> saves(void);
u8 saveDataType(void);
AccountUid userId(void);
std::string userName(void);
private:
u64 mId;
u64 mSaveId;
AccountUid mUserId;
std::string mUserName;
std::string mName;
std::string mSafeName;
std::string mAuthor;
std::string mPath;
std::vector<std::string> mSaves;
std::vector<std::string> mFullSavePaths;
u8 mSaveDataType;
std::pair<std::string, std::string> mDisplayName;
u64 mPlayTimeNanoseconds;
u32 mLastPlayedTimestamp;
};
void getTitle(Title& dst, AccountUid uid, size_t i);
size_t getTitleCount(AccountUid uid);
void loadTitles(void);
void sortTitles(void);
void rotateSortMode(void);
void refreshDirectories(u64 id);
std::unordered_map<std::string, std::string> getCompleteTitleList(void);
#endif

View File

@@ -1,29 +0,0 @@
#pragma once
#include <stdio.h>
#include <stdarg.h>
#include <string>
#include <switch.h>
//Misc stuff for new menu code
typedef void (*funcPtr)(void *);
class threadStatus
{
public:
void setStatus(const char *fmt, ...);
void getStatus(std::string& statusOut);
private:
Mutex statusLock = 0;
std::string status;
};
typedef struct
{
bool running = false, finished = false;
Thread thrd;
ThreadFunc thrdFunc;
void *argPtr = NULL;
funcPtr drawFunc = NULL;//Draw func is passed threadInfo pointer too
threadStatus *status;
} threadInfo;

View File

@@ -1,152 +0,0 @@
#pragma once
#include "data.h"
//#include "ui.h"
#include "fs/file.h"
//#include "gfx.h"
namespace util
{
enum
{
DATE_FMT_YMD,
DATE_FMT_YDM,
DATE_FMT_HOYSTE,
DATE_FMT_JHK,
DATE_FMT_ASC
};
typedef enum
{
CPU_SPEED_204MHz = 204000000,
CPU_SPEED_306MHz = 306000000,
CPU_SPEED_408MHz = 408000000,
CPU_SPEED_510MHz = 510000000,
CPU_SPEED_612MHz = 612000000,
CPU_SPEED_714MHz = 714000000,
CPU_SPEED_816MHz = 816000000,
CPU_SPEED_918MHz = 918000000,
CPU_SPEED_1020MHz = 1020000000, //Default
CPU_SPEED_1122MHz = 1122000000,
CPU_SPEED_1224MHz = 1224000000,
CPU_SPEED_1326MHz = 1326000000,
CPU_SPEED_1428MHz = 1428000000,
CPU_SPEED_1581MHz = 1581000000,
CPU_SPEED_1683MHz = 1683000000,
CPU_SPEED_1785MHz = 1785000000
} cpuSpds;
typedef enum
{
GPU_SPEED_0MHz = 0,
GPU_SPEED_76MHz = 76800000,
GPU_SPEED_153MHz = 153600000,
GPU_SPEED_203MHz = 230400000,
GPU_SPEED_307MHz = 307200000, //Handheld 1
GPU_SPEED_384MHz = 384000000, //Handheld 2
GPU_SPEED_460MHz = 460800000,
GPU_SPEED_537MHz = 537600000,
GPU_SPEED_614MHz = 614400000,
GPU_SPEED_768MHz = 768000000, //Docked
GPU_SPEED_844MHz = 844800000,
GPU_SPEED_921MHZ = 921600000
} gpuSpds;
typedef enum
{
RAM_SPEED_0MHz = 0,
RAM_SPEED_40MHz = 40800000,
RAM_SPEED_68MHz = 68000000,
RAM_SPEED_102MHz = 102000000,
RAM_SPEED_204MHz = 204000000,
RAM_SPEED_408MHz = 408000000,
RAM_SPEED_665MHz = 665600000,
RAM_SPEED_800MHz = 800000000,
RAM_SPEED_1065MHz = 1065600000,
RAM_SPEED_1331MHz = 1331200000,
RAM_SPEED_1600MHz = 1600000000
} ramSpds;
//Returns string with date S+ time
std::string getDateTime(int fmt);
//Removes last folder from '_path'
void removeLastFolderFromString(std::string& _path);
size_t getTotalPlacesInPath(const std::string& _path);
void trimPath(std::string& _path, uint8_t _places);
inline bool isASCII(const uint32_t& t)
{
return t > 30 && t < 127;
}
std::string safeString(const std::string& s);
std::string getStringInput(SwkbdType _type, const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]);
std::string getExtensionFromString(const std::string& get);
std::string getFilenameFromPath(const std::string& get);
std::string generateAbbrev(const uint64_t& tid);
//removes char from C++ string
void stripChar(char _c, std::string& _s);
void replaceStr(std::string& _str, const std::string& _find, const std::string& _rep);
//For future external translation support. Replaces [button] with button chars
void replaceButtonsInString(std::string& rep);
inline u128 accountUIDToU128(AccountUid uid)
{
return ((u128)uid.uid[0] << 64 | uid.uid[1]);
}
inline AccountUid u128ToAccountUID(u128 id)
{
AccountUid ret;
ret.uid[0] = id >> 64;
ret.uid[1] = id;
return ret;
}
inline std::string getIDStr(const uint64_t& _id)
{
char tmp[18];
sprintf(tmp, "%016lX", _id);
return std::string(tmp);
}
inline std::string getIDStrLower(const uint64_t& _id)
{
char tmp[18];
sprintf(tmp, "%08X", (uint32_t)_id);
return std::string(tmp);
}
inline std::string generatePathByTID(const uint64_t& tid)
{
return fs::getWorkDir() + data::getTitleSafeNameByTID(tid) + "/";
}
std::string getSizeString(const uint64_t& _size);
inline void createTitleDirectoryByTID(const uint64_t& tid)
{
std::string makePath = fs::getWorkDir() + data::getTitleSafeNameByTID(tid);
mkdir(makePath.c_str(), 777);
}
Result accountDeleteUser(AccountUid *uid);
void sysBoost();
void sysNormal();
inline bool isApplet()
{
AppletType type = appletGetAppletType();
return type == AppletType_LibraryApplet;
}
void checkForUpdate(void *a);
}

52
include/util.hpp Normal file
View File

@@ -0,0 +1,52 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#ifndef UTIL_HPP
#define UTIL_HPP
#include "account.hpp"
#include "common.hpp"
#include "io.hpp"
#include <switch.h>
#include <sys/stat.h>
// debug
#include <arpa/inet.h>
#include <sys/errno.h>
#include <sys/socket.h>
void servicesExit(void);
Result servicesInit(void);
HidsysNotificationLedPattern blinkLedPattern(u8 times);
void blinkLed(u8 times);
namespace StringUtils {
std::string removeAccents(std::string str);
std::string removeNotAscii(std::string str);
std::u16string UTF8toUTF16(const char* src);
}
#endif

237
server.cpp Normal file
View File

@@ -0,0 +1,237 @@
#include <iostream>
#include <fstream>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#include <filesystem>
#ifdef __SWITCH__
#include <switch.h>
#endif
#define PORT 8080
#define BUFFER_SIZE 1024
#define MULTICAST_PORT 8081
#define MULTICAST_GROUP "239.0.0.1" // Multicast group IP
void sendAck(int sock) {
const char *ack = "ACK";
std::cout << "Sending ACK " << std::endl;
send(sock, ack, strlen(ack), 0);
}
// Функция для получения файла
void receive_file(std::string dirname, int client_socket) {
char buffer[BUFFER_SIZE] = {0};
// Receive filename length
uint32_t filename_len;
ssize_t bytes_read = read(client_socket, &filename_len, sizeof(filename_len));
std::cout << "Filename length: " << filename_len << std::endl;
// Check for end-of-transmission signal
if (bytes_read <= 0 || filename_len == 0) {
std::cout << "End of transmission detected." << std::endl;
pthread_exit(nullptr);
}
// Receive filename
char *filename = new char[filename_len + 1];
read(client_socket, filename, filename_len);
filename[filename_len] = '\0';
std::cout << "Receiving file: " << filename << std::endl;
// Receive file size
size_t file_size;
read(client_socket, &file_size, sizeof(file_size));
std::cout << "With size: " << file_size << std::endl;
// Open a file to write the received data
std::ofstream outfile(dirname + "/" + filename, std::ios::binary);
delete[] filename; // Clean up filename buffer
size_t total_bytes_received = 0;
while (total_bytes_received < file_size) {
ssize_t bytes_received = read(client_socket, buffer, BUFFER_SIZE);
std::cout << "bytes received: " << bytes_received << std::endl;
if (bytes_received <= 0) {
break;
}
outfile.write(buffer, bytes_received);
total_bytes_received += bytes_received;
// Send acknowledgment for each chunk received
sendAck(client_socket);
}
std::cout << "File received successfully." << std::endl;
outfile.close();
}
void *handle_client(void *socket_desc) {
int client_socket = *(int *)socket_desc;
free(socket_desc);
std::cout << "Обработка нового клиента в потоке " << pthread_self() << "\n";
// Receive directory length
uint32_t directory_len;
ssize_t bytes_read = read(client_socket, &directory_len, sizeof(directory_len));
// Check for end-of-transmission signal
if (bytes_read <= 0 || directory_len == 0) {
std::cout << "End of transmission detected." << std::endl;
pthread_exit(nullptr);
}
// Receive filename
char *dirname = new char[directory_len + 1];
read(client_socket, dirname, directory_len);
dirname[directory_len] = '\0';
std::cout << "Directory name is " << dirname << std::endl;
if (!std::filesystem::create_directory(dirname)) {
std::cerr << "Unable to create directory" << std::endl;
pthread_exit(nullptr);
}
// Получаем файлы до тех пор, пока клиент не закроет соединение
while (true) {
receive_file(dirname, client_socket);
}
close(client_socket);
pthread_exit(nullptr);
}
void *broadcast_listener(void *) {
int sockfd;
struct sockaddr_in servaddr;
char buffer[BUFFER_SIZE];
struct ip_mreq group;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
pthread_exit(nullptr);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(MULTICAST_PORT);
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) {
perror("binding datagram socket");
close(sockfd);
pthread_exit(nullptr);
}
group.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
group.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
perror("setsockopt failed");
close(sockfd);
pthread_exit(nullptr);
}
std::cout << "Broadcast listener started" << std::endl;
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
while (true) {
int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&client_addr, &addr_len);
if (n < 0) {
perror("recvfrom failed");
continue;
}
std::cout << buffer << std::endl;
buffer[n] = '\0';
if (strcmp(buffer, "DISCOVER_SERVER") == 0) {
const char *message = "SERVER_HERE";
sendto(sockfd, message, strlen(message), 0, (const struct sockaddr *)&client_addr, addr_len);
std::cout << "Server discovery response sent to multicast group" << std::endl;
}
}
close(sockfd);
pthread_exit(nullptr);
}
int main() {
#ifdef __SWITCH__
socketInitializeDefault();
nxlinkStdio();
#endif
pthread_t broadcast_thread;
if (pthread_create(&broadcast_thread, nullptr, broadcast_listener, nullptr) < 0) {
perror("Thread creation failed");
return 1;
}
int server_fd, new_socket;
struct sockaddr_in address;
socklen_t addrlen = sizeof(address);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0) {
perror("Listen failed");
close(server_fd);
exit(EXIT_FAILURE);
}
std::cout << "Server listening on port " << PORT << std::endl;
while (true) {
sockaddr_in client_address;
socklen_t client_len = sizeof(client_address);
int client_socket = accept(server_fd, (sockaddr *)&client_address, &client_len);
if (client_socket < 0) {
std::cerr << "Ошибка принятия подключения\n";
continue;
}
// Создаем новый поток для обработки клиента
pthread_t thread_id;
int *pclient = new (std::nothrow) int(client_socket);
if (!pclient) {
std::cerr << "Ошибка выделения памяти\n";
close(client_socket);
continue;
}
if (pthread_create(&thread_id, nullptr, handle_client, pclient) != 0) {
std::cerr << "Ошибка создания потока\n";
delete pclient; // Освобождаем память при ошибке
} else {
pthread_detach(thread_id); // Отсоединяем поток, чтобы он мог завершиться самостоятельно
}
}
close(server_fd);
#ifdef __SWITCH__
socketExit();
#endif
return 0;
}

View File

@@ -1,6 +1,6 @@
#include <MainApplication.hpp>
#include <data.h>
#include <fs.h>
#include "util.hpp"
#include "main.hpp"
static int nxlink_sock = -1;
@@ -35,7 +35,14 @@ extern "C" void userAppExit() {
// Main entrypoint
int main() {
printf("main\n");
Result res = servicesInit();
if (R_FAILED(res)) {
servicesExit();
exit(res);
}
loadTitles();
// First create our renderer, where one can customize SDL or other stuff's
// initialization.
auto renderer_opts = pu::ui::render::RendererInitOptions(
@@ -46,8 +53,6 @@ int main() {
auto renderer = pu::ui::render::Renderer::New(renderer_opts);
data::init();
fs::init();
// Create our main application from the renderer
auto main = ui::MainApplication::New(renderer);

View File

@@ -1,43 +1,21 @@
#include <MainApplication.hpp>
#include <cinttypes>
#include <cstdio>
#include <data.h>
#include <stdio.h>
#include <main.hpp>
#include <const.h>
#include <client.hpp>
static std::vector<uint64_t> accSids, devSids, bcatSids, cacheSids;
//Sort save create tids alphabetically by title from data
static struct
{
bool operator()(const uint64_t& tid1, const uint64_t& tid2)
{
std::string tid1Title = data::getTitleNameByTID(tid1);
std::string tid2Title = data::getTitleNameByTID(tid2);
uint32_t pointA = 0, pointB = 0;
for(unsigned i = 0, j = 0; i < tid1Title.length(); )
{
ssize_t tid1Cnt = decode_utf8(&pointA, (const uint8_t *)&tid1Title.c_str()[i]);
ssize_t tid2Cnt = decode_utf8(&pointB, (const uint8_t *)&tid2Title.c_str()[j]);
pointA = tolower(pointA), pointB = tolower(pointB);
if(pointA != pointB)
return pointA < pointB;
i += tid1Cnt, j += tid2Cnt;
}
return false;
}
} sortCreateTIDs;
namespace ui {
extern MainApplication *mainApp;
void TitlesLayout::InitTitles() {
this->titlesMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94, 7);
const data::user *u = data::getCurrentUser();
for(const data::userTitleInfo& t : u->titleInfo) {
auto titleItem = pu::ui::elm::MenuItem::New(data::getTitleNameByTID(t.tid).c_str());
for (size_t i = 0; i < getTitleCount(g_currentUId); i++) {
Title title;
getTitle(title, g_currentUId, i);
auto titleItem = pu::ui::elm::MenuItem::New(title.name().c_str());
titleItem->SetColor(COLOR("#FFFFFFFF"));
titlesMenu->AddItem(titleItem);
this->titlesMenu->AddItem(titleItem);
}
this->Add(this->titlesMenu);
@@ -52,13 +30,32 @@ namespace ui {
}
if (Down & HidNpadButton_A) {
printf("current game index is %i\n", this->titlesMenu->GetSelectedIndex());
data::setTitleIndex(this->titlesMenu->GetSelectedIndex());
int opt = mainApp->CreateShowDialog("", "What do you want?", { "Transfer", "Receive" }, true);
printf("opt is %d\n", opt);
auto index = this->titlesMenu->GetSelectedIndex();
Title title;
getTitle(title, g_currentUId, index);
printf("userid is 0x%lX%lX\n", title.userId().uid[1], title.userId().uid[0]);
printf("current game index is %i\n", index);
int opt = mainApp->CreateShowDialog(title.name().c_str(), "What do you want?", { "Transfer", "Receive" }, true);
switch (opt) {
case 0: {
// Transfert selected
printf("path is %s\n", title.fullPath(0).c_str());
// Transfer selected
auto result = io::backup(index, g_currentUId);
if (std::get<0>(result)) {
printf("path is %s\n", std::get<2>(result).c_str());
std::string path = std::get<2>(result);
std::vector<std::string> files;
std::vector<char*> cstrings{};
auto directory = std::filesystem::path(path);
for (const auto & entry : std::filesystem::directory_iterator(path)) {
std::cout << entry.path() << std::endl;
files.push_back(entry.path().string());
}
for (auto& file : files) {
cstrings.push_back(&file.front());
}
transfer_files(directory, cstrings.data(), cstrings.size());
}
break;
}
case 1: {

View File

@@ -1,17 +1,16 @@
#include <cstdio>
#include <data.h>
#include <MainApplication.hpp>
#include "main.hpp"
namespace ui {
extern MainApplication *mainApp;
UsersLayout::UsersLayout() : Layout::Layout() {
this->usersMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94,
7);
this->usersMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94, 7);
this->usersMenu->SetScrollbarColor(COLOR("#170909FF"));
for (data::user &u: data::users) {
auto username = pu::ui::elm::MenuItem::New(u.getUsername() + ": " + std::to_string(u.titleInfo.size()));
for (AccountUid const& uid : Account::ids()) {
auto username = pu::ui::elm::MenuItem::New(Account::username(uid) + ": " + std::to_string(getTitleCount(uid)));
username->SetColor(COLOR("#FFFFFFFF"));
this->usersMenu->AddItem(username);
}
@@ -31,7 +30,7 @@ namespace ui {
if (Down & HidNpadButton_A) {
printf("current index is %i\n", this->usersMenu->GetSelectedIndex());
data::setUserIndex(this->usersMenu->GetSelectedIndex());
g_currentUId = Account::ids().at(this->usersMenu->GetSelectedIndex());
mainApp->titlesLayout->InitTitles();
mainApp->LoadLayout(mainApp->titlesLayout);
}

95
source/account.cpp Normal file
View File

@@ -0,0 +1,95 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "account.hpp"
#include <main.hpp>
static std::map<AccountUid, User> mUsers;
Result Account::init(void)
{
return accountInitialize(AccountServiceType_Application);
}
void Account::exit(void)
{
accountExit();
}
std::vector<AccountUid> Account::ids(void)
{
std::vector<AccountUid> v;
for (auto& value : mUsers) {
v.push_back(value.second.id);
}
return v;
}
static User getUser(AccountUid id)
{
User user{id, ""};
AccountProfile profile;
AccountProfileBase profilebase;
memset(&profilebase, 0, sizeof(profilebase));
if (R_SUCCEEDED(accountGetProfile(&profile, id)) && R_SUCCEEDED(accountProfileGet(&profile, NULL, &profilebase))) {
user.name = std::string(profilebase.nickname, 0x20);
}
accountProfileClose(&profile);
return user;
}
std::string Account::username(AccountUid id)
{
std::map<AccountUid, User>::const_iterator got = mUsers.find(id);
if (got == mUsers.end()) {
User user = getUser(id);
mUsers.insert({id, user});
return user.name;
}
return got->second.name;
}
AccountUid Account::selectAccount(void)
{
LibAppletArgs args;
libappletArgsCreate(&args, 0x10000);
u8 st_in[0xA0] = {0};
u8 st_out[0x18] = {0};
size_t repsz;
Result res = libappletLaunch(AppletId_LibraryAppletPlayerSelect, &args, st_in, 0xA0, st_out, 0x18, &repsz);
if (R_SUCCEEDED(res)) {
u64 lres = *(u64*)st_out;
AccountUid uid = *(AccountUid*)&st_out[8];
if (lres == 0)
return uid;
}
return g_currentUId;
}

258
source/client.cpp Normal file
View File

@@ -0,0 +1,258 @@
#include <cstring>
#include <fcntl.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <ostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <logger.hpp>
#ifdef __SWITCH__
#include <switch.h>
#include <client.hpp>
namespace fs = std::filesystem;
#else
namespace fs = std::__fs::filesystem;
#endif
#define PORT 8080
#define BUFFER_SIZE 1024
#define MULTICAST_PORT 8081
#define MULTICAST_GROUP "239.0.0.1" // Multicast group IP
struct ThreadArgs
{
char **filenames;
int file_count;
int sock;
fs::path directory;
};
bool receiveAck(int sock)
{
char ack[4] = {0};
int bytes_received = read(sock, ack, 3);
return bytes_received > 0 && std::string(ack) == "ACK";
}
// Отправка строки с учетом её длины
void send_string(int sock, const std::string &str)
{
size_t length = str.size();
send(sock, &length, sizeof(length), 0);
send(sock, str.c_str(), length, 0);
}
void *send_files_thread(void *args)
{
ThreadArgs *thread_args = static_cast<ThreadArgs *>(args);
char **filenames = thread_args->filenames;
int file_count = thread_args->file_count;
int sock = thread_args->sock;
fs::path cwd = thread_args->directory;
delete thread_args;
char buffer[BUFFER_SIZE];
// Send the directory length
std::cout << Logger::INFO << "cwd.filename is: " << cwd.filename().c_str() << std::endl; // Get the parent directory
std::string dirname = cwd.parent_path().filename();
uint32_t directory_len = dirname.size();
send(sock, &directory_len, sizeof(directory_len), 0);
// Send the dirname
send(sock, dirname.c_str(), directory_len, 0);
for (int i = 0; i < file_count; ++i)
{
std::string path = filenames[i];
std::size_t found = path.find_last_of("/\\");
std::string filename = path.substr(found+1);
std::ifstream infile(path, std::ios::binary | std::ios::ate);
if (!infile.is_open())
{
std::cout << Logger::ERROR << "File not found: " << filename.c_str() << std::endl;
return nullptr;
}
// Get the size of the file
std::streamsize file_size = infile.tellg();
infile.seekg(0, std::ios::beg);
// Send the filename length
uint32_t filename_len = filename.size();
std::cout << Logger::INFO << "Send filename length: " << filename_len << std::endl;
send(sock, &filename_len, sizeof(filename_len), 0);
// Send the filename
std::cout << Logger::INFO << "Send file name: " << filename.c_str() << std::endl;
send(sock, filename.c_str(), filename_len, 0);
// Send the file size
std::cout << Logger::INFO << "Send file size: " << file_size << std::endl;
send(sock, &file_size, sizeof(file_size), 0);
char buffer[BUFFER_SIZE];
// Send the file data
while (file_size > 0)
{
infile.read(buffer, BUFFER_SIZE);
send(sock, buffer, infile.gcount(), 0);
file_size -= infile.gcount();
std::cout << Logger::INFO << "wait for ACK" << std::endl;
// Wait for acknowledgment after each chunk
if (!receiveAck(sock))
{
std::cout << Logger::ERROR << "Failed to receive acknowledgment" << std::endl;;
}
}
send(sock, 0, 0, 0);
std::cout << Logger::INFO << "File sent successfully: " << filename.c_str() << std::endl;
infile.close();
}
close(sock);
pthread_exit(nullptr);
}
int find_server(char *server_ip)
{
std::cout << Logger::INFO << "Init find_server" << std::endl;;
int sockfd;
struct sockaddr_in multicast_addr;
std::cout << Logger::INFO << "Create socket" << std::endl;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
std::cout << Logger::ERROR << "Socket creation error" << std::endl;
return -1;
}
memset(&multicast_addr, 0, sizeof(multicast_addr));
multicast_addr.sin_family = AF_INET;
multicast_addr.sin_port = htons(MULTICAST_PORT);
multicast_addr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP);
std::cout << Logger::INFO << "Send DISCOVER_SERVER" << std::endl;
const char *multicast_message = "DISCOVER_SERVER";
if (sendto(sockfd, multicast_message, strlen(multicast_message), 0, (struct sockaddr *)&multicast_addr, sizeof(multicast_addr)) < 0)
{
std::cout << Logger::ERROR << "sendto failed" << std::endl;
close(sockfd);
return -1;
}
else
{
std::cout << Logger::INFO << "send multicast message success" << std::endl;
}
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
char buffer[BUFFER_SIZE];
ssize_t n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, &len);
std::cout << Logger::INFO << "recvfrom n: %i" << n << std::endl;
if (n < 0)
{
std::cout << Logger::ERROR << "recvfrom failed" << std::endl;
close(sockfd);
return -1;
}
std::cout << Logger::INFO << "buffer: " << buffer << std::endl;
buffer[n] = '\0';
if (strcmp(buffer, "SERVER_HERE") == 0)
{
std::cout << Logger::INFO << "Server found" << std::endl;
inet_ntop(AF_INET, &cliaddr.sin_addr, server_ip, INET_ADDRSTRLEN);
}
else
{
std::cout << Logger::ERROR << "Unable to find server, close socket" << std::endl;;
close(sockfd);
return -1;
}
close(sockfd);
return 0;
}
int transfer_files(fs::path directory, char **filenames, int file_count) {
std::cout << Logger::INFO << "Init transfer_files" << std::endl;
char server_ip[INET_ADDRSTRLEN];
if (find_server(server_ip) != 0)
{
std::cout << Logger::ERROR << "Failed to find server" << std::endl;
return -1;
}
int sock = 0;
struct sockaddr_in serv_addr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
std::cout << Logger::ERROR << "Socket creation error" << std::endl;
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, server_ip, &serv_addr.sin_addr) <= 0)
{
std::cout << Logger::ERROR << "Invalid address / Address not supported" << std::endl;
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
std::cout << Logger::ERROR << "Connection failed" << std::endl;
return -1;
}
pthread_t file_thread;
ThreadArgs *thread_args = new ThreadArgs{filenames, file_count, sock, directory};
if (pthread_create(&file_thread, nullptr, send_files_thread,
(void *)thread_args) < 0)
{
std::cout << Logger::ERROR << "Thread creation failed" << std::endl;
close(sock);
delete thread_args;
return -1;
}
else
{
std::cout << Logger::INFO << "Wait for file_thread" << std::endl;
pthread_join(file_thread, nullptr);
}
return 0;
}
#ifndef __SWITCH__ // for desktop
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " <filename1> <filename2> ..." << std::endl;
return 1;
}
char **filenames = const_cast<char **>(&argv[1]);
int file_count = argc - 1;
transfer_files(filenames, file_count);
return 0;
}
#endif

124
source/common.cpp Normal file
View File

@@ -0,0 +1,124 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "common.hpp"
std::string DateTime::timeStr(void)
{
time_t unixTime;
struct tm timeStruct;
time(&unixTime);
localtime_r(&unixTime, &timeStruct);
return StringUtils::format("%02i:%02i:%02i", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
}
std::string DateTime::dateTimeStr(void)
{
time_t unixTime;
struct tm timeStruct;
time(&unixTime);
localtime_r(&unixTime, &timeStruct);
return StringUtils::format("%04i%02i%02i-%02i%02i%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday, timeStruct.tm_hour,
timeStruct.tm_min, timeStruct.tm_sec);
}
std::string DateTime::logDateTime(void)
{
time_t unixTime;
struct tm timeStruct;
time(&unixTime);
localtime_r(&unixTime, &timeStruct);
return StringUtils::format("%04i-%02i-%02i %02i:%02i:%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday,
timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
}
std::string StringUtils::UTF16toUTF8(const std::u16string& src)
{
static std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::string dst = convert.to_bytes(src);
return dst;
}
std::string StringUtils::removeForbiddenCharacters(std::string src)
{
static const std::string illegalChars = ".,!\\/:?*\"<>|";
for (size_t i = 0, sz = src.length(); i < sz; i++) {
if (illegalChars.find(src[i]) != std::string::npos) {
src[i] = ' ';
}
}
size_t i;
for (i = src.length() - 1; i > 0 && src[i] == ' '; i--)
;
src.erase(i + 1, src.length() - i);
return src;
}
std::string StringUtils::format(const std::string fmt_str, ...)
{
va_list ap;
char* fp = NULL;
va_start(ap, fmt_str);
vasprintf(&fp, fmt_str.c_str(), ap);
va_end(ap);
std::unique_ptr<char[]> formatted(fp);
return std::string(formatted.get());
}
bool StringUtils::containsInvalidChar(const std::string& str)
{
for (size_t i = 0, sz = str.length(); i < sz; i++) {
if (!isascii(str[i])) {
return true;
}
}
return false;
}
void StringUtils::ltrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); }));
}
void StringUtils::rtrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end());
}
void StringUtils::trim(std::string& s)
{
ltrim(s);
rtrim(s);
}
char* getConsoleIP(void)
{
struct in_addr in;
in.s_addr = gethostid();
return inet_ntoa(in);
}

View File

@@ -1,352 +0,0 @@
#include <vector>
#include <unordered_map>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <ctime>
#include <switch.h>
#include "data.h"
#include "fs/file.h"
#include "util.h"
#include "type.h"
//FsSaveDataSpaceId_All doesn't work for SD
static const unsigned saveOrder[] = {0, 1, 2, 3, 4, 100, 101};
int selUser = 0, selData = 0;
//User vector
std::vector <data::user> data::users;
//For other save types
static bool sysBCATPushed = false, tempPushed = false;
std::unordered_map <uint64_t, data::titleInfo> data::titles;
//Sorts titles by sortType
static struct {
bool operator()(const data::userTitleInfo &a, const data::userTitleInfo &b) {
std::string titleA = data::getTitleNameByTID(a.tid);
std::string titleB = data::getTitleNameByTID(b.tid);
uint32_t pointA, pointB;
for (unsigned i = 0, j = 0; i < titleA.length();) {
ssize_t aCnt = decode_utf8(&pointA, (const uint8_t *) &titleA.data()[i]);
ssize_t bCnt = decode_utf8(&pointB, (const uint8_t *) &titleB.data()[j]);
pointA = tolower(pointA), pointB = tolower(pointB);
if (pointA != pointB)
return pointA < pointB;
i += aCnt;
j += bCnt;
}
return false;
}
} sortTitles;
//Returns -1 for new
static int getUserIndex(const AccountUid &id) {
u128 nId = util::accountUIDToU128(id);
for (unsigned i = 0; i < data::users.size(); i++)
if (data::users[i].getUID128() == nId) return i;
return -1;
}
static inline bool accountSystemSaveCheck(const FsSaveDataInfo &_inf) {
if (_inf.save_data_type == FsSaveDataType_System && util::accountUIDToU128(_inf.uid) != 0)
return false;
return true;
}
//Minimal init/test to avoid loading and creating things I don't need
static bool testMount(const FsSaveDataInfo &_inf) {
bool ret = false;
if ((ret = fs::mountSave(_inf)))
fs::unmountSave();
return ret;
}
static inline void addTitleToList(const uint64_t &tid) {
uint64_t outSize = 0;
NsApplicationControlData *ctrlData = new NsApplicationControlData;
NacpLanguageEntry *ent;
Result ctrlRes = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, ctrlData,
sizeof(NsApplicationControlData), &outSize);
Result nacpRes = nacpGetLanguageEntry(&ctrlData->nacp, &ent);
size_t iconSize = outSize - sizeof(ctrlData->nacp);
if (R_SUCCEEDED(ctrlRes) && !(outSize < sizeof(ctrlData->nacp)) && R_SUCCEEDED(nacpRes) && iconSize > 0) {
//Copy nacp
memcpy(&data::titles[tid].nacp, &ctrlData->nacp, sizeof(NacpStruct));
//Setup 'shortcuts' to strings
NacpLanguageEntry *ent;
nacpGetLanguageEntry(&data::titles[tid].nacp, &ent);
if (strlen(ent->name) == 0)
data::titles[tid].title = ctrlData->nacp.lang[SetLanguage_ENUS].name;
else
data::titles[tid].title = ent->name;
data::titles[tid].author = ent->author;
if ((data::titles[tid].safeTitle = util::safeString(ent->name)) == "")
data::titles[tid].safeTitle = util::getIDStr(tid);
} else {
memset(&data::titles[tid].nacp, 0, sizeof(NacpStruct));
data::titles[tid].title = util::getIDStr(tid);
data::titles[tid].author = "Someone?";
data::titles[tid].safeTitle = util::getIDStr(tid);
}
delete ctrlData;
}
static inline bool titleIsLoaded(const uint64_t &tid) {
auto findTid = data::titles.find(tid);
return findTid == data::titles.end() ? false : true;
}
static void loadUserAccounts() {
s32 total = 0;
AccountUid *uids = new AccountUid[8];
if (R_SUCCEEDED(accountListAllUsers(uids, 8, &total))) {
for (int i = 0; i < total; i++)
data::users.emplace_back(uids[i], "", "");
}
delete[] uids;
}
//This can load titles installed without having save data
static void loadTitlesFromRecords() {
NsApplicationRecord nsRecord;
int32_t entryCount = 0, recordOffset = 0;
while (R_SUCCEEDED(nsListApplicationRecord(&nsRecord, 1, recordOffset++, &entryCount)) && entryCount > 0) {
if (!titleIsLoaded(nsRecord.application_id))
addTitleToList(nsRecord.application_id);
}
}
bool data::loadUsersTitles(bool clearUsers) {
static unsigned systemUserCount = 4;
FsSaveDataInfoReader it;
FsSaveDataInfo info;
s64 total = 0;
//Clear titles
for (data::user &u: data::users)
u.titleInfo.clear();
if (clearUsers) {
systemUserCount = 4;
data::users.clear();
loadUserAccounts();
sysBCATPushed = false;
tempPushed = false;
users.emplace_back(util::u128ToAccountUID(3), "Device", "Device");
users.emplace_back(util::u128ToAccountUID(2), "BCAT", "BCAT");
users.emplace_back(util::u128ToAccountUID(5), "Cache", "Cache");
users.emplace_back(util::u128ToAccountUID(0), "System", "System");
}
for (unsigned i = 0; i < 7; i++) {
if (R_FAILED(fsOpenSaveDataInfoReader(&it, (FsSaveDataSpaceId) saveOrder[i])))
continue;
while (R_SUCCEEDED(fsSaveDataInfoReaderRead(&it, &info, 1, &total)) && total != 0) {
uint64_t tid = 0;
if (info.save_data_type == FsSaveDataType_System || info.save_data_type == FsSaveDataType_SystemBcat)
tid = info.system_save_data_id;
else
tid = info.application_id;
if (!titleIsLoaded(tid))
addTitleToList(tid);
//Don't bother with this stuff
if (!accountSystemSaveCheck(info) || !testMount(info))
continue;
switch (info.save_data_type) {
case FsSaveDataType_Bcat:
info.uid = util::u128ToAccountUID(2);
break;
case FsSaveDataType_Device:
info.uid = util::u128ToAccountUID(3);
break;
case FsSaveDataType_SystemBcat:
info.uid = util::u128ToAccountUID(4);
if (!sysBCATPushed) {
++systemUserCount;
sysBCATPushed = true;
users.emplace_back(util::u128ToAccountUID(4), "System BCAT",
"System BCAT");
}
break;
case FsSaveDataType_Cache:
info.uid = util::u128ToAccountUID(5);
break;
case FsSaveDataType_Temporary:
info.uid = util::u128ToAccountUID(6);
if (!tempPushed) {
++systemUserCount;
tempPushed = true;
users.emplace_back(util::u128ToAccountUID(6), "Temporary",
"Temporary");
}
break;
}
int u = getUserIndex(info.uid);
if (u == -1) {
users.emplace(data::users.end() - systemUserCount, info.uid, "", "");
u = getUserIndex(info.uid);
}
PdmPlayStatistics playStats;
if (info.save_data_type == FsSaveDataType_Account || info.save_data_type == FsSaveDataType_Device)
pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(info.application_id, info.uid, false,
&playStats);
else
memset(&playStats, 0, sizeof(PdmPlayStatistics));
users[u].addUserTitleInfo(tid, &info, &playStats);
}
fsSaveDataInfoReaderClose(&it);
}
//Get reference to device save user
unsigned devPos = getUserIndex(util::u128ToAccountUID(3));
data::user &dev = data::users[devPos];
for (unsigned i = 0; i < devPos; i++) {
//Not needed but makes this easier to read
data::user &u = data::users[i];
u.titleInfo.insert(u.titleInfo.end(), dev.titleInfo.begin(), dev.titleInfo.end());
}
data::sortUserTitles();
return true;
}
void data::sortUserTitles() {
for (data::user &u: data::users)
std::sort(u.titleInfo.begin(), u.titleInfo.end(), sortTitles);
}
void data::init() {
data::loadUsersTitles(true);
}
void data::exit() {
/*Still needed for planned future revisions*/
}
void data::setUserIndex(unsigned _sUser) {
selUser = _sUser;
}
data::user *data::getCurrentUser() {
return &users[selUser];
}
unsigned data::getCurrentUserIndex() {
return selUser;
}
void data::setTitleIndex(unsigned _sTitle) {
selData = _sTitle;
}
data::userTitleInfo *data::getCurrentUserTitleInfo() {
return &users[selUser].titleInfo[selData];
}
unsigned data::getCurrentUserTitleInfoIndex() {
return selData;
}
data::titleInfo *data::getTitleInfoByTID(const uint64_t &tid) {
if (titles.find(tid) != titles.end())
return &titles[tid];
return NULL;
}
std::string data::getTitleNameByTID(const uint64_t &tid) {
return titles[tid].title;
}
std::string data::getTitleSafeNameByTID(const uint64_t &tid) {
return titles[tid].safeTitle;
}
int data::getTitleIndexInUser(const data::user &u, const uint64_t &tid) {
for (unsigned i = 0; i < u.titleInfo.size(); i++) {
if (u.titleInfo[i].tid == tid)
return i;
}
return -1;
}
data::user::user(const AccountUid &_id, const std::string &_backupName, const std::string &_safeBackupName) {
userID = _id;
uID128 = util::accountUIDToU128(_id);
AccountProfile prof;
AccountProfileBase base;
if (R_SUCCEEDED(accountGetProfile(&prof, userID)) && R_SUCCEEDED(accountProfileGet(&prof, NULL, &base))) {
username = base.nickname;
userSafe = util::safeString(username);
if (userSafe.empty()) {
char tmp[32];
sprintf(tmp, "Acc%08X", (uint32_t) uID128);
userSafe = tmp;
}
uint32_t jpgSize = 0;
accountProfileGetImageSize(&prof, &jpgSize);
uint8_t *jpegData = new uint8_t[jpgSize];
accountProfileLoadImage(&prof, jpegData, jpgSize, &jpgSize);
delete[] jpegData;
accountProfileClose(&prof);
} else {
username = _backupName.empty() ? util::getIDStr((uint64_t) uID128) : _backupName;
userSafe = _safeBackupName.empty() ? util::getIDStr((uint64_t) uID128) : _safeBackupName;
}
titles.reserve(64);
}
void data::user::setUID(const AccountUid &_id) {
userID = _id;
uID128 = util::accountUIDToU128(_id);
}
void data::user::addUserTitleInfo(const uint64_t &tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats) {
data::userTitleInfo newInfo;
newInfo.tid = tid;
memcpy(&newInfo.saveInfo, _saveInfo, sizeof(FsSaveDataInfo));
memcpy(&newInfo.playStats, _stats, sizeof(PdmPlayStatistics));
titleInfo.push_back(newInfo);
}
void data::dispStats() {
data::user *cu = data::getCurrentUser();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
//Easiest/laziest way to do this
std::string stats = std::to_string(users.size()) + "\n";
for (data::user &u: data::users) {
stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n";
}
}

77
source/directory.cpp Normal file
View File

@@ -0,0 +1,77 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "directory.hpp"
Directory::Directory(const std::string& root)
{
mGood = false;
mError = 0;
mList.clear();
DIR* dir = opendir(root.c_str());
struct dirent* ent;
if (dir == NULL) {
mError = (Result)errno;
}
else {
while ((ent = readdir(dir))) {
std::string name = std::string(ent->d_name);
bool directory = ent->d_type == DT_DIR;
struct DirectoryEntry de = {name, directory};
mList.push_back(de);
}
}
closedir(dir);
mGood = true;
}
Result Directory::error(void)
{
return mError;
}
bool Directory::good(void)
{
return mGood;
}
std::string Directory::entry(size_t index)
{
return index < mList.size() ? mList.at(index).name : "";
}
bool Directory::folder(size_t index)
{
return index < mList.size() ? mList.at(index).directory : false;
}
size_t Directory::size(void)
{
return mList.size();
}

42
source/filesystem.cpp Normal file
View File

@@ -0,0 +1,42 @@
/*
* This file is part of Checkpoint
* Copyright (C) 2017-2021 Bernardo Giordano, FlagBrew
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "filesystem.hpp"
Result FileSystem::mount(FsFileSystem* fileSystem, u64 titleID, AccountUid userID)
{
return fsOpen_SaveData(fileSystem, titleID, userID);
}
int FileSystem::mount(FsFileSystem fs)
{
return fsdevMountDevice("save", fs);
}
void FileSystem::unmount(void)
{
fsdevUnmountDevice("save");
}

View File

@@ -1,519 +0,0 @@
#include <switch.h>
#include "fs.h"
#include "threads.h"
#include "util.h"
static std::string wd = "sdmc:/NXST/";
static FSFILE *debLog;
static FsFileSystem sv;
static std::vector <std::string> pathFilter;
void fs::init() {
mkDirRec(wd);
fs::logOpen();
}
bool fs::mountSave(const FsSaveDataInfo &_m) {
Result svOpen;
FsSaveDataAttribute attr = {0};
switch (_m.save_data_type) {
case FsSaveDataType_System:
case FsSaveDataType_SystemBcat: {
attr.uid = _m.uid;
attr.system_save_data_id = _m.system_save_data_id;
attr.save_data_type = _m.save_data_type;
svOpen = fsOpenSaveDataFileSystemBySystemSaveDataId(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Account: {
attr.uid = _m.uid;
attr.application_id = _m.application_id;
attr.save_data_type = _m.save_data_type;
attr.save_data_rank = _m.save_data_rank;
attr.save_data_index = _m.save_data_index;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Device: {
attr.application_id = _m.application_id;
attr.save_data_type = FsSaveDataType_Device;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Bcat: {
attr.application_id = _m.application_id;
attr.save_data_type = FsSaveDataType_Bcat;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Cache: {
attr.application_id = _m.application_id;
attr.save_data_type = FsSaveDataType_Cache;
attr.save_data_index = _m.save_data_index;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Temporary: {
attr.application_id = _m.application_id;
attr.save_data_type = _m.save_data_type;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr);
}
break;
default:
svOpen = 1;
break;
}
return R_SUCCEEDED(svOpen) && fsdevMountDevice("sv", sv) != -1;
}
bool fs::commitToDevice(const std::string &dev) {
bool ret = true;
Result res = fsdevCommitDevice(dev.c_str());
if (R_FAILED(res)) {
fs::logWrite("Error committing file to device -> 0x%X\n", res);
ret = false;
}
return ret;
}
std::string fs::getWorkDir() { return wd; }
void fs::setWorkDir(const std::string &_w) { wd = _w; }
void fs::loadPathFilters(const uint64_t &tid) {
char path[256];
// sprintf(path, "sdmc:/config/JKSV/0x%016lX_filter.txt", tid);
if (fs::fileExists(path)) {
fs::dataFile filter(path);
while (filter.readNextLine(false))
pathFilter.push_back(filter.getLine());
}
}
bool fs::pathIsFiltered(const std::string &_path) {
if (pathFilter.empty())
return false;
for (std::string &_p: pathFilter) {
if (_path == _p)
return true;
}
return false;
}
void fs::freePathFilters() {
pathFilter.clear();
}
void fs::createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t) {
data::titleInfo *tinfo = data::getTitleInfoByTID(_tid);
if (t)
t->status->setStatus("Creating Save Data for #%s#...", tinfo->title.c_str());
uint16_t cacheIndex = 0;
std::string indexStr;
if (_type == FsSaveDataType_Cache &&
!(indexStr = util::getStringInput(SwkbdType_NumPad, "0", "Enter cache index", 2, 0, NULL)).empty())
cacheIndex = strtoul(indexStr.c_str(), NULL, 10);
else if (_type == FsSaveDataType_Cache && indexStr.empty()) {
if (t)
t->finished = true;
return;
}
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(FsSaveDataAttribute));
attr.application_id = _tid;
attr.uid = _uid;
attr.system_save_data_id = 0;
attr.save_data_type = _type;
attr.save_data_rank = 0;
attr.save_data_index = cacheIndex;
FsSaveDataCreationInfo crt;
memset(&crt, 0, sizeof(FsSaveDataCreationInfo));
int64_t saveSize = 0, journalSize = 0;
switch (_type) {
case FsSaveDataType_Account:
saveSize = tinfo->nacp.user_account_save_data_size;
journalSize = tinfo->nacp.user_account_save_data_journal_size;
break;
case FsSaveDataType_Device:
saveSize = tinfo->nacp.device_save_data_size;
journalSize = tinfo->nacp.device_save_data_journal_size;
break;
case FsSaveDataType_Bcat:
saveSize = tinfo->nacp.bcat_delivery_cache_storage_size;
journalSize = tinfo->nacp.bcat_delivery_cache_storage_size;
break;
case FsSaveDataType_Cache:
saveSize = 32 * 1024 * 1024;
if (tinfo->nacp.cache_storage_journal_size > tinfo->nacp.cache_storage_data_and_journal_size_max)
journalSize = tinfo->nacp.cache_storage_journal_size;
else
journalSize = tinfo->nacp.cache_storage_data_and_journal_size_max;
break;
default:
if (t)
t->finished = true;
return;
break;
}
crt.save_data_size = saveSize;
crt.journal_size = journalSize;
crt.available_size = 0x4000;
crt.owner_id = _type == FsSaveDataType_Bcat ? 0x010000000000000C : tinfo->nacp.save_data_owner_id;
crt.flags = 0;
crt.save_data_space_id = FsSaveDataSpaceId_User;
FsSaveDataMetaInfo meta;
memset(&meta, 0, sizeof(FsSaveDataMetaInfo));
if (_type != FsSaveDataType_Bcat) {
meta.size = 0x40060;
meta.type = FsSaveDataMetaType_Thumbnail;
}
Result res = 0;
if (R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &crt, &meta))) {
util::createTitleDirectoryByTID(_tid);
data::loadUsersTitles(false);
} else {
fs::logWrite("SaveCreate Failed -> %X\n", res);
}
}
static void createSaveData_t(void *a) {
threadInfo *t = (threadInfo *) a;
fs::svCreateArgs *crt = (fs::svCreateArgs *) t->argPtr;
fs::createSaveData(crt->type, crt->tid, crt->account, t);
delete crt;
t->finished = true;
}
void fs::createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid) {
fs::svCreateArgs *send = new fs::svCreateArgs;
send->type = _type;
send->tid = _tid;
send->account = _uid;
threads::newThread(createSaveData_t, send, NULL);
}
bool fs::extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t) {
if (t)
t->status->setStatus("Extending Save Data for #%s#...", data::getTitleNameByTID(tinfo->tid).c_str());
uint64_t journal = fs::getJournalSizeMax(tinfo);
uint64_t saveID = tinfo->saveInfo.save_data_id;
FsSaveDataSpaceId space = (FsSaveDataSpaceId) tinfo->saveInfo.save_data_space_id;
Result res = 0;
if (R_FAILED((res = fsExtendSaveDataFileSystem(space, saveID, extSize, journal)))) {
int64_t totalSize = 0;
fs::mountSave(tinfo->saveInfo);
fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &totalSize);
fs::unmountSave();
fs::logWrite("Extend Failed: %uMB to %uMB -> %X\n", totalSize / 1024 / 1024, extSize / 1024 / 1024, res);
// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendFailed", 0));
return false;
}
return true;
}
static void extendSaveData_t(void *a) {
threadInfo *t = (threadInfo *) a;
fs::svExtendArgs *e = (fs::svExtendArgs *) t->argPtr;
fs::extendSaveData(e->tinfo, e->extSize, t);
delete e;
t->finished = true;
}
void fs::extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize) {
fs::svExtendArgs *send = new fs::svExtendArgs;
send->tinfo = tinfo;
send->extSize = extSize;
threads::newThread(extendSaveData_t, send, NULL);
}
uint64_t fs::getJournalSize(const data::userTitleInfo *tinfo) {
uint64_t ret = 0;
data::titleInfo *t = data::getTitleInfoByTID(tinfo->tid);
switch (tinfo->saveInfo.save_data_type) {
case FsSaveDataType_Account:
ret = t->nacp.user_account_save_data_journal_size;
break;
case FsSaveDataType_Device:
ret = t->nacp.device_save_data_journal_size;
break;
case FsSaveDataType_Bcat:
ret = t->nacp.bcat_delivery_cache_storage_size;
break;
case FsSaveDataType_Cache:
if (t->nacp.cache_storage_journal_size > 0)
ret = t->nacp.cache_storage_journal_size;
else
ret = t->nacp.cache_storage_data_and_journal_size_max;
break;
default:
ret = BUFF_SIZE;
break;
}
return ret;
}
uint64_t fs::getJournalSizeMax(const data::userTitleInfo *tinfo) {
uint64_t ret = 0;
data::titleInfo *extend = data::getTitleInfoByTID(tinfo->tid);
switch (tinfo->saveInfo.save_data_type) {
case FsSaveDataType_Account:
if (extend->nacp.user_account_save_data_journal_size_max > extend->nacp.user_account_save_data_journal_size)
ret = extend->nacp.user_account_save_data_journal_size_max;
else
ret = extend->nacp.user_account_save_data_journal_size;
break;
case FsSaveDataType_Bcat:
ret = extend->nacp.bcat_delivery_cache_storage_size;
break;
case FsSaveDataType_Cache:
if (extend->nacp.cache_storage_data_and_journal_size_max > extend->nacp.cache_storage_journal_size)
ret = extend->nacp.cache_storage_data_and_journal_size_max;
else
ret = extend->nacp.cache_storage_journal_size;
break;
case FsSaveDataType_Device:
if (extend->nacp.device_save_data_journal_size_max > extend->nacp.device_save_data_journal_size)
ret = extend->nacp.device_save_data_journal_size_max;
else
ret = extend->nacp.device_save_data_journal_size;
break;
default:
//will just fail
ret = 0;
break;
}
return ret;
}
static void wipeSave_t(void *a) {
threadInfo *t = (threadInfo *) a;
t->status->setStatus("Resetting save data...");
fs::delDir("sv:/");
fs::commitToDevice("sv");
t->finished = true;
}
void fs::wipeSave() {
threads::newThread(wipeSave_t, NULL, NULL);
}
void fs::createNewBackup(void *a) {
if (!fs::dirNotEmpty("sv:/")) {
// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popSaveIsEmpty", 0));
return;
}
uint64_t held = threads::padKeysHeld();
data::user *u = data::getCurrentUser();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
data::titleInfo *t = data::getTitleInfoByTID(d->tid);
std::string out;
const std::string dict[] =
{
util::getDateTime(util::DATE_FMT_YMD),
util::getDateTime(util::DATE_FMT_YDM),
util::getDateTime(util::DATE_FMT_HOYSTE),
util::getDateTime(util::DATE_FMT_JHK),
util::getDateTime(util::DATE_FMT_ASC),
u->getUsernameSafe(),
t->safeTitle,
util::generateAbbrev(d->tid),
".zip"
};
std::string defaultText = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
out = util::getStringInput(SwkbdType_QWERTY, defaultText, "Enter a new name", 64, 9, dict);
out = util::safeString(out);
if (!out.empty()) {
std::string ext = util::getExtensionFromString(out);
std::string path = util::generatePathByTID(d->tid) + out;
fs::mkDir(path);
path += "/";
fs::copyDirToDirThreaded("sv:/", path);
// ui::fldRefreshMenu();
}
}
void fs::overwriteBackup(void *a) {
threadInfo *t = (threadInfo *) a;
std::string *dst = (std::string *) t->argPtr;
bool saveHasFiles = fs::dirNotEmpty("sv:/");
if (fs::isDir(*dst) && saveHasFiles) {
fs::delDir(*dst);
fs::mkDir(*dst);
dst->append("/");
fs::copyDirToDirThreaded("sv:/", *dst);
}
delete dst;
t->finished = true;
}
void fs::restoreBackup(void *a) {
threadInfo *t = (threadInfo *) a;
std::string *restore = (std::string *) t->argPtr;
data::user *u = data::getCurrentUser();
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
if ((utinfo->saveInfo.save_data_type != FsSaveDataType_System)) {
bool saveHasFiles = fs::dirNotEmpty("sv:/");
if (saveHasFiles) {
std::string autoFolder = util::generatePathByTID(utinfo->tid) + "/AUTO - " + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + "/";
fs::mkDir(autoFolder.substr(0, autoFolder.length() - 1));
fs::copyDirToDirThreaded("sv:/", autoFolder);
}
if (fs::isDir(*restore)) {
restore->append("/");
if (fs::dirNotEmpty(*restore)) {
t->status->setStatus("Calculating save data size...");
unsigned dirCount = 0, fileCount = 0;
uint64_t saveSize = 0;
int64_t availSize = 0;
fs::getDirProps(*restore, dirCount, fileCount, saveSize);
fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &availSize);
if ((int) saveSize > availSize) {
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
fs::unmountSave();
fs::extendSaveData(utinfo, saveSize + 0x500000, t);
fs::mountSave(utinfo->saveInfo);
}
fs::wipeSave();
fs::copyDirToDirCommitThreaded(*restore, "sv:/", "sv");
}
// else
// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popFolderIsEmpty", 0));
} else {
std::string dstPath = "sv:/" + util::getFilenameFromPath(*restore);
fs::copyFileCommitThreaded(*restore, dstPath, "sv");
}
}
delete restore;
t->finished = true;
}
void fs::deleteBackup(void *a) {
threadInfo *t = (threadInfo *) a;
std::string *deletePath = (std::string *) t->argPtr;
std::string backupName = util::getFilenameFromPath(*deletePath);
t->status->setStatus("Deleting...");
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
if (fs::isDir(*deletePath)) {
*deletePath += "/";
fs::delDir(*deletePath);
// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str());
} else {
fs::delfile(*deletePath);
// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str());
}
// ui::fldRefreshMenu();
delete deletePath;
t->finished = true;
}
void fs::dumpAllUserSaves(void *a) {
threadInfo *t = (threadInfo *) a;
fs::copyArgs *c = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
t->argPtr = c;
data::user *u = data::getCurrentUser();
for (unsigned i = 0; i < u->titleInfo.size(); i++) {
bool saveMounted = fs::mountSave(u->titleInfo[i].saveInfo);
util::createTitleDirectoryByTID(u->titleInfo[i].tid);
if (saveMounted && fs::dirNotEmpty("sv:/")) {
fs::loadPathFilters(u->titleInfo[i].tid);
std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + "/";
fs::mkDir(dst.substr(0, dst.length() - 1));
fs::copyDirToDir("sv:/", dst, t);
fs::freePathFilters();
}
fs::unmountSave();
}
fs::copyArgsDestroy(c);
t->finished = true;
}
void fs::dumpAllUsersAllSaves(void *a) {
threadInfo *t = (threadInfo *) a;
fs::copyArgs *c = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
t->argPtr = c;
unsigned curUser = 0;
while (data::users[curUser].getUID128() != 2) {
data::user *u = &data::users[curUser++];
for (unsigned i = 0; i < u->titleInfo.size(); i++) {
bool saveMounted = fs::mountSave(u->titleInfo[i].saveInfo);
util::createTitleDirectoryByTID(u->titleInfo[i].tid);
if (saveMounted && fs::dirNotEmpty("sv:/")) {
fs::loadPathFilters(u->titleInfo[i].tid);
std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + "/";
fs::mkDir(dst.substr(0, dst.length() - 1));
fs::copyDirToDir("sv:/", dst, t);
fs::freePathFilters();
}
fs::unmountSave();
}
}
fs::copyArgsDestroy(c);
t->finished = true;
}
void fs::logOpen() {
std::string logPath = wd + "log.txt";
debLog = fsfopen(logPath.c_str(), FsOpenMode_Write);
fsfclose(debLog);
}
void fs::logWrite(const char *fmt, ...) {
std::string logPath = wd + "log.txt";
debLog = fsfopen(logPath.c_str(), FsOpenMode_Append | FsOpenMode_Write);
char tmp[256];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
fsfwrite(tmp, 1, strlen(tmp), debLog);
fsfclose(debLog);
}

View File

@@ -1,266 +0,0 @@
#include <switch.h>
#include <algorithm>
#include "fs.h"
#include "util.h"
#include <threads.h>
static struct
{
bool operator()(const fs::dirItem& a, const fs::dirItem& b)
{
if(a.isDir() != b.isDir())
return a.isDir();
for(unsigned i = 0; i < a.getItm().length(); i++)
{
char charA = tolower(a.getItm()[i]);
char charB = tolower(b.getItm()[i]);
if(charA != charB)
return charA < charB;
}
return false;
}
} sortDirList;
void fs::mkDir(const std::string& _p)
{
mkdir(_p.c_str(), 777);
}
void fs::mkDirRec(const std::string& _p)
{
//skip first slash
size_t pos = _p.find('/', 0) + 1;
while((pos = _p.find('/', pos)) != _p.npos)
{
fs::mkDir(_p.substr(0, pos).c_str());
++pos;
}
}
void fs::delDir(const std::string& path)
{
dirList list(path);
for(unsigned i = 0; i < list.getCount(); i++)
{
if(pathIsFiltered(path + list.getItem(i)))
continue;
if(list.isDir(i))
{
std::string newPath = path + list.getItem(i) + "/";
delDir(newPath);
std::string delPath = path + list.getItem(i);
// rmdir(delPath.c_str());
}
else
{
std::string delPath = path + list.getItem(i);
std::remove(delPath.c_str());
}
}
// rmdir(path.c_str());
}
bool fs::dirNotEmpty(const std::string& _dir)
{
fs::dirList tmp(_dir);
return tmp.getCount() > 0;
}
bool fs::isDir(const std::string& _path)
{
struct stat s;
return stat(_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode);
}
void fs::copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t)
{
if(t)
t->status->setStatus("Opening '#%s#'...");
fs::dirList *list = new fs::dirList(src);
for(unsigned i = 0; i < list->getCount(); i++)
{
if(pathIsFiltered(src + list->getItem(i)))
continue;
if(list->isDir(i))
{
std::string newSrc = src + list->getItem(i) + "/";
std::string newDst = dst + list->getItem(i) + "/";
fs::mkDir(newDst.substr(0, newDst.length() - 1));
fs::copyDirToDir(newSrc, newDst, t);
}
else
{
std::string fullSrc = src + list->getItem(i);
std::string fullDst = dst + list->getItem(i);
if(t)
t->status->setStatus("Copying '#%s#'...");
fs::copyFile(fullSrc, fullDst, t);
}
}
delete list;
}
static void copyDirToDir_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
fs::copyDirToDir(in->src, in->dst, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyDirToDirThreaded(const std::string& src, const std::string& dst)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0);
threads::newThread(copyDirToDir_t, send, fs::fileDrawFunc);
}
void fs::copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t)
{
if(t)
t->status->setStatus("Opening '#%s#'...");
fs::dirList *list = new fs::dirList(src);
for(unsigned i = 0; i < list->getCount(); i++)
{
if(pathIsFiltered(src + list->getItem(i)))
continue;
if(list->isDir(i))
{
std::string newSrc = src + list->getItem(i) + "/";
std::string newDst = dst + list->getItem(i) + "/";
fs::mkDir(newDst.substr(0, newDst.length() - 1));
fs::copyDirToDirCommit(newSrc, newDst, dev, t);
}
else
{
std::string fullSrc = src + list->getItem(i);
std::string fullDst = dst + list->getItem(i);
if(t)
t->status->setStatus("Copying '#%s#'...");
fs::copyFileCommit(fullSrc, fullDst, dev, t);
}
}
delete list;
}
static void copyDirToDirCommit_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
fs::copyDirToDirCommit(in->src, in->dst, in->dev, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0);
threads::newThread(copyDirToDirCommit_t, send, fs::fileDrawFunc);
}
void fs::getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize)
{
fs::dirList *d = new fs::dirList(path);
for(unsigned i = 0; i < d->getCount(); i++)
{
if(d->isDir(i))
{
++dirCount;
std::string newPath = path + d->getItem(i) + "/";
fs::getDirProps(newPath, dirCount, fileCount, totalSize);
}
else
{
++fileCount;
std::string filePath = path + d->getItem(i);
totalSize += fs::fsize(filePath);
}
}
delete d;
}
fs::dirItem::dirItem(const std::string& pathTo, const std::string& sItem)
{
itm = sItem;
std::string fullPath = pathTo + sItem;
struct stat s;
if(stat(fullPath.c_str(), &s) == 0 && S_ISDIR(s.st_mode))
dir = true;
}
std::string fs::dirItem::getName() const
{
size_t extPos = itm.find_last_of('.'), slPos = itm.find_last_of('/');
if(extPos == itm.npos)
return "";
return itm.substr(slPos + 1, extPos);
}
std::string fs::dirItem::getExt() const
{
return util::getExtensionFromString(itm);
}
fs::dirList::dirList(const std::string& _path)
{
DIR *d;
struct dirent *ent;
path = _path;
d = opendir(path.c_str());
while((ent = readdir(d)))
item.emplace_back(path, ent->d_name);
closedir(d);
std::sort(item.begin(), item.end(), sortDirList);
}
void fs::dirList::reassign(const std::string& _path)
{
DIR *d;
struct dirent *ent;
path = _path;
d = opendir(path.c_str());
item.clear();
while((ent = readdir(d)))
item.emplace_back(path, ent->d_name);
closedir(d);
std::sort(item.begin(), item.end(), sortDirList);
}
void fs::dirList::rescan()
{
item.clear();
DIR *d;
struct dirent *ent;
d = opendir(path.c_str());
while((ent = readdir(d)))
item.emplace_back(path, ent->d_name);
closedir(d);
std::sort(item.begin(), item.end(), sortDirList);
}

View File

@@ -1,383 +0,0 @@
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <switch.h>
#include <unistd.h>
#include <cstdarg>
#include <mutex>
#include <condition_variable>
#include <sys/stat.h>
#include "fs.h"
#include "util.h"
#include "data.h"
#include <threads.h>
static std::string wd = "sdmc:/JKSV/";
typedef struct
{
std::mutex bufferLock;
std::condition_variable cond;
std::vector<uint8_t> sharedBuffer;
std::string dst, dev;
bool bufferIsFull = false;
unsigned int filesize = 0, writeLimit = 0;
} fileCpyThreadArgs;
static void writeFile_t(void *a)
{
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
size_t written = 0;
std::vector<uint8_t> localBuffer;
std::FILE *out = std::fopen(in->dst.c_str(), "wb");
while(written < in->filesize)
{
std::unique_lock<std::mutex> buffLock(in->bufferLock);
in->cond.wait(buffLock, [in]{ return in->bufferIsFull;});
localBuffer.clear();
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
in->sharedBuffer.clear();
in->bufferIsFull = false;
buffLock.unlock();
in->cond.notify_one();
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
}
fclose(out);
}
static void writeFileCommit_t(void *a)
{
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
size_t written = 0, journalCount = 0;
std::vector<uint8_t> localBuffer;
FILE *out = fopen(in->dst.c_str(), "wb");
while(written < in->filesize)
{`
std::unique_lock<std::mutex> buffLock(in->bufferLock);
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
localBuffer.clear();
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
in->sharedBuffer.clear();
in->bufferIsFull = false;
buffLock.unlock();
in->cond.notify_one();
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
journalCount += written;
if(journalCount >= in->writeLimit)
{
journalCount = 0;
fclose(out);
fs::commitToDevice(in->dev.c_str());
out = fopen(in->dst.c_str(), "ab");
}
}
fclose(out);
}
fs::copyArgs *fs::copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces)
{
copyArgs *ret = new copyArgs;
ret->src = src;
ret->dst = dst;
ret->dev = dev;
ret->z = z;
ret->unz = unz;
ret->cleanup = _cleanup;
ret->offset = 0;
ret->trimZipPath = _trimZipPath;
ret->trimZipPlaces = _trimPlaces;
return ret;
}
void fs::copyArgsDestroy(copyArgs *c)
{
// delete c->prog;
delete c;
c = NULL;
}
fs::dataFile::dataFile(const std::string& _path)
{
f = fopen(_path.c_str(), "r");
if(f != NULL)
opened = true;
}
fs::dataFile::~dataFile()
{
fclose(f);
}
bool fs::dataFile::readNextLine(bool proc)
{
bool ret = false;
char tmp[1024];
while(fgets(tmp, 1024, f))
{
if(tmp[0] != '#' && tmp[0] != '\n' && tmp[0] != '\r')
{
line = tmp;
ret = true;
break;
}
}
util::stripChar('\n', line);
util::stripChar('\r', line);
if(proc)
procLine();
return ret;
}
void fs::dataFile::procLine()
{
size_t pPos = line.find_first_of("(=,");
if(pPos != line.npos)
{
lPos = pPos;
name.assign(line.begin(), line.begin() + lPos);
}
else
name = line;
util::stripChar(' ', name);
++lPos;
}
std::string fs::dataFile::getNextValueStr()
{
std::string ret = "";
//Skip all spaces until we hit actual text
size_t pos1 = line.find_first_not_of(", ", lPos);
//If reading from quotes
if(line[pos1] == '"')
lPos = line.find_first_of('"', ++pos1);
else
lPos = line.find_first_of(",;\n", pos1);//Set lPos to end of string we want. This should just set lPos to the end of the line if it fails, which is ok
ret = line.substr(pos1, lPos++ - pos1);
util::replaceStr(ret, "\\n", "\n");
return ret;
}
int fs::dataFile::getNextValueInt()
{
int ret = 0;
std::string no = getNextValueStr();
if(no[0] == '0' && tolower(no[1]) == 'x')
ret = strtoul(no.c_str(), NULL, 16);
else
ret = strtoul(no.c_str(), NULL, 10);
return ret;
}
void fs::copyFile(const std::string& src, const std::string& dst, threadInfo *t)
{
fs::copyArgs *c = NULL;
size_t filesize = fs::fsize(src);
if(t)
{
c = (fs::copyArgs *)t->argPtr;
c->offset = 0;
}
FILE *fsrc = fopen(src.c_str(), "rb");
if(!fsrc)
{
fclose(fsrc);
return;
}
fileCpyThreadArgs thrdArgs;
thrdArgs.dst = dst;
thrdArgs.filesize = filesize;
uint8_t *buff = new uint8_t[BUFF_SIZE];
std::vector<uint8_t> transferBuffer;
Thread writeThread;
threadCreate(&writeThread, writeFile_t, &thrdArgs, NULL, 0x40000, 0x2E, 2);
threadStart(&writeThread);
size_t readIn = 0;
uint64_t readCount = 0;
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
readCount += readIn;
if(c)
c->offset = readCount;
if(transferBuffer.size() >= TRANSFER_BUFFER_LIMIT || readCount == filesize)
{
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
transferBuffer.clear();
thrdArgs.bufferIsFull = true;
buffLock.unlock();
thrdArgs.cond.notify_one();
}
}
threadWaitForExit(&writeThread);
threadClose(&writeThread);
fclose(fsrc);
delete[] buff;
}
static void copyFileThreaded_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
t->status->setStatus("Copy file", in->src.c_str());
fs::copyFile(in->src, in->dst, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyFileThreaded(const std::string& src, const std::string& dst)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0);
threads::newThread(copyFileThreaded_t, send, fs::fileDrawFunc);
}
void fs::copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t)
{
fs::copyArgs *c = NULL;
size_t filesize = fs::fsize(src);
if(t)
{
c = (fs::copyArgs *)t->argPtr;
c->offset = 0;
// c->prog->setMax(filesize);
// c->prog->update(0);
}
FILE *fsrc = fopen(src.c_str(), "rb");
if(!fsrc)
{
fclose(fsrc);
return;
}
fileCpyThreadArgs thrdArgs;
thrdArgs.dst = dst;
thrdArgs.dev = dev;
thrdArgs.filesize = filesize;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
uint64_t journalSpace = fs::getJournalSize(utinfo);
thrdArgs.writeLimit = (journalSpace - 0x100000) < TRANSFER_BUFFER_LIMIT ? journalSpace - 0x100000 : TRANSFER_BUFFER_LIMIT;
Thread writeThread;
threadCreate(&writeThread, writeFileCommit_t, &thrdArgs, NULL, 0x040000, 0x2E, 2);
uint8_t *buff = new uint8_t[BUFF_SIZE];
size_t readIn = 0;
uint64_t readCount = 0;
std::vector<uint8_t> transferBuffer;
threadStart(&writeThread);
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
readCount += readIn;
if(c)
c->offset = readCount;
if(transferBuffer.size() >= thrdArgs.writeLimit || readCount == filesize)
{
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
transferBuffer.clear();
thrdArgs.bufferIsFull = true;
buffLock.unlock();
thrdArgs.cond.notify_one();
}
}
threadWaitForExit(&writeThread);
threadClose(&writeThread);
fclose(fsrc);
fs::commitToDevice(dev);
delete[] buff;
}
static void copyFileCommit_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
t->status->setStatus("Copy file", in->src.c_str());
fs::copyFileCommit(in->src, in->dst, in->dev, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0);
threads::newThread(copyFileCommit_t, send, fs::fileDrawFunc);
}
void fs::fileDrawFunc(void *a)
{
threadInfo *t = (threadInfo *)a;
if(!t->finished && t->argPtr)
{
copyArgs *c = (copyArgs *)t->argPtr;
std::string tmp;
t->status->getStatus(tmp);
c->argLock();
// c->prog->update(c->offset);
// c->prog->draw(tmp);
c->argUnlock();
}
}
void fs::delfile(const std::string& path)
{
remove(path.c_str());
}
void fs::getShowFileProps(const std::string& _path)
{
size_t size = fs::fsize(_path);
// ui::showMessage(ui::getUICString("fileModeFileProperties", 0), _path.c_str(), util::getSizeString(size).c_str());
}
bool fs::fileExists(const std::string& path)
{
bool ret = false;
FILE *test = fopen(path.c_str(), "rb");
if(test != NULL)
ret = true;
fclose(test);
return ret;
}
size_t fs::fsize(const std::string& _f)
{
size_t ret = 0;
FILE *get = fopen(_f.c_str(), "rb");
if(get != NULL)
{
fseek(get, 0, SEEK_END);
ret = ftell(get);
}
fclose(get);
return ret;
}

View File

@@ -1,150 +0,0 @@
#include <switch.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
#include "fs/fsfile.h"
char *getDeviceFromPath(char *dev, size_t _max, const char *path)
{
memset(dev, 0, _max);
char *c = strchr(path, ':');
if(c - path > _max)
return NULL;
//probably not good? idk
memcpy(dev, path, c - path);
return dev;
}
char *getFilePath(char *pathOut, size_t _max, const char *path)
{
memset(pathOut, 0, _max);
char *c = strchr(path, '/');
size_t pLength = strlen(c);
if(pLength > _max)
return NULL;
memcpy(pathOut, c, pLength);
return pathOut;
}
bool fsMkDir(const char *_p)
{
char devStr[16];
char path[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p))
return false;
Result res = fsFsCreateDirectory(fsdevGetDeviceFileSystem(devStr), path);
return res == 0;
}
int fsremove(const char *_p)
{
char devStr[16];
char path[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p))
return -1;
Result res = fsFsDeleteFile(fsdevGetDeviceFileSystem(devStr), path);
return res;
}
Result fsDelDirRec(const char *_p)
{
char devStr[16];
char path[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || ! getFilePath(path, FS_MAX_PATH, _p))
return 1;
return fsFsDeleteDirectoryRecursively(fsdevGetDeviceFileSystem(devStr), path);
}
bool fsfcreate(const char *_p, int64_t crSize)
{
char devStr[16];
char filePath[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p))
return false;
FsFileSystem *s = fsdevGetDeviceFileSystem(devStr);
if(s == NULL)
return false;
Result res = fsFsCreateFile(s, filePath, crSize, 0);
if(R_SUCCEEDED(res))
res = fsdevCommitDevice(devStr);
return R_SUCCEEDED(res) ? true : false;
}
FSFILE *fsfopen(const char *_p, uint32_t mode)
{
char devStr[16];
char filePath[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p))
return NULL;
FsFileSystem *s = fsdevGetDeviceFileSystem(devStr);
if(s == NULL)
return NULL;
if(mode == FsOpenMode_Write)
{
fsFsDeleteFile(s, filePath);
fsFsCreateFile(s, filePath, 0, 0);
}
FSFILE *ret = malloc(sizeof(FSFILE));
ret->error = fsFsOpenFile(s, filePath, mode, &ret->_f);
if(R_FAILED(ret->error))
{
free(ret);
return NULL;
}
fsFileGetSize(&ret->_f, &ret->fsize);
ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0;
return ret;
}
FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode)
{
if(mode & FsOpenMode_Write)
{
fsFsDeleteFile(_s, _p);
fsFsCreateFile(_s, _p, 0, 0);
}
else if(mode & FsOpenMode_Append)
fsFsCreateFile(_s, _p, 0, 0);
FSFILE *ret = malloc(sizeof(FSFILE));
ret->error = fsFsOpenFile(_s, _p, mode, &ret->_f);
if(R_FAILED(ret->error))
{
free(ret);
return NULL;
}
fsFileGetSize(&ret->_f, &ret->fsize);
ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0;
return ret;
}
size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f)
{
size_t fullSize = sz * count;
if(_f->offset + fullSize > _f->fsize)
{
s64 newSize = (_f->fsize + fullSize) - (_f->fsize - _f->offset);
fsFileSetSize(&_f->_f, newSize);
_f->fsize = newSize;
}
_f->error = fsFileWrite(&_f->_f, _f->offset, buf, fullSize, FsWriteOption_Flush);
_f->offset += fullSize;
return fullSize;
}

View File

@@ -1,251 +0,0 @@
#include <switch.h>
#include <time.h>
#include <mutex>
#include <vector>
#include <condition_variable>
#include "fs.h"
#include "util.h"
#include "threads.h"
typedef struct
{
std::mutex buffLock;
std::condition_variable cond;
std::vector<uint8_t> sharedBuffer;
std::string dst, dev;
bool bufferIsFull = false;
unzFile unz;
unsigned int fileSize, writeLimit = 0;
} unzThrdArgs;
static void writeFileFromZip_t(void *a)
{
unzThrdArgs *in = (unzThrdArgs *)a;
std::vector<uint8_t> localBuffer;
unsigned int written = 0, journalCount = 0;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
uint64_t journalSpace = fs::getJournalSize(utinfo);
FILE *out = fopen(in->dst.c_str(), "wb");
while(written < in->fileSize)
{
std::unique_lock<std::mutex> buffLock(in->buffLock);
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
localBuffer.clear();
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
in->sharedBuffer.clear();
in->bufferIsFull = false;
buffLock.unlock();
in->cond.notify_one();
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
journalCount += written;
if(journalCount >= in->writeLimit)
{
journalCount = 0;
fclose(out);
fs::commitToDevice(in->dev);
out = fopen(in->dst.c_str(), "ab");
}
}
fclose(out);
}
void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t)
{
fs::copyArgs *c = NULL;
if(t)
{
t->status->setStatus("threadStatusOpeningFolder");
c = (fs::copyArgs *)t->argPtr;
}
fs::dirList *list = new fs::dirList(src);
for(unsigned i = 0; i < list->getCount(); i++)
{
std::string itm = list->getItem(i);
if(fs::pathIsFiltered(src + itm))
continue;
if(list->isDir(i))
{
std::string newSrc = src + itm + "/";
fs::copyDirToZip(newSrc, dst, trimPath, trimPlaces, t);
}
else
{
time_t raw;
time(&raw);
tm *locTime = localtime(&raw);
zip_fileinfo inf = { (unsigned)locTime->tm_sec, (unsigned)locTime->tm_min, (unsigned)locTime->tm_hour,
(unsigned)locTime->tm_mday, (unsigned)locTime->tm_mon, (unsigned)(1900 + locTime->tm_year), 0, 0, 0 };
std::string filename = src + itm;
size_t zipNameStart = 0;
if(trimPath)
util::trimPath(filename, trimPlaces);
else
zipNameStart = filename.find_first_of('/') + 1;
if(t)
t->status->setStatus("threadStatusAddingFileToZip");
int zipOpenFile = zipOpenNewFileInZip64(dst, filename.substr(zipNameStart, filename.npos).c_str(), &inf, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0);
if(zipOpenFile == ZIP_OK)
{
std::string fullSrc = src + itm;
if(c)
{
c->offset = 0;
// c->prog->setMax(fs::fsize(fullSrc));
// c->prog->update(0);
}
FILE *fsrc = fopen(fullSrc.c_str(), "rb");
size_t readIn = 0;
uint8_t *buff = new uint8_t[ZIP_BUFF_SIZE];
while((readIn = fread(buff, 1, ZIP_BUFF_SIZE, fsrc)) > 0)
{
zipWriteInFileInZip(dst, buff, readIn);
if(c)
c->offset += readIn;
}
delete[] buff;
fclose(fsrc);
}
}
}
}
void copyDirToZip_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *c = (fs::copyArgs *)t->argPtr;
fs::copyDirToZip(c->src, c->z, c->trimZipPath, c->trimZipPlaces, t);
if(c->cleanup)
{
zipClose(c->z, NULL);
delete c;
}
t->finished = true;
}
void fs::copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces)
{
fs::copyArgs *send = fs::copyArgsCreate(src, "", "", dst, NULL, true, false, 0);
threads::newThread(copyDirToZip_t, send, fs::fileDrawFunc);
}
void fs::copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t)
{
fs::copyArgs *c = NULL;
if(t)
c = (fs::copyArgs *)t->argPtr;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
uint64_t journalSize = getJournalSize(utinfo), writeCount = 0;
char filename[FS_MAX_PATH];
uint8_t *buff = new uint8_t[BUFF_SIZE];
int readIn = 0;
unz_file_info64 info;
do
{
unzGetCurrentFileInfo64(src, &info, filename, FS_MAX_PATH, NULL, 0, NULL, 0);
if(unzOpenCurrentFile(src) == UNZ_OK)
{
if(t)
t->status->setStatus("threadStatusDecompressingFile");
if(c)
{
// c->prog->setMax(info.uncompressed_size);
// c->prog->update(0);
c->offset = 0;
}
std::string fullDst = dst + filename;
fs::mkDirRec(fullDst.substr(0, fullDst.find_last_of('/') + 1));
unzThrdArgs unzThrd;
unzThrd.dst = fullDst;
unzThrd.fileSize = info.uncompressed_size;
unzThrd.dev = dev;
unzThrd.writeLimit = (journalSize - 0x100000) < TRANSFER_BUFFER_LIMIT ? (journalSize - 0x100000) : TRANSFER_BUFFER_LIMIT;
Thread writeThread;
threadCreate(&writeThread, writeFileFromZip_t, &unzThrd, NULL, 0x8000, 0x2B, 2);
threadStart(&writeThread);
std::vector<uint8_t> transferBuffer;
uint64_t readCount = 0;
while((readIn = unzReadCurrentFile(src, buff, BUFF_SIZE)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
readCount += readIn;
if(c)
c->offset += readIn;
if(transferBuffer.size() >= unzThrd.writeLimit || readCount == info.uncompressed_size)
{
std::unique_lock<std::mutex> buffLock(unzThrd.buffLock);
unzThrd.cond.wait(buffLock, [&unzThrd]{ return unzThrd.bufferIsFull == false; });
unzThrd.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
transferBuffer.clear();
unzThrd.bufferIsFull = true;
unzThrd.cond.notify_one();
}
}
threadWaitForExit(&writeThread);
threadClose(&writeThread);
fs::commitToDevice(dev);
}
}
while(unzGoToNextFile(src) != UNZ_END_OF_LIST_OF_FILE);
delete[] buff;
}
static void copyZipToDir_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *c = (fs::copyArgs *)t->argPtr;
fs::copyZipToDir(c->unz, c->dst, c->dev, t);
if(c->cleanup)
{
unzClose(c->unz);
delete c;
}
t->finished = true;
}
void fs::copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev)
{
fs::copyArgs *send = fs::copyArgsCreate("", dst, dev, NULL, src, true, false, 0);
threads::newThread(copyZipToDir_t, send, fs::fileDrawFunc);
}
uint64_t fs::getZipTotalSize(unzFile unz)
{
uint64_t ret = 0;
if(unzGoToFirstFile(unz) == UNZ_OK)
{
unz_file_info64 finfo;
char filename[FS_MAX_PATH];
do
{
unzGetCurrentFileInfo64(unz, &finfo, filename, FS_MAX_PATH, NULL, 0, NULL, 0);
ret += finfo.uncompressed_size;
} while(unzGoToNextFile(unz) != UNZ_END_OF_LIST_OF_FILE);
unzGoToFirstFile(unz);
}
return ret;
}
bool fs::zipNotEmpty(unzFile unz)
{
return unzGoToFirstFile(unz) == UNZ_OK;
}

Some files were not shown because too many files have changed in this diff Show More