mirror of
https://github.com/BernardoGiordano/Checkpoint
synced 2025-02-26 03:37:10 +00:00
push source code for Switch version
This commit is contained in:
parent
6b154ca5ae
commit
20c4bbffbb
44 changed files with 4678 additions and 13 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,2 +1,4 @@
|
|||
3ds/build/
|
||||
3ds/out/
|
||||
3ds/out/
|
||||
switch/build/
|
||||
switch/out/
|
45
README.md
45
README.md
|
@ -1,47 +1,68 @@
|
|||
# Checkpoint
|
||||
|
||||
A fast and simple save manager for cfw/rosalina-based Homebrew Launchers written in C++.
|
||||
|
||||

|
||||
A fast and simple homebrew save manager for 3DS and Switch written in C++.
|
||||
|
||||
## Why use Checkpoint?
|
||||
|
||||
Checkpoint is created with the ideas of simplicity and efficiency. The UI has been designed to condense as many options as possible, while keeping it simple to work with.
|
||||
Checkpoint is created following ideas of simplicity and efficiency. The UI has been designed to condense as many options as possible, while keeping it simple to work with.
|
||||
|
||||
Moreover, Checkpoint is extremely lightweight and is built using very few (and up-to-date) libraries. It contains minimal assets, while being packaged with a nice graphic user interface.
|
||||
Moreover, Checkpoint is extremely lightweight - while being packaged with a nice graphic user interface - and is built using the most recent libraries available.
|
||||
|
||||
Checkpoint supports DS cartridges, normal titles, and demos. It also automatically checks and filters homebrew titles which may not have a save archive to backup or restore, which is done without an external title list and filters. For this reason, Checkpoint doesn't need constant user maintenance to retain full functionality.
|
||||
Checkpoint for 3DS natively supports 3DS and DS cartridges, digital standard titles and demo titles. It also automatically checks and filters homebrew titles which may not have a save archive to backup or restore, which is done without an external title list and filters. For this reason, Checkpoint doesn't need constant user maintenance to retain full functionality.
|
||||
|
||||
Checkpoint for Switch natively supports NAND saves for the titles you have played. Title informations are loaded automatically.
|
||||
|
||||
## Working path
|
||||
|
||||
Checkpoint uses the following folders to store the files it generates. Note that all the working directories are automatically generated on first launch (or when Checkpoint finds a new title that doesn't have a working directory yet).
|
||||
Checkpoint relies on the following folders to store the files it generates. Note that all the working directories are automatically generated on first launch (or when Checkpoint finds a new title that doesn't have a working directory yet).
|
||||
|
||||
### 3DS
|
||||
|
||||
* **`sdmc:/3ds/Checkpoint`**: root path
|
||||
* **`sdmc:/3ds/Checkpoint/saves/<unique id> <game title>`**: root path for all the save backups for a generic game
|
||||
* **`sdmc:/3ds/Checkpoint/extdata/<unique id> <game title>`**: root path for all the extdata backups for a generic game
|
||||
|
||||
### Switch
|
||||
|
||||
* **`sdmc:/switch/Checkpoint`**: root path
|
||||
* **`sdmc:/switch/Checkpoint/saves/<title id> <game title>`**: root path for all the save backups for a generic game
|
||||
|
||||
## Usage
|
||||
|
||||
You can use Checkpoint with both cfw and Rosalina-based Homebrew Launcher. *hax-based Homebrew Launchers are not supported by Checkpoint.
|
||||
You can use Checkpoint for 3DS with both cfw and Rosalina-based Homebrew Launchers. *hax-based Homebrew Launchers are not supported by Checkpoint. Checkpoint for Switch only runs on homebrew launcher and firmware 3.0.0 is required.
|
||||
|
||||
The first launch will take considerably longer than usual (usually 1-2 minutes depending on how many titles you have installed), due to the working directories being created - Checkpoint will be significatively faster upon launch from then on.
|
||||
|
||||
You can scroll between the title list with the DPAD/LR and target a title with A when the selector is on it. Now, you can use the DPAD or the touchscreen to select a target backup to restore/overwrite.
|
||||
|
||||
## Issues
|
||||
## Troubleshooting
|
||||
|
||||
Checkpoint displays error codes when something weird happens or operations fail. If you have any issues, please ensure they haven't already been addressed, and report the error code and a summary of your operations to reproduce it.
|
||||
|
||||
Additionally, you can receive real-time support by joining PKSM's discord server.
|
||||
|
||||
[](https://discord.gg/bGKEyfY)
|
||||
|
||||
## Building
|
||||
|
||||
Checkpoint uses [latest libctru](https://github.com/smealum/ctrulib), [latest citro3d](https://github.com/fincs/citro3d) and [latest pp2d](https://github.com/BernardoGiordano/Checkpoint/tree/master/source/pp2d).
|
||||
Checkpoint for 3DS relies on [latest libctru](https://github.com/smealum/ctrulib) and [latest citro3d](https://github.com/fincs/citro3d).
|
||||
|
||||
Checkpoint for Switch relies on [latest libnx](https://github.com/switchbrew/libnx).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the GNU GPLv3. See [LICENSE.md](https://github.com/BernardoGiordano/Checkpoint/blob/master/LICENSE) for details.
|
||||
This project is licensed under the GNU GPLv3. Additional Terms 7.b and 7.c of GPLv3 apply to this. See [LICENSE.md](https://github.com/BernardoGiordano/Checkpoint/blob/master/LICENSE) for details.
|
||||
|
||||
## Credits
|
||||
|
||||
Even though this is the result of independent research and work, this couldn't be possible without J-D-K's [JKSM](https://github.com/J-D-K/JKSM), which is an incredible piece of software that you should all be using. Best regards JK, hope you're fine.
|
||||
Even though this is the result of independent research and work, Checkpoint for 3DS couldn't be possible without J-D-K's [JKSM](https://gbatemp.net/threads/release-jks-savemanager-homebrew-cia-save-manager.413143/), which is an incredible piece of software that you should all be using. Best regards JK, hope you're fine.
|
||||
|
||||
TuxSH for [TWLSaveTool](https://github.com/TuxSH/TWLSaveTool), from which SPI code has been taken.
|
||||
|
||||
All the maintainers for [nx-hbmenu](https://github.com/switchbrew/nx-hbmenu), for all the Switch rendering functions.
|
||||
|
||||
Yellows8 and all the mantainers for [switch-examples](https://github.com/switchbrew/switch-examples).
|
||||
|
||||
Hikari-chin and all the other testers for their help with testing.
|
||||
|
||||
If you like my work, **support me on [Patreon](https://www.patreon.com/bernardogiordano)**!
|
||||
|
|
211
switch/Makefile
Normal file
211
switch/Makefile
Normal file
|
@ -0,0 +1,211 @@
|
|||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
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.
|
||||
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.jpg
|
||||
# - icon.jpg
|
||||
# - <libnx folder>/default_icon.jpg
|
||||
#---------------------------------------------------------------------------------
|
||||
VERSION_MAJOR := 3
|
||||
VERSION_MINOR := 1
|
||||
VERSION_MICRO := 0
|
||||
|
||||
APP_TITLE := Checkpoint
|
||||
APP_AUTHOR := Bernardo Giordano
|
||||
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}
|
||||
|
||||
TARGET := $(subst $e ,_,$(notdir $(APP_TITLE)))
|
||||
OUTDIR := out
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
EXEFS_SRC := exefs_src
|
||||
#ROMFS := romfs
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O3 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES) \
|
||||
-DVERSION_MAJOR=${VERSION_MAJOR} \
|
||||
-DVERSION_MINOR=${VERSION_MINOR} \
|
||||
-DVERSION_MICRO=${VERSION_MICRO}
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-no-as-needed,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lnx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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)/$(OUTDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
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
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
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,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.jpg)
|
||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||
else
|
||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
export NROFLAGS += --nacp=$(CURDIR)/$(OUTDIR)/$(TARGET).nacp
|
||||
endif
|
||||
|
||||
ifneq ($(APP_TITLEID),)
|
||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@ $(BUILD) $(OUTDIR)
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(OUTDIR)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).pfs0 $(OUTPUT).nro
|
||||
|
||||
$(OUTPUT).pfs0 : $(OUTPUT).nso
|
||||
|
||||
$(OUTPUT).nso : $(OUTPUT).elf
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||
else
|
||||
$(OUTPUT).nro : $(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
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.nxfnt.o : %.nxfnt
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
BIN
switch/data/checkbox_grey.bin
Normal file
BIN
switch/data/checkbox_grey.bin
Normal file
Binary file not shown.
BIN
switch/data/checkbox_white.bin
Normal file
BIN
switch/data/checkbox_white.bin
Normal file
Binary file not shown.
BIN
switch/data/flag.bin
Normal file
BIN
switch/data/flag.bin
Normal file
Binary file not shown.
BIN
switch/data/interuiregular14.nxfnt
Normal file
BIN
switch/data/interuiregular14.nxfnt
Normal file
Binary file not shown.
BIN
switch/data/interuiregular20.nxfnt
Normal file
BIN
switch/data/interuiregular20.nxfnt
Normal file
Binary file not shown.
BIN
switch/data/tahoma24.nxfnt
Normal file
BIN
switch/data/tahoma24.nxfnt
Normal file
Binary file not shown.
BIN
switch/icon.jpg
Normal file
BIN
switch/icon.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
43
switch/include/account.hpp
Normal file
43
switch/include/account.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNT_HPP
|
||||
#define ACCOUNT_HPP
|
||||
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Account
|
||||
{
|
||||
Result init(void);
|
||||
void exit(void);
|
||||
|
||||
std::string username(u128 id);
|
||||
}
|
||||
|
||||
#endif
|
61
switch/include/clickable.hpp
Normal file
61
switch/include/clickable.hpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 CLICKABLE_HPP
|
||||
#define CLICKABLE_HPP
|
||||
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
#include "draw.hpp"
|
||||
|
||||
class Clickable
|
||||
{
|
||||
public:
|
||||
Clickable(u32 x, u32 y, u16 w, u16 h, color_t colorBg, color_t colorText, const std::string& message, bool centered);
|
||||
~Clickable(void) { };
|
||||
|
||||
void draw(void);
|
||||
void draw(const ffnt_header_t* font, u32 messageHeight);
|
||||
bool held(void);
|
||||
void invertColors(void);
|
||||
bool released(void);
|
||||
void setColors(color_t bg, color_t text);
|
||||
std::string text(void);
|
||||
void text(const std::string& v);
|
||||
|
||||
private:
|
||||
u32 mx;
|
||||
u32 my;
|
||||
u16 mw;
|
||||
u16 mh;
|
||||
color_t mColorBg;
|
||||
color_t mColorText;
|
||||
std::string mText;
|
||||
bool mCentered;
|
||||
bool mOldPressed;
|
||||
};
|
||||
|
||||
#endif
|
60
switch/include/directory.hpp
Normal file
60
switch/include/directory.hpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef DIRECTORY_HPP
|
||||
#define DIRECTORY_HPP
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
struct DirectoryEntry {
|
||||
std::string name;
|
||||
bool directory;
|
||||
};
|
||||
|
||||
class Directory
|
||||
{
|
||||
public:
|
||||
Directory(const std::string& root);
|
||||
~Directory(void) { };
|
||||
|
||||
Result error(void);
|
||||
std::string entry(size_t index);
|
||||
bool folder(size_t index);
|
||||
bool good(void);
|
||||
size_t size(void);
|
||||
|
||||
private:
|
||||
std::vector
|
||||
<struct DirectoryEntry> mList;
|
||||
Result mError;
|
||||
bool mGood;
|
||||
};
|
||||
|
||||
#endif
|
80
switch/include/draw.hpp
Normal file
80
switch/include/draw.hpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2017-2018 nx-hbmenu Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
* with or without fee is hereby granted, provided that the above copyright notice
|
||||
* and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
|
||||
* OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DRAW_HPP
|
||||
#define DRAW_HPP
|
||||
|
||||
#include <switch.h>
|
||||
#include "types.hpp"
|
||||
|
||||
extern const ffnt_header_t tahoma24_nxfnt;
|
||||
extern const ffnt_header_t interuiregular20_nxfnt;
|
||||
extern const ffnt_header_t interuiregular14_nxfnt;
|
||||
#define font24 &tahoma24_nxfnt
|
||||
#define font20 &interuiregular20_nxfnt
|
||||
#define font14 &interuiregular14_nxfnt
|
||||
|
||||
extern u8* framebuf;
|
||||
extern u32 framebuf_width;
|
||||
|
||||
// the following code is from nx-hbmenu
|
||||
// https://github.com/switchbrew/nx-hbmenu/blob/master/common/common.h#L63
|
||||
|
||||
static inline u8 BlendColor(u32 src, u32 dst, u8 alpha)
|
||||
{
|
||||
u8 one_minus_alpha = (u8)255 - alpha;
|
||||
return (dst*alpha + src*one_minus_alpha)/(u8)255;
|
||||
}
|
||||
|
||||
static inline color_t MakeColor(u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
color_t clr;
|
||||
clr.r = r;
|
||||
clr.g = g;
|
||||
clr.b = b;
|
||||
clr.a = a;
|
||||
return clr;
|
||||
}
|
||||
|
||||
static inline void DrawPixel(u32 x, u32 y, color_t clr)
|
||||
{
|
||||
if (x >= 1280 || y >= 720)
|
||||
return;
|
||||
u32 off = (y * framebuf_width + x)*4;
|
||||
framebuf[off] = BlendColor(framebuf[off], clr.r, clr.a); off++;
|
||||
framebuf[off] = BlendColor(framebuf[off], clr.g, clr.a); off++;
|
||||
framebuf[off] = BlendColor(framebuf[off], clr.b, clr.a); off++;
|
||||
framebuf[off] = 0xff;
|
||||
}
|
||||
|
||||
static inline void Draw4PixelsRaw(u32 x, u32 y, color_t clr)
|
||||
{
|
||||
if (x >= 1280 || y >= 720 || x > 1280-4)
|
||||
return;
|
||||
|
||||
u32 color = clr.r | (clr.g<<8) | (clr.b<<16) | (0xff<<24);
|
||||
u128 val = color | ((u128)color<<32) | ((u128)color<<64) | ((u128)color<<96);
|
||||
u32 off = (y * framebuf_width + x)*4;
|
||||
*((u128*)&framebuf[off]) = val;
|
||||
}
|
||||
|
||||
void rectangle(u32 x, u32 y, u32 w, u32 h, color_t color);
|
||||
void DrawPixel(u32 x, u32 y, color_t clr);
|
||||
void DrawText(const ffnt_header_t* font, u32 x, u32 y, color_t clr, const char* text);
|
||||
void DrawTextTruncate(const ffnt_header_t* font, u32 x, u32 y, color_t clr, const char* text, u32 max_width, const char* end_text);
|
||||
void GetTextDimensions(const ffnt_header_t* font, const char* text, u32* width_out, u32* height_out);
|
||||
void DrawImage(int x, int y, int width, int height, const u8 *image, ImageMode mode);
|
||||
|
||||
#endif
|
40
switch/include/filesystem.hpp
Normal file
40
switch/include/filesystem.hpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef FILESYSTEM_HPP
|
||||
#define FILESYSTEM_HPP
|
||||
|
||||
#include <switch.h>
|
||||
#include "gui.hpp"
|
||||
|
||||
namespace FileSystem
|
||||
{
|
||||
Result mount(FsFileSystem* fileSystem, u64 titleID, u128 userID);
|
||||
int mount(FsFileSystem fs);
|
||||
void unmount(void);
|
||||
}
|
||||
|
||||
#endif
|
89
switch/include/gui.hpp
Normal file
89
switch/include/gui.hpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 <math.h>
|
||||
#include <switch.h>
|
||||
#include <string.h>
|
||||
#include "account.hpp"
|
||||
#include "clickable.hpp"
|
||||
#include "draw.hpp"
|
||||
#include "info.hpp"
|
||||
#include "hid.hpp"
|
||||
#include "messagebox.hpp"
|
||||
#include "scrollable.hpp"
|
||||
#include "title.hpp"
|
||||
#include "types.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include "checkbox_grey_bin.h"
|
||||
#include "checkbox_white_bin.h"
|
||||
#include "flag_bin.h"
|
||||
|
||||
#define COLOR_WHITE MakeColor(255, 255, 255, 255)
|
||||
#define COLOR_BLACK MakeColor(0, 0, 0, 255)
|
||||
#define COLOR_BLUE MakeColor(0, 0, 255, 255)
|
||||
#define COLOR_GREEN MakeColor(0, 255, 201, 255)
|
||||
|
||||
#define COLOR_GREY_DARKER MakeColor(70, 70, 70, 255)
|
||||
#define COLOR_GREY_DARK MakeColor(79, 79, 79, 255)
|
||||
#define COLOR_GREY_MEDIUM MakeColor(94, 94, 94, 255)
|
||||
#define COLOR_GREY_LIGHT MakeColor(138, 138, 138, 255)
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
void init(void);
|
||||
void exit(void);
|
||||
void draw(void);
|
||||
|
||||
void createInfo(const std::string& title, const std::string& message);
|
||||
void createError(Result res, const std::string& message);
|
||||
|
||||
bool backupScroll(void);
|
||||
void backupScroll(bool enable);
|
||||
size_t count(entryType_t type);
|
||||
size_t index(entryType_t type);
|
||||
void index(entryType_t type, size_t i);
|
||||
bool isBackupReleased(void);
|
||||
bool isRestoreReleased(void);
|
||||
std::string nameFromCell(entryType_t type, size_t index);
|
||||
void resetIndex(entryType_t type);
|
||||
void updateButtonsColor(void);
|
||||
void updateSelector(void);
|
||||
|
||||
bool askForConfirmation(const std::string& text);
|
||||
void drawCopy(const std::string& src, u64 offset, u64 size);
|
||||
|
||||
void addSelectedEntry(size_t idx);
|
||||
void clearSelectedEntries(void);
|
||||
bool multipleSelectionEnabled(void);
|
||||
std::vector
|
||||
<size_t> selectedEntries(void);
|
||||
}
|
||||
|
||||
#endif
|
51
switch/include/hbkbd.hpp
Normal file
51
switch/include/hbkbd.hpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 HBKBD_HPP
|
||||
#define HBKBD_HPP
|
||||
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
#include "clickable.hpp"
|
||||
#include "draw.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#define CUSTOM_PATH_LEN 49
|
||||
|
||||
extern u8* framebuf;
|
||||
extern u32 framebuf_width;
|
||||
|
||||
namespace hbkbd
|
||||
{
|
||||
void init(void);
|
||||
void exit(void);
|
||||
|
||||
std::string keyboard(const std::string& suggestion);
|
||||
}
|
||||
|
||||
#endif
|
40
switch/include/hid.hpp
Normal file
40
switch/include/hid.hpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 HID_HPP
|
||||
#define HID_HPP
|
||||
|
||||
#include "gui.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace hid
|
||||
{
|
||||
entryType_t entryType(void);
|
||||
void entryType(entryType_t type_);
|
||||
void index(size_t ¤tEntry, int &page, size_t maxpages, size_t maxentries, const size_t entries, const size_t columns);
|
||||
}
|
||||
|
||||
#endif
|
62
switch/include/info.hpp
Normal file
62
switch/include/info.hpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 INFO_HPP
|
||||
#define INFO_HPP
|
||||
|
||||
#include <switch.h>
|
||||
#include <string>
|
||||
#include "draw.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
typedef enum {
|
||||
TYPE_INFO,
|
||||
TYPE_ERROR
|
||||
} Info_t;
|
||||
|
||||
class Info
|
||||
{
|
||||
public:
|
||||
Info(void);
|
||||
~Info(void) { };
|
||||
|
||||
void draw(void);
|
||||
void init(std::string title, std::string message, int ttl, Info_t type);
|
||||
void init(Result res, std::string message, int ttl, Info_t type);
|
||||
|
||||
private:
|
||||
size_t mw;
|
||||
size_t mh;
|
||||
u32 mx;
|
||||
u32 my;
|
||||
int mTTL;
|
||||
Result mRes;
|
||||
Info_t mType;
|
||||
std::string mTitle;
|
||||
std::string mMessage;
|
||||
};
|
||||
|
||||
#endif
|
54
switch/include/io.hpp
Normal file
54
switch/include/io.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef IO_HPP
|
||||
#define IO_HPP
|
||||
|
||||
#include <cstdio>
|
||||
#include <dirent.h>
|
||||
#include <switch.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include "directory.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "hbkbd.hpp"
|
||||
|
||||
#define BUFFER_SIZE 0x50000
|
||||
|
||||
namespace io
|
||||
{
|
||||
void backup(size_t index);
|
||||
void restore(size_t index);
|
||||
|
||||
Result copyDirectory(const std::string& srcPath, const std::string& dstPath);
|
||||
void copyFile(const std::string& srcPath, const std::string& dstPath);
|
||||
Result createDirectory(const std::string& path);
|
||||
int deleteFolderRecursively(const char* path);
|
||||
bool directoryExists(const std::string& path);
|
||||
bool fileExists(const std::string& path);
|
||||
}
|
||||
|
||||
#endif
|
53
switch/include/messagebox.hpp
Normal file
53
switch/include/messagebox.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 MESSAGEBOX_HPP
|
||||
#define MESSAGEBOX_HPP
|
||||
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
#include "draw.hpp"
|
||||
#include "gui.hpp"
|
||||
|
||||
class MessageBox
|
||||
{
|
||||
public:
|
||||
MessageBox(color_t colorbg, color_t colormessage);
|
||||
~MessageBox() { };
|
||||
|
||||
void push_message(const std::string& str);
|
||||
void clear(void);
|
||||
void draw(void);
|
||||
|
||||
private:
|
||||
std::vector
|
||||
<std::string> mList;
|
||||
color_t mColorBg;
|
||||
color_t mColorText;
|
||||
};
|
||||
|
||||
#endif
|
66
switch/include/nanojpeg.h
Normal file
66
switch/include/nanojpeg.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HEADER SECTION //
|
||||
// copy and paste this into nanojpeg.h if you want //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _NANOJPEG_H
|
||||
#define _NANOJPEG_H
|
||||
|
||||
// nj_result_t: Result codes for njDecode().
|
||||
typedef enum _nj_result {
|
||||
NJ_OK = 0, // no error, decoding successful
|
||||
NJ_NO_JPEG, // not a JPEG file
|
||||
NJ_UNSUPPORTED, // unsupported format
|
||||
NJ_OUT_OF_MEM, // out of memory
|
||||
NJ_INTERNAL_ERR, // internal error
|
||||
NJ_SYNTAX_ERROR, // syntax error
|
||||
__NJ_FINISHED, // used internally, will never be reported
|
||||
} nj_result_t;
|
||||
|
||||
// njInit: Initialize NanoJPEG.
|
||||
// For safety reasons, this should be called at least one time before using
|
||||
// using any of the other NanoJPEG functions.
|
||||
void njInit(void);
|
||||
|
||||
// njDecode: Decode a JPEG image.
|
||||
// Decodes a memory dump of a JPEG file into internal buffers.
|
||||
// Parameters:
|
||||
// jpeg = The pointer to the memory dump.
|
||||
// size = The size of the JPEG file.
|
||||
// Return value: The error code in case of failure, or NJ_OK (zero) on success.
|
||||
nj_result_t njDecode(const void* jpeg, const int size);
|
||||
|
||||
// njGetWidth: Return the width (in pixels) of the most recently decoded
|
||||
// image. If njDecode() failed, the result of njGetWidth() is undefined.
|
||||
int njGetWidth(void);
|
||||
|
||||
// njGetHeight: Return the height (in pixels) of the most recently decoded
|
||||
// image. If njDecode() failed, the result of njGetHeight() is undefined.
|
||||
int njGetHeight(void);
|
||||
|
||||
// njIsColor: Return 1 if the most recently decoded image is a color image
|
||||
// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result
|
||||
// of njGetWidth() is undefined.
|
||||
int njIsColor(void);
|
||||
|
||||
// njGetImage: Returns the decoded image data.
|
||||
// Returns a pointer to the most recently image. The memory layout it byte-
|
||||
// oriented, top-down, without any padding between lines. Pixels of color
|
||||
// images will be stored as three consecutive bytes for the red, green and
|
||||
// blue channels. This data format is thus compatible with the PGM or PPM
|
||||
// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.
|
||||
// If njDecode() failed, the result of njGetImage() is undefined.
|
||||
unsigned char* njGetImage(void);
|
||||
|
||||
// njGetImageSize: Returns the size (in bytes) of the image data returned
|
||||
// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is
|
||||
// undefined.
|
||||
int njGetImageSize(void);
|
||||
|
||||
// njDone: Uninitialize NanoJPEG.
|
||||
// Resets NanoJPEG's internal state and frees all memory that has been
|
||||
// allocated at run-time by NanoJPEG. It is still possible to decode another
|
||||
// image after a njDone() call.
|
||||
void njDone(void);
|
||||
|
||||
#endif//_NANOJPEG_H
|
67
switch/include/scrollable.hpp
Normal file
67
switch/include/scrollable.hpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 SCROLLABLE_HPP
|
||||
#define SCROLLABLE_HPP
|
||||
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
#include "clickable.hpp"
|
||||
#include "draw.hpp"
|
||||
#include "hid.hpp"
|
||||
|
||||
class Scrollable
|
||||
{
|
||||
public:
|
||||
Scrollable(u32 x, u32 y, u32 w, u32 h, size_t visibleEntries);
|
||||
~Scrollable(void);
|
||||
|
||||
std::string cellName(size_t i);
|
||||
void draw(void);
|
||||
void flush(void);
|
||||
size_t index(void);
|
||||
void index(size_t i);
|
||||
void invertCellColors(size_t index);
|
||||
size_t maxVisibleEntries(void);
|
||||
int page(void);
|
||||
void push_back(color_t color, color_t colorMessage, const std::string& message);
|
||||
void resetIndex(void);
|
||||
size_t size(void);
|
||||
void updateSelection(void);
|
||||
|
||||
private:
|
||||
u32 mx;
|
||||
u32 my;
|
||||
u32 mw;
|
||||
u32 mh;
|
||||
size_t mVisibleEntries;
|
||||
size_t mIndex;
|
||||
int mPage;
|
||||
std::vector
|
||||
<Clickable*> mCells;
|
||||
};
|
||||
|
||||
#endif
|
40
switch/include/thread.hpp
Normal file
40
switch/include/thread.hpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 THREAD_HPP
|
||||
#define THREAD_HPP
|
||||
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
#include "title.hpp"
|
||||
|
||||
namespace Threads
|
||||
{
|
||||
Result create(ThreadFunc entrypoint);
|
||||
void destroy(void);
|
||||
}
|
||||
|
||||
#endif
|
73
switch/include/title.hpp
Normal file
73
switch/include/title.hpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef TITLE_HPP
|
||||
#define TITLE_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "filesystem.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "nanojpeg.h"
|
||||
}
|
||||
|
||||
class Title
|
||||
{
|
||||
public:
|
||||
void init(u64 titleid, u128 userID, const std::string& name);
|
||||
|
||||
u8* icon(void);
|
||||
void icon(u8* data, size_t iconsize);
|
||||
u64 id(void);
|
||||
std::string name(void);
|
||||
std::string path(void);
|
||||
void refreshDirectories(void);
|
||||
std::vector
|
||||
<std::string> saves(void);
|
||||
u128 userId(void);
|
||||
|
||||
private:
|
||||
u64 mId;
|
||||
u128 mUserId;
|
||||
std::string mName;
|
||||
std::string mPath;
|
||||
u8* mIcon;
|
||||
std::vector
|
||||
<std::string> mSaves;
|
||||
};
|
||||
|
||||
void getTitle(Title &dst, size_t i);
|
||||
size_t getTitleCount(void);
|
||||
void loadTitles(void);
|
||||
void refreshDirectories(u64 id);
|
||||
|
||||
#endif
|
54
switch/include/types.hpp
Normal file
54
switch/include/types.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef TYPES_HPP
|
||||
#define TYPES_HPP
|
||||
|
||||
typedef enum {
|
||||
TITLES,
|
||||
CELLS
|
||||
} entryType_t;
|
||||
|
||||
typedef union {
|
||||
u32 abgr;
|
||||
struct {
|
||||
u8 r,g,b,a;
|
||||
};
|
||||
} color_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IMAGE_MODE_RGB24,
|
||||
IMAGE_MODE_RGBA32
|
||||
} ImageMode;
|
||||
|
||||
typedef struct {
|
||||
u8 magic[4]; // 'fFNT'
|
||||
int version; // 1
|
||||
u16 npages;
|
||||
u8 height;
|
||||
u8 baseline;
|
||||
} ffnt_header_t;
|
||||
|
||||
typedef struct {
|
||||
u32 size, offset;
|
||||
} ffnt_pageentry_t;
|
||||
|
||||
typedef struct {
|
||||
u32 pos[0x100];
|
||||
u8 widths[0x100];
|
||||
u8 heights[0x100];
|
||||
int8_t advances[0x100];
|
||||
int8_t posX[0x100];
|
||||
int8_t posY[0x100];
|
||||
} ffnt_pagehdr_t;
|
||||
|
||||
typedef struct {
|
||||
ffnt_pagehdr_t hdr;
|
||||
u8 data[];
|
||||
} ffnt_page_t;
|
||||
|
||||
typedef struct {
|
||||
u8 width, height;
|
||||
int8_t posX, posY, advance;
|
||||
const u8* data;
|
||||
} glyph_t;
|
||||
|
||||
#endif
|
61
switch/include/util.hpp
Normal file
61
switch/include/util.hpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_HPP
|
||||
#define UTIL_HPP
|
||||
|
||||
#include <switch.h>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include "account.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "hbkbd.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
void servicesExit(void);
|
||||
Result servicesInit(void);
|
||||
|
||||
namespace StringUtils
|
||||
{
|
||||
bool containsInvalidChar(const std::string& str);
|
||||
std::string format(const std::string fmt_str, ...);
|
||||
size_t lines(const std::string& str);
|
||||
std::string removeForbiddenCharacters(std::string src);
|
||||
std::string sizeString(double size);
|
||||
}
|
||||
|
||||
namespace DateTime
|
||||
{
|
||||
std::string dateTimeStr(void);
|
||||
std::string timeStr(void);
|
||||
}
|
||||
|
||||
#endif
|
72
switch/source/account.cpp
Normal file
72
switch/source/account.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "account.hpp"
|
||||
|
||||
static std::unordered_map<u128, std::string> mUsernames;
|
||||
|
||||
Result Account::init(void)
|
||||
{
|
||||
return accountInitialize();
|
||||
}
|
||||
|
||||
void Account::exit(void)
|
||||
{
|
||||
accountExit();
|
||||
}
|
||||
|
||||
std::string Account::username(u128 id)
|
||||
{
|
||||
std::unordered_map<u128, std::string>::const_iterator got = mUsernames.find(id);
|
||||
if (got == mUsernames.end())
|
||||
{
|
||||
// look for a user and add it to the map
|
||||
AccountProfile profile;
|
||||
AccountProfileBase profilebase;
|
||||
char username[0x21] = {0};
|
||||
memset(&profilebase, 0, sizeof(profilebase));
|
||||
|
||||
Result res = accountGetProfile(&profile, id);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
res = accountProfileGet(&profile, NULL, &profilebase);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
strncpy(username, profilebase.username, sizeof(profilebase.username));
|
||||
std::string user = std::string(username);
|
||||
mUsernames.insert({id, user});
|
||||
accountProfileClose(&profile);
|
||||
return user;
|
||||
}
|
||||
|
||||
return got->second;
|
||||
}
|
117
switch/source/clickable.cpp
Normal file
117
switch/source/clickable.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "clickable.hpp"
|
||||
|
||||
Clickable::Clickable(u32 x, u32 y, u16 w, u16 h, color_t colorBg, color_t colorText, const std::string& text, bool centered)
|
||||
{
|
||||
mx = x;
|
||||
my = y;
|
||||
mw = w;
|
||||
mh = h;
|
||||
mColorBg = colorBg;
|
||||
mColorText = colorText;
|
||||
mText = text;
|
||||
mCentered = centered;
|
||||
mOldPressed = false;
|
||||
}
|
||||
|
||||
std::string Clickable::text(void)
|
||||
{
|
||||
return mText;
|
||||
}
|
||||
|
||||
void Clickable::text(const std::string& v)
|
||||
{
|
||||
mText = v;
|
||||
}
|
||||
|
||||
bool Clickable::held()
|
||||
{
|
||||
touchPosition touch;
|
||||
hidTouchRead(&touch, 0);
|
||||
return ((hidKeysHeld(CONTROLLER_P1_AUTO) & KEY_TOUCH) && touch.px > mx && touch.px < mx+mw && touch.py > my && touch.py < my+mh);
|
||||
}
|
||||
|
||||
bool Clickable::released(void)
|
||||
{
|
||||
touchPosition touch;
|
||||
hidTouchRead(&touch, 0);
|
||||
const bool on = touch.px > mx && touch.px < mx+mw && touch.py > my && touch.py < my+mh;
|
||||
|
||||
if (on)
|
||||
{
|
||||
mOldPressed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mOldPressed && !(touch.px > 0 || touch.py > 0))
|
||||
{
|
||||
mOldPressed = false;
|
||||
return true;
|
||||
}
|
||||
mOldPressed = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Clickable::invertColors(void)
|
||||
{
|
||||
color_t tmp = mColorBg;
|
||||
mColorBg = mColorText;
|
||||
mColorText = tmp;
|
||||
}
|
||||
|
||||
void Clickable::setColors(color_t bg, color_t text)
|
||||
{
|
||||
mColorBg = bg;
|
||||
mColorText = text;
|
||||
}
|
||||
|
||||
void Clickable::draw(void)
|
||||
{
|
||||
static const u32 messageHeight = 44;
|
||||
u32 textw;
|
||||
GetTextDimensions(font24, mText.c_str(), &textw, NULL);
|
||||
const u32 messageWidth = mCentered ? textw : mw - 8;
|
||||
bool hld = held();
|
||||
const color_t bgColor = hld ? mColorText : mColorBg;
|
||||
const color_t msgColor = hld ? mColorBg : mColorText;
|
||||
|
||||
rectangle(mx, my, mw, mh, bgColor);
|
||||
DrawText(font24, mx + (mw - messageWidth)/2, my + (mh - messageHeight)/2, msgColor, mText.c_str());
|
||||
}
|
||||
|
||||
void Clickable::draw(const ffnt_header_t* font, u32 messageHeight)
|
||||
{
|
||||
u32 textw;
|
||||
GetTextDimensions(font, mText.c_str(), &textw, NULL);
|
||||
const u32 messageWidth = mCentered ? textw : mw - 8;
|
||||
|
||||
rectangle(mx, my, mw, mh, mColorBg);
|
||||
DrawTextTruncate(font, mx + (mw - messageWidth)/2, my + (mh - messageHeight)/2, mColorText, mText.c_str(), mw - 4*2 - 40, NULL);
|
||||
}
|
80
switch/source/directory.cpp
Normal file
80
switch/source/directory.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "directory.hpp"
|
||||
|
||||
Directory::Directory(const std::string& root)
|
||||
{
|
||||
mGood = false;
|
||||
mError = 0;
|
||||
mList.clear();
|
||||
|
||||
DIR* dir = opendir(root.c_str());
|
||||
struct dirent* ent;
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
mError = (Result)errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((ent = readdir(dir)))
|
||||
{
|
||||
std::string name = std::string(ent->d_name);
|
||||
bool directory = ent->d_type == DT_DIR;
|
||||
struct DirectoryEntry de = { name, directory };
|
||||
mList.push_back(de);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
mGood = true;
|
||||
}
|
||||
|
||||
Result Directory::error(void)
|
||||
{
|
||||
return mError;
|
||||
}
|
||||
|
||||
bool Directory::good(void)
|
||||
{
|
||||
return mGood;
|
||||
}
|
||||
|
||||
std::string Directory::entry(size_t index)
|
||||
{
|
||||
return index < mList.size() ? mList.at(index).name : "";
|
||||
}
|
||||
|
||||
bool Directory::folder(size_t index)
|
||||
{
|
||||
return index < mList.size() ? mList.at(index).directory : false;
|
||||
}
|
||||
|
||||
size_t Directory::size(void)
|
||||
{
|
||||
return mList.size();
|
||||
}
|
249
switch/source/draw.cpp
Normal file
249
switch/source/draw.cpp
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright 2017-2018 nx-hbmenu Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
* with or without fee is hereby granted, provided that the above copyright notice
|
||||
* and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
|
||||
* OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "draw.hpp"
|
||||
|
||||
static inline const ffnt_page_t* FontGetPage(const ffnt_header_t* font, u32 page_id)
|
||||
{
|
||||
if (page_id >= font->npages)
|
||||
return NULL;
|
||||
ffnt_pageentry_t* ent = &((ffnt_pageentry_t*)(font+1))[page_id];
|
||||
if (ent->size == 0)
|
||||
return NULL;
|
||||
return (const ffnt_page_t*)((const u8*)font + ent->offset);
|
||||
}
|
||||
|
||||
static inline bool FontLoadGlyph(glyph_t* glyph, const ffnt_header_t* font, u32 codepoint)
|
||||
{
|
||||
const ffnt_page_t* page = FontGetPage(font, codepoint >> 8);
|
||||
if (!page)
|
||||
return false;
|
||||
|
||||
codepoint &= 0xFF;
|
||||
u32 off = page->hdr.pos[codepoint];
|
||||
if (off == ~(u32)0)
|
||||
return false;
|
||||
|
||||
glyph->width = page->hdr.widths[codepoint];
|
||||
glyph->height = page->hdr.heights[codepoint];
|
||||
glyph->advance = page->hdr.advances[codepoint];
|
||||
glyph->posX = page->hdr.posX[codepoint];
|
||||
glyph->posY = page->hdr.posY[codepoint];
|
||||
glyph->data = &page->data[off];
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DrawGlyph(u32 x, u32 y, color_t clr, const glyph_t* glyph)
|
||||
{
|
||||
u32 i, j;
|
||||
const u8* data = glyph->data;
|
||||
x += glyph->posX;
|
||||
y += glyph->posY;
|
||||
for (j = 0; j < glyph->height; j ++)
|
||||
{
|
||||
for (i = 0; i < glyph->width; i ++)
|
||||
{
|
||||
clr.a = *data++;
|
||||
if (!clr.a) continue;
|
||||
DrawPixel(x+i, y+j, clr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline u8 DecodeByte(const char** ptr)
|
||||
{
|
||||
u8 c = (u8)**ptr;
|
||||
*ptr += 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
// UTF-8 code adapted from http://www.json.org/JSON_checker/utf8_decode.c
|
||||
|
||||
static inline int8_t DecodeUTF8Cont(const char** ptr)
|
||||
{
|
||||
int c = DecodeByte(ptr);
|
||||
return ((c & 0xC0) == 0x80) ? (c & 0x3F) : -1;
|
||||
}
|
||||
|
||||
static inline u32 DecodeUTF8(const char** ptr)
|
||||
{
|
||||
u32 r;
|
||||
u8 c;
|
||||
int8_t c1, c2, c3;
|
||||
|
||||
c = DecodeByte(ptr);
|
||||
if ((c & 0x80) == 0)
|
||||
return c;
|
||||
if ((c & 0xE0) == 0xC0)
|
||||
{
|
||||
c1 = DecodeUTF8Cont(ptr);
|
||||
if (c1 >= 0)
|
||||
{
|
||||
r = ((c & 0x1F) << 6) | c1;
|
||||
if (r >= 0x80)
|
||||
return r;
|
||||
}
|
||||
} else if ((c & 0xF0) == 0xE0)
|
||||
{
|
||||
c1 = DecodeUTF8Cont(ptr);
|
||||
if (c1 >= 0)
|
||||
{
|
||||
c2 = DecodeUTF8Cont(ptr);
|
||||
if (c2 >= 0)
|
||||
{
|
||||
r = ((c & 0x0F) << 12) | (c1 << 6) | c2;
|
||||
if (r >= 0x800 && (r < 0xD800 || r >= 0xE000))
|
||||
return r;
|
||||
}
|
||||
}
|
||||
} else if ((c & 0xF8) == 0xF0)
|
||||
{
|
||||
c1 = DecodeUTF8Cont(ptr);
|
||||
if (c1 >= 0)
|
||||
{
|
||||
c2 = DecodeUTF8Cont(ptr);
|
||||
if (c2 >= 0)
|
||||
{
|
||||
c3 = DecodeUTF8Cont(ptr);
|
||||
if (c3 >= 0)
|
||||
{
|
||||
r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
|
||||
if (r >= 0x10000 && r < 0x110000)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
static void DrawText_(const ffnt_header_t* font, u32 x, u32 y, color_t clr, const char* text, u32 max_width, const char* end_text)
|
||||
{
|
||||
y += font->baseline;
|
||||
u32 origX = x;
|
||||
while (*text)
|
||||
{
|
||||
if (max_width && x-origX >= max_width) {
|
||||
text = end_text;
|
||||
max_width = 0;
|
||||
}
|
||||
|
||||
glyph_t glyph;
|
||||
u32 codepoint = DecodeUTF8(&text);
|
||||
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
if (max_width) {
|
||||
text = end_text;
|
||||
max_width = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
x = origX;
|
||||
y += font->height;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!FontLoadGlyph(&glyph, font, codepoint))
|
||||
{
|
||||
if (!FontLoadGlyph(&glyph, font, '?'))
|
||||
continue;
|
||||
}
|
||||
|
||||
DrawGlyph(x, y, clr, &glyph);
|
||||
x += glyph.advance;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawText(const ffnt_header_t* font, u32 x, u32 y, color_t clr, const char* text)
|
||||
{
|
||||
DrawText_(font, x, y, clr, text, 0, NULL);
|
||||
}
|
||||
|
||||
void DrawTextTruncate(const ffnt_header_t* font, u32 x, u32 y, color_t clr, const char* text, u32 max_width, const char* end_text)
|
||||
{
|
||||
DrawText_(font, x, y, clr, text, max_width, end_text);
|
||||
}
|
||||
|
||||
void GetTextDimensions(const ffnt_header_t* font, const char* text, u32* width_out, u32* height_out)
|
||||
{
|
||||
u32 x = 0;
|
||||
u32 width = 0, height = 0;
|
||||
while (*text)
|
||||
{
|
||||
glyph_t glyph;
|
||||
u32 codepoint = DecodeUTF8(&text);
|
||||
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
x = 0;
|
||||
height += font->height;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!FontLoadGlyph(&glyph, font, codepoint))
|
||||
{
|
||||
if (!FontLoadGlyph(&glyph, font, '?'))
|
||||
continue;
|
||||
}
|
||||
|
||||
x += glyph.advance;
|
||||
|
||||
if (x > width)
|
||||
width = x;
|
||||
}
|
||||
|
||||
if (width_out)
|
||||
*width_out = width;
|
||||
if (height_out)
|
||||
*height_out = height;
|
||||
}
|
||||
|
||||
void DrawImage(int x, int y, int width, int height, const u8 *image, ImageMode mode)
|
||||
{
|
||||
int tmpx, tmpy;
|
||||
int pos;
|
||||
color_t current_color;
|
||||
|
||||
for (tmpy = 0; tmpy < height; tmpy++)
|
||||
{
|
||||
for (tmpx = 0; tmpx < width; tmpx++)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case IMAGE_MODE_RGB24:
|
||||
pos = ((tmpy*width) + tmpx) * 3;
|
||||
current_color = MakeColor(image[pos+0], image[pos+1], image[pos+2], 255);
|
||||
break;
|
||||
case IMAGE_MODE_RGBA32:
|
||||
pos = ((tmpy*width) + tmpx) * 4;
|
||||
current_color = MakeColor(image[pos+0], image[pos+1], image[pos+2], image[pos+3]);
|
||||
break;
|
||||
}
|
||||
DrawPixel(x+tmpx, y+tmpy, current_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rectangle(u32 x, u32 y, u32 w, u32 h, color_t color)
|
||||
{
|
||||
for (u32 j = y; j < y+h; j++)
|
||||
{
|
||||
for (u32 i = x; i < x + w; i+=4)
|
||||
{
|
||||
Draw4PixelsRaw(i, j, color);
|
||||
}
|
||||
}
|
||||
}
|
42
switch/source/filesystem.cpp
Normal file
42
switch/source/filesystem.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "filesystem.hpp"
|
||||
|
||||
Result FileSystem::mount(FsFileSystem* fileSystem, u64 titleID, u128 userID)
|
||||
{
|
||||
return fsMount_SaveData(fileSystem, titleID, userID);
|
||||
}
|
||||
|
||||
int FileSystem::mount(FsFileSystem fs)
|
||||
{
|
||||
return fsdevMountDevice("save", fs);
|
||||
}
|
||||
|
||||
void FileSystem::unmount(void)
|
||||
{
|
||||
fsdevUnmountDevice("save");
|
||||
}
|
390
switch/source/gui.cpp
Normal file
390
switch/source/gui.cpp
Normal file
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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"
|
||||
|
||||
u8* framebuf;
|
||||
u32 framebuf_width;
|
||||
|
||||
static Info* info;
|
||||
static Clickable* buttonBackup;
|
||||
static Clickable* buttonRestore;
|
||||
static MessageBox* messageBox;
|
||||
static MessageBox* copyList;
|
||||
static Scrollable* titleList;
|
||||
static Scrollable* backupList;
|
||||
|
||||
static const size_t cols = 14;
|
||||
static bool backupScrollEnabled;
|
||||
|
||||
static char ver[8];
|
||||
|
||||
void Gui::createInfo(const std::string& title, const std::string& message)
|
||||
{
|
||||
info->init(title, message, 300, TYPE_INFO);
|
||||
}
|
||||
|
||||
void Gui::createError(Result res, const std::string& message)
|
||||
{
|
||||
info->init(res, message, 300, TYPE_ERROR);
|
||||
}
|
||||
|
||||
size_t Gui::count(entryType_t type)
|
||||
{
|
||||
return type == TITLES ? titleList->size() : backupList->size();
|
||||
}
|
||||
|
||||
std::string Gui::nameFromCell(entryType_t type, size_t index)
|
||||
{
|
||||
return type == TITLES ? titleList->cellName(index) : backupList->cellName(index);
|
||||
}
|
||||
|
||||
void Gui::resetIndex(entryType_t type)
|
||||
{
|
||||
if (type == TITLES)
|
||||
{
|
||||
titleList->resetIndex();
|
||||
}
|
||||
else
|
||||
{
|
||||
backupList->resetIndex();
|
||||
}
|
||||
}
|
||||
|
||||
size_t Gui::index(entryType_t type)
|
||||
{
|
||||
return type == TITLES ? titleList->index() : backupList->index();
|
||||
}
|
||||
|
||||
void Gui::index(entryType_t type, size_t i)
|
||||
{
|
||||
if (type == TITLES)
|
||||
{
|
||||
titleList->index(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
backupList->index(i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Multi selection
|
||||
|
||||
static std::vector<size_t> selEnt;
|
||||
|
||||
std::vector<size_t> Gui::selectedEntries(void)
|
||||
{
|
||||
return selEnt;
|
||||
}
|
||||
|
||||
bool Gui::multipleSelectionEnabled(void)
|
||||
{
|
||||
return !selEnt.empty();
|
||||
}
|
||||
|
||||
void Gui::clearSelectedEntries(void)
|
||||
{
|
||||
selEnt.clear();
|
||||
}
|
||||
|
||||
void Gui::addSelectedEntry(size_t idx)
|
||||
{
|
||||
int existing = -1;
|
||||
for (size_t i = 0, sz = selEnt.size(); i < sz && existing == -1; i++)
|
||||
{
|
||||
if (selEnt.at(i) == idx)
|
||||
{
|
||||
existing = (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
if (existing == -1)
|
||||
{
|
||||
selEnt.push_back(idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
selEnt.erase(selEnt.begin() + existing);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gui implementation
|
||||
|
||||
static void drawOutline(u32 x, u32 y, u16 w, u16 h, u8 size, color_t color)
|
||||
{
|
||||
rectangle(x - size, y - size, w + 2*size, size, color); // top
|
||||
rectangle(x - size, y, size, h, color); // left
|
||||
rectangle(x + w, y, size, h, color); // right
|
||||
rectangle(x - size, y + h, w + 2*size, size, color); // bottom
|
||||
}
|
||||
|
||||
static void drawBackground(void)
|
||||
{
|
||||
framebuf = gfxGetFramebuffer(&framebuf_width, NULL);
|
||||
memset(framebuf, 51, gfxGetFramebufferSize());
|
||||
|
||||
rectangle(0, 0, 1280, 40, COLOR_GREY_DARK);
|
||||
rectangle(0, 680, 1280, 40, COLOR_GREY_DARK);
|
||||
|
||||
u32 ver_w, checkpoint_w;
|
||||
GetTextDimensions(font20, ver, &ver_w, NULL);
|
||||
GetTextDimensions(font24, "checkpoint", &checkpoint_w, NULL);
|
||||
DrawText(font20, 10, 7, COLOR_GREY_LIGHT, DateTime::timeStr().c_str());
|
||||
DrawText(font24, 1280 - 10 - ver_w - 40 - 12 - checkpoint_w, 0, COLOR_WHITE, "checkpoint");
|
||||
DrawText(font20, 1280 - 10 - ver_w, 7, COLOR_GREY_LIGHT, ver);
|
||||
DrawImage(1280 - 10 - ver_w - 40 - 6, 0, 40, 40, flag_bin, IMAGE_MODE_RGBA32);
|
||||
}
|
||||
|
||||
void Gui::drawCopy(const std::string& src, u64 offset, u64 size)
|
||||
{
|
||||
copyList->clear();
|
||||
copyList->push_message("Copying " + src);
|
||||
|
||||
drawBackground();
|
||||
copyList->draw();
|
||||
|
||||
static const int barHeight = 40;
|
||||
static const int progressBarHeight = 50;
|
||||
static const int spacingFromSides = 200;
|
||||
static const int spacingFromBars = 220 + (720 - barHeight * 2 - progressBarHeight) / 2;
|
||||
static const int width = 1280 - spacingFromSides * 2;
|
||||
|
||||
rectangle(spacingFromSides - 2, barHeight + spacingFromBars - 2, width + 4, progressBarHeight + 4, COLOR_GREY_LIGHT);
|
||||
rectangle(spacingFromSides, barHeight + spacingFromBars, width, progressBarHeight, COLOR_WHITE);
|
||||
rectangle(spacingFromSides, barHeight + spacingFromBars, (float)offset / (float)size * width, progressBarHeight, MakeColor(116, 222, 126, 255));
|
||||
|
||||
std::string sizeString = StringUtils::sizeString(offset) + " of " + StringUtils::sizeString(size);
|
||||
|
||||
u32 textw;
|
||||
GetTextDimensions(font20, sizeString.c_str(), &textw, NULL);
|
||||
DrawText(font20, ceilf((1280 - textw)/2), spacingFromBars + 48, COLOR_BLACK, sizeString.c_str());
|
||||
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
}
|
||||
|
||||
bool Gui::askForConfirmation(const std::string& text)
|
||||
{
|
||||
bool ret = false;
|
||||
Clickable* buttonYes = new Clickable(293, 540, 200, 80, COLOR_WHITE, COLOR_BLACK, "Yes", true);
|
||||
Clickable* buttonNo = new Clickable(786, 540, 200, 80, COLOR_WHITE, COLOR_BLACK, "No", true);
|
||||
MessageBox* message = new MessageBox(COLOR_GREY_DARK, COLOR_WHITE);
|
||||
message->push_message(text);
|
||||
|
||||
while(appletMainLoop() && !(buttonNo->released() || hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B))
|
||||
{
|
||||
hidScanInput();
|
||||
if (buttonYes->released() || hidKeysDown(CONTROLLER_P1_AUTO) & KEY_A)
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
|
||||
drawBackground();
|
||||
message->draw();
|
||||
|
||||
drawOutline(293, 540, 200, 80, 4, COLOR_GREY_LIGHT);
|
||||
drawOutline(786, 540, 200, 80, 4, COLOR_GREY_LIGHT);
|
||||
buttonYes->draw();
|
||||
buttonNo->draw();
|
||||
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
}
|
||||
|
||||
delete message;
|
||||
delete buttonYes;
|
||||
delete buttonNo;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Gui::init(void)
|
||||
{
|
||||
gfxInitDefault();
|
||||
sprintf(ver, "v%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
|
||||
backupScrollEnabled = false;
|
||||
info = new Info();
|
||||
info->init("", "", 0, TYPE_INFO);
|
||||
titleList = new Scrollable(40, 80, 398, 560, cols);
|
||||
backupList = new Scrollable(444, 80, 398, 560, cols);
|
||||
buttonBackup = new Clickable(984, 476, 256, 80, COLOR_WHITE, COLOR_GREY_LIGHT, "Backup", true);
|
||||
buttonRestore = new Clickable(984, 560, 256, 80, COLOR_WHITE, COLOR_GREY_LIGHT, "Restore", true);
|
||||
copyList = new MessageBox(COLOR_GREY_DARK, COLOR_WHITE);
|
||||
messageBox = new MessageBox(COLOR_GREY_DARK, COLOR_WHITE);
|
||||
messageBox->push_message("Press A to enter target.");
|
||||
messageBox->push_message("Press B to exit target or deselect all titles.");
|
||||
messageBox->push_message("Press X to delete a backup.");
|
||||
messageBox->push_message("Press Y to multiselect a title.");
|
||||
messageBox->push_message("Hold Y to multiselect all titles.");
|
||||
messageBox->push_message("Press the arrows to move between titles.");
|
||||
messageBox->push_message("Press L/R to switch page.");
|
||||
}
|
||||
|
||||
void Gui::exit(void)
|
||||
{
|
||||
delete info;
|
||||
delete titleList;
|
||||
delete backupList;
|
||||
delete copyList;
|
||||
delete buttonBackup;
|
||||
delete buttonRestore;
|
||||
delete messageBox;
|
||||
gfxExit();
|
||||
}
|
||||
|
||||
void Gui::draw(void)
|
||||
{
|
||||
titleList->flush();
|
||||
backupList->flush();
|
||||
|
||||
// draw
|
||||
drawBackground();
|
||||
|
||||
drawOutline(984, 476, 256, 164, 4, COLOR_GREY_LIGHT);
|
||||
rectangle(984, 556, 256, 4, COLOR_GREY_LIGHT);
|
||||
drawOutline(40, 80, 804, 560, 4, COLOR_GREY_LIGHT);
|
||||
rectangle(440, 80, 4, 560, COLOR_GREY_LIGHT);
|
||||
// TODO: optimize
|
||||
rectangle(40, 80, 398, 560, COLOR_GREY_DARK);
|
||||
rectangle(444, 80, 398, 560, COLOR_GREY_DARK);
|
||||
|
||||
for (size_t i = 0, sz = getTitleCount(); i < sz; i++)
|
||||
{
|
||||
Title title;
|
||||
getTitle(title, i);
|
||||
titleList->push_back(COLOR_WHITE, !backupScrollEnabled ? COLOR_BLUE : COLOR_GREY_LIGHT, title.name());
|
||||
|
||||
if (i == Gui::index(TITLES))
|
||||
{
|
||||
std::vector<std::string> dirs = title.saves();
|
||||
for (size_t j = 0, amount = dirs.size(); j < amount; j++)
|
||||
{
|
||||
backupList->push_back(COLOR_WHITE, backupScrollEnabled ? COLOR_BLUE : COLOR_GREY_LIGHT, dirs.at(j));
|
||||
}
|
||||
|
||||
// descriptions
|
||||
u32 userw;
|
||||
DrawText(font14, 980, 354, COLOR_GREY_LIGHT, "User: ");
|
||||
GetTextDimensions(font14, "User: ", &userw, NULL);
|
||||
DrawText(font14, 980 + userw, 354, COLOR_WHITE, Account::username(title.userId()).c_str());
|
||||
|
||||
// icon
|
||||
drawOutline(984, 80, 256, 256, 4, COLOR_BLACK);
|
||||
if (title.icon() != NULL)
|
||||
{
|
||||
DrawImage(984, 80, 256, 256, title.icon(), IMAGE_MODE_RGB24);
|
||||
}
|
||||
else
|
||||
{
|
||||
rectangle(984, 80, 256, 256, COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
titleList->invertCellColors(titleList->index());
|
||||
if (backupScrollEnabled)
|
||||
{
|
||||
backupList->invertCellColors(backupList->index());
|
||||
}
|
||||
|
||||
titleList->draw();
|
||||
backupList->draw();
|
||||
buttonBackup->draw();
|
||||
buttonRestore->draw();
|
||||
|
||||
for (size_t k = titleList->page()*14; k < titleList->page()*14 + titleList->maxVisibleEntries(); k++)
|
||||
{
|
||||
if (!selEnt.empty() && std::find(selEnt.begin(), selEnt.end(), k) != selEnt.end())
|
||||
{
|
||||
DrawImage(398, 80+40*(k%14), 40, 40, k == titleList->index() ? checkbox_white_bin : checkbox_grey_bin, IMAGE_MODE_RGBA32);
|
||||
}
|
||||
}
|
||||
|
||||
info->draw();
|
||||
|
||||
if (hidKeysHeld(CONTROLLER_P1_AUTO) & KEY_MINUS)
|
||||
{
|
||||
messageBox->draw();
|
||||
}
|
||||
|
||||
u32 ins_w, ins_h;
|
||||
const char* instructions = "Hold - to see commands. Press + to exit.";
|
||||
GetTextDimensions(font20, instructions, &ins_w, &ins_h);
|
||||
DrawText(font20, ceil((1280 - ins_w) / 2), 680 + 5, COLOR_WHITE, instructions);
|
||||
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
}
|
||||
|
||||
bool Gui::isBackupReleased(void)
|
||||
{
|
||||
return buttonBackup->released() && backupScrollEnabled;
|
||||
}
|
||||
|
||||
bool Gui::isRestoreReleased(void)
|
||||
{
|
||||
return buttonRestore->released() && backupScrollEnabled;
|
||||
}
|
||||
|
||||
bool Gui::backupScroll(void)
|
||||
{
|
||||
return backupScrollEnabled;
|
||||
}
|
||||
|
||||
void Gui::backupScroll(bool enable)
|
||||
{
|
||||
backupScrollEnabled = enable;
|
||||
}
|
||||
|
||||
void Gui::updateButtonsColor(void)
|
||||
{
|
||||
if (backupScrollEnabled)
|
||||
{
|
||||
buttonBackup->setColors(COLOR_WHITE, COLOR_BLACK);
|
||||
buttonRestore->setColors(COLOR_WHITE, COLOR_BLACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonBackup->setColors(COLOR_WHITE, COLOR_GREY_LIGHT);
|
||||
buttonRestore->setColors(COLOR_WHITE, COLOR_GREY_LIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
void Gui::updateSelector(void)
|
||||
{
|
||||
if (!backupScrollEnabled)
|
||||
{
|
||||
titleList->updateSelection();
|
||||
backupList->resetIndex();
|
||||
}
|
||||
else
|
||||
{
|
||||
backupList->updateSelection();
|
||||
}
|
||||
}
|
204
switch/source/hbkbd.cpp
Normal file
204
switch/source/hbkbd.cpp
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "hbkbd.hpp"
|
||||
|
||||
static const u32 buttonSpacing = 4;
|
||||
static const u32 normalWidth = 92;
|
||||
static const u32 bigWidth = 116;
|
||||
static const u32 height = 60;
|
||||
static const u32 margintb = 20;
|
||||
static const u32 marginlr = 54;
|
||||
static const u32 starty = 720 - 356 + margintb;
|
||||
|
||||
static const std::string letters = "1234567890@qwertyuiop+asdfghjkl_:zxcvbnm,.-/";
|
||||
static std::vector<Clickable*> buttons;
|
||||
|
||||
void hbkbd::init(void)
|
||||
{
|
||||
buttons.clear();
|
||||
|
||||
// fill with the above characters
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
for (size_t j = 0; j < 11; j++)
|
||||
{
|
||||
Clickable* button = new Clickable(
|
||||
marginlr + (buttonSpacing + normalWidth) * j,
|
||||
starty + (buttonSpacing + height) * i,
|
||||
normalWidth,
|
||||
height,
|
||||
COLOR_GREY_DARK,
|
||||
COLOR_WHITE,
|
||||
letters.substr(i*11+j, 1),
|
||||
true
|
||||
);
|
||||
buttons.push_back(button);
|
||||
}
|
||||
}
|
||||
|
||||
Clickable* backspace = new Clickable(
|
||||
marginlr + (buttonSpacing + normalWidth) * 11,
|
||||
starty,
|
||||
bigWidth,
|
||||
height,
|
||||
COLOR_WHITE,
|
||||
COLOR_BLACK,
|
||||
"back",
|
||||
true
|
||||
);
|
||||
buttons.push_back(backspace);
|
||||
|
||||
Clickable* returnb = new Clickable(
|
||||
marginlr + (buttonSpacing + normalWidth) * 11,
|
||||
starty + height + 4,
|
||||
bigWidth,
|
||||
height * 2 + 4,
|
||||
COLOR_GREY_MEDIUM,
|
||||
COLOR_GREY_LIGHT,
|
||||
"return",
|
||||
true
|
||||
);
|
||||
buttons.push_back(returnb);
|
||||
|
||||
Clickable* ok = new Clickable(
|
||||
marginlr + (buttonSpacing + normalWidth) * 11,
|
||||
starty + height*3 + 4*3,
|
||||
bigWidth,
|
||||
height * 2 + 4,
|
||||
COLOR_GREEN,
|
||||
COLOR_BLACK,
|
||||
"OK",
|
||||
true
|
||||
);
|
||||
buttons.push_back(ok);
|
||||
|
||||
Clickable* caps = new Clickable(
|
||||
marginlr + buttonSpacing + normalWidth,
|
||||
starty + height*4 + 4*4,
|
||||
normalWidth,
|
||||
height,
|
||||
COLOR_GREY_MEDIUM,
|
||||
COLOR_WHITE,
|
||||
"caps",
|
||||
true
|
||||
);
|
||||
buttons.push_back(caps);
|
||||
|
||||
Clickable* spacebar = new Clickable(
|
||||
marginlr + (buttonSpacing + normalWidth) * 3,
|
||||
starty + height*4 + 4*4,
|
||||
normalWidth*8 + buttonSpacing*7,
|
||||
height,
|
||||
COLOR_GREY_MEDIUM,
|
||||
COLOR_WHITE,
|
||||
"space",
|
||||
true
|
||||
);
|
||||
buttons.push_back(spacebar);
|
||||
}
|
||||
|
||||
void hbkbd::exit(void)
|
||||
{
|
||||
for (size_t i = 0, sz = buttons.size(); i < sz; i++)
|
||||
{
|
||||
delete buttons[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::string hbkbd::keyboard(const std::string& suggestion)
|
||||
{
|
||||
std::string str;
|
||||
while (appletMainLoop() && !(hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B))
|
||||
{
|
||||
hidScanInput();
|
||||
|
||||
framebuf = gfxGetFramebuffer(&framebuf_width, NULL);
|
||||
memset(framebuf, 51, gfxGetFramebufferSize());
|
||||
|
||||
rectangle(marginlr, 140, 1280 - marginlr*2, 84, COLOR_GREY_MEDIUM);
|
||||
rectangle(0, starty - margintb, 1280, 356, COLOR_GREY_DARKER);
|
||||
|
||||
if (str.empty())
|
||||
{
|
||||
DrawText(font24, marginlr*2, 160, COLOR_GREY_LIGHT, suggestion.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText(font24, marginlr*2, 160, COLOR_WHITE, str.c_str());
|
||||
}
|
||||
|
||||
for (size_t i = 0, sz = buttons.size(); i < sz; i++)
|
||||
{
|
||||
if (buttons.at(i)->released())
|
||||
{
|
||||
if (buttons.at(i)->text().compare("caps") == 0)
|
||||
{
|
||||
std::locale loc;
|
||||
bool islower = std::islower(buttons.at(11)->text()[0], loc);
|
||||
for (size_t t = 0; t < letters.length(); t++)
|
||||
{
|
||||
std::string l = islower ? std::string(1, std::toupper(letters[t], loc)) : std::string(1, std::tolower(letters[t], loc));
|
||||
buttons.at(t)->text(l);
|
||||
}
|
||||
}
|
||||
else if (buttons.at(i)->text().compare("back") == 0)
|
||||
{
|
||||
if (!str.empty())
|
||||
{
|
||||
str.erase(str.length() - 1);
|
||||
}
|
||||
}
|
||||
else if (buttons.at(i)->text().compare("space") == 0)
|
||||
{
|
||||
if (str.length() < CUSTOM_PATH_LEN)
|
||||
{
|
||||
str.append(" ");
|
||||
}
|
||||
}
|
||||
else if (buttons.at(i)->text().compare("return") == 0)
|
||||
{
|
||||
//str.append("\n");
|
||||
}
|
||||
else if (buttons.at(i)->text().compare("OK") == 0)
|
||||
{
|
||||
return str.empty() ? suggestion : str;
|
||||
}
|
||||
else if (str.length() < CUSTOM_PATH_LEN)
|
||||
{
|
||||
str.append(buttons.at(i)->text());
|
||||
}
|
||||
}
|
||||
buttons.at(i)->draw();
|
||||
}
|
||||
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
}
|
||||
|
||||
return suggestion;
|
||||
}
|
182
switch/source/hid.cpp
Normal file
182
switch/source/hid.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "hid.hpp"
|
||||
|
||||
static entryType_t type;
|
||||
|
||||
static size_t refreshMaxEntries(int page, size_t entries)
|
||||
{
|
||||
return (Gui::count(type) - page*entries) > entries ? entries - 1 : Gui::count(type) - page*entries - 1;
|
||||
}
|
||||
|
||||
static void page_back(int& page, int maxpages)
|
||||
{
|
||||
if (page > 0)
|
||||
{
|
||||
page--;
|
||||
}
|
||||
else if (page == 0)
|
||||
{
|
||||
page = maxpages - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void page_forward(int& page, int maxpages)
|
||||
{
|
||||
if (page < maxpages - 1)
|
||||
{
|
||||
page++;
|
||||
}
|
||||
else if (page == maxpages - 1)
|
||||
{
|
||||
page = 0;
|
||||
}
|
||||
}
|
||||
|
||||
entryType_t hid::entryType(void)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
void hid::entryType(entryType_t v)
|
||||
{
|
||||
type = v;
|
||||
}
|
||||
|
||||
void hid::index(size_t ¤tEntry, int &page, size_t maxpages, size_t maxentries, const size_t entries, const size_t columns) {
|
||||
maxentries--;
|
||||
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_L)
|
||||
{
|
||||
page_back(page, maxpages);
|
||||
if (currentEntry > refreshMaxEntries(page, entries))
|
||||
{
|
||||
currentEntry = refreshMaxEntries(page, entries);
|
||||
}
|
||||
}
|
||||
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_R)
|
||||
{
|
||||
page_forward(page, maxpages);
|
||||
if (currentEntry > refreshMaxEntries(page, entries))
|
||||
{
|
||||
currentEntry = refreshMaxEntries(page, entries);
|
||||
}
|
||||
}
|
||||
|
||||
if (columns > 1)
|
||||
{
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_LEFT)
|
||||
{
|
||||
if (currentEntry > 0)
|
||||
{
|
||||
currentEntry--;
|
||||
}
|
||||
else if (currentEntry == 0)
|
||||
{
|
||||
page_back(page, maxpages);
|
||||
currentEntry = refreshMaxEntries(page, entries);
|
||||
}
|
||||
}
|
||||
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_RIGHT)
|
||||
{
|
||||
if (currentEntry < maxentries)
|
||||
{
|
||||
currentEntry++;
|
||||
}
|
||||
else if (currentEntry == maxentries)
|
||||
{
|
||||
page_forward(page, maxpages);
|
||||
currentEntry = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_UP)
|
||||
{
|
||||
if (currentEntry <= columns - 1)
|
||||
{
|
||||
page_back(page, maxpages);
|
||||
if (currentEntry > refreshMaxEntries(page, entries))
|
||||
{
|
||||
currentEntry = refreshMaxEntries(page, entries);
|
||||
}
|
||||
}
|
||||
else if (currentEntry >= columns)
|
||||
{
|
||||
currentEntry -= columns;
|
||||
}
|
||||
}
|
||||
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_DOWN)
|
||||
{
|
||||
if ((int)(maxentries - columns) >= 0)
|
||||
{
|
||||
if (currentEntry <= maxentries - columns)
|
||||
{
|
||||
currentEntry += columns;
|
||||
}
|
||||
else if (currentEntry >= maxentries - columns + 1)
|
||||
{
|
||||
page_forward(page, maxpages);
|
||||
if (currentEntry > refreshMaxEntries(page, entries))
|
||||
{
|
||||
currentEntry = refreshMaxEntries(page, entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_UP)
|
||||
{
|
||||
if (currentEntry > 0)
|
||||
{
|
||||
currentEntry--;
|
||||
}
|
||||
else if (currentEntry == 0)
|
||||
{
|
||||
page_back(page, maxpages);
|
||||
currentEntry = refreshMaxEntries(page, entries);
|
||||
}
|
||||
}
|
||||
|
||||
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_DOWN)
|
||||
{
|
||||
if (currentEntry < maxentries)
|
||||
{
|
||||
currentEntry++;
|
||||
}
|
||||
else if (currentEntry == maxentries)
|
||||
{
|
||||
page_forward(page, maxpages);
|
||||
currentEntry = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
85
switch/source/info.cpp
Normal file
85
switch/source/info.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "info.hpp"
|
||||
|
||||
Info::Info(void)
|
||||
{
|
||||
mw = 480;
|
||||
mh = 150;
|
||||
mx = (1280 - mw) / 2;
|
||||
my = 720 - mh - 48;
|
||||
}
|
||||
|
||||
void Info::init(std::string title, std::string message, int ttl, Info_t type)
|
||||
{
|
||||
mTTL = ttl;
|
||||
mType = type;
|
||||
mRes = 0;
|
||||
mTitle = title;
|
||||
mMessage = message;
|
||||
}
|
||||
|
||||
void Info::init(Result res, std::string message, int ttl, Info_t type)
|
||||
{
|
||||
mTTL = ttl;
|
||||
mType = type;
|
||||
mRes = res;
|
||||
mMessage = message;
|
||||
mTitle = StringUtils::format("Error: %08lX", mRes);
|
||||
}
|
||||
|
||||
void Info::draw(void)
|
||||
{
|
||||
if ((mType == TYPE_INFO && mTTL > 0) || (mType == TYPE_ERROR && mTTL > 0 && mRes != 0))
|
||||
{
|
||||
u32 w, hres = 44, hmessage = 24 * StringUtils::lines(mMessage);
|
||||
u8 alpha = mTTL > 255 ? 255 : mTTL;
|
||||
color_t color, bordercolor, bgcolor;
|
||||
|
||||
if (mType == TYPE_ERROR)
|
||||
{
|
||||
color = MakeColor(255, 255, 255, alpha);
|
||||
bordercolor = MakeColor(70, 70, 70, alpha);
|
||||
bgcolor = MakeColor(79, 79, 79, alpha);
|
||||
}
|
||||
else if (mType == TYPE_INFO)
|
||||
{
|
||||
color = MakeColor(255, 255, 255, alpha);
|
||||
bordercolor = MakeColor(70, 70, 70, alpha);
|
||||
bgcolor = MakeColor(138, 138, 138, alpha);
|
||||
}
|
||||
|
||||
GetTextDimensions(font24, mTitle.c_str(), &w, NULL);
|
||||
const u32 spacing = (mh - hres - hmessage) / 3;
|
||||
rectangle(mx - 2, my - 2, mw + 4, mh + 4, bordercolor);
|
||||
rectangle(mx, my, mw, mh, bgcolor);
|
||||
DrawText(font24, mx + (mw - w) / 2, my + spacing, color, mTitle.c_str());
|
||||
DrawText(font14, mx + 10, my + 2*spacing + hres, color, mMessage.c_str());
|
||||
|
||||
mTTL--;
|
||||
}
|
||||
}
|
321
switch/source/io.cpp
Normal file
321
switch/source/io.cpp
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "io.hpp"
|
||||
|
||||
bool io::fileExists(const std::string& path)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat (path.c_str(), &buffer) == 0);
|
||||
}
|
||||
|
||||
void io::copyFile(const std::string& srcPath, const std::string& dstPath)
|
||||
{
|
||||
FILE* src = fopen(srcPath.c_str(), "rb");
|
||||
FILE* dst = fopen(dstPath.c_str(), "wb");
|
||||
if (src == NULL || dst == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(src, 0, SEEK_END);
|
||||
u64 sz = ftell(src);
|
||||
rewind(src);
|
||||
|
||||
size_t size;
|
||||
char* buf = new char[BUFFER_SIZE];
|
||||
|
||||
u64 offset = 0;
|
||||
size_t slashpos = srcPath.rfind("/");
|
||||
std::string name = srcPath.substr(slashpos + 1, srcPath.length() - slashpos - 1);
|
||||
while ((size = fread(buf, 1, BUFFER_SIZE, src)) > 0)
|
||||
{
|
||||
fwrite(buf, 1, size, dst);
|
||||
offset += size;
|
||||
Gui::drawCopy(name, offset, sz);
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
fclose(src);
|
||||
fclose(dst);
|
||||
}
|
||||
|
||||
Result io::copyDirectory(const std::string& srcPath, const std::string& dstPath)
|
||||
{
|
||||
Result res = 0;
|
||||
bool quit = false;
|
||||
Directory items(srcPath);
|
||||
|
||||
if (!items.good())
|
||||
{
|
||||
return items.error();
|
||||
}
|
||||
|
||||
for (size_t i = 0, sz = items.size(); i < sz && !quit; i++)
|
||||
{
|
||||
std::string newsrc = srcPath + items.entry(i);
|
||||
std::string newdst = dstPath + items.entry(i);
|
||||
|
||||
if (items.folder(i))
|
||||
{
|
||||
res = io::createDirectory(newdst);
|
||||
if (R_SUCCEEDED(res))
|
||||
{
|
||||
newsrc += "/";
|
||||
newdst += "/";
|
||||
res = io::copyDirectory(newsrc, newdst);
|
||||
}
|
||||
else
|
||||
{
|
||||
quit = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
io::copyFile(newsrc, newdst);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result io::createDirectory(const std::string& path)
|
||||
{
|
||||
mkdir(path.c_str(), 777);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool io::directoryExists(const std::string& path)
|
||||
{
|
||||
struct stat sb;
|
||||
return (stat(path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode));
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/2256945/removing-a-non-empty-directory-programmatically-in-c-or-c
|
||||
int io::deleteFolderRecursively(const char* path)
|
||||
{
|
||||
DIR *d = opendir(path);
|
||||
size_t path_len = strlen(path);
|
||||
int r = -1;
|
||||
|
||||
if (d)
|
||||
{
|
||||
struct dirent *p;
|
||||
|
||||
r = 0;
|
||||
while (!r && (p=readdir(d)))
|
||||
{
|
||||
int r2 = -1;
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
||||
/* Skip the names "." and ".." as we don't want to recurse on them. */
|
||||
if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
len = path_len + strlen(p->d_name) + 2;
|
||||
buf = new char[len];
|
||||
|
||||
if (buf)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
snprintf(buf, len, "%s/%s", path, p->d_name);
|
||||
|
||||
if (!stat(buf, &statbuf))
|
||||
{
|
||||
if (S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
r2 = io::deleteFolderRecursively(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
r2 = unlink(buf);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
r = r2;
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
if (!r)
|
||||
{
|
||||
r = rmdir(path);
|
||||
}
|
||||
|
||||
if (!r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void io::backup(size_t index)
|
||||
{
|
||||
// check if multiple selection is enabled and don't ask for confirmation if that's the case
|
||||
if (!Gui::multipleSelectionEnabled())
|
||||
{
|
||||
if (!Gui::askForConfirmation("Backup selected save?"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t cellIndex = Gui::index(CELLS);
|
||||
const bool isNewFolder = cellIndex == 0;
|
||||
Result res = 0;
|
||||
|
||||
Title title;
|
||||
getTitle(title, index);
|
||||
|
||||
FsFileSystem fileSystem;
|
||||
res = FileSystem::mount(&fileSystem, title.id(), title.userId());
|
||||
if (R_SUCCEEDED(res))
|
||||
{
|
||||
int ret = FileSystem::mount(fileSystem);
|
||||
if (ret == -1)
|
||||
{
|
||||
FileSystem::unmount();
|
||||
Gui::createError(-2, "Failed to mount save.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Gui::createError(res, "Failed to mount save.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string suggestion = DateTime::dateTimeStr() + " " + Account::username(title.userId());
|
||||
std::string customPath;
|
||||
|
||||
if (Gui::multipleSelectionEnabled())
|
||||
{
|
||||
customPath = isNewFolder ? suggestion : Gui::nameFromCell(CELLS, cellIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
customPath = isNewFolder ? hbkbd::keyboard(suggestion) : Gui::nameFromCell(CELLS, cellIndex);
|
||||
}
|
||||
|
||||
std::string dstPath = title.path() + "/" + customPath;
|
||||
if (!isNewFolder || io::directoryExists(dstPath))
|
||||
{
|
||||
int ret = io::deleteFolderRecursively(dstPath.c_str());
|
||||
if (ret != 0)
|
||||
{
|
||||
FileSystem::unmount();
|
||||
Gui::createError((Result)ret, "Failed to delete the existing backup directory recursively.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
res = io::createDirectory(dstPath);
|
||||
res = io::copyDirectory("save:/", dstPath + "/");
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
FileSystem::unmount();
|
||||
io::deleteFolderRecursively(dstPath.c_str());
|
||||
Gui::createError(res, "Failed to backup save.");
|
||||
return;
|
||||
}
|
||||
|
||||
refreshDirectories(title.id());
|
||||
|
||||
FileSystem::unmount();
|
||||
Gui::createInfo("Success!", "Progress correctly saved to disk.");
|
||||
}
|
||||
|
||||
void io::restore(size_t index)
|
||||
{
|
||||
const size_t cellIndex = Gui::index(CELLS);
|
||||
if (cellIndex == 0 || !Gui::askForConfirmation("Restore selected save?"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Result res = 0;
|
||||
|
||||
Title title;
|
||||
getTitle(title, index);
|
||||
|
||||
FsFileSystem fileSystem;
|
||||
res = FileSystem::mount(&fileSystem, title.id(), title.userId());
|
||||
if (R_SUCCEEDED(res))
|
||||
{
|
||||
int ret = FileSystem::mount(fileSystem);
|
||||
if (ret == -1)
|
||||
{
|
||||
FileSystem::unmount();
|
||||
Gui::createError(-2, "Failed to mount save.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Gui::createError(res, "Failed to mount save.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string srcPath = title.path() + "/" + Gui::nameFromCell(CELLS, cellIndex) + "/";
|
||||
std::string dstPath = "save:/";
|
||||
|
||||
res = io::deleteFolderRecursively(dstPath.c_str());
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
FileSystem::unmount();
|
||||
Gui::createError(res, "Failed to delete save.");
|
||||
return;
|
||||
}
|
||||
|
||||
res = io::copyDirectory(srcPath, dstPath);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
FileSystem::unmount();
|
||||
Gui::createError(res, "Failed to restore save.");
|
||||
return;
|
||||
}
|
||||
|
||||
res = fsdevCommitDevice("save");
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
Gui::createError(res, "Failed to commit to save device.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Gui::createInfo("Success!", Gui::nameFromCell(CELLS, cellIndex) + " has been restored\nsuccessfully.");
|
||||
}
|
||||
|
||||
FileSystem::unmount();
|
||||
}
|
149
switch/source/main.cpp
Normal file
149
switch/source/main.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 <switch.h>
|
||||
#include "thread.hpp"
|
||||
#include "title.hpp"
|
||||
#include "util.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Result res = servicesInit();
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
servicesExit();
|
||||
return res;
|
||||
}
|
||||
|
||||
res = Threads::create((ThreadFunc)loadTitles);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
Gui::createError(res, "Failed to create thread.");
|
||||
}
|
||||
|
||||
int selectionTimer = 0;
|
||||
|
||||
while(appletMainLoop() && !(hidKeysDown(CONTROLLER_P1_AUTO) & KEY_PLUS))
|
||||
{
|
||||
hidScanInput();
|
||||
u32 kdown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
|
||||
if (kdown & KEY_A || kdown & KEY_RIGHT)
|
||||
{
|
||||
Gui::backupScroll(true);
|
||||
Gui::updateButtonsColor();
|
||||
hid::entryType(CELLS);
|
||||
}
|
||||
|
||||
if (kdown & KEY_B || kdown & KEY_LEFT)
|
||||
{
|
||||
Gui::backupScroll(false);
|
||||
Gui::updateButtonsColor();
|
||||
hid::entryType(TITLES);
|
||||
Gui::clearSelectedEntries();
|
||||
}
|
||||
|
||||
if (kdown & KEY_X)
|
||||
{
|
||||
if (Gui::backupScroll())
|
||||
{
|
||||
size_t index = Gui::index(CELLS);
|
||||
if (index > 0 && Gui::askForConfirmation("Delete selected backup?"))
|
||||
{
|
||||
Title title;
|
||||
getTitle(title, Gui::index(TITLES));
|
||||
std::vector<std::string> list = title.saves();
|
||||
std::string path = title.path() + "/" + list.at(index);
|
||||
io::deleteFolderRecursively(path.c_str());
|
||||
refreshDirectories(title.id());
|
||||
Gui::index(CELLS, index - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kdown & KEY_Y && !(Gui::backupScroll()))
|
||||
{
|
||||
Gui::addSelectedEntry(Gui::index(TITLES));
|
||||
}
|
||||
|
||||
if (hidKeysHeld(CONTROLLER_P1_AUTO) & KEY_Y && !(Gui::backupScroll()))
|
||||
{
|
||||
selectionTimer++;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectionTimer = 0;
|
||||
}
|
||||
|
||||
if (selectionTimer > 90)
|
||||
{
|
||||
Gui::clearSelectedEntries();
|
||||
for (size_t i = 0, sz = getTitleCount(); i < sz; i++)
|
||||
{
|
||||
Gui::addSelectedEntry(i);
|
||||
}
|
||||
selectionTimer = 0;
|
||||
}
|
||||
|
||||
if (Gui::isBackupReleased())
|
||||
{
|
||||
if (Gui::multipleSelectionEnabled())
|
||||
{
|
||||
Gui::resetIndex(CELLS);
|
||||
std::vector<size_t> list = Gui::selectedEntries();
|
||||
for (size_t i = 0, sz = list.size(); i < sz; i++)
|
||||
{
|
||||
io::backup(list.at(i));
|
||||
}
|
||||
Gui::clearSelectedEntries();
|
||||
}
|
||||
else
|
||||
{
|
||||
io::backup(Gui::index(TITLES));
|
||||
}
|
||||
}
|
||||
|
||||
if (Gui::isRestoreReleased())
|
||||
{
|
||||
if (Gui::multipleSelectionEnabled())
|
||||
{
|
||||
Gui::clearSelectedEntries();
|
||||
}
|
||||
else
|
||||
{
|
||||
io::restore(Gui::index(TITLES));
|
||||
}
|
||||
}
|
||||
|
||||
Gui::updateSelector();
|
||||
Gui::draw();
|
||||
}
|
||||
|
||||
Threads::destroy();
|
||||
servicesExit();
|
||||
return 0;
|
||||
}
|
73
switch/source/messagebox.cpp
Normal file
73
switch/source/messagebox.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "messagebox.hpp"
|
||||
|
||||
MessageBox::MessageBox(color_t colorBg, color_t colorText)
|
||||
{
|
||||
mColorBg = colorBg;
|
||||
mColorText = colorText;
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
void MessageBox::push_message(const std::string& newmessage)
|
||||
{
|
||||
mList.push_back(newmessage);
|
||||
}
|
||||
|
||||
void MessageBox::clear(void)
|
||||
{
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
void MessageBox::draw(void)
|
||||
{
|
||||
static const u32 spacingFromEdges = 20;
|
||||
|
||||
u32 w = 0, mh = 30;
|
||||
u32 widths[mList.size()];
|
||||
for (size_t i = 0, sz = mList.size(); i < sz; i++)
|
||||
{
|
||||
GetTextDimensions(font20, mList.at(i).c_str(), &widths[i], NULL);
|
||||
if (widths[i] > w)
|
||||
{
|
||||
w = widths[i];
|
||||
}
|
||||
}
|
||||
w += 2*spacingFromEdges;
|
||||
|
||||
const u32 h = mh*mList.size() + 2*spacingFromEdges;
|
||||
const u32 x = (1280-w)/2;
|
||||
const u32 y = (720-h)/2;
|
||||
|
||||
rectangle(x - 2, y - 2, w + 4, h + 4, COLOR_BLACK);
|
||||
rectangle(x, y, w, h, mColorBg);
|
||||
|
||||
for (size_t i = 0, sz = mList.size(); i < sz; i++)
|
||||
{
|
||||
DrawText(font20, ceil((1280 - widths[i]) / 2), y + spacingFromEdges + mh*i, mColorText, mList.at(i).c_str());
|
||||
}
|
||||
}
|
916
switch/source/nanojpeg.c
Normal file
916
switch/source/nanojpeg.c
Normal file
|
@ -0,0 +1,916 @@
|
|||
// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder
|
||||
// version 1.3.5 (2016-11-14)
|
||||
// Copyright (c) 2009-2016 Martin J. Fiedler <martin.fiedler@gmx.net>
|
||||
// published under the terms of the MIT license
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// DOCUMENTATION SECTION //
|
||||
// read this if you want to know what this is all about //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INTRODUCTION
|
||||
// ============
|
||||
//
|
||||
// This is a minimal decoder for baseline JPEG images. It accepts memory dumps
|
||||
// of JPEG files as input and generates either 8-bit grayscale or packed 24-bit
|
||||
// RGB images as output. It does not parse JFIF or Exif headers; all JPEG files
|
||||
// are assumed to be either grayscale or YCbCr. CMYK or other color spaces are
|
||||
// not supported. All YCbCr subsampling schemes with power-of-two ratios are
|
||||
// supported, as are restart intervals. Progressive or lossless JPEG is not
|
||||
// supported.
|
||||
// Summed up, NanoJPEG should be able to decode all images from digital cameras
|
||||
// and most common forms of other non-progressive JPEG images.
|
||||
// The decoder is not optimized for speed, it's optimized for simplicity and
|
||||
// small code. Image quality should be at a reasonable level. A bicubic chroma
|
||||
// upsampling filter ensures that subsampled YCbCr images are rendered in
|
||||
// decent quality. The decoder is not meant to deal with broken JPEG files in
|
||||
// a graceful manner; if anything is wrong with the bitstream, decoding will
|
||||
// simply fail.
|
||||
// The code should work with every modern C compiler without problems and
|
||||
// should not emit any warnings. It uses only (at least) 32-bit integer
|
||||
// arithmetic and is supposed to be endianness independent and 64-bit clean.
|
||||
// However, it is not thread-safe.
|
||||
|
||||
|
||||
// COMPILE-TIME CONFIGURATION
|
||||
// ==========================
|
||||
//
|
||||
// The following aspects of NanoJPEG can be controlled with preprocessor
|
||||
// defines:
|
||||
//
|
||||
// _NJ_EXAMPLE_PROGRAM = Compile a main() function with an example
|
||||
// program.
|
||||
// _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header
|
||||
// file for NanoJPEG. Example:
|
||||
// #define _NJ_INCLUDE_HEADER_ONLY
|
||||
// #include "nanojpeg.c"
|
||||
// int main(void) {
|
||||
// njInit();
|
||||
// // your code here
|
||||
// njDone();
|
||||
// }
|
||||
// NJ_USE_LIBC=1 = Use the malloc(), free(), memset() and memcpy()
|
||||
// functions from the standard C library (default).
|
||||
// NJ_USE_LIBC=0 = Don't use the standard C library. In this mode,
|
||||
// external functions njAlloc(), njFreeMem(),
|
||||
// njFillMem() and njCopyMem() need to be defined
|
||||
// and implemented somewhere.
|
||||
// NJ_USE_WIN32=0 = Normal mode (default).
|
||||
// NJ_USE_WIN32=1 = If compiling with MSVC for Win32 and
|
||||
// NJ_USE_LIBC=0, NanoJPEG will use its own
|
||||
// implementations of the required C library
|
||||
// functions (default if compiling with MSVC and
|
||||
// NJ_USE_LIBC=0).
|
||||
// NJ_CHROMA_FILTER=1 = Use the bicubic chroma upsampling filter
|
||||
// (default).
|
||||
// NJ_CHROMA_FILTER=0 = Use simple pixel repetition for chroma upsampling
|
||||
// (bad quality, but faster and less code).
|
||||
|
||||
|
||||
// API
|
||||
// ===
|
||||
//
|
||||
// For API documentation, read the "header section" below.
|
||||
|
||||
|
||||
// EXAMPLE
|
||||
// =======
|
||||
//
|
||||
// A few pages below, you can find an example program that uses NanoJPEG to
|
||||
// convert JPEG files into PGM or PPM. To compile it, use something like
|
||||
// gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c
|
||||
// You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :)
|
||||
// The only thing you might need is -Wno-shift-negative-value, because this
|
||||
// code relies on the target machine using two's complement arithmetic, but
|
||||
// the C standard does not, even though *any* practically useful machine
|
||||
// nowadays uses two's complement.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HEADER SECTION //
|
||||
// copy and pase this into nanojpeg.h if you want //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _NANOJPEG_H
|
||||
#define _NANOJPEG_H
|
||||
|
||||
// nj_result_t: Result codes for njDecode().
|
||||
typedef enum _nj_result {
|
||||
NJ_OK = 0, // no error, decoding successful
|
||||
NJ_NO_JPEG, // not a JPEG file
|
||||
NJ_UNSUPPORTED, // unsupported format
|
||||
NJ_OUT_OF_MEM, // out of memory
|
||||
NJ_INTERNAL_ERR, // internal error
|
||||
NJ_SYNTAX_ERROR, // syntax error
|
||||
__NJ_FINISHED, // used internally, will never be reported
|
||||
} nj_result_t;
|
||||
|
||||
// njInit: Initialize NanoJPEG.
|
||||
// For safety reasons, this should be called at least one time before using
|
||||
// using any of the other NanoJPEG functions.
|
||||
void njInit(void);
|
||||
|
||||
// njDecode: Decode a JPEG image.
|
||||
// Decodes a memory dump of a JPEG file into internal buffers.
|
||||
// Parameters:
|
||||
// jpeg = The pointer to the memory dump.
|
||||
// size = The size of the JPEG file.
|
||||
// Return value: The error code in case of failure, or NJ_OK (zero) on success.
|
||||
nj_result_t njDecode(const void* jpeg, const int size);
|
||||
|
||||
// njGetWidth: Return the width (in pixels) of the most recently decoded
|
||||
// image. If njDecode() failed, the result of njGetWidth() is undefined.
|
||||
int njGetWidth(void);
|
||||
|
||||
// njGetHeight: Return the height (in pixels) of the most recently decoded
|
||||
// image. If njDecode() failed, the result of njGetHeight() is undefined.
|
||||
int njGetHeight(void);
|
||||
|
||||
// njIsColor: Return 1 if the most recently decoded image is a color image
|
||||
// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result
|
||||
// of njGetWidth() is undefined.
|
||||
int njIsColor(void);
|
||||
|
||||
// njGetImage: Returns the decoded image data.
|
||||
// Returns a pointer to the most recently image. The memory layout it byte-
|
||||
// oriented, top-down, without any padding between lines. Pixels of color
|
||||
// images will be stored as three consecutive bytes for the red, green and
|
||||
// blue channels. This data format is thus compatible with the PGM or PPM
|
||||
// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.
|
||||
// If njDecode() failed, the result of njGetImage() is undefined.
|
||||
unsigned char* njGetImage(void);
|
||||
|
||||
// njGetImageSize: Returns the size (in bytes) of the image data returned
|
||||
// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is
|
||||
// undefined.
|
||||
int njGetImageSize(void);
|
||||
|
||||
// njDone: Uninitialize NanoJPEG.
|
||||
// Resets NanoJPEG's internal state and frees all memory that has been
|
||||
// allocated at run-time by NanoJPEG. It is still possible to decode another
|
||||
// image after a njDone() call.
|
||||
void njDone(void);
|
||||
|
||||
#endif//_NANOJPEG_H
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CONFIGURATION SECTION //
|
||||
// adjust the default settings for the NJ_ defines here //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NJ_USE_LIBC
|
||||
#define NJ_USE_LIBC 1
|
||||
#endif
|
||||
|
||||
#ifndef NJ_USE_WIN32
|
||||
#ifdef _MSC_VER
|
||||
#define NJ_USE_WIN32 (!NJ_USE_LIBC)
|
||||
#else
|
||||
#define NJ_USE_WIN32 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NJ_CHROMA_FILTER
|
||||
#define NJ_CHROMA_FILTER 1
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EXAMPLE PROGRAM //
|
||||
// just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC) //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _NJ_EXAMPLE_PROGRAM
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int size;
|
||||
char *buf;
|
||||
FILE *f;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <input.jpg> [<output.ppm>]\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
f = fopen(argv[1], "rb");
|
||||
if (!f) {
|
||||
printf("Error opening the input file.\n");
|
||||
return 1;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = (int) ftell(f);
|
||||
buf = (char*) malloc(size);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
size = (int) fread(buf, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
njInit();
|
||||
if (njDecode(buf, size)) {
|
||||
free((void*)buf);
|
||||
printf("Error decoding the input file.\n");
|
||||
return 1;
|
||||
}
|
||||
free((void*)buf);
|
||||
|
||||
f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb");
|
||||
if (!f) {
|
||||
printf("Error opening the output file.\n");
|
||||
return 1;
|
||||
}
|
||||
fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());
|
||||
fwrite(njGetImage(), 1, njGetImageSize(), f);
|
||||
fclose(f);
|
||||
njDone();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IMPLEMENTATION SECTION //
|
||||
// you may stop reading here //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _NJ_INCLUDE_HEADER_ONLY
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define NJ_INLINE static __inline
|
||||
#define NJ_FORCE_INLINE static __forceinline
|
||||
#else
|
||||
#define NJ_INLINE static inline
|
||||
#define NJ_FORCE_INLINE static inline
|
||||
#endif
|
||||
|
||||
#if NJ_USE_LIBC
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define njAllocMem malloc
|
||||
#define njFreeMem free
|
||||
#define njFillMem memset
|
||||
#define njCopyMem memcpy
|
||||
#elif NJ_USE_WIN32
|
||||
#include <windows.h>
|
||||
#define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))
|
||||
#define njFreeMem(block) ((void) LocalFree((HLOCAL) block))
|
||||
NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {
|
||||
mov edi, block
|
||||
mov al, value
|
||||
mov ecx, count
|
||||
rep stosb
|
||||
} }
|
||||
NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {
|
||||
mov edi, dest
|
||||
mov esi, src
|
||||
mov ecx, count
|
||||
rep movsb
|
||||
} }
|
||||
#else
|
||||
extern void* njAllocMem(int size);
|
||||
extern void njFreeMem(void* block);
|
||||
extern void njFillMem(void* block, unsigned char byte, int size);
|
||||
extern void njCopyMem(void* dest, const void* src, int size);
|
||||
#endif
|
||||
|
||||
typedef struct _nj_code {
|
||||
unsigned char bits, code;
|
||||
} nj_vlc_code_t;
|
||||
|
||||
typedef struct _nj_cmp {
|
||||
int cid;
|
||||
int ssx, ssy;
|
||||
int width, height;
|
||||
int stride;
|
||||
int qtsel;
|
||||
int actabsel, dctabsel;
|
||||
int dcpred;
|
||||
unsigned char *pixels;
|
||||
} nj_component_t;
|
||||
|
||||
typedef struct _nj_ctx {
|
||||
nj_result_t error;
|
||||
const unsigned char *pos;
|
||||
int size;
|
||||
int length;
|
||||
int width, height;
|
||||
int mbwidth, mbheight;
|
||||
int mbsizex, mbsizey;
|
||||
int ncomp;
|
||||
nj_component_t comp[3];
|
||||
int qtused, qtavail;
|
||||
unsigned char qtab[4][64];
|
||||
nj_vlc_code_t vlctab[4][65536];
|
||||
int buf, bufbits;
|
||||
int block[64];
|
||||
int rstinterval;
|
||||
unsigned char *rgb;
|
||||
} nj_context_t;
|
||||
|
||||
static nj_context_t nj;
|
||||
|
||||
static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
|
||||
11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
|
||||
42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
|
||||
38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };
|
||||
|
||||
NJ_FORCE_INLINE unsigned char njClip(const int x) {
|
||||
return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);
|
||||
}
|
||||
|
||||
#define W1 2841
|
||||
#define W2 2676
|
||||
#define W3 2408
|
||||
#define W5 1609
|
||||
#define W6 1108
|
||||
#define W7 565
|
||||
|
||||
NJ_INLINE void njRowIDCT(int* blk) {
|
||||
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
|
||||
if (!((x1 = blk[4] << 11)
|
||||
| (x2 = blk[6])
|
||||
| (x3 = blk[2])
|
||||
| (x4 = blk[1])
|
||||
| (x5 = blk[7])
|
||||
| (x6 = blk[5])
|
||||
| (x7 = blk[3])))
|
||||
{
|
||||
blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3;
|
||||
return;
|
||||
}
|
||||
x0 = (blk[0] << 11) + 128;
|
||||
x8 = W7 * (x4 + x5);
|
||||
x4 = x8 + (W1 - W7) * x4;
|
||||
x5 = x8 - (W1 + W7) * x5;
|
||||
x8 = W3 * (x6 + x7);
|
||||
x6 = x8 - (W3 - W5) * x6;
|
||||
x7 = x8 - (W3 + W5) * x7;
|
||||
x8 = x0 + x1;
|
||||
x0 -= x1;
|
||||
x1 = W6 * (x3 + x2);
|
||||
x2 = x1 - (W2 + W6) * x2;
|
||||
x3 = x1 + (W2 - W6) * x3;
|
||||
x1 = x4 + x6;
|
||||
x4 -= x6;
|
||||
x6 = x5 + x7;
|
||||
x5 -= x7;
|
||||
x7 = x8 + x3;
|
||||
x8 -= x3;
|
||||
x3 = x0 + x2;
|
||||
x0 -= x2;
|
||||
x2 = (181 * (x4 + x5) + 128) >> 8;
|
||||
x4 = (181 * (x4 - x5) + 128) >> 8;
|
||||
blk[0] = (x7 + x1) >> 8;
|
||||
blk[1] = (x3 + x2) >> 8;
|
||||
blk[2] = (x0 + x4) >> 8;
|
||||
blk[3] = (x8 + x6) >> 8;
|
||||
blk[4] = (x8 - x6) >> 8;
|
||||
blk[5] = (x0 - x4) >> 8;
|
||||
blk[6] = (x3 - x2) >> 8;
|
||||
blk[7] = (x7 - x1) >> 8;
|
||||
}
|
||||
|
||||
NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {
|
||||
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
|
||||
if (!((x1 = blk[8*4] << 8)
|
||||
| (x2 = blk[8*6])
|
||||
| (x3 = blk[8*2])
|
||||
| (x4 = blk[8*1])
|
||||
| (x5 = blk[8*7])
|
||||
| (x6 = blk[8*5])
|
||||
| (x7 = blk[8*3])))
|
||||
{
|
||||
x1 = njClip(((blk[0] + 32) >> 6) + 128);
|
||||
for (x0 = 8; x0; --x0) {
|
||||
*out = (unsigned char) x1;
|
||||
out += stride;
|
||||
}
|
||||
return;
|
||||
}
|
||||
x0 = (blk[0] << 8) + 8192;
|
||||
x8 = W7 * (x4 + x5) + 4;
|
||||
x4 = (x8 + (W1 - W7) * x4) >> 3;
|
||||
x5 = (x8 - (W1 + W7) * x5) >> 3;
|
||||
x8 = W3 * (x6 + x7) + 4;
|
||||
x6 = (x8 - (W3 - W5) * x6) >> 3;
|
||||
x7 = (x8 - (W3 + W5) * x7) >> 3;
|
||||
x8 = x0 + x1;
|
||||
x0 -= x1;
|
||||
x1 = W6 * (x3 + x2) + 4;
|
||||
x2 = (x1 - (W2 + W6) * x2) >> 3;
|
||||
x3 = (x1 + (W2 - W6) * x3) >> 3;
|
||||
x1 = x4 + x6;
|
||||
x4 -= x6;
|
||||
x6 = x5 + x7;
|
||||
x5 -= x7;
|
||||
x7 = x8 + x3;
|
||||
x8 -= x3;
|
||||
x3 = x0 + x2;
|
||||
x0 -= x2;
|
||||
x2 = (181 * (x4 + x5) + 128) >> 8;
|
||||
x4 = (181 * (x4 - x5) + 128) >> 8;
|
||||
*out = njClip(((x7 + x1) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x3 + x2) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x0 + x4) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x8 + x6) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x8 - x6) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x0 - x4) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x3 - x2) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x7 - x1) >> 14) + 128);
|
||||
}
|
||||
|
||||
#define njThrow(e) do { nj.error = e; return; } while (0)
|
||||
#define njCheckError() do { if (nj.error) return; } while (0)
|
||||
|
||||
static int njShowBits(int bits) {
|
||||
unsigned char newbyte;
|
||||
if (!bits) return 0;
|
||||
while (nj.bufbits < bits) {
|
||||
if (nj.size <= 0) {
|
||||
nj.buf = (nj.buf << 8) | 0xFF;
|
||||
nj.bufbits += 8;
|
||||
continue;
|
||||
}
|
||||
newbyte = *nj.pos++;
|
||||
nj.size--;
|
||||
nj.bufbits += 8;
|
||||
nj.buf = (nj.buf << 8) | newbyte;
|
||||
if (newbyte == 0xFF) {
|
||||
if (nj.size) {
|
||||
unsigned char marker = *nj.pos++;
|
||||
nj.size--;
|
||||
switch (marker) {
|
||||
case 0x00:
|
||||
case 0xFF:
|
||||
break;
|
||||
case 0xD9: nj.size = 0; break;
|
||||
default:
|
||||
if ((marker & 0xF8) != 0xD0)
|
||||
nj.error = NJ_SYNTAX_ERROR;
|
||||
else {
|
||||
nj.buf = (nj.buf << 8) | marker;
|
||||
nj.bufbits += 8;
|
||||
}
|
||||
}
|
||||
} else
|
||||
nj.error = NJ_SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1);
|
||||
}
|
||||
|
||||
NJ_INLINE void njSkipBits(int bits) {
|
||||
if (nj.bufbits < bits)
|
||||
(void) njShowBits(bits);
|
||||
nj.bufbits -= bits;
|
||||
}
|
||||
|
||||
NJ_INLINE int njGetBits(int bits) {
|
||||
int res = njShowBits(bits);
|
||||
njSkipBits(bits);
|
||||
return res;
|
||||
}
|
||||
|
||||
NJ_INLINE void njByteAlign(void) {
|
||||
nj.bufbits &= 0xF8;
|
||||
}
|
||||
|
||||
static void njSkip(int count) {
|
||||
nj.pos += count;
|
||||
nj.size -= count;
|
||||
nj.length -= count;
|
||||
if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
NJ_INLINE unsigned short njDecode16(const unsigned char *pos) {
|
||||
return (pos[0] << 8) | pos[1];
|
||||
}
|
||||
|
||||
static void njDecodeLength(void) {
|
||||
if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.length = njDecode16(nj.pos);
|
||||
if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR);
|
||||
njSkip(2);
|
||||
}
|
||||
|
||||
NJ_INLINE void njSkipMarker(void) {
|
||||
njDecodeLength();
|
||||
njSkip(nj.length);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeSOF(void) {
|
||||
int i, ssxmax = 0, ssymax = 0;
|
||||
nj_component_t* c;
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED);
|
||||
nj.height = njDecode16(nj.pos+1);
|
||||
nj.width = njDecode16(nj.pos+3);
|
||||
if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.ncomp = nj.pos[5];
|
||||
njSkip(6);
|
||||
switch (nj.ncomp) {
|
||||
case 1:
|
||||
case 3:
|
||||
break;
|
||||
default:
|
||||
njThrow(NJ_UNSUPPORTED);
|
||||
}
|
||||
if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR);
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
c->cid = nj.pos[0];
|
||||
if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
|
||||
if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
|
||||
if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR);
|
||||
njSkip(3);
|
||||
nj.qtused |= 1 << c->qtsel;
|
||||
if (c->ssx > ssxmax) ssxmax = c->ssx;
|
||||
if (c->ssy > ssymax) ssymax = c->ssy;
|
||||
}
|
||||
if (nj.ncomp == 1) {
|
||||
c = nj.comp;
|
||||
c->ssx = c->ssy = ssxmax = ssymax = 1;
|
||||
}
|
||||
nj.mbsizex = ssxmax << 3;
|
||||
nj.mbsizey = ssymax << 3;
|
||||
nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex;
|
||||
nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey;
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax;
|
||||
c->height = (nj.height * c->ssy + ssymax - 1) / ssymax;
|
||||
c->stride = nj.mbwidth * c->ssx << 3;
|
||||
if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED);
|
||||
if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM);
|
||||
}
|
||||
if (nj.ncomp == 3) {
|
||||
nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp);
|
||||
if (!nj.rgb) njThrow(NJ_OUT_OF_MEM);
|
||||
}
|
||||
njSkip(nj.length);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeDHT(void) {
|
||||
int codelen, currcnt, remain, spread, i, j;
|
||||
nj_vlc_code_t *vlc;
|
||||
static unsigned char counts[16];
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
while (nj.length >= 17) {
|
||||
i = nj.pos[0];
|
||||
if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (i & 0x02) njThrow(NJ_UNSUPPORTED);
|
||||
i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value
|
||||
for (codelen = 1; codelen <= 16; ++codelen)
|
||||
counts[codelen - 1] = nj.pos[codelen];
|
||||
njSkip(17);
|
||||
vlc = &nj.vlctab[i][0];
|
||||
remain = spread = 65536;
|
||||
for (codelen = 1; codelen <= 16; ++codelen) {
|
||||
spread >>= 1;
|
||||
currcnt = counts[codelen - 1];
|
||||
if (!currcnt) continue;
|
||||
if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR);
|
||||
remain -= currcnt << (16 - codelen);
|
||||
if (remain < 0) njThrow(NJ_SYNTAX_ERROR);
|
||||
for (i = 0; i < currcnt; ++i) {
|
||||
register unsigned char code = nj.pos[i];
|
||||
for (j = spread; j; --j) {
|
||||
vlc->bits = (unsigned char) codelen;
|
||||
vlc->code = code;
|
||||
++vlc;
|
||||
}
|
||||
}
|
||||
njSkip(currcnt);
|
||||
}
|
||||
while (remain--) {
|
||||
vlc->bits = 0;
|
||||
++vlc;
|
||||
}
|
||||
}
|
||||
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeDQT(void) {
|
||||
int i;
|
||||
unsigned char *t;
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
while (nj.length >= 65) {
|
||||
i = nj.pos[0];
|
||||
if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.qtavail |= 1 << i;
|
||||
t = &nj.qtab[i][0];
|
||||
for (i = 0; i < 64; ++i)
|
||||
t[i] = nj.pos[i + 1];
|
||||
njSkip(65);
|
||||
}
|
||||
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeDRI(void) {
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.rstinterval = njDecode16(nj.pos);
|
||||
njSkip(nj.length);
|
||||
}
|
||||
|
||||
static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) {
|
||||
int value = njShowBits(16);
|
||||
int bits = vlc[value].bits;
|
||||
if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; }
|
||||
njSkipBits(bits);
|
||||
value = vlc[value].code;
|
||||
if (code) *code = (unsigned char) value;
|
||||
bits = value & 15;
|
||||
if (!bits) return 0;
|
||||
value = njGetBits(bits);
|
||||
if (value < (1 << (bits - 1)))
|
||||
value += ((-1) << bits) + 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) {
|
||||
unsigned char code = 0;
|
||||
int value, coef = 0;
|
||||
njFillMem(nj.block, 0, sizeof(nj.block));
|
||||
c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL);
|
||||
nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0];
|
||||
do {
|
||||
value = njGetVLC(&nj.vlctab[c->actabsel][0], &code);
|
||||
if (!code) break; // EOB
|
||||
if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR);
|
||||
coef += (code >> 4) + 1;
|
||||
if (coef > 63) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef];
|
||||
} while (coef < 63);
|
||||
for (coef = 0; coef < 64; coef += 8)
|
||||
njRowIDCT(&nj.block[coef]);
|
||||
for (coef = 0; coef < 8; ++coef)
|
||||
njColIDCT(&nj.block[coef], &out[coef], c->stride);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeScan(void) {
|
||||
int i, mbx, mby, sbx, sby;
|
||||
int rstcount = nj.rstinterval, nextrst = 0;
|
||||
nj_component_t* c;
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED);
|
||||
njSkip(1);
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR);
|
||||
c->dctabsel = nj.pos[1] >> 4;
|
||||
c->actabsel = (nj.pos[1] & 1) | 2;
|
||||
njSkip(2);
|
||||
}
|
||||
if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED);
|
||||
njSkip(nj.length);
|
||||
for (mbx = mby = 0;;) {
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c)
|
||||
for (sby = 0; sby < c->ssy; ++sby)
|
||||
for (sbx = 0; sbx < c->ssx; ++sbx) {
|
||||
njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]);
|
||||
njCheckError();
|
||||
}
|
||||
if (++mbx >= nj.mbwidth) {
|
||||
mbx = 0;
|
||||
if (++mby >= nj.mbheight) break;
|
||||
}
|
||||
if (nj.rstinterval && !(--rstcount)) {
|
||||
njByteAlign();
|
||||
i = njGetBits(16);
|
||||
if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR);
|
||||
nextrst = (nextrst + 1) & 7;
|
||||
rstcount = nj.rstinterval;
|
||||
for (i = 0; i < 3; ++i)
|
||||
nj.comp[i].dcpred = 0;
|
||||
}
|
||||
}
|
||||
nj.error = __NJ_FINISHED;
|
||||
}
|
||||
|
||||
#if NJ_CHROMA_FILTER
|
||||
|
||||
#define CF4A (-9)
|
||||
#define CF4B (111)
|
||||
#define CF4C (29)
|
||||
#define CF4D (-3)
|
||||
#define CF3A (28)
|
||||
#define CF3B (109)
|
||||
#define CF3C (-9)
|
||||
#define CF3X (104)
|
||||
#define CF3Y (27)
|
||||
#define CF3Z (-3)
|
||||
#define CF2A (139)
|
||||
#define CF2B (-11)
|
||||
#define CF(x) njClip(((x) + 64) >> 7)
|
||||
|
||||
NJ_INLINE void njUpsampleH(nj_component_t* c) {
|
||||
const int xmax = c->width - 3;
|
||||
unsigned char *out, *lin, *lout;
|
||||
int x, y;
|
||||
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
|
||||
if (!out) njThrow(NJ_OUT_OF_MEM);
|
||||
lin = c->pixels;
|
||||
lout = out;
|
||||
for (y = c->height; y; --y) {
|
||||
lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]);
|
||||
lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]);
|
||||
lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]);
|
||||
for (x = 0; x < xmax; ++x) {
|
||||
lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]);
|
||||
lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]);
|
||||
}
|
||||
lin += c->stride;
|
||||
lout += c->width << 1;
|
||||
lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]);
|
||||
lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]);
|
||||
lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]);
|
||||
}
|
||||
c->width <<= 1;
|
||||
c->stride = c->width;
|
||||
njFreeMem((void*)c->pixels);
|
||||
c->pixels = out;
|
||||
}
|
||||
|
||||
NJ_INLINE void njUpsampleV(nj_component_t* c) {
|
||||
const int w = c->width, s1 = c->stride, s2 = s1 + s1;
|
||||
unsigned char *out, *cin, *cout;
|
||||
int x, y;
|
||||
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
|
||||
if (!out) njThrow(NJ_OUT_OF_MEM);
|
||||
for (x = 0; x < w; ++x) {
|
||||
cin = &c->pixels[x];
|
||||
cout = &out[x];
|
||||
*cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w;
|
||||
*cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w;
|
||||
*cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w;
|
||||
cin += s1;
|
||||
for (y = c->height - 3; y; --y) {
|
||||
*cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w;
|
||||
*cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w;
|
||||
cin += s1;
|
||||
}
|
||||
cin += s1;
|
||||
*cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w;
|
||||
*cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w;
|
||||
*cout = CF(CF2A * cin[0] + CF2B * cin[-s1]);
|
||||
}
|
||||
c->height <<= 1;
|
||||
c->stride = c->width;
|
||||
njFreeMem((void*) c->pixels);
|
||||
c->pixels = out;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
NJ_INLINE void njUpsample(nj_component_t* c) {
|
||||
int x, y, xshift = 0, yshift = 0;
|
||||
unsigned char *out, *lin, *lout;
|
||||
while (c->width < nj.width) { c->width <<= 1; ++xshift; }
|
||||
while (c->height < nj.height) { c->height <<= 1; ++yshift; }
|
||||
out = (unsigned char*) njAllocMem(c->width * c->height);
|
||||
if (!out) njThrow(NJ_OUT_OF_MEM);
|
||||
lin = c->pixels;
|
||||
lout = out;
|
||||
for (y = 0; y < c->height; ++y) {
|
||||
lin = &c->pixels[(y >> yshift) * c->stride];
|
||||
for (x = 0; x < c->width; ++x)
|
||||
lout[x] = lin[x >> xshift];
|
||||
lout += c->width;
|
||||
}
|
||||
c->stride = c->width;
|
||||
njFreeMem((void*) c->pixels);
|
||||
c->pixels = out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
NJ_INLINE void njConvert(void) {
|
||||
int i;
|
||||
nj_component_t* c;
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
#if NJ_CHROMA_FILTER
|
||||
while ((c->width < nj.width) || (c->height < nj.height)) {
|
||||
if (c->width < nj.width) njUpsampleH(c);
|
||||
njCheckError();
|
||||
if (c->height < nj.height) njUpsampleV(c);
|
||||
njCheckError();
|
||||
}
|
||||
#else
|
||||
if ((c->width < nj.width) || (c->height < nj.height))
|
||||
njUpsample(c);
|
||||
#endif
|
||||
if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR);
|
||||
}
|
||||
if (nj.ncomp == 3) {
|
||||
// convert to RGB
|
||||
int x, yy;
|
||||
unsigned char *prgb = nj.rgb;
|
||||
const unsigned char *py = nj.comp[0].pixels;
|
||||
const unsigned char *pcb = nj.comp[1].pixels;
|
||||
const unsigned char *pcr = nj.comp[2].pixels;
|
||||
for (yy = nj.height; yy; --yy) {
|
||||
for (x = 0; x < nj.width; ++x) {
|
||||
register int y = py[x] << 8;
|
||||
register int cb = pcb[x] - 128;
|
||||
register int cr = pcr[x] - 128;
|
||||
*prgb++ = njClip((y + 359 * cr + 128) >> 8);
|
||||
*prgb++ = njClip((y - 88 * cb - 183 * cr + 128) >> 8);
|
||||
*prgb++ = njClip((y + 454 * cb + 128) >> 8);
|
||||
}
|
||||
py += nj.comp[0].stride;
|
||||
pcb += nj.comp[1].stride;
|
||||
pcr += nj.comp[2].stride;
|
||||
}
|
||||
} else if (nj.comp[0].width != nj.comp[0].stride) {
|
||||
// grayscale -> only remove stride
|
||||
unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride];
|
||||
unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width];
|
||||
int y;
|
||||
for (y = nj.comp[0].height - 1; y; --y) {
|
||||
njCopyMem(pout, pin, nj.comp[0].width);
|
||||
pin += nj.comp[0].stride;
|
||||
pout += nj.comp[0].width;
|
||||
}
|
||||
nj.comp[0].stride = nj.comp[0].width;
|
||||
}
|
||||
}
|
||||
|
||||
void njInit(void) {
|
||||
njFillMem(&nj, 0, sizeof(nj_context_t));
|
||||
}
|
||||
|
||||
void njDone(void) {
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels);
|
||||
if (nj.rgb) njFreeMem((void*) nj.rgb);
|
||||
njInit();
|
||||
}
|
||||
|
||||
nj_result_t njDecode(const void* jpeg, const int size) {
|
||||
njDone();
|
||||
nj.pos = (const unsigned char*) jpeg;
|
||||
nj.size = size & 0x7FFFFFFF;
|
||||
if (nj.size < 2) return NJ_NO_JPEG;
|
||||
if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG;
|
||||
njSkip(2);
|
||||
while (!nj.error) {
|
||||
if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR;
|
||||
njSkip(2);
|
||||
switch (nj.pos[-1]) {
|
||||
case 0xC0: njDecodeSOF(); break;
|
||||
case 0xC4: njDecodeDHT(); break;
|
||||
case 0xDB: njDecodeDQT(); break;
|
||||
case 0xDD: njDecodeDRI(); break;
|
||||
case 0xDA: njDecodeScan(); break;
|
||||
case 0xFE: njSkipMarker(); break;
|
||||
default:
|
||||
if ((nj.pos[-1] & 0xF0) == 0xE0)
|
||||
njSkipMarker();
|
||||
else
|
||||
return NJ_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
if (nj.error != __NJ_FINISHED) return nj.error;
|
||||
nj.error = NJ_OK;
|
||||
njConvert();
|
||||
return nj.error;
|
||||
}
|
||||
|
||||
int njGetWidth(void) { return nj.width; }
|
||||
int njGetHeight(void) { return nj.height; }
|
||||
int njIsColor(void) { return (nj.ncomp != 1); }
|
||||
unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; }
|
||||
int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; }
|
||||
|
||||
#endif // _NJ_INCLUDE_HEADER_ONLY
|
131
switch/source/scrollable.cpp
Normal file
131
switch/source/scrollable.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "scrollable.hpp"
|
||||
|
||||
std::string Scrollable::cellName(size_t index)
|
||||
{
|
||||
return mCells.at(index)->text();
|
||||
}
|
||||
|
||||
Scrollable::Scrollable(u32 _x, u32 _y, u32 _w, u32 _h, size_t _visibleEntries)
|
||||
{
|
||||
mx = _x;
|
||||
my = _y;
|
||||
mw = _w;
|
||||
mh = _h;
|
||||
mVisibleEntries = _visibleEntries;
|
||||
mIndex = 0;
|
||||
mPage = 0;
|
||||
}
|
||||
|
||||
Scrollable::~Scrollable(void)
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
void Scrollable::push_back(color_t color, color_t colorMessage, const std::string& message)
|
||||
{
|
||||
static const float spacing = mh / mVisibleEntries;
|
||||
Clickable* cell = new Clickable(mx, my + (size() % mVisibleEntries)*spacing, mw, spacing, color, colorMessage, message, false);
|
||||
mCells.push_back(cell);
|
||||
}
|
||||
|
||||
void Scrollable::flush(void)
|
||||
{
|
||||
for (size_t i = 0, sz = size(); i < sz; i++)
|
||||
{
|
||||
delete mCells[i];
|
||||
}
|
||||
mCells.clear();
|
||||
}
|
||||
|
||||
size_t Scrollable::size(void)
|
||||
{
|
||||
return mCells.size();
|
||||
}
|
||||
|
||||
int Scrollable::page(void)
|
||||
{
|
||||
return mPage;
|
||||
}
|
||||
|
||||
size_t Scrollable::maxVisibleEntries(void)
|
||||
{
|
||||
return (size() - mPage*mVisibleEntries) > mVisibleEntries ? mVisibleEntries : size() - mPage*mVisibleEntries;
|
||||
}
|
||||
|
||||
size_t Scrollable::index(void)
|
||||
{
|
||||
return mIndex + mPage*mVisibleEntries;
|
||||
}
|
||||
|
||||
void Scrollable::invertCellColors(size_t i)
|
||||
{
|
||||
if (i < size())
|
||||
{
|
||||
mCells.at(i)->invertColors();
|
||||
}
|
||||
}
|
||||
|
||||
void Scrollable::resetIndex(void)
|
||||
{
|
||||
mIndex = 0;
|
||||
mPage = 0;
|
||||
}
|
||||
|
||||
void Scrollable::index(size_t i)
|
||||
{
|
||||
mPage = i / mVisibleEntries;
|
||||
mIndex = i - mPage * mVisibleEntries;
|
||||
}
|
||||
|
||||
void Scrollable::updateSelection(void)
|
||||
{
|
||||
touchPosition touch;
|
||||
hidTouchRead(&touch, 0);
|
||||
|
||||
const size_t maxentries = maxVisibleEntries();
|
||||
const size_t maxpages = (size() % mVisibleEntries == 0) ? size() / mVisibleEntries : size() / mVisibleEntries + 1;
|
||||
const u32 hu = maxentries * mh / mVisibleEntries;
|
||||
|
||||
if (hidKeysHeld(CONTROLLER_P1_AUTO) & KEY_TOUCH && touch.py > my && touch.py < my+hu && touch.px > mx && touch.px < mx+mw)
|
||||
{
|
||||
mIndex = (size_t)((touch.py - my)*mVisibleEntries/mh);
|
||||
}
|
||||
|
||||
hid::index(mIndex, mPage, maxpages, maxentries, mVisibleEntries, 1);
|
||||
}
|
||||
|
||||
void Scrollable::draw(void)
|
||||
{
|
||||
const size_t baseIndex = mVisibleEntries*mPage;
|
||||
const size_t sz = size() - baseIndex > mVisibleEntries ? mVisibleEntries : size() - baseIndex;
|
||||
for (size_t i = baseIndex; i < baseIndex + sz; i++)
|
||||
{
|
||||
mCells.at(i)->draw(font14, 24);
|
||||
}
|
||||
}
|
57
switch/source/thread.cpp
Normal file
57
switch/source/thread.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "thread.hpp"
|
||||
|
||||
static std::vector<Thread> threads;
|
||||
|
||||
Result Threads::create(ThreadFunc entrypoint)
|
||||
{
|
||||
Thread thread;
|
||||
Result res = threadCreate(&thread, entrypoint, NULL, 16*1024, 0x2B, -2);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
res = threadStart(&thread);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
threads.push_back(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Threads::destroy(void)
|
||||
{
|
||||
for (u32 i = 0; i < threads.size(); i++)
|
||||
{
|
||||
threadWaitForExit(&threads.at(i));
|
||||
threadClose(&threads.at(i));
|
||||
}
|
||||
}
|
217
switch/source/title.cpp
Normal file
217
switch/source/title.cpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "title.hpp"
|
||||
|
||||
static std::vector<Title> titles;
|
||||
|
||||
static void loadIcon(Title& title, NsApplicationControlData* nsacd, size_t iconsize)
|
||||
{
|
||||
uint8_t* imageptr = NULL;
|
||||
size_t imagesize = 256*256*3;
|
||||
|
||||
njInit();
|
||||
if (njDecode(nsacd->icon, iconsize) != NJ_OK)
|
||||
{
|
||||
njDone();
|
||||
return;
|
||||
}
|
||||
|
||||
if (njGetWidth() != 256 || njGetHeight() != 256 || (size_t)njGetImageSize() != imagesize || njIsColor() != 1)
|
||||
{
|
||||
njDone();
|
||||
return;
|
||||
}
|
||||
|
||||
imageptr = njGetImage();
|
||||
if (imageptr == NULL)
|
||||
{
|
||||
njDone();
|
||||
return;
|
||||
}
|
||||
|
||||
title.icon(imageptr, imagesize);
|
||||
imageptr = NULL;
|
||||
njDone();
|
||||
}
|
||||
|
||||
void Title::init(u64 id, u128 userID, const std::string& name)
|
||||
{
|
||||
mId = id;
|
||||
mUserId = userID;
|
||||
mName = StringUtils::containsInvalidChar(name) ? StringUtils::format("0x%016llX", mId) : StringUtils::removeForbiddenCharacters(name);
|
||||
mPath = "sdmc:/switch/Checkpoint/saves/" + StringUtils::format("0x%016llX", mId) + " " + mName;
|
||||
mIcon = NULL;
|
||||
|
||||
if (!io::directoryExists(mPath))
|
||||
{
|
||||
io::createDirectory(mPath);
|
||||
}
|
||||
|
||||
refreshDirectories();
|
||||
}
|
||||
|
||||
u64 Title::id(void)
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
u128 Title::userId(void)
|
||||
{
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
std::string Title::name(void)
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
std::string Title::path(void)
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
std::vector<std::string> Title::saves()
|
||||
{
|
||||
return mSaves;
|
||||
}
|
||||
|
||||
u8* Title::icon(void)
|
||||
{
|
||||
return mIcon;
|
||||
}
|
||||
|
||||
void Title::icon(u8* data, size_t iconsize)
|
||||
{
|
||||
mIcon = (u8*)malloc(iconsize);
|
||||
std::copy(data, data + iconsize, mIcon);
|
||||
}
|
||||
|
||||
void Title::refreshDirectories(void)
|
||||
{
|
||||
mSaves.clear();
|
||||
Directory savelist(mPath);
|
||||
if (savelist.good())
|
||||
{
|
||||
for (size_t i = 0, sz = savelist.size(); i < sz; i++)
|
||||
{
|
||||
if (savelist.folder(i))
|
||||
{
|
||||
mSaves.push_back(savelist.entry(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(mSaves.rbegin(), mSaves.rend());
|
||||
mSaves.insert(mSaves.begin(), "New...");
|
||||
}
|
||||
else
|
||||
{
|
||||
Gui::createError(savelist.error(), "Couldn't retrieve the directory list for the title " + name() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
void loadTitles(void)
|
||||
{
|
||||
titles.clear();
|
||||
|
||||
FsSaveDataIterator iterator;
|
||||
FsSaveDataInfo info;
|
||||
size_t total_entries = 0;
|
||||
size_t outsize = 0;
|
||||
|
||||
NacpLanguageEntry* nle = NULL;
|
||||
NsApplicationControlData* nsacd = (NsApplicationControlData*)malloc(sizeof(NsApplicationControlData));
|
||||
if (nsacd == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
memset(nsacd, 0, sizeof(NsApplicationControlData));
|
||||
|
||||
Result res = fsOpenSaveDataIterator(&iterator, FsSaveDataSpaceId_NandUser);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
res = fsSaveDataIteratorRead(&iterator, &info, 1, &total_entries);
|
||||
if (R_FAILED(res) || total_entries == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (info.SaveDataType == FsSaveDataType_SaveData)
|
||||
{
|
||||
u64 tid = info.titleID;
|
||||
u128 uid = info.userID;
|
||||
res = nsGetApplicationControlData(1, tid, nsacd, sizeof(NsApplicationControlData), &outsize);
|
||||
if (R_SUCCEEDED(res) && !(outsize < sizeof(nsacd->nacp)))
|
||||
{
|
||||
res = nacpGetLanguageEntry(&nsacd->nacp, &nle);
|
||||
if (R_SUCCEEDED(res) && nle != NULL)
|
||||
{
|
||||
Title title;
|
||||
title.init(tid, uid, std::string(nle->name));
|
||||
loadIcon(title, nsacd, outsize - sizeof(nsacd->nacp));
|
||||
titles.push_back(title);
|
||||
}
|
||||
}
|
||||
nle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(nsacd);
|
||||
fsSaveDataIteratorClose(&iterator);
|
||||
|
||||
std::sort(titles.begin(), titles.end(), [](Title l, Title r) {
|
||||
return l.name() < r.name();
|
||||
});
|
||||
}
|
||||
|
||||
void getTitle(Title &dst, size_t i)
|
||||
{
|
||||
if (i < getTitleCount())
|
||||
{
|
||||
dst = titles.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
size_t getTitleCount(void)
|
||||
{
|
||||
return titles.size();
|
||||
}
|
||||
|
||||
void refreshDirectories(u64 id)
|
||||
{
|
||||
for (size_t i = 0; i < titles.size(); i++)
|
||||
{
|
||||
if (titles.at(i).id() == id)
|
||||
{
|
||||
titles.at(i).refreshDirectories();
|
||||
}
|
||||
}
|
||||
}
|
152
switch/source/util.cpp
Normal file
152
switch/source/util.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* This file is part of Checkpoint
|
||||
* Copyright (C) 2017-2018 Bernardo Giordano
|
||||
*
|
||||
* 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 "util.hpp"
|
||||
|
||||
void servicesExit(void)
|
||||
{
|
||||
nsExit();
|
||||
Account::exit();
|
||||
hbkbd::exit();
|
||||
Gui::exit();
|
||||
}
|
||||
|
||||
Result servicesInit(void)
|
||||
{
|
||||
Result res = 0;
|
||||
res = io::createDirectory("sdmc:/switch");
|
||||
res = io::createDirectory("sdmc:/switch/Checkpoint");
|
||||
res = io::createDirectory("sdmc:/switch/Checkpoint/saves");
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
if (R_FAILED(res = Account::init()))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
if (R_FAILED(res = nsInitialize()))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
Gui::init();
|
||||
hbkbd::init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string DateTime::timeStr(void)
|
||||
{
|
||||
time_t unixTime = time(NULL);
|
||||
struct tm* timeStruct = gmtime((const time_t*)&unixTime);
|
||||
return StringUtils::format("%02i:%02i:%02i", timeStruct->tm_hour, timeStruct->tm_min, timeStruct->tm_sec);
|
||||
}
|
||||
|
||||
std::string DateTime::dateTimeStr(void)
|
||||
{
|
||||
time_t unixTime = time(NULL);
|
||||
struct tm* timeStruct = gmtime((const time_t*)&unixTime);
|
||||
return StringUtils::format("%04i%02i%02i-%02i%02i%02i", timeStruct->tm_year + 1900, timeStruct->tm_mon + 1, timeStruct->tm_mday, timeStruct->tm_hour, timeStruct->tm_min, timeStruct->tm_sec);
|
||||
}
|
||||
|
||||
bool StringUtils::containsInvalidChar(const std::string& str)
|
||||
{
|
||||
for (size_t i = 0, sz = str.length(); i < sz; i++)
|
||||
{
|
||||
if (!isascii(str[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string StringUtils::removeForbiddenCharacters(std::string src)
|
||||
{
|
||||
static const std::string illegalChars = ".,!\\/:?*\"<>|";
|
||||
for (size_t i = 0; i < src.length(); i++)
|
||||
{
|
||||
if (illegalChars.find(src[i]) != std::string::npos)
|
||||
{
|
||||
src[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = src.length() - 1; i > 0 && src[i] == ' '; i--);
|
||||
src.erase(i + 1, src.length() - i);
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf
|
||||
std::string StringUtils::format(const std::string fmt_str, ...)
|
||||
{
|
||||
int final_n, n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */
|
||||
std::unique_ptr<char[]> formatted;
|
||||
va_list ap;
|
||||
while(1)
|
||||
{
|
||||
formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */
|
||||
strcpy(&formatted[0], fmt_str.c_str());
|
||||
va_start(ap, fmt_str);
|
||||
final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
|
||||
va_end(ap);
|
||||
if (final_n < 0 || final_n >= n)
|
||||
n += abs(final_n - n + 1);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return std::string(formatted.get());
|
||||
}
|
||||
|
||||
std::string StringUtils::sizeString(double size)
|
||||
{
|
||||
int i = 0;
|
||||
static const char* units[] = {"B", "kB", "MB", "GB"};
|
||||
while (size > 1024)
|
||||
{
|
||||
size /= 1024;
|
||||
i++;
|
||||
}
|
||||
return StringUtils::format("%.*f %s", i, size, units[i]);
|
||||
}
|
||||
|
||||
size_t StringUtils::lines(const std::string& str)
|
||||
{
|
||||
size_t n = 1;
|
||||
for (size_t i = 0, sz = str.length(); i < sz; i++)
|
||||
{
|
||||
if (str[i] == '\n')
|
||||
{
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
Loading…
Add table
Reference in a new issue