Browse Source

Cleaned up namespaces. Removed ES Patches, Bundles, and Channels. Removed sound due to dependency issue. Removed minizip from code to use devkitPro's minizip library. Increased version number.

tags/v3.0.5
Nichole Mattera 1 year ago
parent
commit
1eee89f63a
100 changed files with 3788 additions and 6797 deletions
  1. +4
    -2
      .gitignore
  2. +87
    -35
      Makefile
  3. BIN
      romfs/back.wav
  4. BIN
      romfs/enter.wav
  5. BIN
      romfs/select.wav
  6. +140
    -0
      source/AssetManager.cpp
  7. +71
    -0
      source/AssetManager.hpp
  8. +214
    -0
      source/ConfigManager.cpp
  9. +92
    -0
      source/ConfigManager.hpp
  10. +368
    -0
      source/FileManager.cpp
  11. +53
    -0
      source/FileManager.hpp
  12. +9
    -9
      source/ModalView.cpp
  13. +13
    -12
      source/ModalView.hpp
  14. +180
    -0
      source/NetManager.cpp
  15. +52
    -0
      source/NetManager.hpp
  16. +65
    -0
      source/Scene.cpp
  17. +25
    -24
      source/Scene.hpp
  18. +191
    -0
      source/SceneDirector.cpp
  19. +36
    -37
      source/SceneDirector.hpp
  20. +23
    -25
      source/View.cpp
  21. +28
    -28
      source/View.hpp
  22. +3
    -2
      source/main.cpp
  23. +14
    -10
      source/models/Action.cpp
  24. +18
    -18
      source/models/Action.hpp
  25. +99
    -0
      source/models/Ini.cpp
  26. +12
    -10
      source/models/Ini.hpp
  27. +17
    -13
      source/models/IniOption.cpp
  28. +11
    -9
      source/models/IniOption.hpp
  29. +84
    -0
      source/models/IniSection.cpp
  30. +18
    -16
      source/models/IniSection.hpp
  31. +130
    -0
      source/models/NetRequest.cpp
  32. +52
    -0
      source/models/NetRequest.hpp
  33. +12
    -10
      source/models/ThreadObj.cpp
  34. +15
    -15
      source/models/ThreadObj.hpp
  35. +3
    -0
      source/models/Touch.cpp
  36. +4
    -4
      source/models/Touch.hpp
  37. +43
    -0
      source/models/Trim.hpp
  38. +40
    -0
      source/models/Zip.cpp
  39. +13
    -14
      source/models/Zip.hpp
  40. +7
    -2
      source/scenes/AppUpdateScene.cpp
  41. +11
    -10
      source/scenes/AppUpdateScene.hpp
  42. +83
    -0
      source/scenes/ExFatWarningScene.cpp
  43. +18
    -17
      source/scenes/ExFatWarningScene.hpp
  44. +13
    -92
      source/scenes/PackageDownloadScene.cpp
  45. +21
    -24
      source/scenes/PackageDownloadScene.hpp
  46. +182
    -0
      source/scenes/PackageSelectScene.cpp
  47. +55
    -0
      source/scenes/PackageSelectScene.hpp
  48. +56
    -0
      source/views/AlertButtonView.cpp
  49. +14
    -13
      source/views/AlertButtonView.hpp
  50. +125
    -0
      source/views/AlertView.cpp
  51. +22
    -21
      source/views/AlertView.hpp
  52. +84
    -0
      source/views/ControlView.cpp
  53. +10
    -9
      source/views/ControlView.hpp
  54. +125
    -0
      source/views/FooterView.cpp
  55. +13
    -12
      source/views/FooterView.hpp
  56. +73
    -0
      source/views/HeaderView.cpp
  57. +14
    -14
      source/views/HeaderView.hpp
  58. +10
    -7
      source/views/ImageView.cpp
  59. +10
    -8
      source/views/ImageView.hpp
  60. +129
    -0
      source/views/ListRowView.cpp
  61. +58
    -0
      source/views/ListRowView.hpp
  62. +64
    -0
      source/views/ProgressBarView.cpp
  63. +9
    -9
      source/views/ProgressBarView.hpp
  64. +61
    -0
      source/views/StatusView.cpp
  65. +15
    -12
      source/views/StatusView.hpp
  66. +118
    -0
      source/views/TextView.cpp
  67. +63
    -0
      source/views/TextView.hpp
  68. +70
    -0
      source/views/UpdateView.cpp
  69. +16
    -15
      source/views/UpdateView.hpp
  70. +0
    -149
      src/AssetManager.cpp
  71. +0
    -77
      src/AssetManager.hpp
  72. +0
    -301
      src/ConfigManager.cpp
  73. +0
    -114
      src/ConfigManager.hpp
  74. +0
    -372
      src/FileManager.cpp
  75. +0
    -54
      src/FileManager.hpp
  76. +0
    -193
      src/NetManager.cpp
  77. +0
    -51
      src/NetManager.hpp
  78. +0
    -67
      src/Scene.cpp
  79. +0
    -191
      src/SceneDirector.cpp
  80. +0
    -247
      src/minizip/ioapi.c
  81. +0
    -208
      src/minizip/ioapi.h
  82. +0
    -2125
      src/minizip/unzip.c
  83. +0
    -437
      src/minizip/unzip.h
  84. +0
    -93
      src/models/Ini.cpp
  85. +0
    -79
      src/models/IniSection.cpp
  86. +0
    -125
      src/models/NetRequest.cpp
  87. +0
    -53
      src/models/NetRequest.hpp
  88. +0
    -41
      src/models/Trim.hpp
  89. +0
    -37
      src/models/Zip.cpp
  90. +0
    -78
      src/scenes/ExFatWarningScene.cpp
  91. +0
    -423
      src/scenes/PackageSelectScene.cpp
  92. +0
    -82
      src/scenes/PackageSelectScene.hpp
  93. +0
    -50
      src/views/AlertButtonView.cpp
  94. +0
    -122
      src/views/AlertView.cpp
  95. +0
    -78
      src/views/ControlView.cpp
  96. +0
    -120
      src/views/FooterView.cpp
  97. +0
    -68
      src/views/HeaderView.cpp
  98. +0
    -47
      src/views/ListHeaderView.cpp
  99. +0
    -36
      src/views/ListHeaderView.hpp
  100. +0
    -121
      src/views/ListRowView.cpp

+ 4
- 2
.gitignore View File

@@ -1,3 +1,5 @@
build
dist
.vscode
.vscode
*.elf
*.nacp
*.nro

+ 87
- 35
Makefile View File

@@ -13,8 +13,9 @@ include $(DEVKITPRO)/libnx/switch_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
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
@@ -27,34 +28,42 @@ include $(DEVKITPRO)/libnx/switch_rules
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
#---------------------------------------------------------------------------------

