mirror of
https://github.com/DarkStore-3DS/DarkStore.git
synced 2026-07-02 16:49:05 +00:00
UNIVERSAL-UPDATER IS BACK! Lmao.
This commit is contained in:
@@ -0,0 +1,278 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
include $(DEVKITARM)/3ds_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# TARGET is the name of the output
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# DATA is a list of directories containing data files
|
||||||
|
# INCLUDES is a list of directories containing header files
|
||||||
|
# GRAPHICS is a list of directories containing graphics files
|
||||||
|
# GFXBUILD is the directory where converted graphics files will be placed
|
||||||
|
# If set to $(BUILD), it will statically link in the converted
|
||||||
|
# files as if they were data files.
|
||||||
|
#
|
||||||
|
# NO_SMDH: if set to anything, no SMDH file is generated.
|
||||||
|
# ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional)
|
||||||
|
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
|
||||||
|
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
|
||||||
|
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
|
||||||
|
# ICON is the filename of the icon (.png), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.png
|
||||||
|
# - icon.png
|
||||||
|
# - <libctru folder>/default_icon.png
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# External tools
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
MAKEROM ?= ../makerom.exe
|
||||||
|
BANNERTOOL ?= ../bannertool.exe
|
||||||
|
|
||||||
|
else
|
||||||
|
MAKEROM ?= makerom
|
||||||
|
BANNERTOOL ?= bannertool
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
# If on a tagged commit, use the tag instead of the commit
|
||||||
|
ifneq ($(shell echo $(shell git tag -l --points-at HEAD) | head -c 1),)
|
||||||
|
GIT_VER := $(shell git tag -l --points-at HEAD)
|
||||||
|
else
|
||||||
|
GIT_VER := $(shell git rev-parse --short HEAD)
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Version number
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(shell echo $(shell git describe --tags) | head -c 2 | tail -c 1),)
|
||||||
|
VERSION_MAJOR := $(shell echo $(shell git describe --tags) | head -c 2 | tail -c 1)
|
||||||
|
else
|
||||||
|
VERSION_MAJOR := 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(shell echo $(shell git describe --tags) | head -c 4 | tail -c 1),)
|
||||||
|
VERSION_MINOR := $(shell echo $(shell git describe --tags) | head -c 4 | tail -c 1)
|
||||||
|
else
|
||||||
|
VERSION_MINOR := 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(shell echo $(shell git describe --tags) | head -c 6 | tail -c 1),)
|
||||||
|
VERSION_MICRO := $(shell echo $(shell git describe --tags) | head -c 6 | tail -c 1)
|
||||||
|
else
|
||||||
|
VERSION_MICRO := 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
TARGET := Universal-Updater
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source source/download source/lang source/screens source/utils
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include include/download include/lang include/screens include/utils
|
||||||
|
GRAPHICS := assets/gfx
|
||||||
|
#GFXBUILD := $(BUILD)
|
||||||
|
ROMFS := romfs
|
||||||
|
GFXBUILD := $(ROMFS)/gfx
|
||||||
|
APP_AUTHOR := Universal-Team
|
||||||
|
APP_DESCRIPTION := A universally good updater!
|
||||||
|
ICON := app/icon.png
|
||||||
|
BNR_IMAGE := app/banner.png
|
||||||
|
BNR_AUDIO := app/BannerAudio.wav
|
||||||
|
RSF_FILE := app/build-cia.rsf
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2 -mword-relocations \
|
||||||
|
-DVERSION_STRING=\"$(GIT_VER)\" \
|
||||||
|
-fomit-frame-pointer -ffunction-sections \
|
||||||
|
$(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE=1
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
LIBS := -lcurl -lmbedtls -lmbedx509 -lmbedcrypto -larchive -lbz2 -llzma -lm -lz -lcitro2d -lcitro3d -lmad -lctru -lstdc++
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(CTRULIB)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
|
||||||
|
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES)) \
|
||||||
|
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o)
|
||||||
|
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
|
||||||
|
|
||||||
|
export HFILES := $(PICAFILES:.v.pica=_shbin.h) $(SHLISTFILES:.shlist=_shbin.h) \
|
||||||
|
$(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
export _3DSXDEPS := $(if $(NO_SMDH),,$(OUTPUT).smdh)
|
||||||
|
|
||||||
|
ifeq ($(strip $(ICON)),)
|
||||||
|
icons := $(wildcard *.png)
|
||||||
|
ifneq (,$(findstring $(TARGET).png,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/$(TARGET).png
|
||||||
|
else
|
||||||
|
ifneq (,$(findstring icon.png,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/icon.png
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_SMDH)),)
|
||||||
|
export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ROMFS),)
|
||||||
|
export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD) $(DEPSDIR)
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).elf
|
||||||
|
@rm -fr $(OUTDIR)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
cia: $(BUILD)
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile cia
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
3dsx: $(BUILD)
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 3dsx
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(OUTPUT).cia $(OUTPUT).elf $(OUTPUT).3dsx
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OUTPUT).cia : $(OUTPUT).elf $(OUTPUT).smdh
|
||||||
|
$(BANNERTOOL) makebanner -i "../app/banner.png" -a "../app/BannerAudio.wav" -o "../app/banner.bin"
|
||||||
|
|
||||||
|
$(BANNERTOOL) makesmdh -i "../app/icon.png" -s "$(TARGET)" -l "$(APP_DESCRIPTION)" -p "$(APP_AUTHOR)" -o "../app/icon.bin"
|
||||||
|
|
||||||
|
$(MAKEROM) -f cia -target t -exefslogo -o "../Universal-Updater.cia" -elf "../Universal-Updater.elf" -rsf "../app/build-cia.rsf" -banner "../app/banner.bin" -icon "../app/icon.bin" -logo "../app/logo.bcma.lz" -DAPP_ROMFS="$(TOPDIR)/$(ROMFS)" -major $(VERSION_MAJOR) -minor $(VERSION_MINOR) -micro $(VERSION_MICRO) -DAPP_VERSION_MAJOR="$(VERSION_MAJOR)"
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# rules for assembling GPU shaders
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
define shader-as
|
||||||
|
$(eval CURBIN := $*.shbin)
|
||||||
|
$(eval DEPSFILE := $(DEPSDIR)/$*.shbin.d)
|
||||||
|
echo "$(CURBIN).o: $< $1" > $(DEPSFILE)
|
||||||
|
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
|
||||||
|
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
|
||||||
|
echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
|
||||||
|
picasso -o $(CURBIN) $1
|
||||||
|
bin2s $(CURBIN) | $(AS) -o $*.shbin.o
|
||||||
|
endef
|
||||||
|
|
||||||
|
%.shbin.o %_shbin.h : %.v.pica %.g.pica
|
||||||
|
@echo $(notdir $^)
|
||||||
|
@$(call shader-as,$^)
|
||||||
|
|
||||||
|
%.shbin.o %_shbin.h : %.v.pica
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(call shader-as,$<)
|
||||||
|
|
||||||
|
%.shbin.o %_shbin.h : %.shlist
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)$(file)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
-include $(DEPSDIR)/*.d
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -0,0 +1,285 @@
|
|||||||
|
BasicInfo:
|
||||||
|
Title : "LeafEdit"
|
||||||
|
ProductCode : "CTR-H-LEDT"
|
||||||
|
Logo : Homebrew # Nintendo / Licensed / Distributed / iQue / iQueForSystem
|
||||||
|
|
||||||
|
RomFs:
|
||||||
|
RootPath: "../romfs"
|
||||||
|
|
||||||
|
TitleInfo:
|
||||||
|
Category : Application
|
||||||
|
UniqueId : 0x43921
|
||||||
|
|
||||||
|
Option:
|
||||||
|
UseOnSD : true # true if App is to be installed to SD
|
||||||
|
FreeProductCode : true # Removes limitations on ProductCode
|
||||||
|
MediaFootPadding : false # If true CCI files are created with padding
|
||||||
|
EnableCrypt : false # Enables encryption for NCCH and CIA
|
||||||
|
EnableCompress : true # Compresses where applicable (currently only exefs:/.code)
|
||||||
|
|
||||||
|
AccessControlInfo:
|
||||||
|
CoreVersion : 2
|
||||||
|
|
||||||
|
# Exheader Format Version
|
||||||
|
DescVersion : 2
|
||||||
|
|
||||||
|
# Minimum Required Kernel Version (below is for 4.5.0)
|
||||||
|
ReleaseKernelMajor : "02"
|
||||||
|
ReleaseKernelMinor : "33"
|
||||||
|
|
||||||
|
# ExtData
|
||||||
|
UseExtSaveData : false # enables ExtData
|
||||||
|
#ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId
|
||||||
|
|
||||||
|
# FS:USER Archive Access Permissions
|
||||||
|
# Uncomment as required
|
||||||
|
FileSystemAccess:
|
||||||
|
- CategorySystemApplication
|
||||||
|
- CategoryHardwareCheck
|
||||||
|
- CategoryFileSystemTool
|
||||||
|
- Debug
|
||||||
|
- TwlCardBackup
|
||||||
|
- TwlNandData
|
||||||
|
#- Boss
|
||||||
|
- DirectSdmc
|
||||||
|
- Core
|
||||||
|
#- CtrNandRo
|
||||||
|
#- CtrNandRw
|
||||||
|
#- CtrNandRoWrite
|
||||||
|
- CategorySystemSettings
|
||||||
|
#- CardBoard
|
||||||
|
#- ExportImportIvs
|
||||||
|
- DirectSdmcWrite
|
||||||
|
#- SwitchCleanup
|
||||||
|
#- SaveDataMove
|
||||||
|
#- Shop
|
||||||
|
#- Shell
|
||||||
|
#- CategoryHomeMenu
|
||||||
|
#- SeedDB
|
||||||
|
IoAccessControl:
|
||||||
|
#- FsMountNand
|
||||||
|
#- FsMountNandRoWrite
|
||||||
|
- FsMountTwln
|
||||||
|
#- FsMountWnand
|
||||||
|
- FsMountCardSpi
|
||||||
|
- UseSdif3
|
||||||
|
#- CreateSeed
|
||||||
|
- UseCardSpi
|
||||||
|
|
||||||
|
# Process Settings
|
||||||
|
MemoryType : Application # Application/System/Base
|
||||||
|
SystemMode : 64MB # 64MB(Default)/96MB/80MB/72MB/32MB
|
||||||
|
IdealProcessor : 0
|
||||||
|
AffinityMask : 1
|
||||||
|
Priority : 16
|
||||||
|
MaxCpu : 0x9E # Default
|
||||||
|
HandleTableSize : 0x200
|
||||||
|
DisableDebug : false
|
||||||
|
EnableForceDebug : false
|
||||||
|
CanWriteSharedPage : true
|
||||||
|
CanUsePrivilegedPriority : false
|
||||||
|
CanUseNonAlphabetAndNumber : true
|
||||||
|
PermitMainFunctionArgument : true
|
||||||
|
CanShareDeviceMemory : true
|
||||||
|
RunnableOnSleep : false
|
||||||
|
SpecialMemoryArrange : true
|
||||||
|
|
||||||
|
# New3DS Exclusive Process Settings
|
||||||
|
SystemModeExt : Legacy # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode
|
||||||
|
CpuSpeed : 804MHz # 268MHz(Default)/804MHz
|
||||||
|
EnableL2Cache : true # false(default)/true
|
||||||
|
CanAccessCore2 : true
|
||||||
|
|
||||||
|
# Virtual Address Mappings
|
||||||
|
IORegisterMapping:
|
||||||
|
- 1ff00000-1ff7ffff # DSP memory
|
||||||
|
MemoryMapping:
|
||||||
|
- 1f000000-1f5fffff:r # VRAM
|
||||||
|
|
||||||
|
# Accessible SVCs, <Name>:<ID>
|
||||||
|
SystemCallAccess:
|
||||||
|
ControlMemory: 1
|
||||||
|
QueryMemory: 2
|
||||||
|
ExitProcess: 3
|
||||||
|
GetProcessAffinityMask: 4
|
||||||
|
SetProcessAffinityMask: 5
|
||||||
|
GetProcessIdealProcessor: 6
|
||||||
|
SetProcessIdealProcessor: 7
|
||||||
|
CreateThread: 8
|
||||||
|
ExitThread: 9
|
||||||
|
SleepThread: 10
|
||||||
|
GetThreadPriority: 11
|
||||||
|
SetThreadPriority: 12
|
||||||
|
GetThreadAffinityMask: 13
|
||||||
|
SetThreadAffinityMask: 14
|
||||||
|
GetThreadIdealProcessor: 15
|
||||||
|
SetThreadIdealProcessor: 16
|
||||||
|
GetCurrentProcessorNumber: 17
|
||||||
|
Run: 18
|
||||||
|
CreateMutex: 19
|
||||||
|
ReleaseMutex: 20
|
||||||
|
CreateSemaphore: 21
|
||||||
|
ReleaseSemaphore: 22
|
||||||
|
CreateEvent: 23
|
||||||
|
SignalEvent: 24
|
||||||
|
ClearEvent: 25
|
||||||
|
CreateTimer: 26
|
||||||
|
SetTimer: 27
|
||||||
|
CancelTimer: 28
|
||||||
|
ClearTimer: 29
|
||||||
|
CreateMemoryBlock: 30
|
||||||
|
MapMemoryBlock: 31
|
||||||
|
UnmapMemoryBlock: 32
|
||||||
|
CreateAddressArbiter: 33
|
||||||
|
ArbitrateAddress: 34
|
||||||
|
CloseHandle: 35
|
||||||
|
WaitSynchronization1: 36
|
||||||
|
WaitSynchronizationN: 37
|
||||||
|
SignalAndWait: 38
|
||||||
|
DuplicateHandle: 39
|
||||||
|
GetSystemTick: 40
|
||||||
|
GetHandleInfo: 41
|
||||||
|
GetSystemInfo: 42
|
||||||
|
GetProcessInfo: 43
|
||||||
|
GetThreadInfo: 44
|
||||||
|
ConnectToPort: 45
|
||||||
|
SendSyncRequest1: 46
|
||||||
|
SendSyncRequest2: 47
|
||||||
|
SendSyncRequest3: 48
|
||||||
|
SendSyncRequest4: 49
|
||||||
|
SendSyncRequest: 50
|
||||||
|
OpenProcess: 51
|
||||||
|
OpenThread: 52
|
||||||
|
GetProcessId: 53
|
||||||
|
GetProcessIdOfThread: 54
|
||||||
|
GetThreadId: 55
|
||||||
|
GetResourceLimit: 56
|
||||||
|
GetResourceLimitLimitValues: 57
|
||||||
|
GetResourceLimitCurrentValues: 58
|
||||||
|
GetThreadContext: 59
|
||||||
|
Break: 60
|
||||||
|
OutputDebugString: 61
|
||||||
|
ControlPerformanceCounter: 62
|
||||||
|
CreatePort: 71
|
||||||
|
CreateSessionToPort: 72
|
||||||
|
CreateSession: 73
|
||||||
|
AcceptSession: 74
|
||||||
|
ReplyAndReceive1: 75
|
||||||
|
ReplyAndReceive2: 76
|
||||||
|
ReplyAndReceive3: 77
|
||||||
|
ReplyAndReceive4: 78
|
||||||
|
ReplyAndReceive: 79
|
||||||
|
BindInterrupt: 80
|
||||||
|
UnbindInterrupt: 81
|
||||||
|
InvalidateProcessDataCache: 82
|
||||||
|
StoreProcessDataCache: 83
|
||||||
|
FlushProcessDataCache: 84
|
||||||
|
StartInterProcessDma: 85
|
||||||
|
StopDma: 86
|
||||||
|
GetDmaState: 87
|
||||||
|
RestartDma: 88
|
||||||
|
DebugActiveProcess: 96
|
||||||
|
BreakDebugProcess: 97
|
||||||
|
TerminateDebugProcess: 98
|
||||||
|
GetProcessDebugEvent: 99
|
||||||
|
ContinueDebugEvent: 100
|
||||||
|
GetProcessList: 101
|
||||||
|
GetThreadList: 102
|
||||||
|
GetDebugThreadContext: 103
|
||||||
|
SetDebugThreadContext: 104
|
||||||
|
QueryDebugProcessMemory: 105
|
||||||
|
ReadProcessMemory: 106
|
||||||
|
WriteProcessMemory: 107
|
||||||
|
SetHardwareBreakPoint: 108
|
||||||
|
GetDebugThreadParam: 109
|
||||||
|
ControlProcessMemory: 112
|
||||||
|
MapProcessMemory: 113
|
||||||
|
UnmapProcessMemory: 114
|
||||||
|
CreateCodeSet: 115
|
||||||
|
CreateProcess: 117
|
||||||
|
TerminateProcess: 118
|
||||||
|
SetProcessResourceLimits: 119
|
||||||
|
CreateResourceLimit: 120
|
||||||
|
SetResourceLimitValues: 121
|
||||||
|
AddCodeSegment: 122
|
||||||
|
Backdoor: 123
|
||||||
|
KernelSetState: 124
|
||||||
|
QueryProcessMemory: 125
|
||||||
|
|
||||||
|
# Service List
|
||||||
|
# Maximum 34 services (32 if firmware is prior to 9.6.0)
|
||||||
|
ServiceAccessControl:
|
||||||
|
- APT:U
|
||||||
|
- ac:u
|
||||||
|
- am:net
|
||||||
|
#- boss:U
|
||||||
|
#- cam:u
|
||||||
|
#- cecd:u
|
||||||
|
#- cfg:nor
|
||||||
|
- cfg:u
|
||||||
|
#- csnd:SND
|
||||||
|
- dsp::DSP
|
||||||
|
#- frd:u
|
||||||
|
- fs:USER
|
||||||
|
- gsp::Gpu
|
||||||
|
- gsp::Lcd
|
||||||
|
- hid:USER
|
||||||
|
- http:C
|
||||||
|
#- ir:rst
|
||||||
|
#- ir:u
|
||||||
|
#- ir:USER
|
||||||
|
#- mic:u
|
||||||
|
#- ndm:u
|
||||||
|
#- news:s
|
||||||
|
- nwm::EXT
|
||||||
|
- nwm::UDS
|
||||||
|
- ptm:sysm
|
||||||
|
- ptm:u
|
||||||
|
- pxi:dev
|
||||||
|
- soc:U
|
||||||
|
- ssl:C
|
||||||
|
#- y2r:u
|
||||||
|
|
||||||
|
|
||||||
|
SystemControlInfo:
|
||||||
|
SaveDataSize: 0KB # Change if the app uses savedata
|
||||||
|
RemasterVersion: $(APP_VERSION_MAJOR)
|
||||||
|
StackSize: 0x40000
|
||||||
|
|
||||||
|
# Modules that run services listed above should be included below
|
||||||
|
# Maximum 48 dependencies
|
||||||
|
# <module name>:<module titleid>
|
||||||
|
Dependency:
|
||||||
|
ac: 0x0004013000002402
|
||||||
|
#act: 0x0004013000003802
|
||||||
|
am: 0x0004013000001502
|
||||||
|
boss: 0x0004013000003402
|
||||||
|
camera: 0x0004013000001602
|
||||||
|
cecd: 0x0004013000002602
|
||||||
|
cfg: 0x0004013000001702
|
||||||
|
codec: 0x0004013000001802
|
||||||
|
csnd: 0x0004013000002702
|
||||||
|
dlp: 0x0004013000002802
|
||||||
|
dsp: 0x0004013000001a02
|
||||||
|
friends: 0x0004013000003202
|
||||||
|
gpio: 0x0004013000001b02
|
||||||
|
gsp: 0x0004013000001c02
|
||||||
|
hid: 0x0004013000001d02
|
||||||
|
http: 0x0004013000002902
|
||||||
|
i2c: 0x0004013000001e02
|
||||||
|
ir: 0x0004013000003302
|
||||||
|
mcu: 0x0004013000001f02
|
||||||
|
mic: 0x0004013000002002
|
||||||
|
ndm: 0x0004013000002b02
|
||||||
|
news: 0x0004013000003502
|
||||||
|
#nfc: 0x0004013000004002
|
||||||
|
nim: 0x0004013000002c02
|
||||||
|
nwm: 0x0004013000002d02
|
||||||
|
pdn: 0x0004013000002102
|
||||||
|
ps: 0x0004013000003102
|
||||||
|
ptm: 0x0004013000002202
|
||||||
|
#qtm: 0x0004013020004202
|
||||||
|
ro: 0x0004013000003702
|
||||||
|
socket: 0x0004013000002e02
|
||||||
|
spi: 0x0004013000002302
|
||||||
|
ssl: 0x0004013000002f02
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
@@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
make
|
||||||
|
pause
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils/common.hpp"
|
||||||
|
|
||||||
|
#define APP_TITLE "Universal-Updater"
|
||||||
|
#define V_STRING "1.0.0"
|
||||||
|
|
||||||
|
enum DownloadError {
|
||||||
|
DL_ERROR_NONE = 0,
|
||||||
|
DL_ERROR_WRITEFILE,
|
||||||
|
DL_ERROR_ALLOC,
|
||||||
|
DL_ERROR_STATUSCODE,
|
||||||
|
DL_ERROR_GIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ThemeEntry {
|
||||||
|
std::string downloadUrl;
|
||||||
|
std::string name;
|
||||||
|
std::string path;
|
||||||
|
std::string sdPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result downloadToFile(std::string url, std::string path);
|
||||||
|
Result downloadFromRelease(std::string url, std::string asset, std::string path);
|
||||||
|
|
||||||
|
void displayProgressBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check Wi-Fi status.
|
||||||
|
* @return True if Wi-Fi is connected; false if not.
|
||||||
|
*/
|
||||||
|
bool checkWifiStatus(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display "Please connect to Wi-Fi" for 2s.
|
||||||
|
*/
|
||||||
|
void notConnectedMsg(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display "Not Implemented Yet" for 2s.
|
||||||
|
*/
|
||||||
|
void notImplemented(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get info from the GitHub API about a Release.
|
||||||
|
* repo is where to get from. (Ex. "RocketRobz/TWiLightMenu")
|
||||||
|
* item is that to get from the API. (Ex. "tag_name")
|
||||||
|
* @return the string from the API.
|
||||||
|
*/
|
||||||
|
std::string getLatestRelease(std::string repo, std::string item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get info from the GitHub API about a Commit.
|
||||||
|
* repo is where to get from. (Ex. "RocketRobz/TWiLightMenu")
|
||||||
|
* item is that to get from the API. (Ex. "sha")
|
||||||
|
* @return the string from the API.
|
||||||
|
*/
|
||||||
|
std::string getLatestCommit(std::string repo, std::string item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get info from the GitHub API about a Commit.
|
||||||
|
* repo is where to get from. (Ex. "RocketRobz/TWiLightMenu")
|
||||||
|
* array is the array the item is in. (Ex. "commit")
|
||||||
|
* item is that to get from the API. (Ex. "message")
|
||||||
|
* @return the string from the API.
|
||||||
|
*/
|
||||||
|
std::string getLatestCommit(std::string repo, std::string array, std::string item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a GitHub directory's contents with the GitHub API.
|
||||||
|
* repo is where to get from. (Ex. "DS-Homebrew/twlmenu-extras")
|
||||||
|
* path is the path within the repo (Ex. "contents/_nds/TWiLightMenu/dsimenu/themes")
|
||||||
|
* @return the string from the API.
|
||||||
|
*/
|
||||||
|
std::vector<ThemeEntry> getThemeList(std::string repo, std::string path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update nds-bootstrap to the latest build.
|
||||||
|
*/
|
||||||
|
void updateBootstrap(bool nightly);
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 GUI_HPP
|
||||||
|
#define GUI_HPP
|
||||||
|
|
||||||
|
#include "screens/screen.hpp"
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include <citro2d.h>
|
||||||
|
#include <citro3d.h>
|
||||||
|
#include <random>
|
||||||
|
#include <stack>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#define BarColor C2D_Color32(0, 102, 204, 255)
|
||||||
|
#define TopBGColor C2D_Color32(51, 153, 255, 255)
|
||||||
|
#define BottomBGColor C2D_Color32(0, 64, 128, 255)
|
||||||
|
#define BLACK C2D_Color32(0, 0, 0, 255)
|
||||||
|
#define WHITE C2D_Color32(255, 255, 255, 255)
|
||||||
|
#define TextColor C2D_Color32(102, 179, 255, 255)
|
||||||
|
|
||||||
|
namespace Gui
|
||||||
|
{
|
||||||
|
// Init and Exit of the GUI.
|
||||||
|
Result init(void);
|
||||||
|
void exit(void);
|
||||||
|
|
||||||
|
// Screen and MainLoops.
|
||||||
|
void mainLoop(u32 hDown, u32 hHeld, touchPosition touch);
|
||||||
|
void setScreen(std::unique_ptr<Screen> screen);
|
||||||
|
void screenBack(void);
|
||||||
|
C3D_RenderTarget* target(gfxScreen_t t);
|
||||||
|
void ScreenDraw(C3D_RenderTarget * screen);
|
||||||
|
|
||||||
|
// Clear Text.
|
||||||
|
void clearTextBufs(void);
|
||||||
|
|
||||||
|
// Misc.
|
||||||
|
bool Draw_Rect(float x, float y, float w, float h, u32 color);
|
||||||
|
|
||||||
|
// Text / String Functions.
|
||||||
|
void DrawStringCentered(float x, float y, float size, u32 color, std::string Text, int maxWidth = 0);
|
||||||
|
void DrawString(float x, float y, float size, u32 color, std::string Text, int maxWidth = 0);
|
||||||
|
void GetStringSize(float size, float *width, float *height, std::string Text);
|
||||||
|
float GetStringWidth(float size, std::string Text);
|
||||||
|
float GetStringHeight(float size, std::string Text);
|
||||||
|
|
||||||
|
// Basic GUI.
|
||||||
|
void DrawTop(void);
|
||||||
|
void DrawBottom(void);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayMsg(std::string text);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef LANG_HPP
|
||||||
|
#define LANG_HPP
|
||||||
|
|
||||||
|
#include "utils/json.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Lang {
|
||||||
|
std::string get(const std::string &key);
|
||||||
|
void load(int lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 MAINMENU_HPP
|
||||||
|
#define MAINMENU_HPP
|
||||||
|
|
||||||
|
#include "screens/screen.hpp"
|
||||||
|
|
||||||
|
class MainMenu : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Draw(void) const override;
|
||||||
|
void Logic(u32 hDown, u32 hHeld, touchPosition touch) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef SCREEN_HPP
|
||||||
|
#define SCREEN_HPP
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Screen() {}
|
||||||
|
virtual void Logic(u32 hDown, u32 hHeld, touchPosition touch) = 0;
|
||||||
|
virtual void Draw() const = 0;
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 SCREENCOMMON_HPP
|
||||||
|
#define SCREENCOMMON_HPP
|
||||||
|
|
||||||
|
#include "gui.hpp"
|
||||||
|
|
||||||
|
extern C3D_RenderTarget* top;
|
||||||
|
extern C3D_RenderTarget* bottom;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
Result installCia(const char * ciaPath);
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "utils/files.h"
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "utils/json.hpp"
|
||||||
|
#include "utils/stringutils.hpp"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <regex>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern char * arg0;
|
||||||
|
|
||||||
|
#define WORKING_DIR "/3ds/"
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
enum ExtractError {
|
||||||
|
EXTRACT_ERROR_NONE = 0,
|
||||||
|
EXTRACT_ERROR_ARCHIVE,
|
||||||
|
EXTRACT_ERROR_ALLOC,
|
||||||
|
EXTRACT_ERROR_FIND,
|
||||||
|
EXTRACT_ERROR_READFILE,
|
||||||
|
EXTRACT_ERROR_OPENFILE,
|
||||||
|
EXTRACT_ERROR_WRITEFILE,
|
||||||
|
};
|
||||||
|
|
||||||
|
Result extractArchive(std::string archivePath, std::string wantedFile, std::string outputPath);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef FILE_BROWSE_H
|
||||||
|
#define FILE_BROWSE_H
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct DirEntry {
|
||||||
|
std::string name;
|
||||||
|
std::string path;
|
||||||
|
bool isDirectory;
|
||||||
|
char tid[5];
|
||||||
|
off_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char gameTitle[12]; //!< 12 characters for the game title.
|
||||||
|
char gameCode[4]; //!< 4 characters for the game code.
|
||||||
|
} sNDSHeadertitlecodeonly;
|
||||||
|
|
||||||
|
void findNdsFiles(vector<DirEntry>& dirContents);
|
||||||
|
|
||||||
|
bool nameEndsWith(const std::string& name, const std::vector<std::string> extensionList);
|
||||||
|
void getDirectoryContents(std::vector<DirEntry>& dirContents, const std::vector<std::string> extensionList);
|
||||||
|
void getDirectoryContents(std::vector<DirEntry>& dirContents);
|
||||||
|
|
||||||
|
#endif //FILE_BROWSE_H
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
Result openFile(Handle* fileHandle, const char * path, bool write);
|
||||||
|
Result deleteFile(const char * path);
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef _INIFILE_H_
|
||||||
|
#define _INIFILE_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CIniFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CIniFile();
|
||||||
|
CIniFile(const std::string& filename);
|
||||||
|
virtual ~CIniFile();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool LoadIniFile(const std::string& FileName);
|
||||||
|
bool SaveIniFile(const std::string& FileName);
|
||||||
|
bool SaveIniFileModified(const std::string& FileName);
|
||||||
|
|
||||||
|
std::string GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue);
|
||||||
|
void SetString(const std::string& Section,const std::string& Item,const std::string& Value);
|
||||||
|
int GetInt(const std::string& Section,const std::string& Item,int DefaultValue);
|
||||||
|
void SetInt(const std::string& Section,const std::string& Item,int Value);
|
||||||
|
void GetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter=',');
|
||||||
|
void SetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter=',');
|
||||||
|
protected:
|
||||||
|
std::string m_sFileName;
|
||||||
|
typedef std::vector<std::string> cStringArray;
|
||||||
|
cStringArray m_FileContainer;
|
||||||
|
bool m_bLastResult;
|
||||||
|
bool m_bModified;
|
||||||
|
bool m_bReadOnly;
|
||||||
|
typedef std::map<std::string,size_t> cSectionCache;
|
||||||
|
cSectionCache m_Cache;
|
||||||
|
|
||||||
|
bool InsertLine(size_t line,const std::string& str);
|
||||||
|
bool ReplaceLine(size_t line,const std::string& str);
|
||||||
|
|
||||||
|
void SetFileString(const std::string& Section,const std::string& Item,const std::string& Value);
|
||||||
|
std::string GetFileString(const std::string& Section,const std::string& Item);
|
||||||
|
|
||||||
|
std::string GetString(const std::string& Section,const std::string& Item);
|
||||||
|
int GetInt(const std::string& Section,const std::string& Item);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _INIFILE_H_
|
||||||
+22684
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
bool matchPattern(std::string pattern, std::string tested);
|
||||||
|
|
||||||
|
namespace StringUtils
|
||||||
|
{
|
||||||
|
std::string format(const std::string& fmt_str, ...);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef THREAD_HPP
|
||||||
|
#define THREAD_HPP
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Threads {
|
||||||
|
void create(ThreadFunc entrypoint);
|
||||||
|
void destroy(void);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"DOWNLOAD_FAILED": "Download Failed!",
|
||||||
|
"NOT_IMPLEMENTED": "Not Implemented Yet.",
|
||||||
|
"DONE": "Done!",
|
||||||
|
"CONNECT_WIFI": "Please Connect to WiFi.",
|
||||||
|
"DOWNLOADING": "Downloading: ",
|
||||||
|
"CURRENTLY_EXTRACTING": "\nCurrently extracting:\n",
|
||||||
|
"KB_DOWNLOADED": "KB downloaded.",
|
||||||
|
"FILE_EXTRACTED": "file extracted.",
|
||||||
|
"FILES_EXTRACTED": "files extracted.",
|
||||||
|
|
||||||
|
"DOWNLOAD_NDSBOOTSTRAP_NIGHTLY": "Downloading nds-bootstrap...\n(Nightly)",
|
||||||
|
"EXTRACT_NDSBOOTSTRAP_NIGHTLY": "Extracting nds-bootstrap...\n(Nightly)",
|
||||||
|
"DOWNLOAD_NDSBOOTSTRAP_RELEASE": "Downloading nds-bootstrap...\n(Release)",
|
||||||
|
"EXTRACT_NDSBOOTSTRAP_RELEASE": "Extracting nds-bootstrap...\n(Release)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,670 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 "gui.hpp"
|
||||||
|
|
||||||
|
#include "download/download.hpp"
|
||||||
|
|
||||||
|
#include "lang/lang.hpp"
|
||||||
|
|
||||||
|
#include "screens/screenCommon.hpp"
|
||||||
|
|
||||||
|
#include "utils/extract.hpp"
|
||||||
|
#include "utils/fileBrowse.h"
|
||||||
|
#include "utils/inifile.h"
|
||||||
|
#include "utils/thread.hpp"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "utils/cia.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USER_AGENT APP_TITLE "-" V_STRING
|
||||||
|
|
||||||
|
static char* result_buf = NULL;
|
||||||
|
static size_t result_sz = 0;
|
||||||
|
static size_t result_written = 0;
|
||||||
|
std::vector<std::string> _topText;
|
||||||
|
std::string jsonName;
|
||||||
|
|
||||||
|
extern bool downloadNightlies;
|
||||||
|
extern int filesExtracted;
|
||||||
|
extern std::string extractingFile;
|
||||||
|
|
||||||
|
char progressBarMsg[128] = "";
|
||||||
|
bool showProgressBar = false;
|
||||||
|
bool progressBarType = 0; // 0 = Download | 1 = Extract
|
||||||
|
|
||||||
|
|
||||||
|
// following function is from
|
||||||
|
// https://github.com/angelsl/libctrfgh/blob/master/curl_test/src/main.c
|
||||||
|
static size_t handle_data(char* ptr, size_t size, size_t nmemb, void* userdata)
|
||||||
|
{
|
||||||
|
(void) userdata;
|
||||||
|
const size_t bsz = size*nmemb;
|
||||||
|
|
||||||
|
if (result_sz == 0 || !result_buf)
|
||||||
|
{
|
||||||
|
result_sz = 0x1000;
|
||||||
|
result_buf = (char*)malloc(result_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool need_realloc = false;
|
||||||
|
while (result_written + bsz > result_sz)
|
||||||
|
{
|
||||||
|
result_sz <<= 1;
|
||||||
|
need_realloc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_realloc)
|
||||||
|
{
|
||||||
|
char *new_buf = (char*)realloc(result_buf, result_sz);
|
||||||
|
if (!new_buf)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
result_buf = new_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result_buf)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(result_buf + result_written, ptr, bsz);
|
||||||
|
result_written += bsz;
|
||||||
|
return bsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result setupContext(CURL *hnd, const char * url)
|
||||||
|
{
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_USERAGENT, USER_AGENT);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, handle_data);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
|
||||||
|
curl_easy_setopt(hnd, CURLOPT_STDERR, stdout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result downloadToFile(std::string url, std::string path)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
printf("Downloading from:\n%s\nto:\n%s\n", url.c_str(), path.c_str());
|
||||||
|
|
||||||
|
void *socubuf = memalign(0x1000, 0x100000);
|
||||||
|
if (!socubuf)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = socInit((u32*)socubuf, 0x100000);
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
{
|
||||||
|
free(socubuf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURL *hnd = curl_easy_init();
|
||||||
|
ret = setupContext(hnd, url.c_str());
|
||||||
|
if (ret != 0) {
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle fileHandle;
|
||||||
|
u64 offset = 0;
|
||||||
|
u32 bytesWritten = 0;
|
||||||
|
|
||||||
|
ret = openFile(&fileHandle, path.c_str(), true);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error: couldn't open file to write.\n");
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return DL_ERROR_WRITEFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 startTime = osGetTime();
|
||||||
|
|
||||||
|
CURLcode cres = curl_easy_perform(hnd);
|
||||||
|
curl_easy_cleanup(hnd);
|
||||||
|
|
||||||
|
if (cres != CURLE_OK) {
|
||||||
|
printf("Error in:\ncurl\n");
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSFILE_Write(fileHandle, &bytesWritten, offset, result_buf, result_written, 0);
|
||||||
|
|
||||||
|
u64 endTime = osGetTime();
|
||||||
|
u64 totalTime = endTime - startTime;
|
||||||
|
printf("Download took %llu milliseconds.\n", totalTime);
|
||||||
|
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
FSFILE_Close(fileHandle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result downloadFromRelease(std::string url, std::string asset, std::string path)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
void *socubuf = memalign(0x1000, 0x100000);
|
||||||
|
if (!socubuf)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = socInit((u32*)socubuf, 0x100000);
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
{
|
||||||
|
free(socubuf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::regex parseUrl("github\\.com\\/(.+)\\/(.+)");
|
||||||
|
std::smatch result;
|
||||||
|
regex_search(url, result, parseUrl);
|
||||||
|
|
||||||
|
std::string repoOwner = result[1].str(), repoName = result[2].str();
|
||||||
|
|
||||||
|
std::stringstream apiurlStream;
|
||||||
|
apiurlStream << "https://api.github.com/repos/" << repoOwner << "/" << repoName << "/releases/latest";
|
||||||
|
std::string apiurl = apiurlStream.str();
|
||||||
|
|
||||||
|
printf("Downloading latest release from repo:\n%s\nby:\n%s\n", repoName.c_str(), repoOwner.c_str());
|
||||||
|
printf("Crafted API url:\n%s\n", apiurl.c_str());
|
||||||
|
|
||||||
|
CURL *hnd = curl_easy_init();
|
||||||
|
ret = setupContext(hnd, apiurl.c_str());
|
||||||
|
if (ret != 0) {
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode cres = curl_easy_perform(hnd);
|
||||||
|
curl_easy_cleanup(hnd);
|
||||||
|
char* newbuf = (char*)realloc(result_buf, result_written + 1);
|
||||||
|
result_buf = newbuf;
|
||||||
|
result_buf[result_written] = 0; //nullbyte to end it as a proper C style string
|
||||||
|
|
||||||
|
if (cres != CURLE_OK) {
|
||||||
|
printf("Error in:\ncurl\n");
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Looking for asset with matching name:\n%s\n", asset.c_str());
|
||||||
|
std::string assetUrl;
|
||||||
|
json parsedAPI = json::parse(result_buf);
|
||||||
|
if (parsedAPI["assets"].is_array()) {
|
||||||
|
for (auto jsonAsset : parsedAPI["assets"]) {
|
||||||
|
if (jsonAsset.is_object() && jsonAsset["name"].is_string() && jsonAsset["browser_download_url"].is_string()) {
|
||||||
|
std::string assetName = jsonAsset["name"];
|
||||||
|
if (matchPattern(asset, assetName)) {
|
||||||
|
assetUrl = jsonAsset["browser_download_url"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
|
||||||
|
if (assetUrl.empty())
|
||||||
|
ret = DL_ERROR_GIT;
|
||||||
|
else
|
||||||
|
ret = downloadToFile(assetUrl, path);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check Wi-Fi status.
|
||||||
|
* @return True if Wi-Fi is connected; false if not.
|
||||||
|
*/
|
||||||
|
bool checkWifiStatus(void) {
|
||||||
|
u32 wifiStatus;
|
||||||
|
bool res = false;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(ACU_GetWifiStatus(&wifiStatus)) && wifiStatus) {
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadFailed(void) {
|
||||||
|
DisplayMsg(Lang::get("DOWNLOAD_FAILED"));
|
||||||
|
for (int i = 0; i < 60*2; i++) {
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void notImplemented(void) {
|
||||||
|
DisplayMsg(Lang::get("NOT_IMPLEMENTED"));
|
||||||
|
for (int i = 0; i < 60*2; i++) {
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void doneMsg(void) {
|
||||||
|
DisplayMsg(Lang::get("DONE"));
|
||||||
|
for (int i = 0; i < 60*2; i++) {
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void notConnectedMsg(void) {
|
||||||
|
DisplayMsg(Lang::get("CONNECT_WIFI"));
|
||||||
|
for (int i = 0; i < 60*2; i++) {
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getLatestRelease(std::string repo, std::string item)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
void *socubuf = memalign(0x1000, 0x100000);
|
||||||
|
if (!socubuf)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = socInit((u32*)socubuf, 0x100000);
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
{
|
||||||
|
free(socubuf);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream apiurlStream;
|
||||||
|
apiurlStream << "https://api.github.com/repos/" << repo << "/releases/latest";
|
||||||
|
std::string apiurl = apiurlStream.str();
|
||||||
|
|
||||||
|
CURL *hnd = curl_easy_init();
|
||||||
|
ret = setupContext(hnd, apiurl.c_str());
|
||||||
|
if (ret != 0) {
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode cres = curl_easy_perform(hnd);
|
||||||
|
curl_easy_cleanup(hnd);
|
||||||
|
char* newbuf = (char*)realloc(result_buf, result_written + 1);
|
||||||
|
result_buf = newbuf;
|
||||||
|
result_buf[result_written] = 0; //nullbyte to end it as a proper C style string
|
||||||
|
|
||||||
|
if (cres != CURLE_OK) {
|
||||||
|
printf("Error in:\ncurl\n");
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string jsonItem;
|
||||||
|
json parsedAPI = json::parse(result_buf);
|
||||||
|
if (parsedAPI[item].is_string()) {
|
||||||
|
jsonItem = parsedAPI[item];
|
||||||
|
}
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
|
||||||
|
return jsonItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getLatestCommit(std::string repo, std::string item)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
void *socubuf = memalign(0x1000, 0x100000);
|
||||||
|
if (!socubuf)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = socInit((u32*)socubuf, 0x100000);
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
{
|
||||||
|
free(socubuf);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream apiurlStream;
|
||||||
|
apiurlStream << "https://api.github.com/repos/" << repo << "/commits/master";
|
||||||
|
std::string apiurl = apiurlStream.str();
|
||||||
|
|
||||||
|
CURL *hnd = curl_easy_init();
|
||||||
|
ret = setupContext(hnd, apiurl.c_str());
|
||||||
|
if (ret != 0) {
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode cres = curl_easy_perform(hnd);
|
||||||
|
curl_easy_cleanup(hnd);
|
||||||
|
char* newbuf = (char*)realloc(result_buf, result_written + 1);
|
||||||
|
result_buf = newbuf;
|
||||||
|
result_buf[result_written] = 0; //nullbyte to end it as a proper C style string
|
||||||
|
|
||||||
|
if (cres != CURLE_OK) {
|
||||||
|
printf("Error in:\ncurl\n");
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string jsonItem;
|
||||||
|
json parsedAPI = json::parse(result_buf);
|
||||||
|
if (parsedAPI[item].is_string()) {
|
||||||
|
jsonItem = parsedAPI[item];
|
||||||
|
}
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
|
||||||
|
return jsonItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getLatestCommit(std::string repo, std::string array, std::string item)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
void *socubuf = memalign(0x1000, 0x100000);
|
||||||
|
if (!socubuf)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = socInit((u32*)socubuf, 0x100000);
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
{
|
||||||
|
free(socubuf);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream apiurlStream;
|
||||||
|
apiurlStream << "https://api.github.com/repos/" << repo << "/commits/master";
|
||||||
|
std::string apiurl = apiurlStream.str();
|
||||||
|
|
||||||
|
CURL *hnd = curl_easy_init();
|
||||||
|
ret = setupContext(hnd, apiurl.c_str());
|
||||||
|
if (ret != 0) {
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode cres = curl_easy_perform(hnd);
|
||||||
|
curl_easy_cleanup(hnd);
|
||||||
|
char* newbuf = (char*)realloc(result_buf, result_written + 1);
|
||||||
|
result_buf = newbuf;
|
||||||
|
result_buf[result_written] = 0; //nullbyte to end it as a proper C style string
|
||||||
|
|
||||||
|
if (cres != CURLE_OK) {
|
||||||
|
printf("Error in:\ncurl\n");
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string jsonItem;
|
||||||
|
json parsedAPI = json::parse(result_buf);
|
||||||
|
if (parsedAPI[array][item].is_string()) {
|
||||||
|
jsonItem = parsedAPI[array][item];
|
||||||
|
}
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
|
||||||
|
return jsonItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ThemeEntry> getThemeList(std::string repo, std::string path)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
void *socubuf = memalign(0x1000, 0x100000);
|
||||||
|
std::vector<ThemeEntry> emptyVector;
|
||||||
|
if (!socubuf)
|
||||||
|
{
|
||||||
|
return emptyVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = socInit((u32*)socubuf, 0x100000);
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
{
|
||||||
|
free(socubuf);
|
||||||
|
return emptyVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream apiurlStream;
|
||||||
|
apiurlStream << "https://api.github.com/repos/" << repo << "/contents/" << path;
|
||||||
|
std::string apiurl = apiurlStream.str();
|
||||||
|
|
||||||
|
CURL *hnd = curl_easy_init();
|
||||||
|
ret = setupContext(hnd, apiurl.c_str());
|
||||||
|
if (ret != 0) {
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
return emptyVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode cres = curl_easy_perform(hnd);
|
||||||
|
curl_easy_cleanup(hnd);
|
||||||
|
char* newbuf = (char*)realloc(result_buf, result_written + 1);
|
||||||
|
result_buf = newbuf;
|
||||||
|
result_buf[result_written] = 0; //nullbyte to end it as a proper C style string
|
||||||
|
|
||||||
|
if (cres != CURLE_OK) {
|
||||||
|
printf("Error in:\ncurl\n");
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
|
||||||
|
return emptyVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ThemeEntry> jsonItems;
|
||||||
|
json parsedAPI = json::parse(result_buf);
|
||||||
|
for(uint i=0;i<parsedAPI.size();i++) {
|
||||||
|
ThemeEntry themeEntry;
|
||||||
|
if (parsedAPI[i]["name"].is_string()) {
|
||||||
|
themeEntry.name = parsedAPI[i]["name"];
|
||||||
|
}
|
||||||
|
if (parsedAPI[i]["download_url"].is_string()) {
|
||||||
|
themeEntry.downloadUrl = parsedAPI[i]["download_url"];
|
||||||
|
}
|
||||||
|
if (parsedAPI[i]["path"].is_string()) {
|
||||||
|
themeEntry.sdPath = "sdmc:/";
|
||||||
|
themeEntry.sdPath += parsedAPI[i]["path"];
|
||||||
|
themeEntry.path = parsedAPI[i]["path"];
|
||||||
|
|
||||||
|
size_t pos;
|
||||||
|
while ((pos = themeEntry.path.find(" ")) != std::string::npos) {
|
||||||
|
themeEntry.path.replace(pos, 1, "%20");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsonItems.push_back(themeEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
socExit();
|
||||||
|
free(result_buf);
|
||||||
|
free(socubuf);
|
||||||
|
result_buf = NULL;
|
||||||
|
result_sz = 0;
|
||||||
|
result_written = 0;
|
||||||
|
|
||||||
|
return jsonItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadTheme(std::string path) {
|
||||||
|
std::vector<ThemeEntry> themeContents = getThemeList("Universal-Team/extras", path);
|
||||||
|
for(uint i=0;i<themeContents.size();i++) {
|
||||||
|
if(themeContents[i].downloadUrl != "") {
|
||||||
|
DisplayMsg((Lang::get("DOWNLOADING")+themeContents[i].name).c_str());
|
||||||
|
downloadToFile(themeContents[i].downloadUrl, themeContents[i].sdPath);
|
||||||
|
} else {
|
||||||
|
DisplayMsg((Lang::get("DOWNLOADING")+themeContents[i].name).c_str());
|
||||||
|
mkdir((themeContents[i].sdPath).c_str(), 0777);
|
||||||
|
downloadTheme(themeContents[i].path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayProgressBar() {
|
||||||
|
char str[256];
|
||||||
|
while(showProgressBar) {
|
||||||
|
snprintf(str, sizeof(str), "%s\n%s%s\n%i %s", progressBarMsg, (!progressBarType ? "" : (Lang::get("CURRENTLY_EXTRACTING")).c_str()), (!progressBarType ? "" : extractingFile.c_str()), (!progressBarType ? (int)round(result_written/1000) : filesExtracted), (!progressBarType ? (Lang::get("KB_DOWNLOADED")).c_str() : (filesExtracted == 1 ? (Lang::get("FILE_EXTRACTED")).c_str() :(Lang::get("FILES_EXTRACTED")).c_str())));
|
||||||
|
DisplayMsg(str);
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void updateBootstrap(bool nightly) {
|
||||||
|
if(nightly) {
|
||||||
|
snprintf(progressBarMsg, sizeof(progressBarMsg), (Lang::get("DOWNLOAD_NDSBOOTSTRAP_NIGHTLY")).c_str());
|
||||||
|
showProgressBar = true;
|
||||||
|
progressBarType = 0;
|
||||||
|
Threads::create((ThreadFunc)displayProgressBar);
|
||||||
|
if (downloadToFile("https://github.com/TWLBot/Builds/blob/master/nds-bootstrap.7z?raw=true", "/nds-bootstrap-nightly.7z") != 0) {
|
||||||
|
showProgressBar = false;
|
||||||
|
downloadFailed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(progressBarMsg, sizeof(progressBarMsg), (Lang::get("EXTRACT_NDSBOOTSTRAP_NIGHTLY")).c_str());
|
||||||
|
filesExtracted = 0;
|
||||||
|
progressBarType = 1;
|
||||||
|
extractArchive("/nds-bootstrap-nightly.7z", "nds-bootstrap/", "/_nds/");
|
||||||
|
showProgressBar = false;
|
||||||
|
|
||||||
|
deleteFile("sdmc:/nds-bootstrap-nightly.7z");
|
||||||
|
} else {
|
||||||
|
DisplayMsg(Lang::get("DOWNLOAD_NDSBOOTSTRAP_RELEASE"));
|
||||||
|
snprintf(progressBarMsg, sizeof(progressBarMsg), (Lang::get("DOWNLOAD_NDSBOOTSTRAP_RELEASE")).c_str());
|
||||||
|
showProgressBar = true;
|
||||||
|
progressBarType = 0;
|
||||||
|
Threads::create((ThreadFunc)displayProgressBar);
|
||||||
|
if (downloadFromRelease("https://github.com/ahezard/nds-bootstrap", "nds-bootstrap\\.zip", "/nds-bootstrap-release.zip") != 0) {
|
||||||
|
showProgressBar = false;
|
||||||
|
downloadFailed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(progressBarMsg, sizeof(progressBarMsg), (Lang::get("EXTRACT_NDSBOOTSTRAP_RELEASE")).c_str());
|
||||||
|
filesExtracted = 0;
|
||||||
|
progressBarType = 1;
|
||||||
|
extractArchive("/nds-bootstrap-release.zip", "/", "/_nds/");
|
||||||
|
showProgressBar = false;
|
||||||
|
|
||||||
|
deleteFile("sdmc:/nds-bootstrap-release.zip");
|
||||||
|
}
|
||||||
|
doneMsg();
|
||||||
|
}
|
||||||
+159
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 "gui.hpp"
|
||||||
|
|
||||||
|
#include "screens/screenCommon.hpp"
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
C3D_RenderTarget* top;
|
||||||
|
C3D_RenderTarget* bottom;
|
||||||
|
|
||||||
|
C2D_TextBuf sizeBuf;
|
||||||
|
std::stack<std::unique_ptr<Screen>> screens;
|
||||||
|
bool currentScreen = false;
|
||||||
|
|
||||||
|
// Clear Text.
|
||||||
|
void Gui::clearTextBufs(void)
|
||||||
|
{
|
||||||
|
C2D_TextBufClear(sizeBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize GUI.
|
||||||
|
Result Gui::init(void)
|
||||||
|
{
|
||||||
|
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
|
||||||
|
C2D_Init(C2D_DEFAULT_MAX_OBJECTS);
|
||||||
|
C2D_Prepare();
|
||||||
|
top = C2D_CreateScreenTarget(GFX_TOP, GFX_LEFT);
|
||||||
|
bottom = C2D_CreateScreenTarget(GFX_BOTTOM, GFX_LEFT);
|
||||||
|
sizeBuf = C2D_TextBufNew(4096);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit the whole GUI.
|
||||||
|
void Gui::exit(void)
|
||||||
|
{
|
||||||
|
C2D_TextBufDelete(sizeBuf);
|
||||||
|
C2D_Fini();
|
||||||
|
C3D_Fini();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayMsg(std::string text) {
|
||||||
|
Gui::clearTextBufs();
|
||||||
|
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
|
||||||
|
C2D_TargetClear(top, BLACK);
|
||||||
|
C2D_TargetClear(bottom, BLACK);
|
||||||
|
Gui::DrawTop();
|
||||||
|
Gui::DrawString(10, 40, 0.45f, WHITE, text, 380);
|
||||||
|
Gui::DrawBottom();
|
||||||
|
C3D_FrameEnd(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::DrawStringCentered(float x, float y, float size, u32 color, std::string Text, int maxWidth) {
|
||||||
|
Gui::DrawString((currentScreen ? 200 : 160)+x-(std::min(maxWidth, (int)Gui::GetStringWidth(size, Text))/2), y, size, color, Text, maxWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw String or Text.
|
||||||
|
void Gui::DrawString(float x, float y, float size, u32 color, std::string Text, int maxWidth) {
|
||||||
|
C2D_Text c2d_text;
|
||||||
|
C2D_TextParse(&c2d_text, sizeBuf, Text.c_str());
|
||||||
|
C2D_TextOptimize(&c2d_text);
|
||||||
|
C2D_DrawText(&c2d_text, C2D_WithColor, x, y, 0.5f, std::min(size, size*(maxWidth/Gui::GetStringWidth(size, Text))), size, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get String or Text Width.
|
||||||
|
float Gui::GetStringWidth(float size, std::string Text) {
|
||||||
|
float width = 0;
|
||||||
|
GetStringSize(size, &width, NULL, Text);
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get String or Text Size.
|
||||||
|
void Gui::GetStringSize(float size, float *width, float *height, std::string Text) {
|
||||||
|
C2D_Text c2d_text;
|
||||||
|
C2D_TextParse(&c2d_text, sizeBuf, Text.c_str());
|
||||||
|
C2D_TextGetDimensions(&c2d_text, size, size, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get String or Text Height.
|
||||||
|
float Gui::GetStringHeight(float size, std::string Text) {
|
||||||
|
float height = 0;
|
||||||
|
GetStringSize(size, NULL, &height, Text.c_str());
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a Rectangle.
|
||||||
|
bool Gui::Draw_Rect(float x, float y, float w, float h, u32 color) {
|
||||||
|
return C2D_DrawRectSolid(x, y, 0.5f, w, h, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mainloop the GUI.
|
||||||
|
void Gui::mainLoop(u32 hDown, u32 hHeld, touchPosition touch) {
|
||||||
|
screens.top()->Draw();
|
||||||
|
screens.top()->Logic(hDown, hHeld, touch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current Screen.
|
||||||
|
void Gui::setScreen(std::unique_ptr<Screen> screen)
|
||||||
|
{
|
||||||
|
screens.push(std::move(screen));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go a Screen back.
|
||||||
|
void Gui::screenBack()
|
||||||
|
{
|
||||||
|
screens.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select, on which Screen should be drawn.
|
||||||
|
void Gui::ScreenDraw(C3D_RenderTarget * screen)
|
||||||
|
{
|
||||||
|
C2D_SceneBegin(screen);
|
||||||
|
currentScreen = screen == top ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::DrawTop(void) {
|
||||||
|
Gui::ScreenDraw(top);
|
||||||
|
Gui::Draw_Rect(0, 0, 400, 30, BarColor);
|
||||||
|
Gui::Draw_Rect(0, 30, 400, 180, TopBGColor);
|
||||||
|
Gui::Draw_Rect(0, 210, 400, 30, BarColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::DrawBottom(void) {
|
||||||
|
Gui::ScreenDraw(bottom);
|
||||||
|
Gui::Draw_Rect(0, 0, 320, 30, BarColor);
|
||||||
|
Gui::Draw_Rect(0, 30, 320, 180, BottomBGColor);
|
||||||
|
Gui::Draw_Rect(0, 210, 320, 30, BarColor);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#include "lang/lang.hpp"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
nlohmann::json appJson;
|
||||||
|
|
||||||
|
std::string Lang::get(const std::string &key) {
|
||||||
|
if(!appJson.contains(key)) {
|
||||||
|
return "MISSING: " + key;
|
||||||
|
}
|
||||||
|
return appJson.at(key).get_ref<const std::string&>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string langs[] = {"de", "en", "es", "fr", "it", "jp", "lt", "pt"};
|
||||||
|
|
||||||
|
void Lang::load(int lang) {
|
||||||
|
FILE* values;
|
||||||
|
values = fopen(("romfs:/lang/"+langs[lang]+"/app.json").c_str(), "rt");
|
||||||
|
if(values) appJson = nlohmann::json::parse(values, nullptr, false);
|
||||||
|
fclose(values);
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 "gui.hpp"
|
||||||
|
|
||||||
|
#include "lang/lang.hpp"
|
||||||
|
|
||||||
|
#include "screens/mainMenu.hpp"
|
||||||
|
#include "screens/screenCommon.hpp"
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
bool exiting = false;
|
||||||
|
|
||||||
|
touchPosition touch;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
gfxInitDefault();
|
||||||
|
Gui::init();
|
||||||
|
romfsInit();
|
||||||
|
sdmcInit();
|
||||||
|
cfguInit();
|
||||||
|
Lang::load(1);
|
||||||
|
|
||||||
|
Gui::setScreen(std::make_unique<MainMenu>());
|
||||||
|
osSetSpeedupEnable(true); // Enable speed-up for New 3DS users
|
||||||
|
|
||||||
|
// Loop as long as the status is not exit
|
||||||
|
while (aptMainLoop() && !exiting)
|
||||||
|
{
|
||||||
|
hidScanInput();
|
||||||
|
u32 hHeld = hidKeysHeld();
|
||||||
|
u32 hDown = hidKeysDown();
|
||||||
|
hidTouchRead(&touch);
|
||||||
|
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
|
||||||
|
C2D_TargetClear(top, BLACK);
|
||||||
|
C2D_TargetClear(bottom, BLACK);
|
||||||
|
Gui::clearTextBufs();
|
||||||
|
Gui::mainLoop(hDown, hHeld, touch);
|
||||||
|
C3D_FrameEnd(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gui::exit();
|
||||||
|
gfxExit();
|
||||||
|
cfguExit();
|
||||||
|
romfsExit();
|
||||||
|
sdmcExit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 "download.hpp"
|
||||||
|
#include "screens/mainMenu.hpp"
|
||||||
|
#include "screens/screenCommon.hpp"
|
||||||
|
|
||||||
|
extern bool exiting;
|
||||||
|
|
||||||
|
void MainMenu::Draw(void) const {
|
||||||
|
Gui::DrawTop();
|
||||||
|
Gui::DrawStringCentered(0, 2, 0.7f, TextColor, "Universal-Updater", 400);
|
||||||
|
Gui::DrawString(395-Gui::GetStringWidth(0.72f, VERSION_STRING), 218, 0.72f, WHITE, VERSION_STRING);
|
||||||
|
Gui::DrawBottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainMenu::Logic(u32 hDown, u32 hHeld, touchPosition touch) {
|
||||||
|
if (hDown & KEY_START) {
|
||||||
|
exiting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hDown & KEY_X) {
|
||||||
|
updateBootstrap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#include "utils/cia.h"
|
||||||
|
|
||||||
|
bool updatingSelf;
|
||||||
|
|
||||||
|
static Result CIA_LaunchTitle(u64 titleId, FS_MediaType mediaType) {
|
||||||
|
Result ret = 0;
|
||||||
|
u8 param[0x300];
|
||||||
|
u8 hmac[0x20];
|
||||||
|
|
||||||
|
if (R_FAILED(ret = APT_PrepareToDoApplicationJump(0, titleId, mediaType))) {
|
||||||
|
printf("Error In:\nAPT_PrepareToDoApplicationJump");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (R_FAILED(ret = APT_DoApplicationJump(param, sizeof(param), hmac))) {
|
||||||
|
printf("Error In:\nAPT_DoApplicationJump");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result deletePrevious(u64 titleid, FS_MediaType media)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
|
||||||
|
u32 titles_amount = 0;
|
||||||
|
ret = AM_GetTitleCount(media, &titles_amount);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nAM_GetTitleCount\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 read_titles = 0;
|
||||||
|
u64 * titleIDs = malloc(titles_amount * sizeof(u64));
|
||||||
|
ret = AM_GetTitleList(&read_titles, media, titles_amount, titleIDs);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
free(titleIDs);
|
||||||
|
printf("Error in:\nAM_GetTitleList\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < read_titles; i++) {
|
||||||
|
if (titleIDs[i] == titleid) {
|
||||||
|
ret = AM_DeleteAppTitle(media, titleid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(titleIDs);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nAM_DeleteAppTitle\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FS_MediaType getTitleDestination(u64 titleId) {
|
||||||
|
u16 platform = (u16) ((titleId >> 48) & 0xFFFF);
|
||||||
|
u16 category = (u16) ((titleId >> 32) & 0xFFFF);
|
||||||
|
u8 variation = (u8) (titleId & 0xFF);
|
||||||
|
|
||||||
|
// DSiWare 3DS DSiWare, System, DLP Application System Title
|
||||||
|
return platform == 0x0003 || (platform == 0x0004 && ((category & 0x8011) != 0 || (category == 0x0000 && variation == 0x02))) ? MEDIATYPE_NAND : MEDIATYPE_SD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Result installCia(const char * ciaPath)
|
||||||
|
{
|
||||||
|
u64 size = 0;
|
||||||
|
u32 bytes;
|
||||||
|
Handle ciaHandle;
|
||||||
|
Handle fileHandle;
|
||||||
|
AM_TitleEntry info;
|
||||||
|
Result ret = 0;
|
||||||
|
|
||||||
|
FS_MediaType media = MEDIATYPE_SD;
|
||||||
|
|
||||||
|
ret = openFile(&fileHandle, ciaPath, false);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nopenFile\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = AM_GetCiaFileInfo(media, &info, fileHandle);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nAM_GetCiaFileInfo\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
media = getTitleDestination(info.titleID);
|
||||||
|
|
||||||
|
if (!updatingSelf) {
|
||||||
|
ret = deletePrevious(info.titleID, media);
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = FSFILE_GetSize(fileHandle, &size);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nFSFILE_GetSize\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = AM_StartCiaInstall(media, &ciaHandle);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nAM_StartCiaInstall\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 toRead = 0x1000;
|
||||||
|
u8 * cia_buffer = malloc(toRead);
|
||||||
|
for (u64 startSize = size; size != 0; size -= toRead) {
|
||||||
|
if (size < toRead) toRead = size;
|
||||||
|
FSFILE_Read(fileHandle, &bytes, startSize-size, cia_buffer, toRead);
|
||||||
|
FSFILE_Write(ciaHandle, &bytes, startSize-size, cia_buffer, toRead, 0);
|
||||||
|
}
|
||||||
|
free(cia_buffer);
|
||||||
|
|
||||||
|
ret = AM_FinishCiaInstall(ciaHandle);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nAM_FinishCiaInstall\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = FSFILE_Close(fileHandle);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
printf("Error in:\nFSFILE_Close\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatingSelf) {
|
||||||
|
if (R_FAILED(ret = CIA_LaunchTitle(info.titleID, MEDIATYPE_SD)))
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Universal-Updater
|
||||||
|
* Copyright (C) 2019 VoltZ, Epicpkmn11, Flame, RocketRobz, TotallyNotGuy
|
||||||
|
*
|
||||||
|
* 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 "utils/extract.hpp"
|
||||||
|
|
||||||
|
#include <archive.h>
|
||||||
|
#include <archive_entry.h>
|
||||||
|
|
||||||
|
|
||||||
|
int filesExtracted = 0;
|
||||||
|
std::string extractingFile = "";
|
||||||
|
|
||||||
|
Result extractArchive(std::string archivePath, std::string wantedFile, std::string outputPath)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
|
||||||
|
struct archive *a = archive_read_new();
|
||||||
|
archive_read_support_format_all(a);
|
||||||
|
archive_read_support_format_raw(a);
|
||||||
|
|
||||||
|
r = archive_read_open_filename(a, archivePath.c_str(), 0x4000);
|
||||||
|
if (r != ARCHIVE_OK) {
|
||||||
|
return EXTRACT_ERROR_ARCHIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ret = EXTRACT_ERROR_FIND;
|
||||||
|
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||||
|
std::string entryName(archive_entry_pathname(entry));
|
||||||
|
if (wantedFile == "/") wantedFile = "";
|
||||||
|
if (matchPattern(wantedFile, entryName.substr(0,wantedFile.length())) || wantedFile == "") {
|
||||||
|
extractingFile = (entryName.length() > wantedFile.length() ? entryName.substr(wantedFile.length()) : wantedFile);
|
||||||
|
ret = EXTRACT_ERROR_NONE;
|
||||||
|
|
||||||
|
Handle fileHandle;
|
||||||
|
std::string outputPathFinal = outputPath;
|
||||||
|
if (entryName.length() > wantedFile.length())
|
||||||
|
outputPathFinal += entryName.substr(wantedFile.length());
|
||||||
|
if (outputPathFinal.substr(outputPathFinal.length()-1) == "/") continue;
|
||||||
|
Result res = openFile(&fileHandle, outputPathFinal.c_str(), true);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
ret = EXTRACT_ERROR_OPENFILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 fileSize = archive_entry_size(entry);
|
||||||
|
u32 toRead = 0x4000;
|
||||||
|
u8 * buf = (u8 *)malloc(toRead);
|
||||||
|
if (buf == NULL) {
|
||||||
|
ret = EXTRACT_ERROR_ALLOC;
|
||||||
|
FSFILE_Close(fileHandle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 bytesWritten = 0;
|
||||||
|
u64 offset = 0;
|
||||||
|
do {
|
||||||
|
if (toRead > fileSize) toRead = fileSize;
|
||||||
|
ssize_t size = archive_read_data(a, buf, toRead);
|
||||||
|
if (size < 0) {
|
||||||
|
ret = EXTRACT_ERROR_READFILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = FSFILE_Write(fileHandle, &bytesWritten, offset, buf, toRead, 0);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
ret = EXTRACT_ERROR_WRITEFILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += bytesWritten;
|
||||||
|
fileSize -= bytesWritten;
|
||||||
|
} while(fileSize);
|
||||||
|
|
||||||
|
FSFILE_Close(fileHandle);
|
||||||
|
free(buf);
|
||||||
|
filesExtracted++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
archive_read_free(a);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#include "utils/files.h"
|
||||||
|
|
||||||
|
FS_Path getPathInfo(const char * path, FS_ArchiveID * archive)
|
||||||
|
{
|
||||||
|
*archive = ARCHIVE_SDMC;
|
||||||
|
FS_Path filePath = {0};
|
||||||
|
unsigned int prefixlen = 0;
|
||||||
|
|
||||||
|
if (!strncmp(path, "ctrnand:/", 9)) {
|
||||||
|
*archive = ARCHIVE_NAND_CTR_FS;
|
||||||
|
prefixlen = 8;
|
||||||
|
}
|
||||||
|
else if (!strncmp(path, "twlp:/", 6)) {
|
||||||
|
*archive = ARCHIVE_TWL_PHOTO;
|
||||||
|
prefixlen = 5;
|
||||||
|
}
|
||||||
|
else if (!strncmp(path, "twln:/", 6)) {
|
||||||
|
*archive = ARCHIVE_NAND_TWL_FS;
|
||||||
|
prefixlen = 5;
|
||||||
|
}
|
||||||
|
else if (!strncmp(path, "sdmc:/", 6)) {
|
||||||
|
prefixlen = 5;
|
||||||
|
}
|
||||||
|
else if (*path != '/') {
|
||||||
|
//if the path is local (doesnt start with a slash), it needs to be appended to the working dir to be valid
|
||||||
|
char * actualPath = NULL;
|
||||||
|
asprintf(&actualPath, "%s%s", WORKING_DIR, path);
|
||||||
|
filePath = fsMakePath(PATH_ASCII, actualPath);
|
||||||
|
free(actualPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the filePath wasnt set above, set it
|
||||||
|
if (filePath.size == 0)
|
||||||
|
filePath = fsMakePath(PATH_ASCII, path+prefixlen);
|
||||||
|
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result makeDirs(FS_ArchiveID archiveID, char * path)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
FS_Archive archive;
|
||||||
|
|
||||||
|
ret = FSUSER_OpenArchive(&archive, archiveID, fsMakePath(PATH_EMPTY, ""));
|
||||||
|
|
||||||
|
for (char * slashpos = strchr(path+1, '/'); slashpos != NULL; slashpos = strchr(slashpos+1, '/')) {
|
||||||
|
char bak = *(slashpos);
|
||||||
|
*(slashpos) = '\0';
|
||||||
|
|
||||||
|
FS_Path dirpath = fsMakePath(PATH_ASCII, path);
|
||||||
|
Handle dirHandle;
|
||||||
|
|
||||||
|
ret = FSUSER_OpenDirectory(&dirHandle, archive, dirpath);
|
||||||
|
if (R_SUCCEEDED(ret))
|
||||||
|
FSDIR_Close(dirHandle);
|
||||||
|
else
|
||||||
|
ret = FSUSER_CreateDirectory(archive, dirpath, FS_ATTRIBUTE_DIRECTORY);
|
||||||
|
|
||||||
|
*(slashpos) = bak;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSUSER_CloseArchive(archive);
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result openFile(Handle* fileHandle, const char * path, bool write)
|
||||||
|
{
|
||||||
|
FS_ArchiveID archive;
|
||||||
|
FS_Path filePath = getPathInfo(path, &archive);
|
||||||
|
u32 flags = (write ? (FS_OPEN_CREATE | FS_OPEN_WRITE) : FS_OPEN_READ);
|
||||||
|
|
||||||
|
Result ret = 0;
|
||||||
|
ret = makeDirs(archive, strdup(path));
|
||||||
|
ret = FSUSER_OpenFileDirectly(fileHandle, archive, fsMakePath(PATH_EMPTY, ""), filePath, flags, 0);
|
||||||
|
if (write)
|
||||||
|
ret = FSFILE_SetSize(*fileHandle, 0); //truncate the file to remove previous contents before writing
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result deleteFile(const char * path)
|
||||||
|
{
|
||||||
|
FS_ArchiveID archiveID;
|
||||||
|
FS_Path filePath = getPathInfo(path, &archiveID);
|
||||||
|
|
||||||
|
FS_Archive archive;
|
||||||
|
Result ret = FSUSER_OpenArchive(&archive, archiveID, fsMakePath(PATH_EMPTY, ""));
|
||||||
|
if (R_FAILED(ret)) return ret;
|
||||||
|
ret = FSUSER_DeleteFile(archive, filePath);
|
||||||
|
FSUSER_CloseArchive(archive);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
#include "utils/inifile.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
|
static bool freadLine(FILE* f,std::string& str)
|
||||||
|
{
|
||||||
|
str.clear();
|
||||||
|
__read:
|
||||||
|
char p=0;
|
||||||
|
|
||||||
|
size_t readed=fread(&p,1,1,f);
|
||||||
|
if(0==readed)
|
||||||
|
{
|
||||||
|
str="";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if('\n'==p||'\r'==p)
|
||||||
|
{
|
||||||
|
str="";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(p!='\n'&&p!='\r'&&readed)
|
||||||
|
{
|
||||||
|
str+=p;
|
||||||
|
readed=fread(&p,1,1,f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str.empty()||""==str)
|
||||||
|
{
|
||||||
|
goto __read;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trimString(std::string& str)
|
||||||
|
{
|
||||||
|
size_t first=str.find_first_not_of(" \t"),last;
|
||||||
|
if(first==str.npos)
|
||||||
|
{
|
||||||
|
str="";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last=str.find_last_not_of(" \t");
|
||||||
|
if(first>0||(last+1)<str.length()) str=str.substr(first,last-first+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CIniFile::CIniFile()
|
||||||
|
{
|
||||||
|
m_bLastResult=false;
|
||||||
|
m_bModified=false;
|
||||||
|
m_bReadOnly=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CIniFile::CIniFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
m_sFileName=filename;
|
||||||
|
m_bLastResult=false;
|
||||||
|
m_bModified=false;
|
||||||
|
m_bReadOnly=false;
|
||||||
|
LoadIniFile(m_sFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
CIniFile::~CIniFile()
|
||||||
|
{
|
||||||
|
if(m_FileContainer.size()>0)
|
||||||
|
{
|
||||||
|
m_FileContainer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIniFile::SetString(const std::string& Section,const std::string& Item,const std::string& Value)
|
||||||
|
{
|
||||||
|
if(GetFileString(Section,Item)!=Value)
|
||||||
|
{
|
||||||
|
SetFileString(Section,Item,Value);
|
||||||
|
m_bModified=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIniFile::SetInt(const std::string& Section,const std::string& Item,int Value)
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
snprintf(buf, sizeof(buf), "%d", Value);
|
||||||
|
std::string strtemp(buf);
|
||||||
|
|
||||||
|
if(GetFileString(Section,Item)!=strtemp)
|
||||||
|
{
|
||||||
|
SetFileString(Section,Item,strtemp);
|
||||||
|
m_bModified=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CIniFile::GetString(const std::string& Section,const std::string& Item)
|
||||||
|
{
|
||||||
|
return GetFileString(Section,Item);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CIniFile::GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue)
|
||||||
|
{
|
||||||
|
std::string temp=GetString(Section,Item);
|
||||||
|
if(!m_bLastResult)
|
||||||
|
{
|
||||||
|
SetString(Section,Item,DefaultValue);
|
||||||
|
temp=DefaultValue;
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIniFile::GetStringVector(const std::string& Section,const std::string& Item,std::vector< std::string >& strings,char delimiter)
|
||||||
|
{
|
||||||
|
std::string strValue=GetFileString(Section,Item);
|
||||||
|
strings.clear();
|
||||||
|
size_t pos;
|
||||||
|
while((pos=strValue.find(delimiter),strValue.npos!=pos))
|
||||||
|
{
|
||||||
|
const std::string string=strValue.substr(0,pos);
|
||||||
|
if(string.length())
|
||||||
|
{
|
||||||
|
strings.push_back(string);
|
||||||
|
}
|
||||||
|
strValue=strValue.substr(pos+1,strValue.npos);
|
||||||
|
}
|
||||||
|
if(strValue.length())
|
||||||
|
{
|
||||||
|
strings.push_back(strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIniFile::SetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter)
|
||||||
|
{
|
||||||
|
std::string strValue;
|
||||||
|
for(size_t ii=0;ii<strings.size();++ii)
|
||||||
|
{
|
||||||
|
if(ii) strValue+=delimiter;
|
||||||
|
strValue+=strings[ii];
|
||||||
|
}
|
||||||
|
SetString(Section,Item,strValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CIniFile::GetInt(const std::string& Section,const std::string& Item)
|
||||||
|
{
|
||||||
|
std::string value=GetFileString(Section,Item);
|
||||||
|
if(value.size()>2&&'0'==value[0]&&('x'==value[1]||'X'==value[1]))
|
||||||
|
return strtol(value.c_str(),NULL,16);
|
||||||
|
else
|
||||||
|
return strtol(value.c_str(),NULL,10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CIniFile::GetInt(const std::string& Section,const std::string& Item,int DefaultValue)
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
temp=GetInt(Section,Item);
|
||||||
|
if(!m_bLastResult)
|
||||||
|
{
|
||||||
|
SetInt(Section,Item,DefaultValue);
|
||||||
|
temp=DefaultValue;
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CIniFile::LoadIniFile(const std::string& FileName)
|
||||||
|
{
|
||||||
|
//dbg_printf("load %s\n",FileName.c_str());
|
||||||
|
if(FileName!="") m_sFileName=FileName;
|
||||||
|
|
||||||
|
FILE* f=fopen(FileName.c_str(),"rb");
|
||||||
|
|
||||||
|
if(NULL==f) return false;
|
||||||
|
|
||||||
|
//check for utf8 bom.
|
||||||
|
char bom[3];
|
||||||
|
if(fread(bom,3,1,f)==1&&bom[0]==0xef&&bom[1]==0xbb&&bom[2]==0xbf) ;
|
||||||
|
else fseek(f,0,SEEK_SET);
|
||||||
|
|
||||||
|
std::string strline("");
|
||||||
|
m_FileContainer.clear();
|
||||||
|
|
||||||
|
while(freadLine(f,strline))
|
||||||
|
{
|
||||||
|
trimString(strline);
|
||||||
|
if(strline!=""&&';'!=strline[0]&&'/'!=strline[0]&&'!'!=strline[0]) m_FileContainer.push_back(strline);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
m_bLastResult=false;
|
||||||
|
m_bModified=false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CIniFile::SaveIniFileModified(const std::string& FileName)
|
||||||
|
{
|
||||||
|
if(m_bModified==true)
|
||||||
|
{
|
||||||
|
return SaveIniFile(FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CIniFile::SaveIniFile(const std::string& FileName)
|
||||||
|
{
|
||||||
|
if(FileName!="")
|
||||||
|
m_sFileName=FileName;
|
||||||
|
|
||||||
|
FILE* f=fopen(m_sFileName.c_str(),"wb");
|
||||||
|
if(NULL==f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t ii=0;ii<m_FileContainer.size();ii++)
|
||||||
|
{
|
||||||
|
std::string& strline=m_FileContainer[ii];
|
||||||
|
size_t notSpace=strline.find_first_not_of(' ');
|
||||||
|
strline=strline.substr(notSpace);
|
||||||
|
if(strline.find('[')==0&&ii>0)
|
||||||
|
{
|
||||||
|
if(!m_FileContainer[ii-1].empty()&&m_FileContainer[ii-1]!="")
|
||||||
|
fwrite("\r\n",1,2,f);
|
||||||
|
}
|
||||||
|
if(!strline.empty()&&strline!="")
|
||||||
|
{
|
||||||
|
fwrite(strline.c_str(),1,strline.length(),f);
|
||||||
|
fwrite("\r\n",1,2,f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
m_bModified=false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CIniFile::GetFileString(const std::string& Section,const std::string& Item)
|
||||||
|
{
|
||||||
|
std::string strline;
|
||||||
|
std::string strSection;
|
||||||
|
std::string strItem;
|
||||||
|
std::string strValue;
|
||||||
|
|
||||||
|
size_t ii=0;
|
||||||
|
size_t iFileLines=m_FileContainer.size();
|
||||||
|
|
||||||
|
if(m_bReadOnly)
|
||||||
|
{
|
||||||
|
cSectionCache::iterator it=m_Cache.find(Section);
|
||||||
|
if((it!=m_Cache.end())) ii=it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bLastResult=false;
|
||||||
|
|
||||||
|
if(iFileLines>=0)
|
||||||
|
{
|
||||||
|
while(ii<iFileLines)
|
||||||
|
{
|
||||||
|
strline=m_FileContainer[ii++];
|
||||||
|
|
||||||
|
size_t rBracketPos=0;
|
||||||
|
if('['==strline[0]) rBracketPos=strline.find(']');
|
||||||
|
if(rBracketPos>0&&rBracketPos!=std::string::npos)
|
||||||
|
{
|
||||||
|
strSection=strline.substr(1,rBracketPos-1);
|
||||||
|
if(m_bReadOnly) m_Cache.insert(std::make_pair(strSection,ii-1));
|
||||||
|
if(strSection==Section)
|
||||||
|
{
|
||||||
|
while(ii<iFileLines)
|
||||||
|
{
|
||||||
|
strline=m_FileContainer[ii++];
|
||||||
|
size_t equalsignPos=strline.find('=');
|
||||||
|
if(equalsignPos!=strline.npos)
|
||||||
|
{
|
||||||
|
size_t last=equalsignPos?strline.find_last_not_of(" \t",equalsignPos-1):strline.npos;
|
||||||
|
if(last==strline.npos) strItem="";
|
||||||
|
else strItem=strline.substr(0,last+1);
|
||||||
|
|
||||||
|
if(strItem==Item)
|
||||||
|
{
|
||||||
|
size_t first=strline.find_first_not_of(" \t",equalsignPos+1);
|
||||||
|
if(first==strline.npos) strValue="";
|
||||||
|
else strValue=strline.substr(first);
|
||||||
|
m_bLastResult=true;
|
||||||
|
return strValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if('['==strline[0])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIniFile::SetFileString(const std::string& Section,const std::string& Item,const std::string& Value)
|
||||||
|
{
|
||||||
|
std::string strline;
|
||||||
|
std::string strSection;
|
||||||
|
std::string strItem;
|
||||||
|
|
||||||
|
if(m_bReadOnly) return;
|
||||||
|
|
||||||
|
size_t ii=0;
|
||||||
|
size_t iFileLines=m_FileContainer.size();
|
||||||
|
|
||||||
|
while(ii<iFileLines)
|
||||||
|
{
|
||||||
|
strline=m_FileContainer[ii++];
|
||||||
|
|
||||||
|
size_t rBracketPos=0;
|
||||||
|
if('['==strline[0]) rBracketPos=strline.find(']');
|
||||||
|
if(rBracketPos>0&&rBracketPos!=std::string::npos)
|
||||||
|
{
|
||||||
|
strSection=strline.substr(1,rBracketPos-1);
|
||||||
|
if(strSection==Section)
|
||||||
|
{
|
||||||
|
while(ii<iFileLines)
|
||||||
|
{
|
||||||
|
strline=m_FileContainer[ii++];
|
||||||
|
size_t equalsignPos=strline.find('=');
|
||||||
|
if(equalsignPos!=strline.npos)
|
||||||
|
{
|
||||||
|
size_t last=equalsignPos?strline.find_last_not_of(" \t",equalsignPos-1):strline.npos;
|
||||||
|
if(last==strline.npos) strItem="";
|
||||||
|
else strItem=strline.substr(0,last+1);
|
||||||
|
|
||||||
|
if(Item==strItem)
|
||||||
|
{
|
||||||
|
ReplaceLine(ii-1,Item+" = "+Value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if('['==strline[0])
|
||||||
|
{
|
||||||
|
InsertLine(ii-1,Item+" = "+Value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InsertLine(ii,Item+" = "+Value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertLine(ii,"["+Section+"]");
|
||||||
|
InsertLine(ii+1,Item+" = "+Value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool CIniFile::InsertLine(size_t line,const std::string& str)
|
||||||
|
{
|
||||||
|
m_FileContainer.insert(m_FileContainer.begin()+line,str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CIniFile::ReplaceLine(size_t line,const std::string& str)
|
||||||
|
{
|
||||||
|
m_FileContainer[line]=str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include "utils/stringutils.hpp"
|
||||||
|
|
||||||
|
bool matchPattern(std::string pattern, std::string tested)
|
||||||
|
{
|
||||||
|
std::regex patternRegex(pattern);
|
||||||
|
return regex_match(tested, patternRegex);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, decltype(free)*> formatted(fp, free);
|
||||||
|
return std::string(formatted.get());
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include "utils/thread.hpp"
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static std::vector<Thread> threads;
|
||||||
|
|
||||||
|
void Threads::create(ThreadFunc entrypoint)
|
||||||
|
{
|
||||||
|
s32 prio = 0;
|
||||||
|
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
|
||||||
|
Thread thread = threadCreate((ThreadFunc)entrypoint, NULL, 64 * 1024, prio - 1, -2, false);
|
||||||
|
threads.push_back(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Threads::destroy(void)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < threads.size(); i++) {
|
||||||
|
threadJoin(threads.at(i), U64_MAX);
|
||||||
|
threadFree(threads.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user