diff --git a/Makefile b/Makefile index 5f71be7..4c33748 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ CFLAGS += `aarch64-none-elf-pkg-config libxml-2.0 --cflags` CFLAGS += `aarch64-none-elf-pkg-config json-c --cflags` CFLAGS += `aarch64-none-elf-pkg-config libturbojpeg --cflags` -CXXFLAGS := $(CFLAGS) -std=c++1z -O2 -Wno-volatile -Wno-unused-parameter +CXXFLAGS := $(CFLAGS) -std=c++20 -O2 -Wno-volatile -Wno-unused-parameter ASFLAGS := -g $(ARCH) LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) diff --git a/include/core/common.h b/include/core/nxdt_includes.h similarity index 79% rename from include/core/common.h rename to include/core/nxdt_includes.h index da306f0..ba88ba0 100644 --- a/include/core/common.h +++ b/include/core/nxdt_includes.h @@ -1,5 +1,5 @@ /* - * common.h + * nxdt_includes.h * * Copyright (c) 2020-2021, DarkMatterCore . * @@ -21,9 +21,10 @@ #pragma once -#ifndef __COMMON_H__ -#define __COMMON_H__ +#ifndef __NXDT_INCLUDES_H__ +#define __NXDT_INCLUDES_H__ +/* C headers. */ #include #include #include @@ -38,7 +39,6 @@ #include #include #include -#include #ifndef __cplusplus #include @@ -47,19 +47,18 @@ #define _Atomic(X) std::atomic< X > #endif +/* libnx header. */ +#include + +/* Global defines. */ +#include "../defines.h" + +/* File-based logger. */ #include "nxdt_log.h" + +/* USB Mass Storage support. */ #include "ums.h" -#define FS_SYSMODULE_TID (u64)0x0100000000000000 -#define BOOT_SYSMODULE_TID (u64)0x0100000000000005 -#define SPL_SYSMODULE_TID (u64)0x0100000000000028 -#define ES_SYSMODULE_TID (u64)0x0100000000000033 -#define SYSTEM_UPDATE_TID (u64)0x0100000000000816 - -#define FAT32_FILESIZE_LIMIT (u64)0xFFFFFFFF /* 4 GiB - 1 (4294967295 bytes). */ - -#define NXDT_ASSERT(name, size) static_assert(sizeof(name) == (size), "Bad size for " #name "! Expected " #size ".") - /// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}". /// Referenced by multiple header files. typedef struct { @@ -93,4 +92,4 @@ typedef struct { NXDT_ASSERT(VersionType2, 0x4); -#endif /* __COMMON_H__ */ +#endif /* __NXDT_INCLUDES_H__ */ diff --git a/include/core/nxdt_utils.h b/include/core/nxdt_utils.h index 7960974..2b3beee 100644 --- a/include/core/nxdt_utils.h +++ b/include/core/nxdt_utils.h @@ -24,29 +24,15 @@ #ifndef __NXDT_UTILS_H__ #define __NXDT_UTILS_H__ -#include "common.h" +/* Included here for convenience. */ +#include "nxdt_includes.h" #ifdef __cplusplus extern "C" { #endif -#define APP_BASE_PATH "sdmc:/switch/" APP_TITLE "/" - -#define BIS_SYSTEM_PARTITION_MOUNT_NAME "sys:" - -#define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member) - -#define MAX_ELEMENTS(x) ((sizeof((x))) / (sizeof((x)[0]))) - -#define BIT_LONG(n) (1UL << (n)) - -#define ALIGN_UP(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) -#define ALIGN_DOWN(x, y) ((x) & ~((y) - 1)) -#define IS_ALIGNED(x, y) (((x) & ((y) - 1)) == 0) - -#define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0) - -#define SCOPED_LOCK(mtx) for(UtilsScopedLock scoped_lock __attribute__((__cleanup__(utilsUnlockScope))) = utilsLockScope(mtx); scoped_lock.cond; scoped_lock.cond = 0) +/* Scoped lock macro. */ +#define SCOPED_LOCK(mtx) for(UtilsScopedLock ANONYMOUS_VARIABLE(scoped_lock) __attribute__((__cleanup__(utilsUnlockScope))) = utilsLockScope(mtx); ANONYMOUS_VARIABLE(scoped_lock).cond; ANONYMOUS_VARIABLE(scoped_lock).cond = 0) /// Used by scoped locks. typedef struct { diff --git a/include/defines.h b/include/defines.h new file mode 100644 index 0000000..6218d2d --- /dev/null +++ b/include/defines.h @@ -0,0 +1,70 @@ +/* + * defines.h + * + * Copyright (c) 2020-2021, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool 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. + * + * nxdumptool 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 . + */ + +#pragma once + +#ifndef __DEFINES_H__ +#define __DEFINES_H__ + +/* Broadly useful language defines. */ + +#define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member) + +#define MAX_ELEMENTS(x) ((sizeof((x))) / (sizeof((x)[0]))) + +#define BIT_LONG(n) (1UL << (n)) + +#define ALIGN_UP(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) +#define ALIGN_DOWN(x, y) ((x) & ~((y) - 1)) +#define IS_ALIGNED(x, y) (((x) & ((y) - 1)) == 0) + +#define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0) + +#define CONCATENATE_IMPL(s1, s2) s1##s2 +#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2) + +#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__) + +#define NON_COPYABLE(cls) \ + cls(const cls&) = delete; \ + cls& operator=(const cls&) = delete + +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#define ALWAYS_INLINE_LAMBDA __attribute__((always_inline)) + +#define NXDT_ASSERT(name, size) static_assert(sizeof(name) == (size), "Bad size for " #name "! Expected " #size ".") + +/* Global constants used throughout the application. */ + +#define FS_SYSMODULE_TID (u64)0x0100000000000000 +#define BOOT_SYSMODULE_TID (u64)0x0100000000000005 +#define SPL_SYSMODULE_TID (u64)0x0100000000000028 +#define ES_SYSMODULE_TID (u64)0x0100000000000033 +#define SYSTEM_UPDATE_TID (u64)0x0100000000000816 + +#define FAT32_FILESIZE_LIMIT (u64)0xFFFFFFFF /* 4 GiB - 1 (4294967295 bytes). */ + +/* Path defines. */ + +#define APP_BASE_PATH "sdmc:/switch/" APP_TITLE "/" +#define BIS_SYSTEM_PARTITION_MOUNT_NAME "sys:" + +#endif /* __DEFINES_H__ */ diff --git a/include/scope_guard.hpp b/include/scope_guard.hpp new file mode 100644 index 0000000..c93ac4d --- /dev/null +++ b/include/scope_guard.hpp @@ -0,0 +1,80 @@ +/* + * scope_guard.hpp + * + * Copyright (c) 2020-2021, DarkMatterCore . + * Copyright (c) 2018-2021, SciresM. + * + * Scope guard logic lovingly taken from Andrei Alexandrescu's "Systemic Error Handling in C++". + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool 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. + * + * nxdumptool 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 . + */ + +#pragma once + +#ifndef __SCOPE_GUARD_HPP__ +#define __SCOPE_GUARD_HPP__ + +#include "defines.h" + +#define SCOPE_GUARD ::nxdt::utils::ScopeGuardOnExit() + [&]() ALWAYS_INLINE_LAMBDA +#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD + +namespace nxdt::utils { + template + class ScopeGuard { + NON_COPYABLE(ScopeGuard); + + private: + F f; + bool active; + + public: + constexpr ALWAYS_INLINE ScopeGuard(F f) : f(std::move(f)), active(true) {} + + constexpr ALWAYS_INLINE ~ScopeGuard() + { + if (active) f(); + } + + constexpr ALWAYS_INLINE void Cancel() + { + active = false; + } + + constexpr ALWAYS_INLINE ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) + { + rhs.Cancel(); + } + + ScopeGuard &operator=(ScopeGuard&& rhs) = delete; + }; + + template + constexpr ALWAYS_INLINE ScopeGuard MakeScopeGuard(F f) + { + return ScopeGuard(std::move(f)); + } + + enum class ScopeGuardOnExit {}; + + template + constexpr ALWAYS_INLINE ScopeGuard operator+(ScopeGuardOnExit, F&& f) + { + return ScopeGuard(std::forward(f)); + } +} + +#endif /* __SCOPE_GUARD_HPP__ */ diff --git a/libs/borealis b/libs/borealis index 595ee20..45a33d8 160000 --- a/libs/borealis +++ b/libs/borealis @@ -1 +1 @@ -Subproject commit 595ee205233322065bee12121e02cab5a80f70d6 +Subproject commit 45a33d8a2bdb81b53378a8c6dbff1b3d6cb83ebd diff --git a/romfs/i18n/en-US/main.json b/romfs/i18n/en-US/main.json index f265712..c398ccf 100644 --- a/romfs/i18n/en-US/main.json +++ b/romfs/i18n/en-US/main.json @@ -1,5 +1,5 @@ { - "name": "Borealis Example App", + "name": "{0}", "tabs": { "first": "First tab", "second": "Second tab", diff --git a/source/core/usb.c b/source/core/usb.c index 41c3716..548f9ee 100644 --- a/source/core/usb.c +++ b/source/core/usb.c @@ -666,7 +666,7 @@ static bool usbSendCommand(void) /* Write command header first. */ if (!usbWrite(cmd_header, sizeof(UsbCommandHeader))) { - LOG_MSG("Failed to write header for type 0x%X command!", cmd); + if (!g_usbDetectionThreadExitFlag) LOG_MSG("Failed to write header for type 0x%X command!", cmd); status = UsbStatusType_WriteCommandFailed; goto end; } @@ -1221,7 +1221,7 @@ static bool usbTransferData(void *buf, u64 size, UsbDsEndpoint *endpoint) /* If the USB session has already been established, then use a regular timeout value. */ rc = eventWait(&(endpoint->CompletionEvent), USB_TRANSFER_TIMEOUT * (u64)1000000000); } else { - /* If we're starting a USB session, wait indefinitely inside a loop to let the user start the companion app. */ + /* If we're starting a USB session, wait indefinitely inside a loop to let the user start the host script. */ int idx = 0; Waiter completion_event_waiter = waiterForEvent(&(endpoint->CompletionEvent)); Waiter exit_event_waiter = waiterForUEvent(&g_usbDetectionThreadExitEvent); diff --git a/source/main.cpp b/source/main.cpp index 2f8e733..80cbebf 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -44,11 +45,9 @@ std::vector NOTIFICATIONS = { int main(int argc, char* argv[]) { - if (!utilsInitializeResources(argc, (const char**)argv)) - { - utilsCloseResources(); - return EXIT_FAILURE; - } + ON_SCOPE_EXIT { utilsCloseResources(); }; + + if (!utilsInitializeResources(argc, (const char**)argv)) return EXIT_FAILURE; // Init the app brls::Logger::setLogLevel(brls::LogLevel::DEBUG); @@ -57,13 +56,12 @@ int main(int argc, char* argv[]) if (!brls::Application::init("main/name"_i18n)) { brls::Logger::error("Unable to init Borealis application"); - utilsCloseResources(); return EXIT_FAILURE; } // Create a sample view brls::TabFrame* rootFrame = new brls::TabFrame(); - rootFrame->setTitle("main/name"_i18n); + rootFrame->setTitle(i18n::getStr("main/name", APP_TITLE)); rootFrame->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg" )); brls::List* testList = new brls::List(); @@ -114,15 +112,6 @@ int main(int argc, char* argv[]) brls::ListItem* crashItem = new brls::ListItem("main/divide/title"_i18n, "main/divide/description"_i18n); crashItem->getClickEvent()->subscribe([](brls::View* view) { brls::Application::crash("main/divide/crash"_i18n); }); - brls::ListItem* popupItem = new brls::ListItem("popup/open"_i18n); - popupItem->getClickEvent()->subscribe([](brls::View* view) { - brls::TabFrame* popupTabFrame = new brls::TabFrame(); - popupTabFrame->addTab("popup/red"_i18n, new brls::Rectangle(nvgRGB(255, 0, 0))); - popupTabFrame->addTab("popup/green"_i18n, new brls::Rectangle(nvgRGB(0, 255, 0))); - popupTabFrame->addTab("popup/blue"_i18n, new brls::Rectangle(nvgRGB(0, 0, 255))); - brls::PopupFrame::open("popup/title"_i18n, BOREALIS_ASSET("icon/" APP_TITLE ".jpg"), popupTabFrame, "popup/subtitle/left"_i18n, "popup/subtitle/right"_i18n); - }); - brls::ListItem* installerItem = new brls::ListItem("installer/open"_i18n); installerItem->getClickEvent()->subscribe([](brls::View* view) { brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame(); @@ -135,6 +124,15 @@ int main(int argc, char* argv[]) brls::Application::pushView(stagedFrame); }); + brls::ListItem* popupItem = new brls::ListItem("popup/open"_i18n); + popupItem->getClickEvent()->subscribe([](brls::View* view) { + brls::TabFrame* popupTabFrame = new brls::TabFrame(); + popupTabFrame->addTab("popup/red"_i18n, new brls::Rectangle(nvgRGB(255, 0, 0))); + popupTabFrame->addTab("popup/green"_i18n, new brls::Rectangle(nvgRGB(0, 255, 0))); + popupTabFrame->addTab("popup/blue"_i18n, new brls::Rectangle(nvgRGB(0, 0, 255))); + brls::PopupFrame::open("popup/title"_i18n, BOREALIS_ASSET("icon/" APP_TITLE ".jpg"), popupTabFrame, "popup/subtitle/left"_i18n, "popup/subtitle/right"_i18n); + }); + brls::SelectListItem* layerSelectItem = new brls::SelectListItem("main/layers/title"_i18n, { "main/layers/layer1"_i18n, "main/layers/layer2"_i18n }); brls::InputListItem* keyboardItem = new brls::InputListItem("main/keyboard/string/title"_i18n, "main/keyboard/string/default"_i18n, "main/keyboard/string/help"_i18n, "", 16); @@ -199,8 +197,6 @@ int main(int argc, char* argv[]) // Run the app while (brls::Application::mainLoop()); - utilsCloseResources(); - // Exit return EXIT_SUCCESS; }