TARGET := $(notdir $(CURDIR))
BUILD := build
DIST := dist
SOURCES := src $(wildcard src/**)
EXEFS_SRC := exefs_src
SOURCES := source source/models source/scenes source/views
DATA := data
INCLUDES := include
ROMFS := romfs

APP_TITLE := Kosmos Updater
APP_AUTHOR := Steven Mattera
APP_VERSION := 3.0.4
APP_TITLE := Kosmos Updater
APP_AUTHOR := Steven Mattera

APP_VERSION := 3.0.5
APP_VERSION_MAJOR := 3
APP_VERSION_MINOR := 0
APP_VERSION_PATCH := 4
API_VERSION := v3

ICON := Icon.jpg
APP_VERSION_PATCH := 5
API_VERSION := v4

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------

ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE

DEFINES += -D__SWITCH__ -DUSE_FILE32API -DVERSION=\"$(APP_VERSION)\" \
-DVERSION_MAJOR=$(APP_VERSION_MAJOR) -DVERSION_MINOR=$(APP_VERSION_MINOR) \
-DVERSION_PATCH=$(APP_VERSION_PATCH) -DAPI_VERSION=\"$(API_VERSION)\"
DEFINES += -D__SWITCH__ \
-DVERSION=\"$(APP_VERSION)\" \
-DVERSION_MAJOR=$(APP_VERSION_MAJOR) \
-DVERSION_MINOR=$(APP_VERSION_MINOR) \
-DVERSION_PATCH=$(APP_VERSION_PATCH) \
-DAPI_VERSION=\"$(API_VERSION)\"

CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES) $(INCLUDE)
@@ -62,17 +71,20 @@ CFLAGS := -g -Wall -O2 -ffunction-sections \
CXXFLAGS := $(CFLAGS) -fno-rtti -fexceptions -std=gnu++17

ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) \
-Wl,-Map,$(notdir $*.map)

LIBS := -lSDL2_ttf -lSDL2_image -lSDL2_gfx -lSDL2_mixer \
-lpng -lturbojpeg -lvorbisidec -logg -lmpg123 -lmodplug \
-lconfig -lcurl -lz -lmbedtls -lmbedx509 -lmbedcrypto -lnx `sdl2-config --libs` `freetype-config --libs`
LIBS := -lSDL2_ttf -lSDL2_image -lSDL2_gfx \
-lfreetype \
-lwebp -lpng -ljpeg \
-lcurl -lz -lmbedtls -lmbedcrypto -lmbedx509 \
-lminizip -lconfig -lnx `sdl2-config --libs` `freetype-config --libs`

#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
LIBDIRS := $(PORTLIBS) $(LIBNX)


#---------------------------------------------------------------------------------
@@ -82,15 +94,18 @@ LIBDIRS := $(PORTLIBS) $(LIBNX)
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------

export OUTPUT := $(CURDIR)/$(DIST)/$(TARGET)
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)

export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))

export DEPSDIR := $(CURDIR)/$(BUILD)

CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))

#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
@@ -106,14 +121,29 @@ else
endif
#---------------------------------------------------------------------------------

export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o)
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))

export INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
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 LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)

export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif

ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
@@ -133,7 +163,7 @@ ifeq ($(strip $(NO_ICON)),)
endif

ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(DIST)/$(TARGET).nacp
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif

ifneq ($(APP_TITLEID),)
@@ -151,13 +181,17 @@ all: $(BUILD)

$(BUILD):
@[ -d $@ ] || mkdir -p $@
@[ -d $(DIST) ] || mkdir $(DIST)
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile

#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(DIST)
ifeq ($(strip $(APP_JSON)),)
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
else
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
endif


#---------------------------------------------------------------------------------
else
@@ -168,11 +202,9 @@ DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).pfs0 $(OUTPUT).nro
ifeq ($(strip $(APP_JSON)),)

$(OUTPUT).pfs0 : $(OUTPUT).nso

$(OUTPUT).nso : $(OUTPUT).elf
all : $(OUTPUT).nro

ifeq ($(strip $(NO_NACP)),)
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
@@ -180,8 +212,28 @@ else
$(OUTPUT).nro : $(OUTPUT).elf
endif

else

all : $(OUTPUT).nsp

$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm

$(OUTPUT).nso : $(OUTPUT).elf

endif

$(OUTPUT).elf : $(OFILES)

$(OFILES_SRC) : $(HFILES_BIN)

#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)

-include $(DEPENDS)

#---------------------------------------------------------------------------------------


BIN
romfs/back.wav View File


BIN
romfs/enter.wav View File


BIN
romfs/select.wav View File


+ 140
- 0
source/AssetManager.cpp View File

@@ -0,0 +1,140 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#include "AssetManager.hpp"
#include "SceneDirector.hpp"

using namespace std;

namespace ku {
void AssetManager::dealloc() {
if (AssetManager::large_button_font != NULL)
TTF_CloseFont(AssetManager::large_button_font);

if (AssetManager::button_font != NULL)
TTF_CloseFont(AssetManager::button_font);

if (AssetManager::subbody_font != NULL)
TTF_CloseFont(AssetManager::subbody_font);

if (AssetManager::body_font != NULL)
TTF_CloseFont(AssetManager::body_font);

if (AssetManager::header_font != NULL)
TTF_CloseFont(AssetManager::header_font);

if (AssetManager::icon != NULL)
SDL_DestroyTexture(AssetManager::icon);
if (AssetManager::downloading != NULL)
SDL_DestroyTexture(AssetManager::downloading);

if (AssetManager::checkmark != NULL)
SDL_DestroyTexture(AssetManager::checkmark);

if (AssetManager::handheld != NULL)
SDL_DestroyTexture(AssetManager::handheld);

if (AssetManager::y_button != NULL)
SDL_DestroyTexture(AssetManager::y_button);

if (AssetManager::x_button != NULL)
SDL_DestroyTexture(AssetManager::x_button);

if (AssetManager::b_button != NULL)
SDL_DestroyTexture(AssetManager::b_button);

if (AssetManager::a_button != NULL)
SDL_DestroyTexture(AssetManager::a_button);
}

bool AssetManager::initialize() {
Result rc;

setsysGetColorSetId(&AssetManager::theme);
if (AssetManager::theme == ColorSetId_Light) {
AssetManager::background = { 235, 235, 235, 255 };
AssetManager::sidebard_background = { 240, 240, 240, 255 };
AssetManager::header_footer_divider = { 45, 45, 45, 255 };
AssetManager::header_bullet = { 121, 121, 121, 255 };
AssetManager::list_divider = { 205, 205, 205, 255 };
AssetManager::active_player_indicator = { 158, 228, 0, 255 };
AssetManager::player_indicator = { 125, 125, 125, 255 };
AssetManager::selected_background = { 253, 253, 253, 255 };
AssetManager::selected_border_1 = { 0, 255, 196, 255 };
AssetManager::selected_border_2 = { 22, 146, 197, 255 };
AssetManager::modal_faded_background = { 18, 27, 36, 229 };
AssetManager::modal_background = { 240, 240, 240, 255 };
AssetManager::text = { 45, 45, 45, 255 };
AssetManager::active_text = { 50, 80, 240, 255 };
AssetManager::disabled_text = { 165, 165, 165, 255 };
} else {
AssetManager::background = { 45, 45, 45, 255 };
AssetManager::sidebard_background = { 51, 51, 51, 255 };
AssetManager::header_footer_divider = { 255, 255, 255, 255 };
AssetManager::header_bullet = { 160, 160, 160, 255 };
AssetManager::list_divider = { 77, 77, 77, 255 };
AssetManager::active_player_indicator = { 158, 228, 0, 255 };
AssetManager::player_indicator = { 125, 125, 125, 255 };
AssetManager::selected_background = { 31, 34, 39, 255 };
AssetManager::selected_border_1 = { 0, 255, 196, 255 };
AssetManager::selected_border_2 = { 22, 146, 197, 255 };
AssetManager::modal_faded_background = { 18, 27, 36, 229 };
AssetManager::modal_background = { 70, 70, 70, 255 };
AssetManager::text = { 255, 255, 255, 255 };
AssetManager::active_text = { 0, 255, 196, 255 };
AssetManager::disabled_text = { 125, 125, 125, 255 };
}

rc = plGetSharedFontByType(&AssetManager::standardFontData, PlSharedFontType_Standard);
if (R_FAILED(rc))
return false;

AssetManager::header_font = TTF_OpenFontRW(SDL_RWFromMem(AssetManager::standardFontData.address, AssetManager::standardFontData.size), 1, 28);
AssetManager::body_font = TTF_OpenFontRW(SDL_RWFromMem(AssetManager::standardFontData.address, AssetManager::standardFontData.size), 1, 23);
AssetManager::subbody_font = TTF_OpenFontRW(SDL_RWFromMem(AssetManager::standardFontData.address, AssetManager::standardFontData.size), 1, 18);
if (!AssetManager::header_font || !AssetManager::body_font)
return false;

rc = plGetSharedFontByType(&AssetManager::extendedFontData, PlSharedFontType_NintendoExt);
if (R_FAILED(rc))
return false;
AssetManager::button_font = TTF_OpenFontRW(SDL_RWFromMem(AssetManager::extendedFontData.address, AssetManager::extendedFontData.size), 1, 25);
if (!AssetManager::button_font)
return false;

AssetManager::large_button_font = TTF_OpenFontRW(SDL_RWFromMem(AssetManager::extendedFontData.address, AssetManager::extendedFontData.size), 1, 70);
if (!AssetManager::large_button_font)
return false;

return true;
}

void AssetManager::setRenderColor(SDL_Color color) {
SDL_SetRenderDrawColor(SceneDirector::renderer, color.r, color.g, color.b, color.a);
}

SDL_Texture * AssetManager::loadAsset(string file) {
string themeDirectory = (AssetManager::theme == ColorSetId_Light) ? "light" : "dark";
string path = "romfs:/" + themeDirectory + "/" + file;
SDL_Surface * image = IMG_Load(path.c_str());
SDL_Texture * texture = SDL_CreateTextureFromSurface(SceneDirector::renderer, image);
SDL_FreeSurface(image);
return texture;
}
}

+ 71
- 0
source/AssetManager.hpp View File

@@ -0,0 +1,71 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#pragma once

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <string>
#include <switch.h>

namespace ku {
class AssetManager {
public:
/* Textures */
static inline SDL_Texture * a_button = NULL;
static inline SDL_Texture * b_button = NULL;
static inline SDL_Texture * x_button = NULL;
static inline SDL_Texture * y_button = NULL;
static inline SDL_Texture * handheld = NULL;
static inline SDL_Texture * checkmark = NULL;
static inline SDL_Texture * downloading = NULL;
static inline SDL_Texture * icon = NULL;

/* Colors */
static inline ColorSetId theme;
static inline SDL_Color background;
static inline SDL_Color sidebard_background;
static inline SDL_Color header_footer_divider;
static inline SDL_Color header_bullet;
static inline SDL_Color list_divider;
static inline SDL_Color active_player_indicator;
static inline SDL_Color player_indicator;
static inline SDL_Color selected_background;
static inline SDL_Color selected_border_1;
static inline SDL_Color selected_border_2;
static inline SDL_Color modal_faded_background;
static inline SDL_Color modal_background;
static inline SDL_Color text;
static inline SDL_Color active_text;
static inline SDL_Color disabled_text;

/* Fonts */
static inline PlFontData standardFontData;
static inline TTF_Font * header_font = NULL;
static inline TTF_Font * body_font = NULL;
static inline TTF_Font * subbody_font = NULL;
static inline PlFontData extendedFontData;
static inline TTF_Font * button_font = NULL;
static inline TTF_Font * large_button_font = NULL;
static bool initialize();
static void dealloc();
static void setRenderColor(SDL_Color color);
static SDL_Texture * loadAsset(std::string file);
};
}

