draft transfer implementation
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal 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
8
.idea/.gitignore
generated
vendored
@@ -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
18
.idea/misc.xml
generated
@@ -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
7
.idea/vcs.xml
generated
@@ -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>
|
|
||||||
11
.vscode/c_cpp_properties.json
vendored
11
.vscode/c_cpp_properties.json
vendored
@@ -10,9 +10,16 @@
|
|||||||
"${env:DEVKITPRO}/portlibs/switch/include/**",
|
"${env:DEVKITPRO}/portlibs/switch/include/**",
|
||||||
"${workspaceFolder}/include/**",
|
"${workspaceFolder}/include/**",
|
||||||
"${workspaceFolder}/lib/Plutonium/include/**",
|
"${workspaceFolder}/lib/Plutonium/include/**",
|
||||||
"/opt/homebrew/opt/lz4/include/**"
|
"/usr/local/include/**",
|
||||||
|
"/opt/homebrew/opt/lz4/include/**",
|
||||||
|
"/opt/devkitpro/devkitA64/aarch64-none-elf/include/machine"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"SWITCH",
|
||||||
|
"__SWITCH__",
|
||||||
|
"DEBUG",
|
||||||
|
"__BSD_VISIBLE"
|
||||||
],
|
],
|
||||||
"defines": ["SWITCH", "__SWITCH__", "DEBUG", "__BSD_VISIBLE"],
|
|
||||||
"compilerPath": "${env:DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++",
|
"compilerPath": "${env:DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++",
|
||||||
"cStandard": "c17",
|
"cStandard": "c17",
|
||||||
"cppStandard": "c++14",
|
"cppStandard": "c++14",
|
||||||
|
|||||||
53
.vscode/settings.json
vendored
53
.vscode/settings.json
vendored
@@ -3,30 +3,23 @@
|
|||||||
"string.h": "c",
|
"string.h": "c",
|
||||||
"stdlib.h": "c",
|
"stdlib.h": "c",
|
||||||
"switch.h": "c",
|
"switch.h": "c",
|
||||||
"psm.h": "c",
|
"optional": "cpp",
|
||||||
"vector": "cpp",
|
|
||||||
"any": "cpp",
|
|
||||||
"array": "cpp",
|
"array": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"any": "cpp",
|
||||||
"atomic": "cpp",
|
"atomic": "cpp",
|
||||||
"barrier": "cpp",
|
|
||||||
"bit": "cpp",
|
"bit": "cpp",
|
||||||
"*.tcc": "cpp",
|
"*.tcc": "cpp",
|
||||||
"bitset": "cpp",
|
"bitset": "cpp",
|
||||||
"cctype": "cpp",
|
"cctype": "cpp",
|
||||||
"cfenv": "cpp",
|
|
||||||
"charconv": "cpp",
|
"charconv": "cpp",
|
||||||
"chrono": "cpp",
|
"chrono": "cpp",
|
||||||
"cinttypes": "cpp",
|
|
||||||
"clocale": "cpp",
|
"clocale": "cpp",
|
||||||
"cmath": "cpp",
|
"cmath": "cpp",
|
||||||
"codecvt": "cpp",
|
"codecvt": "cpp",
|
||||||
"compare": "cpp",
|
"compare": "cpp",
|
||||||
"complex": "cpp",
|
|
||||||
"concepts": "cpp",
|
"concepts": "cpp",
|
||||||
"condition_variable": "cpp",
|
"condition_variable": "cpp",
|
||||||
"coroutine": "cpp",
|
|
||||||
"csetjmp": "cpp",
|
|
||||||
"csignal": "cpp",
|
|
||||||
"cstdarg": "cpp",
|
"cstdarg": "cpp",
|
||||||
"cstddef": "cpp",
|
"cstddef": "cpp",
|
||||||
"cstdint": "cpp",
|
"cstdint": "cpp",
|
||||||
@@ -34,7 +27,6 @@
|
|||||||
"cstdlib": "cpp",
|
"cstdlib": "cpp",
|
||||||
"cstring": "cpp",
|
"cstring": "cpp",
|
||||||
"ctime": "cpp",
|
"ctime": "cpp",
|
||||||
"cuchar": "cpp",
|
|
||||||
"cwchar": "cpp",
|
"cwchar": "cpp",
|
||||||
"cwctype": "cpp",
|
"cwctype": "cpp",
|
||||||
"deque": "cpp",
|
"deque": "cpp",
|
||||||
@@ -44,20 +36,16 @@
|
|||||||
"set": "cpp",
|
"set": "cpp",
|
||||||
"string": "cpp",
|
"string": "cpp",
|
||||||
"unordered_map": "cpp",
|
"unordered_map": "cpp",
|
||||||
"unordered_set": "cpp",
|
"vector": "cpp",
|
||||||
"exception": "cpp",
|
"exception": "cpp",
|
||||||
"expected": "cpp",
|
|
||||||
"algorithm": "cpp",
|
"algorithm": "cpp",
|
||||||
"functional": "cpp",
|
"functional": "cpp",
|
||||||
"iterator": "cpp",
|
"iterator": "cpp",
|
||||||
"memory": "cpp",
|
"memory": "cpp",
|
||||||
"memory_resource": "cpp",
|
"memory_resource": "cpp",
|
||||||
"numeric": "cpp",
|
"numeric": "cpp",
|
||||||
"optional": "cpp",
|
|
||||||
"random": "cpp",
|
"random": "cpp",
|
||||||
"ratio": "cpp",
|
"ratio": "cpp",
|
||||||
"regex": "cpp",
|
|
||||||
"source_location": "cpp",
|
|
||||||
"string_view": "cpp",
|
"string_view": "cpp",
|
||||||
"system_error": "cpp",
|
"system_error": "cpp",
|
||||||
"tuple": "cpp",
|
"tuple": "cpp",
|
||||||
@@ -65,37 +53,48 @@
|
|||||||
"utility": "cpp",
|
"utility": "cpp",
|
||||||
"format": "cpp",
|
"format": "cpp",
|
||||||
"fstream": "cpp",
|
"fstream": "cpp",
|
||||||
"future": "cpp",
|
|
||||||
"initializer_list": "cpp",
|
"initializer_list": "cpp",
|
||||||
"iomanip": "cpp",
|
"iomanip": "cpp",
|
||||||
"iosfwd": "cpp",
|
"iosfwd": "cpp",
|
||||||
"iostream": "cpp",
|
"iostream": "cpp",
|
||||||
"istream": "cpp",
|
"istream": "cpp",
|
||||||
"latch": "cpp",
|
|
||||||
"limits": "cpp",
|
"limits": "cpp",
|
||||||
"mutex": "cpp",
|
|
||||||
"new": "cpp",
|
"new": "cpp",
|
||||||
"numbers": "cpp",
|
"numbers": "cpp",
|
||||||
"ostream": "cpp",
|
"ostream": "cpp",
|
||||||
"ranges": "cpp",
|
"ranges": "cpp",
|
||||||
"scoped_allocator": "cpp",
|
|
||||||
"semaphore": "cpp",
|
"semaphore": "cpp",
|
||||||
"shared_mutex": "cpp",
|
|
||||||
"span": "cpp",
|
"span": "cpp",
|
||||||
"spanstream": "cpp",
|
|
||||||
"sstream": "cpp",
|
"sstream": "cpp",
|
||||||
"stacktrace": "cpp",
|
|
||||||
"stdexcept": "cpp",
|
"stdexcept": "cpp",
|
||||||
"stdfloat": "cpp",
|
|
||||||
"stop_token": "cpp",
|
"stop_token": "cpp",
|
||||||
"streambuf": "cpp",
|
"streambuf": "cpp",
|
||||||
"syncstream": "cpp",
|
|
||||||
"thread": "cpp",
|
"thread": "cpp",
|
||||||
"typeindex": "cpp",
|
"cinttypes": "cpp",
|
||||||
"typeinfo": "cpp",
|
"typeinfo": "cpp",
|
||||||
"valarray": "cpp",
|
"valarray": "cpp",
|
||||||
"variant": "cpp",
|
"variant": "cpp",
|
||||||
"filesystem": "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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
5
Makefile
5
Makefile
@@ -49,7 +49,7 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
|||||||
CFLAGS += -g -O2 -ffunction-sections \
|
CFLAGS += -g -O2 -ffunction-sections \
|
||||||
$(ARCH) $(DEFINES)
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
CFLAGS += $(INCLUDE) -D__SWITCH__ -D_GNU_SOURCE=1
|
||||||
|
|
||||||
CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||||
|
|
||||||
@@ -153,8 +153,7 @@ $(BUILD):
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
clean:
|
clean:
|
||||||
@echo clean ...
|
@echo clean ...
|
||||||
@rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
@rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf $(TARGET).lst
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
send: $(BUILD)
|
send: $(BUILD)
|
||||||
|
|||||||
10
cleanup
10
cleanup
@@ -1,10 +0,0 @@
|
|||||||
rm build/ -r || true
|
|
||||||
|
|
||||||
# TRY to remove Iridium.nsp, ignore if it fails
|
|
||||||
|
|
||||||
rm Iridium.nro || true
|
|
||||||
rm Iridium.nacp || true
|
|
||||||
rm Iridium.elf || true
|
|
||||||
rm Iridium.lst || true
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
37
deps/asprintf/asprintf.c
vendored
Normal 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
10
deps/asprintf/asprintf.h
vendored
Normal 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
9
deps/asprintf/clib.json
vendored
Normal 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"]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <pu/Plutonium>
|
#include <pu/Plutonium>
|
||||||
#include <const.h>
|
#include <const.h>
|
||||||
#include <data.h>
|
#include <title.hpp>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class TitlesLayout : public pu::ui::Layout {
|
class TitlesLayout : public pu::ui::Layout {
|
||||||
|
|||||||
74
include/account.hpp
Normal file
74
include/account.hpp
Normal 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
7
include/client.hpp
Normal 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
65
include/common.hpp
Normal 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
|
||||||
@@ -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
58
include/directory.hpp
Normal 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
39
include/filesystem.hpp
Normal 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
|
||||||
54
include/fs.h
54
include/fs.h
@@ -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, ...);
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
};
|
|
||||||
@@ -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
55
include/io.hpp
Normal 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
84
include/logger.hpp
Normal 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
26
include/main.hpp
Normal 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
|
||||||
@@ -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
90
include/title.hpp
Normal 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
|
||||||
@@ -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;
|
|
||||||
152
include/util.h
152
include/util.h
@@ -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
52
include/util.hpp
Normal 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
237
server.cpp
Normal 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;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <MainApplication.hpp>
|
#include <MainApplication.hpp>
|
||||||
#include <data.h>
|
#include "util.hpp"
|
||||||
#include <fs.h>
|
#include "main.hpp"
|
||||||
|
|
||||||
static int nxlink_sock = -1;
|
static int nxlink_sock = -1;
|
||||||
|
|
||||||
@@ -35,7 +35,14 @@ extern "C" void userAppExit() {
|
|||||||
|
|
||||||
// Main entrypoint
|
// Main entrypoint
|
||||||
int main() {
|
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
|
// First create our renderer, where one can customize SDL or other stuff's
|
||||||
// initialization.
|
// initialization.
|
||||||
auto renderer_opts = pu::ui::render::RendererInitOptions(
|
auto renderer_opts = pu::ui::render::RendererInitOptions(
|
||||||
@@ -46,8 +53,6 @@ int main() {
|
|||||||
|
|
||||||
auto renderer = pu::ui::render::Renderer::New(renderer_opts);
|
auto renderer = pu::ui::render::Renderer::New(renderer_opts);
|
||||||
|
|
||||||
data::init();
|
|
||||||
fs::init();
|
|
||||||
// Create our main application from the renderer
|
// Create our main application from the renderer
|
||||||
auto main = ui::MainApplication::New(renderer);
|
auto main = ui::MainApplication::New(renderer);
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,21 @@
|
|||||||
#include <MainApplication.hpp>
|
#include <MainApplication.hpp>
|
||||||
#include <cinttypes>
|
#include <stdio.h>
|
||||||
#include <cstdio>
|
#include <main.hpp>
|
||||||
#include <data.h>
|
#include <const.h>
|
||||||
|
#include <client.hpp>
|
||||||
|
|
||||||
static std::vector<uint64_t> accSids, devSids, bcatSids, cacheSids;
|
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 {
|
namespace ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication *mainApp;
|
||||||
void TitlesLayout::InitTitles() {
|
void TitlesLayout::InitTitles() {
|
||||||
this->titlesMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94, 7);
|
this->titlesMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94, 7);
|
||||||
const data::user *u = data::getCurrentUser();
|
for (size_t i = 0; i < getTitleCount(g_currentUId); i++) {
|
||||||
for(const data::userTitleInfo& t : u->titleInfo) {
|
Title title;
|
||||||
auto titleItem = pu::ui::elm::MenuItem::New(data::getTitleNameByTID(t.tid).c_str());
|
getTitle(title, g_currentUId, i);
|
||||||
|
auto titleItem = pu::ui::elm::MenuItem::New(title.name().c_str());
|
||||||
titleItem->SetColor(COLOR("#FFFFFFFF"));
|
titleItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
titlesMenu->AddItem(titleItem);
|
this->titlesMenu->AddItem(titleItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->Add(this->titlesMenu);
|
this->Add(this->titlesMenu);
|
||||||
@@ -52,13 +30,32 @@ namespace ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Down & HidNpadButton_A) {
|
if (Down & HidNpadButton_A) {
|
||||||
printf("current game index is %i\n", this->titlesMenu->GetSelectedIndex());
|
auto index = this->titlesMenu->GetSelectedIndex();
|
||||||
data::setTitleIndex(this->titlesMenu->GetSelectedIndex());
|
Title title;
|
||||||
int opt = mainApp->CreateShowDialog("", "What do you want?", { "Transfer", "Receive" }, true);
|
getTitle(title, g_currentUId, index);
|
||||||
printf("opt is %d\n", opt);
|
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) {
|
switch (opt) {
|
||||||
case 0: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <data.h>
|
|
||||||
#include <MainApplication.hpp>
|
#include <MainApplication.hpp>
|
||||||
|
#include "main.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication *mainApp;
|
||||||
|
|
||||||
UsersLayout::UsersLayout() : Layout::Layout() {
|
UsersLayout::UsersLayout() : Layout::Layout() {
|
||||||
this->usersMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94,
|
this->usersMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94, 7);
|
||||||
7);
|
|
||||||
this->usersMenu->SetScrollbarColor(COLOR("#170909FF"));
|
this->usersMenu->SetScrollbarColor(COLOR("#170909FF"));
|
||||||
|
|
||||||
for (data::user &u: data::users) {
|
for (AccountUid const& uid : Account::ids()) {
|
||||||
auto username = pu::ui::elm::MenuItem::New(u.getUsername() + ": " + std::to_string(u.titleInfo.size()));
|
auto username = pu::ui::elm::MenuItem::New(Account::username(uid) + ": " + std::to_string(getTitleCount(uid)));
|
||||||
username->SetColor(COLOR("#FFFFFFFF"));
|
username->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->usersMenu->AddItem(username);
|
this->usersMenu->AddItem(username);
|
||||||
}
|
}
|
||||||
@@ -31,7 +30,7 @@ namespace ui {
|
|||||||
|
|
||||||
if (Down & HidNpadButton_A) {
|
if (Down & HidNpadButton_A) {
|
||||||
printf("current index is %i\n", this->usersMenu->GetSelectedIndex());
|
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->titlesLayout->InitTitles();
|
||||||
mainApp->LoadLayout(mainApp->titlesLayout);
|
mainApp->LoadLayout(mainApp->titlesLayout);
|
||||||
}
|
}
|
||||||
|
|||||||
95
source/account.cpp
Normal file
95
source/account.cpp
Normal 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
258
source/client.cpp
Normal 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
124
source/common.cpp
Normal 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);
|
||||||
|
}
|
||||||
352
source/data.cpp
352
source/data.cpp
@@ -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
77
source/directory.cpp
Normal 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
42
source/filesystem.cpp
Normal 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");
|
||||||
|
}
|
||||||
519
source/fs.cpp
519
source/fs.cpp
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user