+ 214
- 0
source/ConfigManager.cpp View File

@@ -0,0 +1,214 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#include "ConfigManager.hpp"

using namespace std;

namespace ku {
void ConfigManager::initialize() {
config_init(&_cfg);
config_init(&_internalDb);

if(!config_read_file(&_cfg, CONFIG_FILENAME.c_str())) {
config_setting_t * root, * setting;
root = config_root_setting(&_cfg);

setting = config_setting_add(root, HOST_KEY.c_str(), CONFIG_TYPE_STRING);
config_setting_set_string(setting, HOST_DEF.c_str());

setting = config_setting_add(root, IGNORE_KEY.c_str(), CONFIG_TYPE_ARRAY);

setting = config_setting_add(root, AUTOUPDATE_KEY.c_str(), CONFIG_TYPE_BOOL);
config_setting_set_bool(setting, AUTOUPDATE_DEF);

setting = config_setting_add(root, PROXY_ENABLED_KEY.c_str(), CONFIG_TYPE_BOOL);
config_setting_set_bool(setting, PROXY_ENABLED_DEF);
setting = config_setting_add(root, PROXY_URL_KEY.c_str(), CONFIG_TYPE_STRING);
config_setting_set_string(setting, PROXY_URL_DEF.c_str());

setting = config_setting_add(root, PROXY_USERNAME_KEY.c_str(), CONFIG_TYPE_STRING);
config_setting_set_string(setting, PROXY_USERNAME_DEF.c_str());

setting = config_setting_add(root, PROXY_PASSWORD_KEY.c_str(), CONFIG_TYPE_STRING);
config_setting_set_string(setting, PROXY_PASSWORD_DEF.c_str());

config_write_file(&_cfg, CONFIG_FILENAME.c_str());
}

if(!config_read_file(&_internalDb, INTERNAL_FILENAME.c_str())) {
config_setting_t * root, * setting;
root = config_root_setting(&_internalDb);

setting = config_setting_add(root, VERSION_KEY.c_str(), CONFIG_TYPE_STRING);
config_setting_set_string(setting, VERSION_DEF.c_str());

setting = config_setting_add(root, INSTALLED_FILES_KEY.c_str(), CONFIG_TYPE_ARRAY);
setting = config_setting_add(root, RECEIVED_EXFAT_WARNING_KEY.c_str(), CONFIG_TYPE_BOOL);
config_setting_set_bool(setting, RECEIVED_EXFAT_WARNING_DEF);
config_write_file(&_internalDb, INTERNAL_FILENAME.c_str());
}
}

void ConfigManager::dealloc() {
config_destroy(&_cfg);
config_destroy(&_internalDb);
}

string ConfigManager::getHost() {
return _readString(HOST_KEY, HOST_DEF, _cfg);
}

vector<string> ConfigManager::getFilesToIgnore() {
vector<string> defaultValue;
return _readArrayOfStrings(IGNORE_KEY, defaultValue, _cfg);
}

bool ConfigManager::shouldAutoUpdate() {
#ifdef DEBUG
return false;
#endif

return _readBoolean(AUTOUPDATE_KEY, AUTOUPDATE_DEF, _cfg);
}

bool ConfigManager::shouldUseProxy() {
return _readBoolean(PROXY_ENABLED_KEY, PROXY_ENABLED_DEF, _cfg);
}

string ConfigManager::getProxy() {
return _readString(PROXY_URL_KEY, PROXY_URL_DEF, _cfg);
}

string ConfigManager::getProxyUsername() {
return _readString(PROXY_USERNAME_KEY, PROXY_USERNAME_DEF, _cfg);
}

string ConfigManager::getProxyPassword() {
return _readString(PROXY_PASSWORD_KEY, PROXY_PASSWORD_DEF, _cfg);
}


string ConfigManager::getCurrentVersion() {
return _readString(VERSION_KEY, VERSION_DEF, _internalDb);
}

vector<string> ConfigManager::getInstalledFiles() {
vector<string> defaultValue;
return _readArrayOfStrings(INSTALLED_FILES_KEY, defaultValue, _internalDb);
}

bool ConfigManager::getReceivedExFATWarning() {
return _readBoolean(RECEIVED_EXFAT_WARNING_KEY, RECEIVED_EXFAT_WARNING_DEF, _internalDb);
}

bool ConfigManager::setCurrentVersion(string version) {
return _writeString(VERSION_KEY, version, _internalDb, INTERNAL_FILENAME);
}

bool ConfigManager::setInstalledFiles(vector<string> files) {
return _writeArrayOfStrings(INSTALLED_FILES_KEY, files, _internalDb, INTERNAL_FILENAME);
}

bool ConfigManager::setReceivedExFATWarning(bool received) {
return _writeBoolean(RECEIVED_EXFAT_WARNING_KEY, received, _internalDb, INTERNAL_FILENAME);
}

// Private Methods

bool ConfigManager::_readBoolean(string key, bool def, config_t config) {
int result;

if (!config_lookup_bool(&config, key.c_str(), &result))
return def;

return result;
}

string ConfigManager::_readString(string key, string def, config_t config) {
const char * result;

if (!config_lookup_string(&config, key.c_str(), &result))
return def;

return string(result);
}

vector<string> ConfigManager::_readArrayOfStrings(string key, vector<string> def, config_t config) {
vector<string> result;
config_setting_t * array = config_lookup(&config, key.c_str());
if (array == NULL)
return def;

int count = config_setting_length(array);
for (int i = 0; i < count; i++) {
result.push_back(string(config_setting_get_string_elem(array, i)));
}

return result;
}

bool ConfigManager::_writeBoolean(string key, bool value, config_t config, string filename) {
config_setting_t * root, * setting;
root = config_root_setting(&config);

setting = config_setting_get_member(root, key.c_str());
if (setting == NULL) {
setting = config_setting_add(root, key.c_str(), CONFIG_TYPE_BOOL);
}

config_setting_set_bool(setting, value);

return config_write_file(&config, filename.c_str());
}

bool ConfigManager::_writeString(string key, string value, config_t config, string filename) {
config_setting_t * root, * setting;
root = config_root_setting(&config);

setting = config_setting_get_member(root, key.c_str());
if (setting == NULL) {
setting = config_setting_add(root, key.c_str(), CONFIG_TYPE_STRING);
}

config_setting_set_string(setting, value.c_str());

return config_write_file(&config, filename.c_str());
}

bool ConfigManager::_writeArrayOfStrings(string key, vector<string> values, config_t config, string filename) {
config_setting_t * root = config_root_setting(&config);
config_setting_remove(root, key.c_str());

config_setting_t * array = config_setting_add(root, key.c_str(), CONFIG_TYPE_ARRAY);
for (auto const& value : values) {
config_setting_set_string_elem(array, -1, value.c_str());
}

return config_write_file(&config, filename.c_str());
}

bool ConfigManager::_removeSetting(string key, config_t config, string filename) {
config_setting_t * root = config_root_setting(&config);
config_setting_remove(root, key.c_str());
return config_write_file(&config, filename.c_str());
}
}

+ 92
- 0
source/ConfigManager.hpp View File

@@ -0,0 +1,92 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#pragma once

#include <libconfig.h>
#include <string>
#include <vector>

namespace ku {
class ConfigManager {
public:
static void initialize();
static void dealloc();

static std::string getHost();
static std::vector<std::string> getFilesToIgnore();
static bool shouldAutoUpdate();
static bool shouldUseProxy();
static std::string getProxy();
static std::string getProxyUsername();
static std::string getProxyPassword();

static std::string getCurrentVersion();
static std::vector<std::string> getInstalledFiles();
static bool getReceivedExFATWarning();

static bool setCurrentVersion(std::string version);
static bool setInstalledFiles(std::vector<std::string> files);
static bool setReceivedExFATWarning(bool received);

private:
static inline config_t _cfg;
static inline config_t _internalDb;

static bool _readBoolean(std::string key, bool def, config_t config);
static std::string _readString(std::string key, std::string def, config_t config);
static std::vector<std::string> _readArrayOfStrings(std::string key, std::vector<std::string> def, config_t config);

static bool _writeBoolean(std::string key, bool value, config_t config, std::string filename);
static bool _writeString(std::string key, std::string value, config_t config, std::string filename);
static bool _writeArrayOfStrings(std::string key, std::vector<std::string> values, config_t config, std::string filename);

static bool _removeSetting(std::string key, config_t config, std::string filename);

static inline const std::string CONFIG_FILENAME = "settings.cfg";
static inline const std::string INTERNAL_FILENAME = "internal.db";

static inline const std::string HOST_KEY = "host";
static inline const std::string HOST_DEF = "http://kosmos-updater.teamatlasnx.com";

static inline const std::string IGNORE_KEY = "ignore";

static inline const std::string AUTOUPDATE_KEY = "autoupdate";
static inline const bool AUTOUPDATE_DEF = true;

static inline const std::string PROXY_ENABLED_KEY = "proxy_enabled";
static inline const bool PROXY_ENABLED_DEF = false;

static inline const std::string PROXY_URL_KEY = "proxy_url";
static inline const std::string PROXY_URL_DEF = "";

static inline const std::string PROXY_USERNAME_KEY = "proxy_username";
static inline const std::string PROXY_USERNAME_DEF = "";

static inline const std::string PROXY_PASSWORD_KEY = "proxy_password";
static inline const std::string PROXY_PASSWORD_DEF = "";


static inline const std::string VERSION_KEY = "version";
static inline const std::string VERSION_DEF = "";

static inline const std::string INSTALLED_FILES_KEY = "installed_files";

static inline const std::string RECEIVED_EXFAT_WARNING_KEY = "received_exfat_warning";
static inline const bool RECEIVED_EXFAT_WARNING_DEF = false;
};
}

+ 368
- 0
source/FileManager.cpp View File

@@ -0,0 +1,368 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#include <algorithm>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include "FileManager.hpp"

#include "ConfigManager.hpp"
#include "models/Ini.hpp"

using namespace std;
using namespace ku::models;

namespace ku {
bool FileManager::writeFile(string filename, NetRequest * request) {
deleteFile(filename);

FILE * file = fopen(filename.c_str(), "wb");
if (!file) {
return false;
}

size_t result = fwrite(request->getData(), sizeof(char), request->getSize(), file);

fflush(file);
fclose(file);

return (result == request->getSize());
}

bool FileManager::deleteFile(string filename) {
if (fileExists(filename)) {
return remove(filename.c_str()) == 0;
}

return false;
}

bool FileManager::fileExists(string filename) {
FILE * file = fopen(filename.c_str(), "r");

if (file) {
fflush(file);
fclose(file);
return true;
}

return false;
}

// http://stackoverflow.com/a/11366985
bool FileManager::createSubfolder(string path) {
bool bSuccess = false;
int nRC = ::mkdir(path.c_str(), 0775);
if(nRC == -1)
{
switch(errno)
{
case ENOENT:
//parent didn't exist, try to create it
if(createSubfolder(path.substr(0, path.find_last_of('/'))))
//Now, try to create again.
bSuccess = 0 == ::mkdir(path.c_str(), 0775);
else
bSuccess = false;
break;
case EEXIST:
//Done!
bSuccess = true;
break;std::string getHost();
default:
bSuccess = false;
break;
}
}
else
bSuccess = true;
return bSuccess;
}

void FileManager::extract(Zip * zip) {
_createThread(_extract, zip);
}

void FileManager::cleanUpFiles(ThreadObj * status) {
_createThread(_cleanUpFiles, status);
}

void FileManager::applyNoGC(ThreadObj * status) {
_createThread(_applyNoGC, status);
}

Result FileManager::_createThread(ThreadFunc func, ThreadObj * arg) {
Thread thread;
Result res;

if (R_FAILED( res = threadCreate(&thread, func, (void *) arg, 0x2000, 0x2B, -2)))
return res;
if (R_FAILED( res = threadStart(&thread)))
return res;

arg->thread = thread;
_threads.push_back(thread);

return 0;
}

void FileManager::_extract(void * ptr) {
Zip * zipObj = (Zip *) ptr;
unzFile unz = unzOpen(zipObj->getFilename().c_str());
vector<string> filesToIgnore = ConfigManager::getFilesToIgnore();
vector<string> filesInstalled = ConfigManager::getInstalledFiles();
int i = 0;
for (;;) {
int code;
if (i == 0) {
code = unzGoToFirstFile(unz);
} else {
code = unzGoToNextFile(unz);
}
i++;

if (code == UNZ_END_OF_LIST_OF_FILE) {
break;
} else {
unz_file_pos pos;
unzGetFilePos(unz, &pos);

mutexLock(&zipObj->mutexRequest);
zipObj->progress = (double) i / (double) zipObj->getNumberOfFiles();
mutexUnlock(&zipObj->mutexRequest);
}

unz_file_info_s * fileInfo = _getFileInfo(unz);

std::string fileName(zipObj->getDestination());
fileName += '/';
fileName += _getFullFileName(unz, fileInfo);

if (find(begin(filesToIgnore), end(filesToIgnore), fileName) != end(filesToIgnore)) {
free(fileInfo);
continue;
}

if (fileName.back() != '/') {
filesInstalled.push_back(fileName);

int result = _extractFile(fileName.c_str(), unz, fileInfo);

if (result < 0) {
mutexLock(&zipObj->mutexRequest);
zipObj->progress = 1;
zipObj->isComplete = false;
zipObj->hasError = true;
zipObj->errorMessage = "There was an error while trying to extract files.";
mutexUnlock(&zipObj->mutexRequest);

free(fileInfo);

return;
}
}

free(fileInfo);
}

mutexLock(&zipObj->mutexRequest);
zipObj->progress = 1;
zipObj->isComplete = (i >= 1);
zipObj->hasError = (i <= 0);

if (i <= 0) {
zipObj->errorMessage = "There was no files to extract.";
} else {
ConfigManager::setInstalledFiles(filesInstalled);
}

mutexUnlock(&zipObj->mutexRequest);

unzClose(unz);
}

void FileManager::_cleanUpFiles(void * ptr) {
ThreadObj * threadObj = (ThreadObj *) ptr;
vector<string> installedFiles = ConfigManager::getInstalledFiles();
vector<string> filesToIgnore = ConfigManager::getFilesToIgnore();

int i = 0;
for (auto const& fileName : installedFiles) {
i++;

mutexLock(&threadObj->mutexRequest);
threadObj->progress = (double) i / (double) installedFiles.size();
threadObj->isComplete = false;
mutexUnlock(&threadObj->mutexRequest);

if (find(begin(filesToIgnore), end(filesToIgnore), fileName) != end(filesToIgnore)) {
continue;
}

deleteFile(fileName);
}

vector<string> blankVector;
ConfigManager::setInstalledFiles(blankVector);

mutexLock(&threadObj->mutexRequest);
threadObj->progress = 1;
threadObj->isComplete = true;
mutexUnlock(&threadObj->mutexRequest);
}

void FileManager::_applyNoGC(void * ptr) {
ThreadObj * threadObj = (ThreadObj *) ptr;

Ini * ini = Ini::parseFile(HEKATE_FILE);
for (auto const& section : ini->sections) {
if (section->isCaption() || section->isComment())
continue;

if (section->value == "config") {
bool patchApplied = false;
for (auto const& option : section->options) {
if (option->key == "autonogc") {
option->value = "1";
patchApplied = true;
break;
}
}

if (!patchApplied) {
section->options.push_back(new IniOption("autonogc", "1"));
}

break;
}
}

ini->writeToFile(HEKATE_FILE);
delete ini;

mutexLock(&threadObj->mutexRequest);
threadObj->progress = 1;
threadObj->isComplete = true;
mutexUnlock(&threadObj->mutexRequest);
}

unz_file_info_s * FileManager::_getFileInfo(unzFile unz) {
unz_file_info_s * fileInfo = (unz_file_info_s*) malloc(sizeof(unz_file_info_s));
unzGetCurrentFileInfo(unz, fileInfo, NULL, 0, NULL, 0, NULL, 0);
return fileInfo;
}

string FileManager::_getFullFileName(unzFile unz, unz_file_info_s * fileInfo) {
char filePath[fileInfo->size_filename + 1];
unzGetCurrentFileInfo(unz, fileInfo, filePath, fileInfo->size_filename, NULL, 0, NULL, 0);
filePath[fileInfo->size_filename] = '\0';
string path(filePath);
path.resize(fileInfo->size_filename);

return path;
}

bool FileManager::_makeDirectoryParents(string path)
{
bool bSuccess = false;
int nRC = ::mkdir(path.c_str(), 0775);
if(nRC == -1)
{
switch(errno)
{
case ENOENT:
//parent didn't exist, try to create it
if( _makeDirectoryParents(path.substr(0, path.find_last_of('/'))))
//Now, try to create again.
bSuccess = 0 == ::mkdir(path.c_str(), 0775);
else
bSuccess = false;
break;
case EEXIST:
//Done!
bSuccess = true;
break;std::string getHost();
default:
bSuccess = false;
break;
}
}
else
bSuccess = true;
return bSuccess;
}

int FileManager::_extractFile(const char * path, unzFile unz, unz_file_info_s * fileInfo) {
//check to make sure filepath or fileInfo isnt null
if (path == NULL || fileInfo == NULL)
return -1;
if (unzOpenCurrentFile(unz) != UNZ_OK)
return -2;
char folderPath[strlen(path) + 1];
strcpy(folderPath, path);
char * pos = strrchr(folderPath, '/');
if (pos != NULL) {
*pos = '\0';
_makeDirectoryParents(string(folderPath));
}
u32 blocksize = 0x8000;
u8 * buffer = (u8*) malloc(blocksize);
if (buffer == NULL)
return -3;
u32 done = 0;
int writeBytes = 0;
FILE * fp = fopen(path, "w");
if (fp == NULL) {
free(buffer);
return -4;
}
while (done < fileInfo->uncompressed_size) {
if (done + blocksize > fileInfo->uncompressed_size) {
blocksize = fileInfo->uncompressed_size - done;
}
unzReadCurrentFile(unz, buffer, blocksize);
writeBytes = write(fileno(fp), buffer, blocksize);
if (writeBytes <= 0) {
break;
}
done += writeBytes;
}
fflush(fp);
fsync(fileno(fp));
fclose(fp);
free(buffer);
if (done != fileInfo->uncompressed_size)
return -4;
unzCloseCurrentFile(unz);
return 0;
}
}

+ 53
- 0
source/FileManager.hpp View File

@@ -0,0 +1,53 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#pragma once

#include <minizip/unzip.h>
#include <string>
#include <vector>

#include "models/NetRequest.hpp"
#include "models/ThreadObj.hpp"
#include "models/Zip.hpp"

namespace ku {
class FileManager {
public:
static bool writeFile(std::string filename, models::NetRequest * request);
static bool deleteFile(std::string filename);
static bool fileExists(std::string filename);
static bool createSubfolder(std::string path);
static void extract(models::Zip * zip);
static void cleanUpFiles(models::ThreadObj * status);
static void applyNoGC(models::ThreadObj * status);

private:
static inline std::vector<Thread> _threads;

static Result _createThread(ThreadFunc func, models::ThreadObj * arg);
static void _extract(void * ptr);
static void _cleanUpFiles(void * ptr);
static void _applyNoGC(void * ptr);
static unz_file_info_s * _getFileInfo(unzFile unz);
static std::string _getFullFileName(unzFile unz, unz_file_info_s * fileInfo);
static bool _makeDirectoryParents(std::string path);
static int _extractFile(const char * path, unzFile unz, unz_file_info_s * fileInfo);

static inline const std::string HEKATE_FILE = "sdmc:/bootloader/hekate_ipl.ini";
};
}

src/ModalView.cpp → source/ModalView.cpp View File

@@ -18,15 +18,15 @@
#include "ModalView.hpp"
#include "SceneDirector.hpp"

void ModalView::handleButton(u32 buttons, double dTime) {}

void ModalView::show() {
SceneDirector::modal = this;
}
namespace ku {
void ModalView::show() {
SceneDirector::modal = this;
}

void ModalView:: dismiss(bool success) {
SceneDirector::modal = NULL;
if (onDismiss) {
onDismiss(this, success);
void ModalView:: dismiss(bool success) {
SceneDirector::modal = NULL;
if (onDismiss) {
onDismiss(this, success);
}
}
}

src/ModalView.hpp → source/ModalView.hpp View File

@@ -17,20 +17,21 @@

#pragma once

#include <switch.h>
#include <list>
#include <functional>
#include <list>
#include <SDL2/SDL.h>
#include "View.hpp"
#include <switch.h>

using namespace std;
#include "View.hpp"

class ModalView : public View {
public:
function<void(ModalView *, bool)> onDismiss;
virtual void handleButton(u32 buttons, double dTime);
namespace ku {
class ModalView : public ku::View {
public:
std::function<void(ModalView *, bool)> onDismiss;
virtual void handleButton(u32 buttons, double dTime){};

void show();
void dismiss(bool success);
};
void show();
void dismiss(bool success);
};
}

+ 180
- 0
source/NetManager.cpp View File

@@ -0,0 +1,180 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#include "NetManager.hpp"

#include "ConfigManager.hpp"

using namespace std;
using namespace ku::models;

namespace ku {
void NetManager::initialize() {
#ifndef DEBUG
socketInitializeDefault();
#endif
curl_global_init(CURL_GLOBAL_ALL);
_hostname = ConfigManager::getHost();
_shouldUseProxy = ConfigManager::shouldUseProxy();
_proxyURL = ConfigManager::getProxy();
_proxyUsername = ConfigManager::getProxyUsername();
_proxyPassword = ConfigManager::getProxyPassword();
}

void NetManager::dealloc() {
curl_global_cleanup();
#ifndef DEBUG
socketExit();
#endif
}

NetRequest * NetManager::getLatestAppVersion() {
NetRequest * request = new NetRequest("GET", _hostname + "/" + API_VERSION + "/app/version-number");
_createThread(_request, request);
return request;
}

NetRequest * NetManager::getLatestApp() {
NetRequest * request = new NetRequest("GET", _hostname + "/" + API_VERSION + "/app");
_createThread(_request, request);
return request;
}

NetRequest * NetManager::getLatestKosmosVersion() {
NetRequest * request = new NetRequest("GET", _hostname + "/" + API_VERSION + "/package/version-number");
_createThread(_request, request);
return request;
}

NetRequest * NetManager::getLatestKosmos() {
NetRequest * request = new NetRequest("GET", _hostname + "/" + API_VERSION + "/package");
_createThread(_request, request);
return request;
}

Result NetManager::_createThread(ThreadFunc func, NetRequest * request) {
Thread thread;
Result res;

if (R_FAILED( res = threadCreate(&thread, func, (void *) request, 0x2000, 0x2B, -2)))
return res;
if (R_FAILED( res = threadStart(&thread)))
return res;

request->thread = thread;
_threads.push_back(thread);

return 0;
}

void NetManager::_request(void * ptr) {
NetRequest * request = (NetRequest *) ptr;
CURL * curl;
CURLcode res;
string userAgent = string("kosmos-updater/") + VERSION;

curl = curl_easy_init();

if (curl) {
string url = request->getURL();

struct curl_slist * headers = NULL;
headers = curl_slist_append(headers, "Cache-Control: no-cache");

curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, request->getMethod().c_str());
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION , _headerFunction);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *) request);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _writeFunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) request);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, _progressFunction);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, (void *) request);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str());

if (_shouldUseProxy && _proxyURL.size() > 0) {
curl_easy_setopt(curl, CURLOPT_PROXY, _proxyURL.c_str());

if (_proxyUsername.size() > 0)
curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, _proxyUsername.c_str());
if (_proxyPassword.size() > 0)
curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, _proxyPassword.c_str());
}

res = curl_easy_perform(curl);
if (res != CURLE_OK) {
mutexLock(&request->mutexRequest);

request->hasError = true;
request->errorMessage = string(curl_easy_strerror(res));

mutexUnlock(&request->mutexRequest);

curl_easy_cleanup(curl);
curl_slist_free_all(headers);
return;
}

long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code != 200) {
mutexLock(&request->mutexRequest);

request->hasError = true;
request->errorMessage = "There was an error on the server, please try again later.";

mutexUnlock(&request->mutexRequest);

curl_easy_cleanup(curl);
curl_slist_free_all(headers);
return;
}

curl_easy_cleanup(curl);
curl_slist_free_all(headers);
}

mutexLock(&request->mutexRequest);

request->isComplete = true;

mutexUnlock(&request->mutexRequest);
}

int NetManager::_progressFunction(void *ptr, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
NetRequest * request = (NetRequest *) ptr;
mutexLock(&request->mutexRequest);

request->progress = (double) dlnow / (double) dltotal;

mutexUnlock(&request->mutexRequest);
return 0;
}

size_t NetManager::_writeFunction(void *contents, size_t size, size_t nmemb, void * ptr) {
NetRequest * request = (NetRequest *) ptr;
return request->appendData(contents, size, nmemb);
}

size_t NetManager::_headerFunction(void *contents, size_t size, size_t nmemb, void * ptr) {
NetRequest * request = (NetRequest *) ptr;
return request->appendHeaderData(contents, size, nmemb);
}
}

+ 52
- 0
source/NetManager.hpp View File

@@ -0,0 +1,52 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#pragma once

#include <curl/curl.h>
#include <string>
#include <switch.h>
#include <vector>

#include "models/NetRequest.hpp"

namespace ku {
class NetManager {
public:
static void initialize();
static void dealloc();

static models::NetRequest * getLatestAppVersion();
static models::NetRequest * getLatestApp();
static models::NetRequest * getLatestKosmosVersion();
static models::NetRequest * getLatestKosmos();

private:
static inline bool _shouldUseProxy;
static inline std::string _proxyURL;
static inline std::string _proxyUsername;
static inline std::string _proxyPassword;
static inline std::string _hostname;
static inline std::vector<Thread> _threads;
static Result _createThread(ThreadFunc func, models::NetRequest * ptr);
static void _request(void * ptr);
static int _progressFunction(void *ptr, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
static size_t _writeFunction(void *contents, size_t size, size_t nmemb, void * ptr);
static size_t _headerFunction(void *contents, size_t size, size_t nmemb, void * ptr);
};
}

+ 65
- 0
source/Scene.cpp View File

@@ -0,0 +1,65 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#include "Scene.hpp"

namespace ku {
Scene::Scene() {
_touchedView = NULL;
}

void Scene::render(SDL_Rect rect, double dTime) {
for (auto const& view : subviews) {
if (!view->hidden) {
SDL_Rect subviewFrame = view->frame;
view->render({ rect.x + subviewFrame.x, rect.y + subviewFrame.y, subviewFrame.w, subviewFrame.h }, dTime);
}
}
}

void Scene::touchStarted() {
for (auto const& view : subviews) {
// TODO: Check if touch is within the view
if (view->isTouchable) {
_touchedView = view;
_touchedView->touchStarted();
}
}
}

void Scene::touchMoved() {
if (_touchedView != NULL) {
_touchedView->touchMoved();
}
}

void Scene::touchEnded() {
if (_touchedView != NULL) {
_touchedView->touchEnded();
}
}

void Scene::addSubView(View * view) {
view->superview = NULL;
subviews.push_back(view);
}

void Scene::removeSubView(View * view) {
view->superview = NULL;
subviews.remove(view);
}
}

src/Scene.hpp → source/Scene.hpp View File

@@ -17,31 +17,32 @@

#pragma once

#include <list>
#include <SDL2/SDL.h>
#include <switch.h>
#include <list>
#include "View.hpp"

using namespace std;

class Scene {
public:
Scene();
virtual ~Scene();

virtual void handleButton(u32 buttons, double dTime);
virtual void render(SDL_Rect rect, double dTime);

/* Touch Controls */
void touchStarted();
void touchMoved();
void touchEnded();

/* View Hierarchy */
list<View *> subviews;
void addSubView(View * view);
void removeSubView(View * view);
#include "View.hpp"

private:
View * _touchedView;
};
namespace ku {
class Scene {
public:
Scene();
virtual ~Scene(){};

virtual void handleButton(u32 buttons, double dTime){};
virtual void render(SDL_Rect rect, double dTime);

/* Touch Controls */
void touchStarted();
void touchMoved();
void touchEnded();

/* View Hierarchy */
std::list<View *> subviews;
void addSubView(View * view);
void removeSubView(View * view);

private:
View * _touchedView;
};
}

+ 191
- 0
source/SceneDirector.cpp View File

@@ -0,0 +1,191 @@
// Kosmos Updater
// Copyright (C) 2019 Steven Mattera
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#include <switch.h>

#include "AssetManager.hpp"
#include "ConfigManager.hpp"
#include "SceneDirector.hpp"

using namespace ku::scenes;

namespace ku {
SceneDirector::SceneDirector() {
romfsInit();
setsysInitialize();
plInitialize();

SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_AUDIO);

if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG))
return;

SceneDirector::window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_FULLSCREEN);
if (!SceneDirector::window)
return;

SceneDirector::renderer = SDL_CreateRenderer(SceneDirector::window, 0, SDL_RENDERER_SOFTWARE);
if (!SceneDirector::renderer)
return;

TTF_Init();

_now = SDL_GetPerformanceCounter();
_last = 0;
_exFatWarningScene = NULL;
_appUpdateScene = NULL;
_packageSelectScene = NULL;
_packageDownloadScene = NULL;
_currentScene = NULL;

if (!ConfigManager::getReceivedExFATWarning()) {
currentScene = SCENE_EXFAT_WARNING;
}
else if (!ConfigManager::shouldAutoUpdate()) {
currentScene = SCENE_PACKAGE_SELECT;
}
}

SceneDirector::~SceneDirector() {
if (_exFatWarningScene != NULL)
delete _exFatWarningScene;

if (_appUpdateScene != NULL)
delete _appUpdateScene;

if (_packageSelectScene != NULL)
delete _packageSelectScene;

if (_packageDownloadScene != NULL)
delete _packageDownloadScene;

TTF_Quit();

if (SceneDirector::renderer != NULL)
SDL_DestroyRenderer(SceneDirector::renderer);

if (SceneDirector::window != NULL)
SDL_DestroyWindow(SceneDirector::window);

IMG_Quit();
SDL_Quit();

plExit();
setsysExit();
romfsExit();
}

bool SceneDirector::direct() {
_last = _now;
_now = SDL_GetPerformanceCounter();
double dTime = (double) ((_now - _last) * 1000 / SDL_GetPerformanceFrequency());

hidScanInput();
u32 kDown = hidKeysDown(CONTROLLER_P1_AUTO);

// TODO: Handle touch controls

AssetManager::setRenderColor(AssetManager::background);
SDL_RenderClear(SceneDirector::renderer);

// Unload previous scenes
switch(SceneDirector::currentScene) {
case SCENE_APP_UPDATE:
if (_exFatWarningScene != NULL) {
delete _exFatWarningScene;
_exFatWarningScene = NULL;
}
break;

case SCENE_PACKAGE_SELECT:
if (_appUpdateScene != NULL) {
delete _appUpdateScene;
_appUpdateScene = NULL;
}
break;

case SCENE_PACKAGE_DOWNLOAD:
if (_appUpdateScene != NULL) {
delete _appUpdateScene;
_appUpdateScene = NULL;
}

if (_packageSelectScene != NULL) {
delete _packageSelectScene;
_packageSelectScene = NULL;
}
break;

default:
/* Do Nothing */
break;
}

// Load new scenes
switch(SceneDirector::currentScene) {
case SCENE_EXFAT_WARNING:
if (_exFatWarningScene == NULL)
_exFatWarningScene = new ExFatWarningScene();

_currentScene = _exFatWarningScene;
break;

case SCENE_APP_UPDATE:
if (_appUpdateScene == NULL)
_appUpdateScene = new AppUpdateScene();
_currentScene = _appUpdateScene;
break;

case SCENE_PACKAGE_SELECT:
if (_packageSelectScene == NULL)
_packageSelectScene = new PackageSelectScene();
_currentScene = _packageSelectScene;
break;

case SCENE_PACKAGE_DOWNLOAD:
if (_packageDownloadScene == NULL)
_packageDownloadScene = new PackageDownloadScene();
_currentScene = _packageDownloadScene;
break;
}

if (modal != NULL) {
modal->handleButton(kDown, dTime);
} else {
_currentScene->handleButton(kDown, dTime);
}

_currentScene->render({ 0, 0, 1280, 720 }, dTime);

if (modal != NULL) {
// Draw Faded background.
AssetManager::setRenderColor(AssetManager::modal_faded_background);
SDL_Rect fadedBGFrame = { 0, 0, 1280, 720 };
SDL_SetRenderDrawBlendMode(SceneDirector::renderer, SDL_BLENDMODE_BLEND);
SDL_RenderFillRect(SceneDirector::renderer, &fadedBGFrame);

modal->render({ 0, 0, 1280, 720 }, dTime);
}

SDL_RenderPresent(SceneDirector::renderer);

return !SceneDirector::exitApp;
}
}

src/SceneDirector.hpp → source/SceneDirector.hpp View File

@@ -18,44 +18,43 @@
#pragma once

#include <SDL2/SDL.h>
#include "AssetManager.hpp"
#include "Scene.hpp"
#include "ModalView.hpp"

#include "scenes/ExFatWarningScene.hpp"
#include "ModalView.hpp"
#include "Scene.hpp"
#include "scenes/AppUpdateScene.hpp"
#include "scenes/PackageSelectScene.hpp"
#include "scenes/ExFatWarningScene.hpp"
#include "scenes/PackageDownloadScene.hpp"
#include "scenes/PackageSelectScene.hpp"

typedef enum {
SCENE_EXFAT_WARNING,
SCENE_APP_UPDATE,
SCENE_PACKAGE_SELECT,
SCENE_PACKAGE_DOWNLOAD
} Scenes;
using namespace std;
class SceneDirector {
public:
static inline SDL_Window * window = NULL;
static inline SDL_Renderer * renderer = NULL;
static inline ModalView * modal = NULL;
static inline Scenes currentScene = SCENE_APP_UPDATE;
static inline bool exitApp = false;
SceneDirector();
~SceneDirector();
bool direct();
private:
Uint64 _now;
Uint64 _last;
Scene * _currentScene;
ExFatWarningScene * _exFatWarningScene;
AppUpdateScene * _appUpdateScene;
PackageSelectScene * _packageSelectScene;
PackageDownloadScene * _packageDownloadScene;
};
namespace ku {
typedef enum {
SCENE_EXFAT_WARNING,
SCENE_APP_UPDATE,
SCENE_PACKAGE_SELECT,
SCENE_PACKAGE_DOWNLOAD
} Scenes;
class SceneDirector {
public:
static inline SDL_Window * window = NULL;
static inline SDL_Renderer * renderer = NULL;
static inline ModalView * modal = NULL;
static inline Scenes currentScene = SCENE_APP_UPDATE;
static inline bool exitApp = false;
SceneDirector();
~SceneDirector();
bool direct();
private:
Uint64 _now;
Uint64 _last;
Scene * _currentScene;
scenes::ExFatWarningScene * _exFatWarningScene;
AppUpdateScene * _appUpdateScene;
scenes::PackageSelectScene * _packageSelectScene;
PackageDownloadScene * _packageDownloadScene;
};
}

src/View.cpp → source/View.cpp View File

@@ -17,35 +17,33 @@

#include "View.hpp"

View::View() {
frame = { 0, 0, 0, 0 };
hidden = false;
hasFocus = false;
}
namespace ku {
View::View() {
frame = { 0, 0, 0, 0 };
hidden = false;
hasFocus = false;
}

View::~View() {
subviews.clear();
}
View::~View() {
subviews.clear();
}

void View::render(SDL_Rect rect, double dTime) {
for (auto const& view : subviews) {
if (!view->hidden) {
SDL_Rect subviewFrame = view->frame;
view->render({ rect.x + subviewFrame.x, rect.y + subviewFrame.y, subviewFrame.w, subviewFrame.h }, dTime);
void View::render(SDL_Rect rect, double dTime) {
for (auto const& view : subviews) {
if (!view->hidden) {
SDL_Rect subviewFrame = view->frame;
view->render({ rect.x + subviewFrame.x, rect.y + subviewFrame.y, subviewFrame.w, subviewFrame.h }, dTime);
}
}
}
}

void View::touchStarted() {}
void View::touchMoved() {}
void View::touchEnded() {}

void View::addSubView(View * view) {
view->superview = view;
subviews.push_back(view);
}
void View::addSubView(View * view) {
view->superview = view;
subviews.push_back(view);
}

void View::removeSubView(View * view) {
view->superview = NULL;
subviews.remove(view);
void View::removeSubView(View * view) {
view->superview = NULL;
subviews.remove(view);
}
}

src/View.hpp → source/View.hpp View File

@@ -20,31 +20,31 @@
#include <list>
#include <SDL2/SDL.h>

using namespace std;
class View {
public:
SDL_Rect frame;
bool hidden;
View();
virtual ~View();
virtual void render(SDL_Rect rect, double dTime);
/* Controller Input */
bool isFocusable;
bool hasFocus;
/* Touch Controls */
bool isTouchable;
virtual void touchStarted();
virtual void touchMoved();
virtual void touchEnded();
/* View Hierarchy */
View * superview;
list<View *> subviews;
void addSubView(View * view);
void removeSubView(View * view);
};
namespace ku {
class View {
public:
SDL_Rect frame;
bool hidden;
View();
virtual ~View();
virtual void render(SDL_Rect rect, double dTime);
/* Controller Input */
bool isFocusable;
bool hasFocus;
/* Touch Controls */
bool isTouchable;
virtual void touchStarted(){};
virtual void touchMoved(){};
virtual void touchEnded(){};
/* View Hierarchy */
View * superview;
std::list<View *> subviews;
void addSubView(View * view);
void removeSubView(View * view);
};
}

src/main.cpp → source/main.cpp View File

@@ -19,12 +19,13 @@
#include <SDL2/SDL_image.h>
#include <switch.h>

#include "SceneDirector.hpp"
#include "NetManager.hpp"
#include "AssetManager.hpp"
#include "ConfigManager.hpp"
#include "NetManager.hpp"
#include "SceneDirector.hpp"

using namespace std;
using namespace ku;

int main(int argc, char **argv)
{

src/models/Action.cpp → source/models/Action.cpp View File

@@ -17,17 +17,21 @@