├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── Tinfoil.LICENSE ├── icon.jpg ├── include ├── data │ ├── buffered_placeholder_writer.hpp │ ├── byte_buffer.hpp │ └── byte_stream.hpp ├── install │ ├── hfs0.hpp │ ├── http_nsp.hpp │ ├── http_xci.hpp │ ├── install.hpp │ ├── install_nsp.hpp │ ├── install_xci.hpp │ ├── nca.hpp │ ├── nsp.hpp │ ├── pfs0.hpp │ ├── sdmc_nsp.hpp │ ├── sdmc_xci.hpp │ ├── simple_filesystem.hpp │ ├── usb_nsp.hpp │ ├── usb_xci.hpp │ └── xci.hpp ├── netInstall.hpp ├── nx │ ├── content_meta.hpp │ ├── fs.hpp │ ├── ipc │ │ ├── es.h │ │ ├── ns_ext.h │ │ └── tin_ipc.h │ ├── nca_writer.h │ └── ncm.hpp ├── sdInstall.hpp ├── sigInstall.hpp ├── ui │ ├── MainApplication.hpp │ ├── instPage.hpp │ ├── mainPage.hpp │ ├── netInstPage.hpp │ ├── optionsPage.hpp │ ├── sdInstPage.hpp │ └── usbInstPage.hpp ├── usbInstall.hpp └── util │ ├── config.hpp │ ├── crypto.hpp │ ├── curl.hpp │ ├── debug.h │ ├── error.hpp │ ├── file_util.hpp │ ├── json.hpp │ ├── lang.hpp │ ├── network_util.hpp │ ├── title_util.hpp │ ├── unzip.hpp │ ├── usb_comms_awoo.h │ ├── usb_util.hpp │ └── util.hpp ├── romfs ├── audio │ ├── awoo.wav │ └── bark.wav ├── images │ ├── awoos │ │ ├── 5bbdbcf9a5625cd307c9e9bc360d78bd.png │ │ ├── 7d8a05cddfef6da4901b20d2698d5a71.png │ │ └── a8cb40e465dadaf9708c9b1896777ce6.png │ ├── background.jpg │ ├── icons │ │ ├── check-box-outline.png │ │ ├── checkbox-blank-outline.png │ │ ├── cloud-download.png │ │ ├── exit-run.png │ │ ├── folder-upload.png │ │ ├── folder.png │ │ ├── lan-connection-waiting.png │ │ ├── micro-sd.png │ │ ├── settings.png │ │ ├── usb-connection-waiting.png │ │ ├── usb-port.png │ │ └── wrench.png │ └── logo.png └── lang │ ├── de.json │ ├── en.json │ ├── es-419.json │ ├── fr.json │ ├── it.json │ ├── jp.json │ ├── ko.json │ ├── pt.json │ ├── ru.json │ ├── zh-CN.json │ ├── zh-Hant.json │ └── zh-TW.json └── source ├── data ├── buffered_placeholder_writer.cpp ├── byte_buffer.cpp └── byte_stream.cpp ├── install ├── http_nsp.cpp ├── http_xci.cpp ├── install.cpp ├── install_nsp.cpp ├── install_xci.cpp ├── nsp.cpp ├── sdmc_nsp.cpp ├── sdmc_xci.cpp ├── simple_filesystem.cpp ├── usb_nsp.cpp ├── usb_xci.cpp └── xci.cpp ├── main.cpp ├── netInstall.cpp ├── nx ├── content_meta.cpp ├── fs.cpp ├── ipc │ ├── es.c │ └── ns_ext.c ├── nca_writer.cpp └── ncm.cpp ├── sdInstall.cpp ├── sigInstall.cpp ├── ui ├── MainApplication.cpp ├── instPage.cpp ├── mainPage.cpp ├── netInstPage.cpp ├── optionsPage.cpp ├── sdInstPage.cpp └── usbInstPage.cpp ├── usbInstall.cpp └── util ├── config.cpp ├── crypto.cpp ├── curl.cpp ├── debug.c ├── file_util.cpp ├── lang.cpp ├── network_util.cpp ├── title_util.cpp ├── unzip.cpp ├── usb_comms_awoo.c ├── usb_util.cpp └── util.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.elf 2 | *.nacp 3 | *.nro 4 | build 5 | .vscode 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "include/Plutonium"] 2 | path = include/Plutonium 3 | url = https://github.com/HookedBehemoth/Plutonium 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awoo Installer 2 | A No-Bullshit NSP, NSZ, XCI, and XCZ Installer for Nintendo Switch 3 | 4 | ![Awoo Installer Main Menu](https://i.imgur.com/q5Qff0R.jpg) 5 | 6 | ## Features 7 | - Installs NSP/NSZ/XCI/XCZ files and split NSP/XCI files from your SD card 8 | - Installs NSP/NSZ/XCI/XCZ files over LAN or USB from tools such as [NS-USBloader](https://github.com/developersu/ns-usbloader) 9 | - Installs NSP/NSZ/XCI/XCZ files over the internet by URL or Google Drive 10 | - Verifies NCAs by header signature before they're installed 11 | - Installs and manages the latest signature patches quickly and easily 12 | - Based on [Adubbz Tinfoil](https://github.com/Adubbz/Tinfoil) 13 | - Uses [XorTroll's Plutonium](https://github.com/XorTroll/Plutonium) for a pretty graphical interface 14 | - Just werks 15 | 16 | ## Why? 17 | Because Goldleaf tends to not "Just werk" when installing NSP files. I wanted a *free software* solution that installs, looks pretty, and doesn't make me rip my hair out whenever I want to put software on my Nintendo Switch. Awoo Installer does exactly that. It installs software. That's about it! 18 | 19 | If you want to do other things like manage installed tickets, titles, and user accounts, check out [Goldleaf](https://github.com/XorTroll/Goldleaf)! 20 | 21 | ## Thanks to 22 | - HookedBehemoth for A LOT of contributions 23 | - Adubbz and other contributors for [Tinfoil](https://github.com/Adubbz/Tinfoil) 24 | - XorTroll for [Plutonium](https://github.com/XorTroll/Plutonium) and [Goldleaf](https://github.com/XorTroll/Goldleaf) 25 | - blawar (wife strangulator) and nicoboss for [NSZ](https://github.com/nicoboss/nsz) support 26 | - The kind folks at the AtlasNX Discuck (or at least some of them) 27 | - The also kind folks at the RetroNX Discuck (of no direct involvement) 28 | - [namako8982](https://www.pixiv.net/member.php?id=14235616) for the Momiji art 29 | - TheXzoron for being a baka 30 | -------------------------------------------------------------------------------- /Tinfoil.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2018 Adubbz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/icon.jpg -------------------------------------------------------------------------------- /include/data/buffered_placeholder_writer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "nx/ncm.hpp" 30 | #include "nx/nca_writer.h" 31 | 32 | namespace tin::data 33 | { 34 | static const size_t BUFFER_SEGMENT_DATA_SIZE = 0x800000; // Approximately 8MB 35 | extern int NUM_BUFFER_SEGMENTS; 36 | 37 | struct BufferSegment 38 | { 39 | std::atomic_bool isFinalized = false; 40 | u64 writeOffset = 0; 41 | u8 data[BUFFER_SEGMENT_DATA_SIZE] = {0}; 42 | }; 43 | 44 | // Receives data in a circular buffer split into 8MB segments 45 | class BufferedPlaceholderWriter 46 | { 47 | private: 48 | size_t m_totalDataSize = 0; 49 | size_t m_sizeBuffered = 0; 50 | size_t m_sizeWrittenToPlaceholder = 0; 51 | 52 | // The current segment to which further data will be appended 53 | u64 m_currentFreeSegment = 0; 54 | BufferSegment* m_currentFreeSegmentPtr = NULL; 55 | // The current segment that will be written to the placeholder 56 | u64 m_currentSegmentToWrite = 0; 57 | BufferSegment* m_currentSegmentToWritePtr = NULL; 58 | 59 | std::unique_ptr m_bufferSegments; 60 | 61 | std::shared_ptr m_contentStorage; 62 | NcmContentId m_ncaId; 63 | NcaWriter m_writer; 64 | 65 | public: 66 | BufferedPlaceholderWriter(std::shared_ptr& contentStorage, NcmContentId ncaId, size_t totalDataSize); 67 | 68 | void AppendData(void* source, size_t length); 69 | bool CanAppendData(size_t length); 70 | 71 | void WriteSegmentToPlaceholder(); 72 | bool CanWriteSegmentToPlaceholder(); 73 | 74 | // Determine the number of segments required to fit data of this size 75 | u32 CalcNumSegmentsRequired(size_t size); 76 | 77 | // Check if there are enough free segments to fit data of this size 78 | bool IsSizeAvailable(size_t size); 79 | 80 | bool IsBufferDataComplete(); 81 | bool IsPlaceholderComplete(); 82 | 83 | size_t GetTotalDataSize(); 84 | size_t GetSizeBuffered(); 85 | size_t GetSizeWrittenToPlaceholder(); 86 | 87 | void DebugPrintBuffers(); 88 | }; 89 | } -------------------------------------------------------------------------------- /include/data/byte_buffer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace tin::data 30 | { 31 | class ByteBuffer 32 | { 33 | private: 34 | std::vector m_buffer; 35 | 36 | public: 37 | ByteBuffer(size_t reserveSize=0); 38 | 39 | size_t GetSize(); 40 | u8* GetData(); // TODO: Remove this, it shouldn't be needed 41 | void Resize(size_t size); 42 | 43 | void DebugPrintContents(); 44 | 45 | template 46 | T Read(u64 offset) 47 | { 48 | if (offset + sizeof(T) <= m_buffer.size()) 49 | return *((T*)&m_buffer.data()[offset]); 50 | 51 | T def; 52 | memset(&def, 0, sizeof(T)); 53 | return def; 54 | } 55 | 56 | template 57 | void Write(T data, u64 offset) 58 | { 59 | size_t requiredSize = offset + sizeof(T); 60 | 61 | if (requiredSize > m_buffer.size()) 62 | m_buffer.resize(requiredSize, 0); 63 | 64 | memcpy(m_buffer.data() + offset, &data, sizeof(T)); 65 | } 66 | template 67 | void Append(T data) 68 | { 69 | this->Write(data, this->GetSize()); 70 | } 71 | }; 72 | } -------------------------------------------------------------------------------- /include/data/byte_stream.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include "data/byte_buffer.hpp" 27 | 28 | namespace tin::data 29 | { 30 | class ByteStream 31 | { 32 | protected: 33 | u64 m_offset = 0; 34 | 35 | public: 36 | virtual void ReadBytes(void* dest, size_t length) = 0; 37 | }; 38 | 39 | // NOTE: This isn't generally useful, it's mainly for things like libpng 40 | // which rely on streams 41 | class BufferedByteStream : public ByteStream 42 | { 43 | private: 44 | ByteBuffer m_byteBuffer; 45 | 46 | public: 47 | BufferedByteStream(ByteBuffer buffer); 48 | 49 | void ReadBytes(void* dest, size_t length) override; 50 | }; 51 | } -------------------------------------------------------------------------------- /include/install/hfs0.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define MAGIC_HFS0 0x30534648 6 | 7 | namespace tin::install 8 | { 9 | struct HFS0FileEntry 10 | { 11 | u64 dataOffset; 12 | u64 fileSize; 13 | u32 stringTableOffset; 14 | u32 hashedSize; 15 | u64 padding; 16 | unsigned char hash[0x20]; 17 | } PACKED; 18 | 19 | static_assert(sizeof(HFS0FileEntry) == 0x40, "HFS0FileEntry must be 0x18"); 20 | 21 | struct HFS0BaseHeader 22 | { 23 | u32 magic; 24 | u32 numFiles; 25 | u32 stringTableSize; 26 | u32 reserved; 27 | } PACKED; 28 | 29 | static_assert(sizeof(HFS0BaseHeader) == 0x10, "HFS0BaseHeader must be 0x10"); 30 | 31 | NX_INLINE const HFS0FileEntry *hfs0GetFileEntry(const HFS0BaseHeader *header, u32 i) 32 | { 33 | if (i >= header->numFiles) 34 | return NULL; 35 | return (const HFS0FileEntry*)(header + 0x1 + i * 0x4); 36 | } 37 | 38 | NX_INLINE const char *hfs0GetStringTable(const HFS0BaseHeader *header) 39 | { 40 | return (const char*)(header + 0x1 + header->numFiles * 0x4); 41 | } 42 | 43 | NX_INLINE u64 hfs0GetHeaderSize(const HFS0BaseHeader *header) 44 | { 45 | return 0x1 + header->numFiles * 0x4 + header->stringTableSize; 46 | } 47 | 48 | NX_INLINE const char *hfs0GetFileName(const HFS0BaseHeader *header, u32 i) 49 | { 50 | return hfs0GetStringTable(header) + hfs0GetFileEntry(header, i)->stringTableOffset; 51 | } 52 | 53 | NX_INLINE const char *hfs0GetFileName(const HFS0BaseHeader *header, const HFS0FileEntry *entry) 54 | { 55 | return hfs0GetStringTable(header) + entry->stringTableOffset; 56 | } 57 | } -------------------------------------------------------------------------------- /include/install/http_nsp.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "install/nsp.hpp" 26 | #include 27 | 28 | namespace tin::install::nsp 29 | { 30 | class HTTPNSP : public NSP 31 | { 32 | public: 33 | tin::network::HTTPDownload m_download; 34 | 35 | HTTPNSP(std::string url); 36 | 37 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId placeholderId) override; 38 | virtual void BufferData(void* buf, off_t offset, size_t size) override; 39 | }; 40 | } -------------------------------------------------------------------------------- /include/install/http_xci.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "install/xci.hpp" 26 | #include "util/network_util.hpp" 27 | #include 28 | 29 | namespace tin::install::xci 30 | { 31 | class HTTPXCI : public XCI 32 | { 33 | public: 34 | tin::network::HTTPDownload m_download; 35 | 36 | HTTPXCI(std::string url); 37 | 38 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId placeholderId) override; 39 | virtual void BufferData(void* buf, off_t offset, size_t size) override; 40 | }; 41 | } -------------------------------------------------------------------------------- /include/install/install.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | extern "C" 26 | { 27 | #include 28 | } 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "install/simple_filesystem.hpp" 35 | #include "data/byte_buffer.hpp" 36 | 37 | #include "nx/content_meta.hpp" 38 | #include "nx/ipc/tin_ipc.h" 39 | 40 | namespace tin::install 41 | { 42 | class Install 43 | { 44 | protected: 45 | const NcmStorageId m_destStorageId; 46 | bool m_ignoreReqFirmVersion = false; 47 | bool m_declinedValidation = false; 48 | 49 | std::vector m_contentMeta; 50 | 51 | Install(NcmStorageId destStorageId, bool ignoreReqFirmVersion); 52 | 53 | virtual std::vector> ReadCNMT() = 0; 54 | 55 | virtual void InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf, int i); 56 | virtual void InstallApplicationRecord(int i); 57 | virtual void InstallTicketCert() = 0; 58 | virtual void InstallNCA(const NcmContentId &ncaId) = 0; 59 | 60 | public: 61 | virtual ~Install(); 62 | 63 | virtual void Prepare(); 64 | virtual void Begin(); 65 | 66 | virtual u64 GetTitleId(int i = 0); 67 | virtual NcmContentMetaType GetContentMetaType(int i = 0); 68 | }; 69 | } -------------------------------------------------------------------------------- /include/install/install_nsp.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include "install/install.hpp" 28 | #include "install/nsp.hpp" 29 | 30 | namespace tin::install::nsp 31 | { 32 | class NSPInstall : public Install 33 | { 34 | private: 35 | const std::shared_ptr m_NSP; 36 | 37 | protected: 38 | std::vector> ReadCNMT() override; 39 | void InstallNCA(const NcmContentId& ncaId) override; 40 | void InstallTicketCert() override; 41 | 42 | public: 43 | NSPInstall(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr& remoteNSP); 44 | }; 45 | } -------------------------------------------------------------------------------- /include/install/install_xci.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include "install/install.hpp" 27 | #include "install/xci.hpp" 28 | #include "nx/content_meta.hpp" 29 | #include "nx/ipc/tin_ipc.h" 30 | 31 | namespace tin::install::xci 32 | { 33 | class XCIInstallTask : public Install 34 | { 35 | private: 36 | const std::shared_ptr m_xci; 37 | 38 | protected: 39 | std::vector> ReadCNMT() override; 40 | void InstallNCA(const NcmContentId& ncaId) override; 41 | void InstallTicketCert() override; 42 | 43 | public: 44 | XCIInstallTask(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr& xci); 45 | }; 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /include/install/nca.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define NCA_HEADER_SIZE 0x4000 6 | #define MAGIC_NCA3 0x3341434E /* "NCA3" */ 7 | namespace tin::install 8 | { 9 | struct NcaFsHeader 10 | { 11 | u8 _0x0; 12 | u8 _0x1; 13 | u8 partition_type; 14 | u8 fs_type; 15 | u8 crypt_type; 16 | u8 _0x5[0x3]; 17 | u8 superblock_data[0x138]; 18 | /*union { 19 | pfs0_superblock_t pfs0_superblock; 20 | romfs_superblock_t romfs_superblock; 21 | //nca0_romfs_superblock_t nca0_romfs_superblock; 22 | bktr_superblock_t bktr_superblock; 23 | };*/ 24 | union { 25 | u64 section_ctr; 26 | struct { 27 | u32 section_ctr_low; 28 | u32 section_ctr_high; 29 | }; 30 | }; 31 | u8 _0x148[0xB8]; /* Padding. */ 32 | } PACKED; 33 | 34 | static_assert(sizeof(NcaFsHeader) == 0x200, "NcaFsHeader must be 0x200"); 35 | 36 | struct NcaSectionEntry 37 | { 38 | u32 media_start_offset; 39 | u32 media_end_offset; 40 | u8 _0x8[0x8]; /* Padding. */ 41 | } PACKED; 42 | 43 | static_assert(sizeof(NcaSectionEntry) == 0x10, "NcaSectionEntry must be 0x10"); 44 | 45 | struct NcaHeader 46 | { 47 | u8 fixed_key_sig[0x100]; /* RSA-PSS signature over header with fixed key. */ 48 | u8 npdm_key_sig[0x100]; /* RSA-PSS signature over header with key in NPDM. */ 49 | u32 magic; 50 | u8 distribution; /* System vs gamecard. */ 51 | u8 content_type; 52 | u8 m_cryptoType; /* Which keyblob (field 1) */ 53 | u8 m_kaekIndex; /* Which kaek index? */ 54 | u64 nca_size; /* Entire archive size. */ 55 | u64 m_titleId; 56 | u8 _0x218[0x4]; /* Padding. */ 57 | union { 58 | uint32_t sdk_version; /* What SDK was this built with? */ 59 | struct { 60 | u8 sdk_revision; 61 | u8 sdk_micro; 62 | u8 sdk_minor; 63 | u8 sdk_major; 64 | }; 65 | }; 66 | u8 m_cryptoType2; /* Which keyblob (field 2) */ 67 | u8 _0x221[0xF]; /* Padding. */ 68 | u64 m_rightsId[2]; /* Rights ID (for titlekey crypto). */ 69 | NcaSectionEntry section_entries[4]; /* Section entry metadata. */ 70 | u8 section_hashes[4 * 0x20]; /* SHA-256 hashes for each section header. */ 71 | u8 m_keys[4 * 0x10]; /* Encrypted key area. */ 72 | u8 _0x340[0xC0]; /* Padding. */ 73 | NcaFsHeader fs_headers[4]; /* FS section headers. */ 74 | } PACKED; 75 | 76 | static_assert(sizeof(NcaHeader) == 0xc00, "NcaHeader must be 0xc00"); 77 | } -------------------------------------------------------------------------------- /include/install/nsp.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include "install/pfs0.hpp" 30 | #include "nx/ncm.hpp" 31 | #include "util/network_util.hpp" 32 | 33 | namespace tin::install::nsp 34 | { 35 | class NSP 36 | { 37 | protected: 38 | std::vector m_headerBytes; 39 | 40 | NSP(); 41 | 42 | public: 43 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId placeholderId) = 0; 44 | virtual void BufferData(void* buf, off_t offset, size_t size) = 0; 45 | 46 | virtual void RetrieveHeader(); 47 | virtual const PFS0BaseHeader* GetBaseHeader(); 48 | virtual u64 GetDataOffset(); 49 | 50 | virtual const PFS0FileEntry* GetFileEntry(unsigned int index); 51 | virtual const PFS0FileEntry* GetFileEntryByName(std::string name); 52 | virtual const PFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId); 53 | virtual std::vector GetFileEntriesByExtension(std::string extension); 54 | 55 | virtual const char* GetFileEntryName(const PFS0FileEntry* fileEntry); 56 | }; 57 | } -------------------------------------------------------------------------------- /include/install/pfs0.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | namespace tin::install 28 | { 29 | struct PFS0FileEntry 30 | { 31 | u64 dataOffset; 32 | u64 fileSize; 33 | u32 stringTableOffset; 34 | u32 padding; 35 | } PACKED; 36 | 37 | static_assert(sizeof(PFS0FileEntry) == 0x18, "PFS0FileEntry must be 0x18"); 38 | 39 | struct PFS0BaseHeader 40 | { 41 | u32 magic; 42 | u32 numFiles; 43 | u32 stringTableSize; 44 | u32 reserved; 45 | } PACKED; 46 | 47 | static_assert(sizeof(PFS0BaseHeader) == 0x10, "PFS0BaseHeader must be 0x10"); 48 | } -------------------------------------------------------------------------------- /include/install/sdmc_nsp.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "install/nsp.hpp" 26 | 27 | namespace tin::install::nsp 28 | { 29 | class SDMCNSP : public NSP 30 | { 31 | public: 32 | SDMCNSP(std::string path); 33 | ~SDMCNSP(); 34 | 35 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId ncaId) override; 36 | virtual void BufferData(void* buf, off_t offset, size_t size) override; 37 | private: 38 | FILE* m_nspFile; 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /include/install/sdmc_xci.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "install/xci.hpp" 26 | 27 | namespace tin::install::xci 28 | { 29 | class SDMCXCI : public XCI 30 | { 31 | public: 32 | SDMCXCI(std::string path); 33 | ~SDMCXCI(); 34 | 35 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId ncaId) override; 36 | virtual void BufferData(void* buf, off_t offset, size_t size) override; 37 | private: 38 | FILE* m_xciFile; 39 | }; 40 | } -------------------------------------------------------------------------------- /include/install/simple_filesystem.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include "nx/fs.hpp" 27 | 28 | namespace tin::install::nsp 29 | { 30 | class SimpleFileSystem final 31 | { 32 | private: 33 | nx::fs::IFileSystem* m_fileSystem; 34 | 35 | public: 36 | const std::string m_rootPath; 37 | const std::string m_absoluteRootPath; 38 | 39 | SimpleFileSystem(nx::fs::IFileSystem& fileSystem, std::string rootPath, std::string absoluteRootPath); 40 | ~SimpleFileSystem(); 41 | 42 | nx::fs::IFile OpenFile(std::string path); 43 | bool HasFile(std::string path); 44 | std::string GetFileNameFromExtension(std::string path, std::string extension); 45 | }; 46 | } -------------------------------------------------------------------------------- /include/install/usb_nsp.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include "install/nsp.hpp" 27 | 28 | namespace tin::install::nsp 29 | { 30 | class USBNSP : public NSP 31 | { 32 | private: 33 | std::string m_nspName; 34 | 35 | public: 36 | USBNSP(std::string nspName); 37 | 38 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId placeholderId) override; 39 | virtual void BufferData(void* buf, off_t offset, size_t size) override; 40 | }; 41 | } -------------------------------------------------------------------------------- /include/install/usb_xci.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include "install/xci.hpp" 27 | 28 | namespace tin::install::xci 29 | { 30 | class USBXCI : public XCI 31 | { 32 | private: 33 | std::string m_xciName; 34 | 35 | public: 36 | USBXCI(std::string xciName); 37 | 38 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId placeholderId) override; 39 | virtual void BufferData(void* buf, off_t offset, size_t size) override; 40 | }; 41 | } -------------------------------------------------------------------------------- /include/install/xci.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include "install/hfs0.hpp" 30 | #include "nx/ncm.hpp" 31 | #include 32 | 33 | namespace tin::install::xci 34 | { 35 | class XCI 36 | { 37 | protected: 38 | u64 m_secureHeaderOffset; 39 | std::vector m_secureHeaderBytes; 40 | 41 | XCI(); 42 | 43 | public: 44 | virtual void StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId placeholderId) = 0; 45 | virtual void BufferData(void* buf, off_t offset, size_t size) = 0; 46 | 47 | virtual void RetrieveHeader(); 48 | virtual const HFS0BaseHeader* GetSecureHeader(); 49 | virtual u64 GetDataOffset(); 50 | 51 | virtual const HFS0FileEntry* GetFileEntry(unsigned int index); 52 | virtual const HFS0FileEntry* GetFileEntryByName(std::string name); 53 | virtual const HFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId); 54 | virtual std::vector GetFileEntriesByExtension(std::string extension); 55 | 56 | virtual const char* GetFileEntryName(const HFS0FileEntry* fileEntry); 57 | }; 58 | } -------------------------------------------------------------------------------- /include/netInstall.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | #include 23 | 24 | namespace netInstStuff { 25 | void OnUnwound(); 26 | void sendExitCommands(std::string url); 27 | void installTitleNet(std::vector ourUrlList, int ourStorage, std::vector urlListAltNames, std::string ourSource); 28 | std::vector OnSelected(); 29 | } -------------------------------------------------------------------------------- /include/nx/content_meta.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "data/byte_buffer.hpp" 30 | 31 | namespace nx::ncm 32 | { 33 | struct PackagedContentInfo 34 | { 35 | u8 hash[0x20]; 36 | NcmContentInfo content_info; 37 | } PACKED; 38 | 39 | struct PackagedContentMetaHeader 40 | { 41 | u64 title_id; 42 | u32 version; 43 | u8 type; 44 | u8 _0xd; 45 | u16 extended_header_size; 46 | u16 content_count; 47 | u16 content_meta_count; 48 | u8 attributes; 49 | u8 storage_id; 50 | u8 install_type; 51 | bool comitted; 52 | u32 required_system_version; 53 | u32 _0x1c; 54 | }; 55 | 56 | static_assert(sizeof(PackagedContentMetaHeader) == 0x20, "PackagedContentMetaHeader must be 0x20!"); 57 | 58 | class ContentMeta final 59 | { 60 | private: 61 | tin::data::ByteBuffer m_bytes; 62 | 63 | public: 64 | ContentMeta(); 65 | ContentMeta(u8* data, size_t size); 66 | 67 | PackagedContentMetaHeader GetPackagedContentMetaHeader(); 68 | NcmContentMetaKey GetContentMetaKey(); 69 | std::vector GetContentInfos(); 70 | 71 | void GetInstallContentMeta(tin::data::ByteBuffer& installContentMetaBuffer, NcmContentInfo& cnmtContentInfo, bool ignoreReqFirmVersion); 72 | }; 73 | } -------------------------------------------------------------------------------- /include/nx/fs.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | extern "C" 28 | { 29 | #include 30 | #include 31 | } 32 | 33 | #include "nx/ipc/tin_ipc.h" 34 | 35 | namespace nx::fs 36 | { 37 | class IFileSystem; 38 | 39 | class IFile 40 | { 41 | friend IFileSystem; 42 | 43 | private: 44 | FsFile m_file; 45 | 46 | IFile(FsFile& file); 47 | 48 | public: 49 | // Don't allow copying, or garbage may be closed by the destructor 50 | IFile& operator=(const IFile&) = delete; 51 | IFile(const IFile&) = delete; 52 | 53 | ~IFile(); 54 | 55 | void Read(u64 offset, void* buf, size_t size); 56 | s64 GetSize(); 57 | }; 58 | 59 | class IDirectory 60 | { 61 | friend IFileSystem; 62 | 63 | private: 64 | FsDir m_dir; 65 | 66 | IDirectory(FsDir& dir); 67 | 68 | public: 69 | // Don't allow copying, or garbage may be closed by the destructor 70 | IDirectory& operator=(const IDirectory&) = delete; 71 | IDirectory(const IDirectory&) = delete; 72 | 73 | ~IDirectory(); 74 | 75 | void Read(s64 inval, FsDirectoryEntry* buf, size_t numEntries); 76 | u64 GetEntryCount(); 77 | }; 78 | 79 | class IFileSystem 80 | { 81 | private: 82 | FsFileSystem m_fileSystem; 83 | 84 | public: 85 | // Don't allow copying, or garbage may be closed by the destructor 86 | IFileSystem& operator=(const IFileSystem&) = delete; 87 | IFileSystem(const IFileSystem&) = delete; 88 | 89 | IFileSystem(); 90 | ~IFileSystem(); 91 | 92 | Result OpenSdFileSystem(); 93 | void OpenFileSystemWithId(std::string path, FsFileSystemType fileSystemType, u64 titleId); 94 | void CloseFileSystem(); 95 | 96 | IFile OpenFile(std::string path); 97 | IDirectory OpenDirectory(std::string path, int flags); 98 | }; 99 | } -------------------------------------------------------------------------------- /include/nx/ipc/es.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | Result esInitialize(void); 28 | void esExit(void); 29 | 30 | Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize); 31 | -------------------------------------------------------------------------------- /include/nx/ipc/ns_ext.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | typedef enum { 29 | NsApplicationRecordType_Installed = 0x3, 30 | NsApplicationRecordType_GamecardMissing = 0x5, 31 | NsApplicationRecordType_Archived = 0xB, 32 | } NsApplicationRecordType; 33 | 34 | typedef struct { 35 | NcmContentMetaKey metaRecord; 36 | u64 storageId; 37 | } ContentStorageRecord; 38 | 39 | Result nsextInitialize(void); 40 | void nsextExit(void); 41 | 42 | Result nsPushApplicationRecord(u64 application_id, NsApplicationRecordType last_modified_event, ContentStorageRecord *content_records, u32 count); 43 | -------------------------------------------------------------------------------- /include/nx/ipc/tin_ipc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include "nx/ipc/es.h" 30 | #include "nx/ipc/ns_ext.h" 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /include/nx/nca_writer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | #include 25 | #include 26 | #include "nx/ncm.hpp" 27 | #include 28 | #include "install/nca.hpp" 29 | 30 | class NcaBodyWriter 31 | { 32 | public: 33 | NcaBodyWriter(const NcmContentId& ncaId, u64 offset, std::shared_ptr& contentStorage); 34 | virtual ~NcaBodyWriter(); 35 | virtual u64 write(const u8* ptr, u64 sz); 36 | 37 | bool isOpen() const; 38 | 39 | protected: 40 | std::shared_ptr m_contentStorage; 41 | NcmContentId m_ncaId; 42 | 43 | u64 m_offset; 44 | }; 45 | 46 | class NcaWriter 47 | { 48 | public: 49 | NcaWriter(const NcmContentId& ncaId, std::shared_ptr& contentStorage); 50 | virtual ~NcaWriter(); 51 | 52 | bool isOpen() const; 53 | bool close(); 54 | u64 write(const u8* ptr, u64 sz); 55 | void flushHeader(); 56 | 57 | protected: 58 | NcmContentId m_ncaId; 59 | std::shared_ptr m_contentStorage; 60 | std::vector m_buffer; 61 | std::shared_ptr m_writer; 62 | }; 63 | -------------------------------------------------------------------------------- /include/nx/ncm.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | extern "C" 28 | { 29 | #include 30 | #include 31 | } 32 | 33 | #include "nx/ipc/tin_ipc.h" 34 | 35 | namespace nx::ncm 36 | { 37 | class ContentStorage final 38 | { 39 | private: 40 | NcmContentStorage m_contentStorage; 41 | 42 | public: 43 | // Don't allow copying, or garbage may be closed by the destructor 44 | ContentStorage& operator=(const ContentStorage&) = delete; 45 | ContentStorage(const ContentStorage&) = delete; 46 | 47 | ContentStorage(NcmStorageId storageId); 48 | ~ContentStorage(); 49 | 50 | void CreatePlaceholder(const NcmContentId &placeholderId, const NcmPlaceHolderId ®isteredId, size_t size); 51 | void DeletePlaceholder(const NcmPlaceHolderId &placeholderId); 52 | void WritePlaceholder(const NcmPlaceHolderId &placeholderId, u64 offset, void *buffer, size_t bufSize); 53 | void Register(const NcmPlaceHolderId &placeholderId, const NcmContentId ®isteredId); 54 | void Delete(const NcmContentId ®isteredId); 55 | bool Has(const NcmContentId ®isteredId); 56 | std::string GetPath(const NcmContentId ®isteredId); 57 | }; 58 | } -------------------------------------------------------------------------------- /include/sdInstall.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | #include 25 | #include 26 | namespace nspInstStuff { 27 | void installNspFromFile(std::vector ourNspList, int whereToInstall); 28 | } 29 | -------------------------------------------------------------------------------- /include/sigInstall.hpp: -------------------------------------------------------------------------------- 1 | namespace sig { 2 | void installSigPatches (); 3 | } -------------------------------------------------------------------------------- /include/ui/MainApplication.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ui/mainPage.hpp" 4 | #include "ui/netInstPage.hpp" 5 | #include "ui/sdInstPage.hpp" 6 | #include "ui/usbInstPage.hpp" 7 | #include "ui/instPage.hpp" 8 | #include "ui/optionsPage.hpp" 9 | 10 | namespace inst::ui { 11 | class MainApplication : public pu::ui::Application { 12 | public: 13 | using Application::Application; 14 | PU_SMART_CTOR(MainApplication) 15 | void OnLoad() override; 16 | MainPage::Ref mainPage; 17 | netInstPage::Ref netinstPage; 18 | sdInstPage::Ref sdinstPage; 19 | usbInstPage::Ref usbinstPage; 20 | instPage::Ref instpage; 21 | optionsPage::Ref optionspage; 22 | }; 23 | } -------------------------------------------------------------------------------- /include/ui/instPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | using namespace pu::ui::elm; 5 | namespace inst::ui { 6 | class instPage : public pu::ui::Layout 7 | { 8 | public: 9 | instPage(); 10 | PU_SMART_CTOR(instPage) 11 | void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos); 12 | TextBlock::Ref pageInfoText; 13 | TextBlock::Ref installInfoText; 14 | pu::ui::elm::ProgressBar::Ref installBar; 15 | Image::Ref awooImage; 16 | Image::Ref titleImage; 17 | TextBlock::Ref appVersionText; 18 | static void setTopInstInfoText(std::string ourText); 19 | static void setInstInfoText(std::string ourText); 20 | static void setInstBarPerc(double ourPercent); 21 | static void loadMainMenu(); 22 | static void loadInstallScreen(); 23 | private: 24 | Rectangle::Ref infoRect; 25 | Rectangle::Ref topRect; 26 | }; 27 | } -------------------------------------------------------------------------------- /include/ui/mainPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | using namespace pu::ui::elm; 5 | namespace inst::ui { 6 | class MainPage : public pu::ui::Layout 7 | { 8 | public: 9 | MainPage(); 10 | PU_SMART_CTOR(MainPage) 11 | void installMenuItem_Click(); 12 | void netInstallMenuItem_Click(); 13 | void usbInstallMenuItem_Click(); 14 | void sigPatchesMenuItem_Click(); 15 | void settingsMenuItem_Click(); 16 | void exitMenuItem_Click(); 17 | void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos); 18 | Image::Ref awooImage; 19 | Image::Ref titleImage; 20 | TextBlock::Ref appVersionText; 21 | private: 22 | bool appletFinished; 23 | bool updateFinished; 24 | TextBlock::Ref butText; 25 | Rectangle::Ref topRect; 26 | Rectangle::Ref botRect; 27 | pu::ui::elm::Menu::Ref optionMenu; 28 | pu::ui::elm::MenuItem::Ref installMenuItem; 29 | pu::ui::elm::MenuItem::Ref netInstallMenuItem; 30 | pu::ui::elm::MenuItem::Ref usbInstallMenuItem; 31 | pu::ui::elm::MenuItem::Ref sigPatchesMenuItem; 32 | pu::ui::elm::MenuItem::Ref settingsMenuItem; 33 | pu::ui::elm::MenuItem::Ref exitMenuItem; 34 | Image::Ref eggImage; 35 | }; 36 | } -------------------------------------------------------------------------------- /include/ui/netInstPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | using namespace pu::ui::elm; 5 | namespace inst::ui { 6 | class netInstPage : public pu::ui::Layout 7 | { 8 | public: 9 | netInstPage(); 10 | PU_SMART_CTOR(netInstPage) 11 | void startInstall(bool urlMode); 12 | void startNetwork(); 13 | void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos); 14 | TextBlock::Ref pageInfoText; 15 | Image::Ref titleImage; 16 | TextBlock::Ref appVersionText; 17 | private: 18 | std::vector ourUrls; 19 | std::vector selectedUrls; 20 | std::vector alternativeNames; 21 | TextBlock::Ref butText; 22 | Rectangle::Ref topRect; 23 | Rectangle::Ref infoRect; 24 | Rectangle::Ref botRect; 25 | pu::ui::elm::Menu::Ref menu; 26 | Image::Ref infoImage; 27 | void drawMenuItems(bool clearItems); 28 | void selectTitle(int selectedIndex); 29 | }; 30 | } -------------------------------------------------------------------------------- /include/ui/optionsPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | using namespace pu::ui::elm; 5 | namespace inst::ui { 6 | class optionsPage : public pu::ui::Layout 7 | { 8 | public: 9 | optionsPage(); 10 | PU_SMART_CTOR(optionsPage) 11 | void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos); 12 | static void askToUpdate(std::vector updateInfo); 13 | Image::Ref titleImage; 14 | TextBlock::Ref appVersionText; 15 | private: 16 | TextBlock::Ref butText; 17 | Rectangle::Ref topRect; 18 | Rectangle::Ref infoRect; 19 | Rectangle::Ref botRect; 20 | TextBlock::Ref pageInfoText; 21 | pu::ui::elm::Menu::Ref menu; 22 | void setMenuText(); 23 | std::string getMenuOptionIcon(bool ourBool); 24 | std::string getMenuLanguage(int ourLangCode); 25 | }; 26 | } -------------------------------------------------------------------------------- /include/ui/sdInstPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | using namespace pu::ui::elm; 6 | namespace inst::ui { 7 | class sdInstPage : public pu::ui::Layout 8 | { 9 | public: 10 | sdInstPage(); 11 | PU_SMART_CTOR(sdInstPage) 12 | pu::ui::elm::Menu::Ref menu; 13 | void startInstall(); 14 | void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos); 15 | TextBlock::Ref pageInfoText; 16 | void drawMenuItems(bool clearItems, std::filesystem::path ourPath); 17 | Image::Ref titleImage; 18 | TextBlock::Ref appVersionText; 19 | private: 20 | std::vector ourDirectories; 21 | std::vector ourFiles; 22 | std::vector selectedTitles; 23 | std::filesystem::path currentDir; 24 | TextBlock::Ref butText; 25 | Rectangle::Ref topRect; 26 | Rectangle::Ref infoRect; 27 | Rectangle::Ref botRect; 28 | void followDirectory(); 29 | void selectNsp(int selectedIndex); 30 | }; 31 | } -------------------------------------------------------------------------------- /include/ui/usbInstPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | using namespace pu::ui::elm; 5 | namespace inst::ui { 6 | class usbInstPage : public pu::ui::Layout 7 | { 8 | public: 9 | usbInstPage(); 10 | PU_SMART_CTOR(usbInstPage) 11 | void startInstall(); 12 | void startUsb(); 13 | void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos); 14 | TextBlock::Ref pageInfoText; 15 | Image::Ref titleImage; 16 | TextBlock::Ref appVersionText; 17 | private: 18 | std::vector ourTitles; 19 | std::vector selectedTitles; 20 | std::string lastUrl; 21 | std::string lastFileID; 22 | TextBlock::Ref butText; 23 | Rectangle::Ref topRect; 24 | Rectangle::Ref infoRect; 25 | Rectangle::Ref botRect; 26 | pu::ui::elm::Menu::Ref menu; 27 | Image::Ref infoImage; 28 | void drawMenuItems(bool clearItems); 29 | void selectTitle(int selectedIndex); 30 | }; 31 | } -------------------------------------------------------------------------------- /include/usbInstall.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace usbInstStuff { 6 | std::vector OnSelected(); 7 | void installTitleUsb(std::vector ourNspList, int ourStorage); 8 | } -------------------------------------------------------------------------------- /include/util/config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace inst::config { 6 | static const std::string appDir = "sdmc:/switch/Awoo-Installer"; 7 | static const std::string configPath = appDir + "/config.json"; 8 | static const std::string appVersion = "1.3.5"; 9 | 10 | extern std::string gAuthKey; 11 | extern std::string sigPatchesUrl; 12 | extern std::string lastNetUrl; 13 | extern std::vector updateInfo; 14 | extern int languageSetting; 15 | extern bool ignoreReqVers; 16 | extern bool validateNCAs; 17 | extern bool overClock; 18 | extern bool deletePrompt; 19 | extern bool autoUpdate; 20 | extern bool gayMode; 21 | extern bool usbAck; 22 | 23 | void setConfig(); 24 | void parseConfig(); 25 | } -------------------------------------------------------------------------------- /include/util/crypto.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Crypto 7 | { 8 | #define RSA_2048_BYTES 0x100 9 | #define RSA_2048_BITS (RSA_2048_BYTES*8) 10 | static const unsigned char NCAHeaderSignature[0x100] = { /* Fixed RSA key used to validate NCA signature 0. */ 11 | 0xBF, 0xBE, 0x40, 0x6C, 0xF4, 0xA7, 0x80, 0xE9, 0xF0, 0x7D, 0x0C, 0x99, 0x61, 0x1D, 0x77, 0x2F, 12 | 0x96, 0xBC, 0x4B, 0x9E, 0x58, 0x38, 0x1B, 0x03, 0xAB, 0xB1, 0x75, 0x49, 0x9F, 0x2B, 0x4D, 0x58, 13 | 0x34, 0xB0, 0x05, 0xA3, 0x75, 0x22, 0xBE, 0x1A, 0x3F, 0x03, 0x73, 0xAC, 0x70, 0x68, 0xD1, 0x16, 14 | 0xB9, 0x04, 0x46, 0x5E, 0xB7, 0x07, 0x91, 0x2F, 0x07, 0x8B, 0x26, 0xDE, 0xF6, 0x00, 0x07, 0xB2, 15 | 0xB4, 0x51, 0xF8, 0x0D, 0x0A, 0x5E, 0x58, 0xAD, 0xEB, 0xBC, 0x9A, 0xD6, 0x49, 0xB9, 0x64, 0xEF, 16 | 0xA7, 0x82, 0xB5, 0xCF, 0x6D, 0x70, 0x13, 0xB0, 0x0F, 0x85, 0xF6, 0xA9, 0x08, 0xAA, 0x4D, 0x67, 17 | 0x66, 0x87, 0xFA, 0x89, 0xFF, 0x75, 0x90, 0x18, 0x1E, 0x6B, 0x3D, 0xE9, 0x8A, 0x68, 0xC9, 0x26, 18 | 0x04, 0xD9, 0x80, 0xCE, 0x3F, 0x5E, 0x92, 0xCE, 0x01, 0xFF, 0x06, 0x3B, 0xF2, 0xC1, 0xA9, 0x0C, 19 | 0xCE, 0x02, 0x6F, 0x16, 0xBC, 0x92, 0x42, 0x0A, 0x41, 0x64, 0xCD, 0x52, 0xB6, 0x34, 0x4D, 0xAE, 20 | 0xC0, 0x2E, 0xDE, 0xA4, 0xDF, 0x27, 0x68, 0x3C, 0xC1, 0xA0, 0x60, 0xAD, 0x43, 0xF3, 0xFC, 0x86, 21 | 0xC1, 0x3E, 0x6C, 0x46, 0xF7, 0x7C, 0x29, 0x9F, 0xFA, 0xFD, 0xF0, 0xE3, 0xCE, 0x64, 0xE7, 0x35, 22 | 0xF2, 0xF6, 0x56, 0x56, 0x6F, 0x6D, 0xF1, 0xE2, 0x42, 0xB0, 0x83, 0x40, 0xA5, 0xC3, 0x20, 0x2B, 23 | 0xCC, 0x9A, 0xAE, 0xCA, 0xED, 0x4D, 0x70, 0x30, 0xA8, 0x70, 0x1C, 0x70, 0xFD, 0x13, 0x63, 0x29, 24 | 0x02, 0x79, 0xEA, 0xD2, 0xA7, 0xAF, 0x35, 0x28, 0x32, 0x1C, 0x7B, 0xE6, 0x2F, 0x1A, 0xAA, 0x40, 25 | 0x7E, 0x32, 0x8C, 0x27, 0x42, 0xFE, 0x82, 0x78, 0xEC, 0x0D, 0xEB, 0xE6, 0x83, 0x4B, 0x6D, 0x81, 26 | 0x04, 0x40, 0x1A, 0x9E, 0x9A, 0x67, 0xF6, 0x72, 0x29, 0xFA, 0x04, 0xF0, 0x9D, 0xE4, 0xF4, 0x03 27 | }; 28 | 29 | class Keys 30 | { 31 | public: 32 | Keys() 33 | { 34 | u8 kek[0x10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 35 | 36 | splCryptoGenerateAesKek(headerKekSource, 0, 0, kek); 37 | splCryptoGenerateAesKey(kek, headerKeySource, headerKey); 38 | splCryptoGenerateAesKey(kek, headerKeySource + 0x10, headerKey + 0x10); 39 | } 40 | 41 | u8 headerKekSource[0x10] = { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A }; 42 | u8 headerKeySource[0x20] = { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2 }; 43 | 44 | u8 headerKey[0x20] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 45 | }; 46 | 47 | void calculateMGF1andXOR(unsigned char* data, size_t data_size, const void* source, size_t source_size); 48 | bool rsa2048PssVerify(const void *data, size_t len, const unsigned char *signature, const unsigned char *modulus); 49 | 50 | template 51 | T swapEndian(T s) 52 | { 53 | T result; 54 | u8* dest = (u8*)&result; 55 | u8* src = (u8*)&s; 56 | for (unsigned int i = 0; i < sizeof(s); i++) 57 | { 58 | dest[i] = src[sizeof(s) - i - 1]; 59 | } 60 | return result; 61 | } 62 | class AesCtr 63 | { 64 | public: 65 | AesCtr() : m_high(0), m_low(0) 66 | { 67 | } 68 | 69 | AesCtr(u64 iv) : m_high(swapEndian(iv)), m_low(0) 70 | { 71 | } 72 | 73 | u64& high() { return m_high; } 74 | u64& low() { return m_low; } 75 | private: 76 | u64 m_high; 77 | u64 m_low; 78 | }; 79 | 80 | 81 | class Aes128Ctr 82 | { 83 | public: 84 | Aes128Ctr(const u8* key, const AesCtr& iv) 85 | { 86 | counter = iv; 87 | aes128CtrContextCreate(&ctx, key, &iv); 88 | seek(0); 89 | } 90 | 91 | virtual ~Aes128Ctr() 92 | { 93 | } 94 | 95 | void seek(u64 offset) 96 | { 97 | counter.low() = swapEndian(offset >> 4); 98 | aes128CtrContextResetCtr(&ctx, &counter); 99 | } 100 | 101 | void encrypt(void *dst, const void *src, size_t l) 102 | { 103 | aes128CtrCrypt(&ctx, dst, src, l); 104 | } 105 | 106 | void decrypt(void *dst, const void *src, size_t l) 107 | { 108 | encrypt(dst, src, l); 109 | } 110 | protected: 111 | AesCtr counter; 112 | 113 | Aes128CtrContext ctx; 114 | }; 115 | 116 | class AesXtr 117 | { 118 | public: 119 | AesXtr(const u8* key, bool is_encryptor) 120 | { 121 | aes128XtsContextCreate(&ctx, key, key + 0x10, is_encryptor); 122 | } 123 | 124 | virtual ~AesXtr() 125 | { 126 | } 127 | 128 | void encrypt(void *dst, const void *src, size_t l, size_t sector, size_t sector_size) 129 | { 130 | for (size_t i = 0; i < l; i += sector_size) 131 | { 132 | aes128XtsContextResetSector(&ctx, sector++, true); 133 | aes128XtsEncrypt(&ctx, dst, src, sector_size); 134 | 135 | dst = (u8*)dst + sector_size; 136 | src = (const u8*)src + sector_size; 137 | } 138 | } 139 | 140 | void decrypt(void *dst, const void *src, size_t l, size_t sector, size_t sector_size) 141 | { 142 | for (size_t i = 0; i < l; i += sector_size) 143 | { 144 | aes128XtsContextResetSector(&ctx, sector++, true); 145 | aes128XtsDecrypt(&ctx, dst, src, sector_size); 146 | 147 | dst = (u8*)dst + sector_size; 148 | src = (const u8*)src + sector_size; 149 | } 150 | } 151 | protected: 152 | Aes128XtsContext ctx; 153 | }; 154 | } 155 | -------------------------------------------------------------------------------- /include/util/curl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace inst::curl { 5 | bool downloadFile(const std::string ourUrl, const char *pagefilename, long timeout = 5000, bool writeProgress = false); 6 | std::string downloadToBuffer (const std::string ourUrl, int firstRange = -1, int secondRange = -1, long timeout = 5000); 7 | } -------------------------------------------------------------------------------- /include/util/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include 30 | #include 31 | 32 | void printBytes(u8 *bytes, size_t size, bool includeHeader); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif -------------------------------------------------------------------------------- /include/util/error.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #define ASSERT_OK(res_expr, desc) \ 30 | ({ \ 31 | const auto tmp_rc = (res_expr); \ 32 | if (R_FAILED(tmp_rc)) { \ 33 | char msg[256] = {}; std::snprintf(msg, 256-1, "%s:%u: %s. Error code: 0x%08x\n", __func__, __LINE__, desc, tmp_rc); \ 34 | throw std::runtime_error(msg); \ 35 | } \ 36 | }) 37 | 38 | #define THROW_FORMAT(format, ...) \ 39 | ({ \ 40 | char error_prefix[512] = {}; std::snprintf(error_prefix, 256-1, "%s:%u: ", __func__, __LINE__); \ 41 | char formatted_msg[256] = {}; std::snprintf(formatted_msg, 256-1, format, ##__VA_ARGS__); \ 42 | std::strncat(error_prefix, formatted_msg, 512-1); throw std::runtime_error(error_prefix); \ 43 | }) 44 | 45 | 46 | #ifdef NXLINK_DEBUG 47 | #define LOG_DEBUG(format, ...) { std::printf("%s:%u: ", __func__, __LINE__); std::printf(format, ##__VA_ARGS__); } 48 | #else 49 | #define LOG_DEBUG(format, ...) ; 50 | #endif 51 | -------------------------------------------------------------------------------- /include/util/file_util.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "nx/content_meta.hpp" 30 | 31 | namespace tin::util 32 | { 33 | NcmContentInfo CreateNSPCNMTContentRecord(const std::string& nspPath); 34 | nx::ncm::ContentMeta GetContentMetaFromNCA(const std::string& ncaPath); 35 | std::vector GetNSPList(); 36 | } -------------------------------------------------------------------------------- /include/util/lang.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "json.hpp" 7 | 8 | using json = nlohmann::json; 9 | 10 | namespace Language { 11 | void Load(); 12 | std::string LanguageEntry(std::string key); 13 | std::string GetRandomMsg(); 14 | inline json GetRelativeJson(json j, std::string key) { 15 | std::istringstream ss(key); 16 | std::string token; 17 | 18 | while (std::getline(ss, token, '.') && j != nullptr) { 19 | j = j[token]; 20 | } 21 | 22 | return j; 23 | } 24 | } 25 | 26 | inline std::string operator ""_lang (const char* key, size_t size) { 27 | return Language::LanguageEntry(std::string(key, size)); 28 | } -------------------------------------------------------------------------------- /include/util/network_util.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | namespace tin::network 47 | { 48 | class HTTPHeader 49 | { 50 | private: 51 | std::string m_url; 52 | std::map m_values; 53 | 54 | static size_t ParseHTMLHeader(char* bytes, size_t size, size_t numItems, void* userData); 55 | 56 | public: 57 | HTTPHeader(std::string url); 58 | 59 | void PerformRequest(); 60 | 61 | bool HasValue(std::string key); 62 | std::string GetValue(std::string key); 63 | }; 64 | 65 | class HTTPDownload 66 | { 67 | private: 68 | std::string m_url; 69 | HTTPHeader m_header; 70 | bool m_rangesSupported = false; 71 | 72 | static size_t ParseHTMLData(char* bytes, size_t size, size_t numItems, void* userData); 73 | 74 | public: 75 | HTTPDownload(std::string url); 76 | 77 | void BufferDataRange(void* buffer, size_t offset, size_t size, std::function progressFunc); 78 | int StreamDataRange(size_t offset, size_t size, std::function streamFunc); 79 | }; 80 | 81 | void NSULDrop(std::string url); 82 | 83 | size_t WaitReceiveNetworkData(int sockfd, void* buf, size_t len); 84 | size_t WaitSendNetworkData(int sockfd, void* buf, size_t len); 85 | } -------------------------------------------------------------------------------- /include/util/title_util.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include "nx/content_meta.hpp" 28 | #include "nx/ipc/tin_ipc.h" 29 | 30 | namespace tin::util 31 | { 32 | u64 GetRightsIdTid(FsRightsId rightsId); 33 | u64 GetRightsIdKeyGen(FsRightsId rightsId); 34 | 35 | std::string GetNcaIdString(const NcmContentId& ncaId); 36 | NcmContentId GetNcaIdFromString(std::string ncaIdStr); 37 | 38 | u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType); 39 | std::string GetBaseTitleName(u64 baseTitleId); 40 | std::string GetTitleName(u64 titleId, NcmContentMetaType contentMetaType); 41 | } -------------------------------------------------------------------------------- /include/util/unzip.hpp: -------------------------------------------------------------------------------- 1 | namespace inst::zip { 2 | bool extractFile(const std::string filename, const std::string destination); 3 | } -------------------------------------------------------------------------------- /include/util/usb_comms_awoo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file usb_comms.h 3 | * @brief USB comms. 4 | * @author yellows8 5 | * @author plutoo 6 | * @copyright libnx Authors 7 | */ 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #pragma once 13 | #include "switch/types.h" 14 | 15 | typedef struct { 16 | u8 bInterfaceClass; 17 | u8 bInterfaceSubClass; 18 | u8 bInterfaceProtocol; 19 | } awoo_UsbCommsInterfaceInfo; 20 | 21 | /// Initializes usbComms with the default number of interfaces (1) 22 | Result awoo_usbCommsInitialize(void); 23 | 24 | /// Initializes usbComms with a specific number of interfaces. 25 | Result awoo_usbCommsInitializeEx(u32 num_interfaces, const awoo_UsbCommsInterfaceInfo *infos); 26 | 27 | /// Exits usbComms. 28 | void awoo_usbCommsExit(void); 29 | 30 | /// Sets whether to throw a fatal error in usbComms{Read/Write}* on failure, or just return the transferred size. By default (false) the latter is used. 31 | void awoo_usbCommsSetErrorHandling(bool flag); 32 | 33 | /// Read data with the default interface. 34 | size_t awoo_usbCommsRead(void* buffer, size_t size, u64 timeout); 35 | 36 | /// Write data with the default interface. 37 | size_t awoo_usbCommsWrite(const void* buffer, size_t size, u64 timeout); 38 | 39 | /// Same as usbCommsRead except with the specified interface. 40 | size_t awoo_usbCommsReadEx(void* buffer, size_t size, u32 interface, u64 timeout); 41 | 42 | /// Same as usbCommsWrite except with the specified interface. 43 | size_t awoo_usbCommsWriteEx(const void* buffer, size_t size, u32 interface, u64 timeout); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif -------------------------------------------------------------------------------- /include/util/usb_util.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | namespace tin::util 29 | { 30 | enum USBCmdType : u8 31 | { 32 | REQUEST = 0, 33 | RESPONSE = 1 34 | }; 35 | 36 | struct USBCmdHeader 37 | { 38 | u32 magic; 39 | USBCmdType type; 40 | u8 padding[0x3] = {0}; 41 | u32 cmdId; 42 | u64 dataSize; 43 | u8 reserved[0xC] = {0}; 44 | } PACKED; 45 | 46 | static_assert(sizeof(USBCmdHeader) == 0x20, "USBCmdHeader must be 0x20!"); 47 | 48 | class USBCmdManager 49 | { 50 | public: 51 | static void SendCmdHeader(u32 cmdId, size_t dataSize); 52 | 53 | static void SendExitCmd(); 54 | static USBCmdHeader SendFileRangeCmd(std::string nspName, u64 offset, u64 size); 55 | }; 56 | 57 | size_t USBRead(void* out, size_t len, u64 timeout = 5000000000); 58 | size_t USBWrite(const void* in, size_t len, u64 timeout = 5000000000); 59 | } -------------------------------------------------------------------------------- /include/util/util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace inst::util { 5 | void initApp (); 6 | void deinitApp (); 7 | void initInstallServices(); 8 | void deinitInstallServices(); 9 | bool ignoreCaseCompare(const std::string &a, const std::string &b); 10 | std::vector getDirectoryFiles(const std::string & dir, const std::vector & extensions); 11 | std::vector getDirsAtPath(const std::string & dir); 12 | bool removeDirectory(std::string dir); 13 | bool copyFile(std::string inFile, std::string outFile); 14 | std::string formatUrlString(std::string ourString); 15 | std::string formatUrlLink(std::string ourString); 16 | std::string shortenString(std::string ourString, int ourLength, bool isFile); 17 | std::string readTextFromFile(std::string ourFile); 18 | std::string softwareKeyboard(std::string guideText, std::string initialText, int LenMax); 19 | std::string getDriveFileName(std::string fileId); 20 | std::vector setClockSpeed(int deviceToClock, uint32_t clockSpeed); 21 | std::string getIPAddress(); 22 | bool usbIsConnected(); 23 | void playAudio(std::string audioPath); 24 | std::vector checkForAppUpdate(); 25 | } -------------------------------------------------------------------------------- /romfs/audio/awoo.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/audio/awoo.wav -------------------------------------------------------------------------------- /romfs/audio/bark.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/audio/bark.wav -------------------------------------------------------------------------------- /romfs/images/awoos/5bbdbcf9a5625cd307c9e9bc360d78bd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/awoos/5bbdbcf9a5625cd307c9e9bc360d78bd.png -------------------------------------------------------------------------------- /romfs/images/awoos/7d8a05cddfef6da4901b20d2698d5a71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/awoos/7d8a05cddfef6da4901b20d2698d5a71.png -------------------------------------------------------------------------------- /romfs/images/awoos/a8cb40e465dadaf9708c9b1896777ce6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/awoos/a8cb40e465dadaf9708c9b1896777ce6.png -------------------------------------------------------------------------------- /romfs/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/background.jpg -------------------------------------------------------------------------------- /romfs/images/icons/check-box-outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/check-box-outline.png -------------------------------------------------------------------------------- /romfs/images/icons/checkbox-blank-outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/checkbox-blank-outline.png -------------------------------------------------------------------------------- /romfs/images/icons/cloud-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/cloud-download.png -------------------------------------------------------------------------------- /romfs/images/icons/exit-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/exit-run.png -------------------------------------------------------------------------------- /romfs/images/icons/folder-upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/folder-upload.png -------------------------------------------------------------------------------- /romfs/images/icons/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/folder.png -------------------------------------------------------------------------------- /romfs/images/icons/lan-connection-waiting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/lan-connection-waiting.png -------------------------------------------------------------------------------- /romfs/images/icons/micro-sd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/micro-sd.png -------------------------------------------------------------------------------- /romfs/images/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/settings.png -------------------------------------------------------------------------------- /romfs/images/icons/usb-connection-waiting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/usb-connection-waiting.png -------------------------------------------------------------------------------- /romfs/images/icons/usb-port.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/usb-port.png -------------------------------------------------------------------------------- /romfs/images/icons/wrench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/icons/wrench.png -------------------------------------------------------------------------------- /romfs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huntereb/Awoo-Installer/b9304c85798991fb3a7f20c713b247535e2dc9e1/romfs/images/logo.png -------------------------------------------------------------------------------- /romfs/lang/zh-TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "main":{ 3 | "menu": { 4 | "sd": "通過SD卡安裝", 5 | "net": "通過網路安裝", 6 | "usb": "通過USB安裝", 7 | "sig": "管理簽名補丁(signature patches)", 8 | "set": "設置", 9 | "exit": "退出" 10 | }, 11 | "net": { 12 | "title": "連接錯誤", 13 | "desc": "請確認關閉飛行模式,並確保網路連接暢通。" 14 | }, 15 | "usb": { 16 | "warn": { 17 | "title": "警告!", 18 | "desc": "USB安裝方式不一定能“正常工作”。\n如果您不幸遇到這樣的情況,那就用力扯自己的頭髮吧!\n推薦在PC端使用NS-USBloader配合安裝。\n還是不行就通過網路安裝吧...", 19 | "opt1": "不再對此進行警告" 20 | }, 21 | "error": { 22 | "title": "USB未連接", 23 | "desc": "請通過USB線連接您的遠程設備" 24 | } 25 | }, 26 | "applet": { 27 | "title": "不支援Applet模式", 28 | "desc": "您可以嘗試在“Applet模式”下使用本程式,但如果出現問題請切換到“非Applet模式”再運行。\n切換方法:\n 退回系統桌面選中任意一個遊戲,按住\ue0e5後點\ue0e0進入遊戲,直到跳回hbmenu界面再鬆開按鈕!\n然後再選擇Awoo Installer,屆時將不會彈出此對話框!" 29 | }, 30 | "buttons": "\ue0e0 選擇 \ue0e1 退出" 31 | }, 32 | 33 | "inst": { 34 | "net": { 35 | "help": { 36 | "title": "幫助", 37 | "desc": "文件可以通過NS-USBloader遠程安裝。\n也可以選擇輸入URL地址安裝。\n如果您的遠程工具對某種文件格式不支援,您可以嘗試修改文件的擴展名再選擇它,安裝的時候Awoo並不在意擴展名!\n如果還是搞不懂,那就使用SD卡安裝方式吧!" 38 | }, 39 | "src": { 40 | "title": "您想要通過哪種方式安裝", 41 | "opt0": "URL", 42 | "opt1": "谷歌網盤(Google Drive)" 43 | }, 44 | "url": { 45 | "hint": "輸入文件的URL地址", 46 | "invalid": "URL地址無效!", 47 | "source_string": " 通過URL" 48 | }, 49 | "gdrive": { 50 | "hint": "請輸入一個谷歌網盤文件的ID", 51 | "alt_name": "谷歌網盤文件", 52 | "source_string": " 從谷歌網盤" 53 | }, 54 | "top_info": "選擇您要安裝的文件,然後按下 \ue0ef 號", 55 | "top_info1": "等待連接中... 您的Switch主機IP是: ", 56 | "failed": "遠程安裝失敗!", 57 | "transfer_interput": "傳輸過程中產生了一個錯誤,請您檢查網路連接是否正常!", 58 | "source_string": " 通過局域網安裝", 59 | "buttons": "\ue0e3 通過Internet \ue0e2 幫助 \ue0e1 取消", 60 | "buttons1": "\ue0e0 選擇文件 \ue0e3 全選 \ue0ef 安裝選中的文件 \ue0e1 返回" 61 | }, 62 | "sd": { 63 | "help": { 64 | "title": "幫助", 65 | "desc": "複製您的 NSP, NSZ, XCI, XCZ 文件到SD卡, \n選擇想要安裝的文件,然後按 \ue0ef 安裝!" 66 | }, 67 | "top_info": "選擇想要安裝的文件,然後按 \ue0ef 安裝!", 68 | "source_string": " 從SD卡", 69 | "delete_info": " 安裝完成!要將原文件從SD卡刪除嗎?", 70 | "delete_info_multi": " 所有文件已安裝!要把所有原文件從SD卡刪除嗎?", 71 | "delete_desc": "安裝成功後已經不需要原文件。", 72 | "buttons": "\ue0e0 選擇文件 \ue0e3 全選 \ue0ef 安裝 \ue0e2 幫助 \ue0e1 取消" 73 | }, 74 | "usb": { 75 | "help": { 76 | "title": "幫助", 77 | "desc": "文件可以通過NS-USBloader遠程安裝。\n也可以選擇輸入URL地址安裝。\n如果您的遠程工具對某種文件格式不支援,您可以嘗試修改文件的擴展名再選擇它,安裝的時候Awoo並不在意擴展名!\n如果還是搞不懂,那就使用SD卡安裝方式吧!" 78 | }, 79 | "top_info": "USB連接成功! 正在接收文件列表...", 80 | "top_info2": "選擇您想通過USB安裝的文件, 然後按 \ue0ef 安裝", 81 | "error": "USB傳輸超時...", 82 | "source_string": " 通過USB", 83 | "buttons": "\ue0e2 (按住) 幫助 \ue0e1 (按住) 取消", 84 | "buttons2": "\ue0e0 選擇文件 \ue0e3 全選 \ue0ef 安裝文件 \ue0e1 取消" 85 | }, 86 | "target": { 87 | "desc0": "將 ", 88 | "desc1": " 安裝到哪?", 89 | "desc00": "將已選擇的 ", 90 | "desc01": " 文件安裝到哪?", 91 | "opt0": "SD卡", 92 | "opt1": "內部閃存" 93 | }, 94 | "info_page": { 95 | "top_info0": "正在安裝 ", 96 | "preparing": "初始化安裝...", 97 | "failed": "安裝失敗 ", 98 | "failed_desc": "可以從系統設置中刪除部分安裝的內容。", 99 | "complete": "安裝完成", 100 | "desc0": " 安裝成功!", 101 | "desc1": " 已安裝!", 102 | "downloading": "下載中 ", 103 | "at": " 在 " 104 | }, 105 | "nca_verify": { 106 | "title": "無效的 NCA 簽名!", 107 | "desc": "簽名不正確的文件只能自己評估可靠性。\n重新打包的文件或DLC通常會報這樣的警告。 您可以通過設置選項忽略這些警告。\n您確定要繼續安裝嗎?", 108 | "opt1": "是的,我知道風險在哪", 109 | "error": "NCA沒有正確簽名: " 110 | }, 111 | "finished": [ 112 | "享受您的“合法版本”吧!", 113 | "我敢保證當您玩過之後,更有興趣購買正版遊戲!", 114 | "您會買這遊戲的,對吧?任天堂感謝您!", 115 | "繞過DRM很棒,不是嗎?", 116 | "粗來混,早晚要還的!", 117 | "任天堂已經對您派遣了忍者", 118 | "您甚至不需要相信民主自由就能拿到這樣的好處了..." 119 | ] 120 | }, 121 | "sig": { 122 | "install": "安裝", 123 | "uninstall": "卸載", 124 | "update": "更新", 125 | "version_text": "您目前已安裝適用於HOS版本的簽名補丁 ", 126 | "title0": "安裝簽名補丁?", 127 | "desc0": "官方軟件需要安裝簽名補丁。", 128 | "backup_failed": "不能備份Hekate的patches.ini! 繼續安裝?", 129 | "backup_failed_desc": "如果您沒在用Hekate的話,可以忽略這個警告!", 130 | "download_failed": "無法下載簽名補丁", 131 | "download_failed_desc": "您可能在設置中提供了無效的來源,\n或者服務器正好掛了。", 132 | "version_text2": "簽名補丁已更新 ", 133 | "install_complete": "安裝完成!", 134 | "complete_desc": "需要重啟您的主機", 135 | "restart": "立即重啟", 136 | "later": "稍後重啟", 137 | "extract_failed": "無法解壓文件!", 138 | "restore_failed": "不能回復原Hekate的patches.ini!要繼續卸載嗎?", 139 | "uninstall_complete": "卸載完成", 140 | "remove_failed": "無法刪除簽名補丁", 141 | "remove_failed_desc": "文件已經被重命名或刪除", 142 | "generic_error": "安裝簽名補丁失敗!" 143 | }, 144 | "options": { 145 | "menu_items": { 146 | "ignore_firm": "忽略固件版本要求", 147 | "nca_verify": "安裝前驗證NCA簽名", 148 | "boost_mode": "安裝過程中開啟“超頻”模式", 149 | "ask_delete": "安裝後詢問是否刪除原文件", 150 | "auto_update": "自動更新", 151 | "gay_option": "基友模式", 152 | "sig_url": "簽名補丁來源URL: ", 153 | "language": "語言: ", 154 | "check_update": "檢測更新", 155 | "credits": "致谢" 156 | }, 157 | "nca_warn": { 158 | "title": "警告!", 159 | "desc": "有些可安裝文件可能存在木馬!\n您要非常信任這個文件才能關閉此驗證\n您是否確定要關閉NCA簽名驗證?", 160 | "opt1": "是的,我不怕Switch變磚!" 161 | }, 162 | "sig_hint": "輸入獲取簽名補丁的URL", 163 | "update": { 164 | "title": "有新版本可以更新", 165 | "desc0": "Awoo Installer ", 166 | "desc1": " 新的更新! 要繼續嗎?", 167 | "opt0": "更新", 168 | "top_info": "正在更新 ...", 169 | "bot_info": "正在下載 ...", 170 | "bot_info2": "正在解壓 ...", 171 | "complete": "更新完成!", 172 | "failed": "更新失敗!", 173 | "end_desc": "本程式將關閉!", 174 | "title_check_fail": "找不到更新", 175 | "desc_check_fail": "已更新到最新版!" 176 | }, 177 | "credits": { 178 | "title": "感謝下列人士", 179 | "desc": "- 來自HookedBehemoth 的巨大貢獻\n- Adubbz 以及其他為Tinfoil貢獻過的人\n- XorTroll 強大的Plutonium庫和金葉子工具\n- blawar (wife strangulator)和nicoboss 對NSZ 格式的支持\n- 來自AtlasNX Discuck的好心人 (至少其中一部分)\n- 來自RetroNX Discuck的好心人 (雖然沒直接參與)\n- 來自namako8982的Momiji美術\n- 也特別感謝TheXzoron" 180 | }, 181 | "language": { 182 | "title": "選擇語言", 183 | "desc": "更改語言後本程式將關閉,請重新打開, 或按 \ue0e1 返回。", 184 | "system_language": "系統默認" 185 | }, 186 | "title": "更改 Awoo 安裝器的設置!", 187 | "buttons": "\ue0e0 選擇/更改 \ue0e1 取消" 188 | }, 189 | "common": { 190 | "ok": "確定", 191 | "cancel": "取消", 192 | "close": "關閉", 193 | "yes": "是", 194 | "no": "否", 195 | "cancel_desc": "按 \ue0e1 取消" 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /source/data/byte_buffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "data/byte_buffer.hpp" 24 | 25 | #include "util/error.hpp" 26 | #include "util/debug.h" 27 | 28 | namespace tin::data 29 | { 30 | ByteBuffer::ByteBuffer(size_t reserveSize) 31 | { 32 | m_buffer.resize(reserveSize); 33 | } 34 | 35 | size_t ByteBuffer::GetSize() 36 | { 37 | return m_buffer.size(); 38 | } 39 | 40 | u8* ByteBuffer::GetData() 41 | { 42 | return m_buffer.data(); 43 | } 44 | 45 | void ByteBuffer::Resize(size_t size) 46 | { 47 | m_buffer.resize(size, 0); 48 | } 49 | 50 | void ByteBuffer::DebugPrintContents() 51 | { 52 | LOG_DEBUG("Buffer Size: 0x%lx\n", this->GetSize()); 53 | printBytes(this->GetData(), this->GetSize(), true); 54 | } 55 | } -------------------------------------------------------------------------------- /source/data/byte_stream.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "data/byte_stream.hpp" 24 | 25 | namespace tin::data 26 | { 27 | BufferedByteStream::BufferedByteStream(ByteBuffer buffer) : 28 | m_byteBuffer(buffer) 29 | { 30 | 31 | } 32 | 33 | void BufferedByteStream::ReadBytes(void* dest, size_t length) 34 | { 35 | if (m_offset + length > m_byteBuffer.GetSize()) 36 | return; 37 | 38 | memcpy(dest, m_byteBuffer.GetData() + m_offset, length); 39 | m_offset += length; 40 | } 41 | } -------------------------------------------------------------------------------- /source/install/http_nsp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "install/http_nsp.hpp" 24 | 25 | #include 26 | #include 27 | #include "data/buffered_placeholder_writer.hpp" 28 | #include "util/title_util.hpp" 29 | #include "util/error.hpp" 30 | #include "util/debug.h" 31 | #include "util/util.hpp" 32 | #include "util/lang.hpp" 33 | #include "ui/instPage.hpp" 34 | 35 | namespace tin::install::nsp 36 | { 37 | bool stopThreadsHttpNsp; 38 | 39 | HTTPNSP::HTTPNSP(std::string url) : 40 | m_download(url) 41 | { 42 | 43 | } 44 | 45 | struct StreamFuncArgs 46 | { 47 | tin::network::HTTPDownload* download; 48 | tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter; 49 | u64 pfs0Offset; 50 | u64 ncaSize; 51 | }; 52 | 53 | int CurlStreamFunc(void* in) 54 | { 55 | StreamFuncArgs* args = reinterpret_cast(in); 56 | 57 | auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t 58 | { 59 | while (true) 60 | { 61 | if (args->bufferedPlaceholderWriter->CanAppendData(streamBufSize)) 62 | break; 63 | } 64 | 65 | args->bufferedPlaceholderWriter->AppendData(streamBuf, streamBufSize); 66 | return streamBufSize; 67 | }; 68 | 69 | if (args->download->StreamDataRange(args->pfs0Offset, args->ncaSize, streamFunc) == 1) stopThreadsHttpNsp = true; 70 | return 0; 71 | } 72 | 73 | int PlaceholderWriteFunc(void* in) 74 | { 75 | StreamFuncArgs* args = reinterpret_cast(in); 76 | 77 | while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsHttpNsp) 78 | { 79 | if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder()) 80 | args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder(); 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | void HTTPNSP::StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId placeholderId) 87 | { 88 | const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId); 89 | std::string ncaFileName = this->GetFileEntryName(fileEntry); 90 | 91 | LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str()); 92 | size_t ncaSize = fileEntry->fileSize; 93 | 94 | tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize); 95 | StreamFuncArgs args; 96 | args.download = &m_download; 97 | args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter; 98 | args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset; 99 | args.ncaSize = ncaSize; 100 | thrd_t curlThread; 101 | thrd_t writeThread; 102 | 103 | stopThreadsHttpNsp = false; 104 | thrd_create(&curlThread, CurlStreamFunc, &args); 105 | thrd_create(&writeThread, PlaceholderWriteFunc, &args); 106 | 107 | u64 freq = armGetSystemTickFreq(); 108 | u64 startTime = armGetSystemTick(); 109 | size_t startSizeBuffered = 0; 110 | double speed = 0.0; 111 | 112 | inst::ui::instPage::setInstBarPerc(0); 113 | while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsHttpNsp) 114 | { 115 | u64 newTime = armGetSystemTick(); 116 | 117 | if (newTime - startTime >= freq * 0.5) 118 | { 119 | size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered(); 120 | double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0); 121 | double duration = ((double)(newTime - startTime) / (double)freq); 122 | speed = mbBuffered / duration; 123 | 124 | startTime = newTime; 125 | startSizeBuffered = newSizeBuffered; 126 | 127 | int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0); 128 | 129 | inst::ui::instPage::setInstInfoText("inst.info_page.downloading"_lang + inst::util::formatUrlString(ncaFileName) + "inst.info_page.at"_lang + std::to_string(speed).substr(0, std::to_string(speed).size()-4) + "MB/s"); 130 | inst::ui::instPage::setInstBarPerc((double)downloadProgress); 131 | } 132 | } 133 | inst::ui::instPage::setInstBarPerc(100); 134 | 135 | inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "..."); 136 | inst::ui::instPage::setInstBarPerc(0); 137 | while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsHttpNsp) 138 | { 139 | int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0); 140 | 141 | inst::ui::instPage::setInstBarPerc((double)installProgress); 142 | } 143 | inst::ui::instPage::setInstBarPerc(100); 144 | 145 | thrd_join(curlThread, NULL); 146 | thrd_join(writeThread, NULL); 147 | if (stopThreadsHttpNsp) THROW_FORMAT(("inst.net.transfer_interput"_lang).c_str()); 148 | } 149 | 150 | void HTTPNSP::BufferData(void* buf, off_t offset, size_t size) 151 | { 152 | m_download.BufferDataRange(buf, offset, size, nullptr); 153 | } 154 | } -------------------------------------------------------------------------------- /source/install/http_xci.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "install/http_xci.hpp" 24 | 25 | #include 26 | #include "data/buffered_placeholder_writer.hpp" 27 | #include "util/error.hpp" 28 | #include "util/util.hpp" 29 | #include "util/lang.hpp" 30 | #include "ui/instPage.hpp" 31 | 32 | namespace tin::install::xci 33 | { 34 | bool stopThreadsHttpXci; 35 | 36 | HTTPXCI::HTTPXCI(std::string url) : 37 | m_download(url) 38 | { 39 | 40 | } 41 | 42 | struct StreamFuncArgs 43 | { 44 | tin::network::HTTPDownload* download; 45 | tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter; 46 | u64 pfs0Offset; 47 | u64 ncaSize; 48 | }; 49 | 50 | int CurlStreamFunc(void* in) 51 | { 52 | StreamFuncArgs* args = reinterpret_cast(in); 53 | 54 | auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t 55 | { 56 | while (true) 57 | { 58 | if (args->bufferedPlaceholderWriter->CanAppendData(streamBufSize)) 59 | break; 60 | } 61 | 62 | args->bufferedPlaceholderWriter->AppendData(streamBuf, streamBufSize); 63 | return streamBufSize; 64 | }; 65 | 66 | if (args->download->StreamDataRange(args->pfs0Offset, args->ncaSize, streamFunc) == 1) stopThreadsHttpXci = true; 67 | return 0; 68 | } 69 | 70 | int PlaceholderWriteFunc(void* in) 71 | { 72 | StreamFuncArgs* args = reinterpret_cast(in); 73 | 74 | while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsHttpXci) 75 | { 76 | if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder()) 77 | args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder(); 78 | } 79 | 80 | return 0; 81 | } 82 | 83 | void HTTPXCI::StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId ncaId) 84 | { 85 | const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId); 86 | std::string ncaFileName = this->GetFileEntryName(fileEntry); 87 | 88 | LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str()); 89 | size_t ncaSize = fileEntry->fileSize; 90 | 91 | tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, ncaId, ncaSize); 92 | StreamFuncArgs args; 93 | args.download = &m_download; 94 | args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter; 95 | args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset; 96 | args.ncaSize = ncaSize; 97 | thrd_t curlThread; 98 | thrd_t writeThread; 99 | 100 | stopThreadsHttpXci = false; 101 | thrd_create(&curlThread, CurlStreamFunc, &args); 102 | thrd_create(&writeThread, PlaceholderWriteFunc, &args); 103 | 104 | u64 freq = armGetSystemTickFreq(); 105 | u64 startTime = armGetSystemTick(); 106 | size_t startSizeBuffered = 0; 107 | double speed = 0.0; 108 | 109 | inst::ui::instPage::setInstBarPerc(0); 110 | while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsHttpXci) 111 | { 112 | u64 newTime = armGetSystemTick(); 113 | 114 | if (newTime - startTime >= freq * 0.5) 115 | { 116 | size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered(); 117 | double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0); 118 | double duration = ((double)(newTime - startTime) / (double)freq); 119 | speed = mbBuffered / duration; 120 | 121 | startTime = newTime; 122 | startSizeBuffered = newSizeBuffered; 123 | int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0); 124 | #ifdef NXLINK_DEBUG 125 | u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000; 126 | u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000; 127 | LOG_DEBUG("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed); 128 | #endif 129 | 130 | inst::ui::instPage::setInstInfoText("inst.info_page.downloading"_lang + inst::util::formatUrlString(ncaFileName) + "inst.info_page.at"_lang + std::to_string(speed).substr(0, std::to_string(speed).size()-4) + "MB/s"); 131 | inst::ui::instPage::setInstBarPerc((double)downloadProgress); 132 | } 133 | } 134 | inst::ui::instPage::setInstBarPerc(100); 135 | 136 | #ifdef NXLINK_DEBUG 137 | u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000; 138 | #endif 139 | 140 | inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "..."); 141 | inst::ui::instPage::setInstBarPerc(0); 142 | while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsHttpXci) 143 | { 144 | int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0); 145 | #ifdef NXLINK_DEBUG 146 | u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000; 147 | LOG_DEBUG("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%"); 148 | #endif 149 | inst::ui::instPage::setInstBarPerc((double)installProgress); 150 | } 151 | inst::ui::instPage::setInstBarPerc(100); 152 | 153 | thrd_join(curlThread, NULL); 154 | thrd_join(writeThread, NULL); 155 | if (stopThreadsHttpXci) THROW_FORMAT(("inst.net.transfer_interput"_lang).c_str()); 156 | } 157 | 158 | void HTTPXCI::BufferData(void* buf, off_t offset, size_t size) 159 | { 160 | m_download.BufferDataRange(buf, offset, size, nullptr); 161 | } 162 | } -------------------------------------------------------------------------------- /source/install/install.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "install/install.hpp" 24 | 25 | #include 26 | #include 27 | #include 28 | #include "util/error.hpp" 29 | 30 | #include "nx/ncm.hpp" 31 | #include "util/title_util.hpp" 32 | 33 | 34 | // TODO: Check NCA files are present 35 | // TODO: Check tik/cert is present 36 | namespace tin::install 37 | { 38 | Install::Install(NcmStorageId destStorageId, bool ignoreReqFirmVersion) : 39 | m_destStorageId(destStorageId), m_ignoreReqFirmVersion(ignoreReqFirmVersion), m_contentMeta() 40 | { 41 | appletSetMediaPlaybackState(true); 42 | } 43 | 44 | Install::~Install() 45 | { 46 | appletSetMediaPlaybackState(false); 47 | } 48 | 49 | // TODO: Implement RAII on NcmContentMetaDatabase 50 | void Install::InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf, int i) 51 | { 52 | NcmContentMetaDatabase contentMetaDatabase; 53 | NcmContentMetaKey contentMetaKey = m_contentMeta[i].GetContentMetaKey(); 54 | 55 | try 56 | { 57 | ASSERT_OK(ncmOpenContentMetaDatabase(&contentMetaDatabase, m_destStorageId), "Failed to open content meta database"); 58 | ASSERT_OK(ncmContentMetaDatabaseSet(&contentMetaDatabase, &contentMetaKey, (NcmContentMetaHeader*)installContentMetaBuf.GetData(), installContentMetaBuf.GetSize()), "Failed to set content records"); 59 | ASSERT_OK(ncmContentMetaDatabaseCommit(&contentMetaDatabase), "Failed to commit content records"); 60 | } 61 | catch (std::runtime_error& e) 62 | { 63 | serviceClose(&contentMetaDatabase.s); 64 | THROW_FORMAT(e.what()); 65 | } 66 | 67 | serviceClose(&contentMetaDatabase.s); 68 | } 69 | 70 | void Install::InstallApplicationRecord(int i) 71 | { 72 | const u64 baseTitleId = tin::util::GetBaseTitleId(this->GetTitleId(i), this->GetContentMetaType(i)); 73 | 74 | // Add our new content meta 75 | ContentStorageRecord storageRecord; 76 | storageRecord.metaRecord = m_contentMeta[i].GetContentMetaKey(); 77 | storageRecord.storageId = m_destStorageId; 78 | 79 | LOG_DEBUG("Pushing application record...\n"); 80 | ASSERT_OK(nsPushApplicationRecord(baseTitleId, NsApplicationRecordType_Installed, &storageRecord, 1), "Failed to push application record"); 81 | } 82 | 83 | // Validate and obtain all data needed for install 84 | void Install::Prepare() 85 | { 86 | tin::data::ByteBuffer cnmtBuf; 87 | 88 | std::vector> tupelList = this->ReadCNMT(); 89 | 90 | for (size_t i = 0; i < tupelList.size(); i++) { 91 | std::tuple cnmtTuple = tupelList[i]; 92 | 93 | m_contentMeta.push_back(std::get<0>(cnmtTuple)); 94 | NcmContentInfo cnmtContentRecord = std::get<1>(cnmtTuple); 95 | 96 | nx::ncm::ContentStorage contentStorage(m_destStorageId); 97 | 98 | if (!contentStorage.Has(cnmtContentRecord.content_id)) 99 | { 100 | LOG_DEBUG("Installing CNMT NCA...\n"); 101 | this->InstallNCA(cnmtContentRecord.content_id); 102 | } 103 | else 104 | { 105 | LOG_DEBUG("CNMT NCA already installed. Proceeding...\n"); 106 | } 107 | 108 | // Parse data and create install content meta 109 | if (m_ignoreReqFirmVersion) 110 | LOG_DEBUG("WARNING: Required system firmware version is being IGNORED!\n"); 111 | 112 | tin::data::ByteBuffer installContentMetaBuf; 113 | m_contentMeta[i].GetInstallContentMeta(installContentMetaBuf, cnmtContentRecord, m_ignoreReqFirmVersion); 114 | 115 | this->InstallContentMetaRecords(installContentMetaBuf, i); 116 | this->InstallApplicationRecord(i); 117 | } 118 | } 119 | 120 | void Install::Begin() 121 | { 122 | LOG_DEBUG("Installing ticket and cert...\n"); 123 | try 124 | { 125 | this->InstallTicketCert(); 126 | } 127 | catch (std::runtime_error& e) 128 | { 129 | LOG_DEBUG("WARNING: Ticket installation failed! This may not be an issue, depending on your use case.\nProceed with caution!\n"); 130 | } 131 | 132 | for (nx::ncm::ContentMeta contentMeta: m_contentMeta) { 133 | LOG_DEBUG("Installing NCAs...\n"); 134 | for (auto& record : contentMeta.GetContentInfos()) 135 | { 136 | LOG_DEBUG("Installing from %s\n", tin::util::GetNcaIdString(record.content_id).c_str()); 137 | this->InstallNCA(record.content_id); 138 | } 139 | } 140 | } 141 | 142 | u64 Install::GetTitleId(int i) 143 | { 144 | return m_contentMeta[i].GetContentMetaKey().id; 145 | } 146 | 147 | NcmContentMetaType Install::GetContentMetaType(int i) 148 | { 149 | return static_cast(m_contentMeta[i].GetContentMetaKey().type); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /source/install/nsp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "install/nsp.hpp" 24 | 25 | #include 26 | #include "data/buffered_placeholder_writer.hpp" 27 | #include "util/title_util.hpp" 28 | #include "util/error.hpp" 29 | #include "util/debug.h" 30 | 31 | namespace tin::install::nsp 32 | { 33 | NSP::NSP() {} 34 | 35 | // TODO: Do verification: PFS0 magic, sizes not zero 36 | void NSP::RetrieveHeader() 37 | { 38 | LOG_DEBUG("Retrieving remote NSP header...\n"); 39 | 40 | // Retrieve the base header 41 | m_headerBytes.resize(sizeof(PFS0BaseHeader), 0); 42 | this->BufferData(m_headerBytes.data(), 0x0, sizeof(PFS0BaseHeader)); 43 | 44 | LOG_DEBUG("Base header: \n"); 45 | printBytes(m_headerBytes.data(), sizeof(PFS0BaseHeader), true); 46 | 47 | // Retrieve the full header 48 | size_t remainingHeaderSize = this->GetBaseHeader()->numFiles * sizeof(PFS0FileEntry) + this->GetBaseHeader()->stringTableSize; 49 | m_headerBytes.resize(sizeof(PFS0BaseHeader) + remainingHeaderSize, 0); 50 | this->BufferData(m_headerBytes.data() + sizeof(PFS0BaseHeader), sizeof(PFS0BaseHeader), remainingHeaderSize); 51 | 52 | LOG_DEBUG("Full header: \n"); 53 | printBytes(m_headerBytes.data(), m_headerBytes.size(), true); 54 | } 55 | 56 | const PFS0FileEntry* NSP::GetFileEntry(unsigned int index) 57 | { 58 | if (index >= this->GetBaseHeader()->numFiles) 59 | THROW_FORMAT("File entry index is out of bounds\n"); 60 | 61 | size_t fileEntryOffset = sizeof(PFS0BaseHeader) + index * sizeof(PFS0FileEntry); 62 | 63 | if (m_headerBytes.size() < fileEntryOffset + sizeof(PFS0FileEntry)) 64 | THROW_FORMAT("Header bytes is too small to get file entry!"); 65 | 66 | return reinterpret_cast(m_headerBytes.data() + fileEntryOffset); 67 | } 68 | 69 | std::vector NSP::GetFileEntriesByExtension(std::string extension) 70 | { 71 | std::vector entryList; 72 | 73 | for (unsigned int i = 0; i < this->GetBaseHeader()->numFiles; i++) 74 | { 75 | const PFS0FileEntry* fileEntry = this->GetFileEntry(i); 76 | std::string name(this->GetFileEntryName(fileEntry)); 77 | auto foundExtension = name.substr(name.find(".") + 1); 78 | 79 | if (foundExtension == extension) 80 | entryList.push_back(fileEntry); 81 | } 82 | 83 | return entryList; 84 | } 85 | 86 | const PFS0FileEntry* NSP::GetFileEntryByName(std::string name) 87 | { 88 | for (unsigned int i = 0; i < this->GetBaseHeader()->numFiles; i++) 89 | { 90 | const PFS0FileEntry* fileEntry = this->GetFileEntry(i); 91 | std::string foundName(this->GetFileEntryName(fileEntry)); 92 | 93 | if (foundName == name) 94 | return fileEntry; 95 | } 96 | 97 | return nullptr; 98 | } 99 | 100 | const PFS0FileEntry* NSP::GetFileEntryByNcaId(const NcmContentId& ncaId) 101 | { 102 | const PFS0FileEntry* fileEntry = nullptr; 103 | std::string ncaIdStr = tin::util::GetNcaIdString(ncaId); 104 | 105 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".nca")) == nullptr) 106 | { 107 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.nca")) == nullptr) 108 | { 109 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".ncz")) == nullptr) 110 | { 111 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.ncz")) == nullptr) 112 | { 113 | return nullptr; 114 | } 115 | } 116 | } 117 | } 118 | 119 | return fileEntry; 120 | } 121 | 122 | const char* NSP::GetFileEntryName(const PFS0FileEntry* fileEntry) 123 | { 124 | u64 stringTableStart = sizeof(PFS0BaseHeader) + this->GetBaseHeader()->numFiles * sizeof(PFS0FileEntry); 125 | return reinterpret_cast(m_headerBytes.data() + stringTableStart + fileEntry->stringTableOffset); 126 | } 127 | 128 | const PFS0BaseHeader* NSP::GetBaseHeader() 129 | { 130 | if (m_headerBytes.empty()) 131 | THROW_FORMAT("Cannot retrieve header as header bytes are empty. Have you retrieved it yet?\n"); 132 | 133 | return reinterpret_cast(m_headerBytes.data()); 134 | } 135 | 136 | u64 NSP::GetDataOffset() 137 | { 138 | if (m_headerBytes.empty()) 139 | THROW_FORMAT("Cannot get data offset as header is empty. Have you retrieved it yet?\n"); 140 | 141 | return m_headerBytes.size(); 142 | } 143 | } -------------------------------------------------------------------------------- /source/install/sdmc_nsp.cpp: -------------------------------------------------------------------------------- 1 | #include "install/sdmc_nsp.hpp" 2 | #include "error.hpp" 3 | #include "debug.h" 4 | #include "nx/nca_writer.h" 5 | #include "ui/instPage.hpp" 6 | #include "util/lang.hpp" 7 | 8 | namespace tin::install::nsp 9 | { 10 | SDMCNSP::SDMCNSP(std::string path) 11 | { 12 | m_nspFile = fopen((path).c_str(), "rb"); 13 | if (!m_nspFile) 14 | THROW_FORMAT("can't open file at %s\n", path.c_str()); 15 | } 16 | 17 | SDMCNSP::~SDMCNSP() 18 | { 19 | fclose(m_nspFile); 20 | } 21 | 22 | void SDMCNSP::StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId ncaId) 23 | { 24 | const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId); 25 | std::string ncaFileName = this->GetFileEntryName(fileEntry); 26 | 27 | LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str()); 28 | size_t ncaSize = fileEntry->fileSize; 29 | 30 | NcaWriter writer(ncaId, contentStorage); 31 | 32 | float progress; 33 | 34 | u64 fileStart = GetDataOffset() + fileEntry->dataOffset; 35 | u64 fileOff = 0; 36 | size_t readSize = 0x400000; // 4MB buff 37 | auto readBuffer = std::make_unique(readSize); 38 | 39 | try 40 | { 41 | inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "..."); 42 | inst::ui::instPage::setInstBarPerc(0); 43 | while (fileOff < ncaSize) 44 | { 45 | progress = (float) fileOff / (float) ncaSize; 46 | 47 | if (fileOff % (0x400000 * 3) == 0) { 48 | LOG_DEBUG("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%"); 49 | inst::ui::instPage::setInstBarPerc((double)(progress * 100.0)); 50 | } 51 | 52 | if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff; 53 | 54 | this->BufferData(readBuffer.get(), fileOff + fileStart, readSize); 55 | writer.write(readBuffer.get(), readSize); 56 | 57 | fileOff += readSize; 58 | } 59 | inst::ui::instPage::setInstBarPerc(100); 60 | } 61 | catch (std::exception& e) 62 | { 63 | LOG_DEBUG("something went wrong: %s\n", e.what()); 64 | } 65 | 66 | writer.close(); 67 | } 68 | 69 | void SDMCNSP::BufferData(void* buf, off_t offset, size_t size) 70 | { 71 | fseeko(m_nspFile, offset, SEEK_SET); 72 | fread(buf, 1, size, m_nspFile); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /source/install/sdmc_xci.cpp: -------------------------------------------------------------------------------- 1 | #include "install/sdmc_xci.hpp" 2 | #include "error.hpp" 3 | #include "debug.h" 4 | #include "nx/nca_writer.h" 5 | #include "ui/instPage.hpp" 6 | #include "util/lang.hpp" 7 | 8 | namespace tin::install::xci 9 | { 10 | SDMCXCI::SDMCXCI(std::string path) 11 | { 12 | m_xciFile = fopen((path).c_str(), "rb"); 13 | if (!m_xciFile) 14 | THROW_FORMAT("can't open file at %s\n", path.c_str()); 15 | } 16 | 17 | SDMCXCI::~SDMCXCI() 18 | { 19 | fclose(m_xciFile); 20 | } 21 | 22 | void SDMCXCI::StreamToPlaceholder(std::shared_ptr& contentStorage, NcmContentId ncaId) 23 | { 24 | const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId); 25 | std::string ncaFileName = this->GetFileEntryName(fileEntry); 26 | 27 | LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str()); 28 | size_t ncaSize = fileEntry->fileSize; 29 | 30 | NcaWriter writer(ncaId, contentStorage); 31 | 32 | float progress; 33 | 34 | u64 fileStart = GetDataOffset() + fileEntry->dataOffset; 35 | u64 fileOff = 0; 36 | size_t readSize = 0x400000; // 4MB buff 37 | auto readBuffer = std::make_unique(readSize); 38 | 39 | try 40 | { 41 | inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "..."); 42 | inst::ui::instPage::setInstBarPerc(0); 43 | while (fileOff < ncaSize) 44 | { 45 | progress = (float) fileOff / (float) ncaSize; 46 | 47 | if (fileOff % (0x400000 * 3) == 0) { 48 | LOG_DEBUG("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%"); 49 | inst::ui::instPage::setInstBarPerc((double)(progress * 100.0)); 50 | } 51 | 52 | if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff; 53 | 54 | this->BufferData(readBuffer.get(), fileOff + fileStart, readSize); 55 | writer.write(readBuffer.get(), readSize); 56 | 57 | fileOff += readSize; 58 | } 59 | inst::ui::instPage::setInstBarPerc(100); 60 | } 61 | catch (std::exception& e) 62 | { 63 | LOG_DEBUG("something went wrong: %s\n", e.what()); 64 | } 65 | 66 | writer.close(); 67 | } 68 | 69 | void SDMCXCI::BufferData(void* buf, off_t offset, size_t size) 70 | { 71 | fseeko(m_xciFile, offset, SEEK_SET); 72 | fread(buf, 1, size, m_xciFile); 73 | } 74 | } -------------------------------------------------------------------------------- /source/install/simple_filesystem.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "install/simple_filesystem.hpp" 24 | 25 | #include 26 | #include 27 | #include "nx/fs.hpp" 28 | #include "util/error.hpp" 29 | 30 | namespace tin::install::nsp 31 | { 32 | SimpleFileSystem::SimpleFileSystem(nx::fs::IFileSystem& fileSystem, std::string rootPath, std::string absoluteRootPath) : 33 | m_fileSystem(&fileSystem) , m_rootPath(rootPath), m_absoluteRootPath(absoluteRootPath) 34 | {} 35 | 36 | SimpleFileSystem::~SimpleFileSystem() {} 37 | 38 | nx::fs::IFile SimpleFileSystem::OpenFile(std::string path) 39 | { 40 | return m_fileSystem->OpenFile(m_rootPath + path); 41 | } 42 | 43 | bool SimpleFileSystem::HasFile(std::string path) 44 | { 45 | try 46 | { 47 | LOG_DEBUG(("Attempting to find file at " + m_rootPath + path + "\n").c_str()); 48 | m_fileSystem->OpenFile(m_rootPath + path); 49 | return true; 50 | } 51 | catch (std::exception& e) {} 52 | return false; 53 | } 54 | 55 | std::string SimpleFileSystem::GetFileNameFromExtension(std::string path, std::string extension) 56 | { 57 | nx::fs::IDirectory dir = m_fileSystem->OpenDirectory(m_rootPath + path, FsDirOpenMode_ReadFiles | FsDirOpenMode_ReadDirs); 58 | 59 | u64 entryCount = dir.GetEntryCount(); 60 | auto dirEntries = std::make_unique(entryCount); 61 | 62 | dir.Read(0, dirEntries.get(), entryCount); 63 | 64 | for (unsigned int i = 0; i < entryCount; i++) 65 | { 66 | FsDirectoryEntry dirEntry = dirEntries[i]; 67 | std::string dirEntryName = dirEntry.name; 68 | 69 | if (dirEntry.type == FsDirEntryType_Dir) 70 | { 71 | auto subdirPath = path + dirEntryName + "/"; 72 | auto subdirFound = this->GetFileNameFromExtension(subdirPath, extension); 73 | 74 | if (subdirFound != "") 75 | return subdirFound; 76 | continue; 77 | } 78 | else if (dirEntry.type == FsDirEntryType_File) 79 | { 80 | auto foundExtension = dirEntryName.substr(dirEntryName.find(".") + 1); 81 | 82 | if (foundExtension == extension) 83 | return dirEntryName; 84 | } 85 | } 86 | 87 | return ""; 88 | } 89 | } -------------------------------------------------------------------------------- /source/install/xci.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "install/xci.hpp" 24 | #include "util/title_util.hpp" 25 | #include "error.hpp" 26 | #include "debug.h" 27 | 28 | namespace tin::install::xci 29 | { 30 | XCI::XCI() 31 | { 32 | } 33 | 34 | void XCI::RetrieveHeader() 35 | { 36 | LOG_DEBUG("Retrieving HFS0 header...\n"); 37 | 38 | // Retrieve hfs0 offset 39 | u64 hfs0Offset = 0xf000; 40 | 41 | // Retrieve main hfs0 header 42 | std::vector m_headerBytes; 43 | m_headerBytes.resize(sizeof(HFS0BaseHeader), 0); 44 | this->BufferData(m_headerBytes.data(), hfs0Offset, sizeof(HFS0BaseHeader)); 45 | 46 | LOG_DEBUG("Base header: \n"); 47 | printBytes(m_headerBytes.data(), sizeof(HFS0BaseHeader), true); 48 | 49 | // Retrieve full header 50 | HFS0BaseHeader *header = reinterpret_cast(m_headerBytes.data()); 51 | if (header->magic != MAGIC_HFS0) 52 | THROW_FORMAT("hfs0 magic doesn't match at 0x%lx\n", hfs0Offset); 53 | 54 | size_t remainingHeaderSize = header->numFiles * sizeof(HFS0FileEntry) + header->stringTableSize; 55 | m_headerBytes.resize(sizeof(HFS0BaseHeader) + remainingHeaderSize, 0); 56 | this->BufferData(m_headerBytes.data() + sizeof(HFS0BaseHeader), hfs0Offset + sizeof(HFS0BaseHeader), remainingHeaderSize); 57 | 58 | LOG_DEBUG("Base header: \n"); 59 | printBytes(m_headerBytes.data(), sizeof(HFS0BaseHeader) + remainingHeaderSize, true); 60 | 61 | // Find Secure partition 62 | header = reinterpret_cast(m_headerBytes.data()); 63 | for (unsigned int i = 0; i < header->numFiles; i++) 64 | { 65 | const HFS0FileEntry *entry = hfs0GetFileEntry(header, i); 66 | std::string entryName(hfs0GetFileName(header, entry)); 67 | 68 | if (entryName != "secure") 69 | continue; 70 | 71 | m_secureHeaderOffset = hfs0Offset + remainingHeaderSize + 0x10 + entry->dataOffset; 72 | m_secureHeaderBytes.resize(sizeof(HFS0BaseHeader), 0); 73 | this->BufferData(m_secureHeaderBytes.data(), m_secureHeaderOffset, sizeof(HFS0BaseHeader)); 74 | 75 | LOG_DEBUG("Secure header: \n"); 76 | printBytes(m_secureHeaderBytes.data(), sizeof(HFS0BaseHeader), true); 77 | 78 | if (this->GetSecureHeader()->magic != MAGIC_HFS0) 79 | THROW_FORMAT("hfs0 magic doesn't match at 0x%lx\n", m_secureHeaderOffset); 80 | 81 | // Retrieve full header 82 | remainingHeaderSize = this->GetSecureHeader()->numFiles * sizeof(HFS0FileEntry) + this->GetSecureHeader()->stringTableSize; 83 | m_secureHeaderBytes.resize(sizeof(HFS0BaseHeader) + remainingHeaderSize, 0); 84 | this->BufferData(m_secureHeaderBytes.data() + sizeof(HFS0BaseHeader), m_secureHeaderOffset + sizeof(HFS0BaseHeader), remainingHeaderSize); 85 | 86 | LOG_DEBUG("Base header: \n"); 87 | printBytes(m_secureHeaderBytes.data(), sizeof(HFS0BaseHeader) + remainingHeaderSize, true); 88 | return; 89 | } 90 | THROW_FORMAT("couldn't optain secure hfs0 header\n"); 91 | } 92 | 93 | const HFS0BaseHeader* XCI::GetSecureHeader() 94 | { 95 | if (m_secureHeaderBytes.empty()) 96 | THROW_FORMAT("Cannot retrieve header as header bytes are empty. Have you retrieved it yet?\n"); 97 | 98 | return reinterpret_cast(m_secureHeaderBytes.data()); 99 | } 100 | 101 | u64 XCI::GetDataOffset() 102 | { 103 | if (m_secureHeaderBytes.empty()) 104 | THROW_FORMAT("Cannot get data offset as header is empty. Have you retrieved it yet?\n"); 105 | 106 | return m_secureHeaderOffset + m_secureHeaderBytes.size(); 107 | } 108 | 109 | const HFS0FileEntry* XCI::GetFileEntry(unsigned int index) 110 | { 111 | if (index >= this->GetSecureHeader()->numFiles) 112 | THROW_FORMAT("File entry index is out of bounds\n"); 113 | 114 | return hfs0GetFileEntry(this->GetSecureHeader(), index); 115 | } 116 | 117 | const HFS0FileEntry* XCI::GetFileEntryByName(std::string name) 118 | { 119 | for (unsigned int i = 0; i < this->GetSecureHeader()->numFiles; i++) 120 | { 121 | const HFS0FileEntry* fileEntry = this->GetFileEntry(i); 122 | std::string foundName(this->GetFileEntryName(fileEntry)); 123 | 124 | if (foundName == name) 125 | return fileEntry; 126 | } 127 | 128 | return nullptr; 129 | } 130 | 131 | const HFS0FileEntry* XCI::GetFileEntryByNcaId(const NcmContentId& ncaId) 132 | { 133 | const HFS0FileEntry* fileEntry = nullptr; 134 | std::string ncaIdStr = tin::util::GetNcaIdString(ncaId); 135 | 136 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".nca")) == nullptr) 137 | { 138 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.nca")) == nullptr) 139 | { 140 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".ncz")) == nullptr) 141 | { 142 | if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.ncz")) == nullptr) 143 | { 144 | return nullptr; 145 | } 146 | } 147 | } 148 | } 149 | 150 | return fileEntry; 151 | } 152 | 153 | std::vector XCI::GetFileEntriesByExtension(std::string extension) 154 | { 155 | std::vector entryList; 156 | 157 | for (unsigned int i = 0; i < this->GetSecureHeader()->numFiles; i++) 158 | { 159 | const HFS0FileEntry* fileEntry = this->GetFileEntry(i); 160 | std::string name(this->GetFileEntryName(fileEntry)); 161 | auto foundExtension = name.substr(name.find(".") + 1); 162 | 163 | if (foundExtension == extension) 164 | entryList.push_back(fileEntry); 165 | } 166 | 167 | return entryList; 168 | } 169 | 170 | const char* XCI::GetFileEntryName(const HFS0FileEntry* fileEntry) 171 | { 172 | return hfs0GetFileName(this->GetSecureHeader(), fileEntry); 173 | } 174 | } -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "switch.h" 3 | #include "util/error.hpp" 4 | #include "ui/MainApplication.hpp" 5 | #include "util/util.hpp" 6 | #include "util/config.hpp" 7 | 8 | using namespace pu::ui::render; 9 | int main(int argc, char* argv[]) 10 | { 11 | inst::util::initApp(); 12 | try { 13 | auto renderer = Renderer::New(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER, 14 | RendererInitOptions::RendererNoSound, RendererHardwareFlags); 15 | auto main = inst::ui::MainApplication::New(renderer); 16 | std::thread updateThread; 17 | if (inst::config::autoUpdate && inst::util::getIPAddress() != "1.0.0.127") updateThread = std::thread(inst::util::checkForAppUpdate); 18 | main->Prepare(); 19 | main->ShowWithFadeIn(); 20 | updateThread.join(); 21 | } catch (std::exception& e) { 22 | LOG_DEBUG("An error occurred:\n%s", e.what()); 23 | } 24 | inst::util::deinitApp(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /source/nx/content_meta.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "nx/content_meta.hpp" 24 | 25 | #include 26 | #include "util/title_util.hpp" 27 | #include "util/debug.h" 28 | #include "util/error.hpp" 29 | 30 | namespace nx::ncm 31 | { 32 | ContentMeta::ContentMeta() 33 | { 34 | m_bytes.Resize(sizeof(PackagedContentMetaHeader)); 35 | } 36 | 37 | ContentMeta::ContentMeta(u8* data, size_t size) : 38 | m_bytes(size) 39 | { 40 | if (size < sizeof(PackagedContentMetaHeader)) 41 | THROW_FORMAT("Content meta data size is too small!"); 42 | 43 | m_bytes.Resize(size); 44 | memcpy(m_bytes.GetData(), data, size); 45 | } 46 | 47 | PackagedContentMetaHeader ContentMeta::GetPackagedContentMetaHeader() 48 | { 49 | return m_bytes.Read(0); 50 | } 51 | 52 | NcmContentMetaKey ContentMeta::GetContentMetaKey() 53 | { 54 | NcmContentMetaKey metaRecord; 55 | PackagedContentMetaHeader contentMetaHeader = this->GetPackagedContentMetaHeader(); 56 | 57 | memset(&metaRecord, 0, sizeof(NcmContentMetaKey)); 58 | metaRecord.id = contentMetaHeader.title_id; 59 | metaRecord.version = contentMetaHeader.version; 60 | metaRecord.type = static_cast(contentMetaHeader.type); 61 | 62 | return metaRecord; 63 | } 64 | 65 | // TODO: Cache this 66 | std::vector ContentMeta::GetContentInfos() 67 | { 68 | PackagedContentMetaHeader contentMetaHeader = this->GetPackagedContentMetaHeader(); 69 | 70 | std::vector contentInfos; 71 | PackagedContentInfo* packagedContentInfos = (PackagedContentInfo*)(m_bytes.GetData() + sizeof(PackagedContentMetaHeader) + contentMetaHeader.extended_header_size); 72 | 73 | for (unsigned int i = 0; i < contentMetaHeader.content_count; i++) 74 | { 75 | PackagedContentInfo packagedContentInfo = packagedContentInfos[i]; 76 | 77 | // Don't install delta fragments. Even patches don't seem to install them. 78 | if (static_cast(packagedContentInfo.content_info.content_type) <= 5) 79 | { 80 | contentInfos.push_back(packagedContentInfo.content_info); 81 | } 82 | } 83 | 84 | return contentInfos; 85 | } 86 | 87 | void ContentMeta::GetInstallContentMeta(tin::data::ByteBuffer& installContentMetaBuffer, NcmContentInfo& cnmtNcmContentInfo, bool ignoreReqFirmVersion) 88 | { 89 | PackagedContentMetaHeader packagedContentMetaHeader = this->GetPackagedContentMetaHeader(); 90 | std::vector contentInfos = this->GetContentInfos(); 91 | 92 | // Setup the content meta header 93 | NcmContentMetaHeader contentMetaHeader; 94 | contentMetaHeader.extended_header_size = packagedContentMetaHeader.extended_header_size; 95 | contentMetaHeader.content_count = contentInfos.size() + 1; // Add one for the cnmt content record 96 | contentMetaHeader.content_meta_count = packagedContentMetaHeader.content_meta_count; 97 | contentMetaHeader.attributes = packagedContentMetaHeader.attributes; 98 | contentMetaHeader.storage_id = 0; 99 | 100 | installContentMetaBuffer.Append(contentMetaHeader); 101 | 102 | // Setup the meta extended header 103 | LOG_DEBUG("Install content meta pre size: 0x%lx\n", installContentMetaBuffer.GetSize()); 104 | installContentMetaBuffer.Resize(installContentMetaBuffer.GetSize() + contentMetaHeader.extended_header_size); 105 | LOG_DEBUG("Install content meta post size: 0x%lx\n", installContentMetaBuffer.GetSize()); 106 | auto* extendedHeaderSourceBytes = m_bytes.GetData() + sizeof(PackagedContentMetaHeader); 107 | u8* installExtendedHeaderStart = installContentMetaBuffer.GetData() + sizeof(NcmContentMetaHeader); 108 | memcpy(installExtendedHeaderStart, extendedHeaderSourceBytes, contentMetaHeader.extended_header_size); 109 | 110 | // Optionally disable the required system version field 111 | if (ignoreReqFirmVersion && (packagedContentMetaHeader.type == NcmContentMetaType_Application || packagedContentMetaHeader.type == NcmContentMetaType_Patch)) 112 | { 113 | installContentMetaBuffer.Write(0, sizeof(NcmContentMetaHeader) + 8); 114 | } 115 | 116 | // Setup cnmt content record 117 | installContentMetaBuffer.Append(cnmtNcmContentInfo); 118 | 119 | // Setup the content records 120 | for (auto& contentInfo : contentInfos) 121 | { 122 | installContentMetaBuffer.Append(contentInfo); 123 | } 124 | 125 | if (packagedContentMetaHeader.type == NcmContentMetaType_Patch) 126 | { 127 | NcmPatchMetaExtendedHeader* patchMetaExtendedHeader = (NcmPatchMetaExtendedHeader*)extendedHeaderSourceBytes; 128 | installContentMetaBuffer.Resize(installContentMetaBuffer.GetSize() + patchMetaExtendedHeader->extended_data_size); 129 | } 130 | } 131 | } 132 | 133 | -------------------------------------------------------------------------------- /source/nx/fs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "nx/fs.hpp" 24 | 25 | #include 26 | #include "util/error.hpp" 27 | 28 | namespace nx::fs 29 | { 30 | // IFile 31 | 32 | IFile::IFile(FsFile& file) 33 | { 34 | m_file = file; 35 | } 36 | 37 | IFile::~IFile() 38 | { 39 | fsFileClose(&m_file); 40 | } 41 | 42 | void IFile::Read(u64 offset, void* buf, size_t size) 43 | { 44 | u64 sizeRead; 45 | ASSERT_OK(fsFileRead(&m_file, offset, buf, size, FsReadOption_None, &sizeRead), "Failed to read file"); 46 | 47 | if (sizeRead != size) 48 | { 49 | std::string msg = "Size read " + std::string("" + sizeRead) + " doesn't match expected size " + std::string("" + size); 50 | THROW_FORMAT(msg.c_str()); 51 | } 52 | } 53 | 54 | s64 IFile::GetSize() 55 | { 56 | s64 sizeOut; 57 | ASSERT_OK(fsFileGetSize(&m_file, &sizeOut), "Failed to get file size"); 58 | return sizeOut; 59 | } 60 | 61 | // End IFile 62 | 63 | // IDirectory 64 | IDirectory::IDirectory(FsDir& dir) 65 | { 66 | m_dir = dir; 67 | } 68 | 69 | IDirectory::~IDirectory() 70 | { 71 | fsDirClose(&m_dir); 72 | } 73 | 74 | void IDirectory::Read(s64 inval, FsDirectoryEntry* buf, size_t numEntries) 75 | { 76 | ASSERT_OK(fsDirRead(&m_dir, &inval, numEntries, buf), "Failed to read directory"); 77 | 78 | /*if (entriesRead != numEntries) 79 | { 80 | std::string msg = "Entries read " + std::string("" + entriesRead) + " doesn't match expected number " + std::string("" + numEntries); 81 | THROW_FORMAT(msg); 82 | }*/ 83 | } 84 | 85 | u64 IDirectory::GetEntryCount() 86 | { 87 | s64 entryCount = 0; 88 | ASSERT_OK(fsDirGetEntryCount(&m_dir, &entryCount), "Failed to get entry count"); 89 | return entryCount; 90 | } 91 | 92 | // End IDirectory 93 | 94 | IFileSystem::IFileSystem() {} 95 | 96 | IFileSystem::~IFileSystem() 97 | { 98 | this->CloseFileSystem(); 99 | } 100 | 101 | Result IFileSystem::OpenSdFileSystem() 102 | { 103 | ASSERT_OK(fsOpenSdCardFileSystem(&m_fileSystem), "Failed to mount sd card"); 104 | return 0; 105 | } 106 | 107 | void IFileSystem::OpenFileSystemWithId(std::string path, FsFileSystemType fileSystemType, u64 titleId) 108 | { 109 | Result rc = 0; 110 | if (path.length() >= FS_MAX_PATH) 111 | THROW_FORMAT("Directory path is too long!"); 112 | 113 | // libnx expects a FS_MAX_PATH-sized buffer 114 | path.reserve(FS_MAX_PATH); 115 | 116 | std::string errorMsg = "Failed to open file system with id: " + path; 117 | rc = fsOpenFileSystemWithId(&m_fileSystem, titleId, fileSystemType, path.c_str()); 118 | 119 | if (rc == 0x236e02) 120 | errorMsg = "File " + path + " is unreadable! You may have a bad dump, fs_mitm may need to be removed, or your firmware version may be too low to decrypt it."; 121 | else if (rc == 0x234c02) 122 | errorMsg = "Failed to open filesystem. Make sure your signature patches are up to date and set up properly!"; 123 | 124 | ASSERT_OK(rc, errorMsg.c_str()); 125 | } 126 | 127 | void IFileSystem::CloseFileSystem() 128 | { 129 | fsFsClose(&m_fileSystem); 130 | } 131 | 132 | IFile IFileSystem::OpenFile(std::string path) 133 | { 134 | if (path.length() >= FS_MAX_PATH) 135 | THROW_FORMAT("Directory path is too long!"); 136 | 137 | // libnx expects a FS_MAX_PATH-sized buffer 138 | path.reserve(FS_MAX_PATH); 139 | 140 | FsFile file; 141 | ASSERT_OK(fsFsOpenFile(&m_fileSystem, path.c_str(), FsOpenMode_Read, &file), ("Failed to open file " + path).c_str()); 142 | return IFile(file); 143 | } 144 | 145 | IDirectory IFileSystem::OpenDirectory(std::string path, int flags) 146 | { 147 | // Account for null at the end of c strings 148 | if (path.length() >= FS_MAX_PATH) 149 | THROW_FORMAT("Directory path is too long!"); 150 | 151 | // libnx expects a FS_MAX_PATH-sized buffer 152 | path.reserve(FS_MAX_PATH); 153 | 154 | FsDir dir; 155 | ASSERT_OK(fsFsOpenDirectory(&m_fileSystem, path.c_str(), flags, &dir), ("Failed to open directory " + path).c_str()); 156 | return IDirectory(dir); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /source/nx/ipc/es.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "nx/ipc/es.h" 24 | 25 | #include 26 | 27 | #include 28 | 29 | static Service g_esSrv; 30 | 31 | Result esInitialize(void) { 32 | return smGetService(&g_esSrv, "es"); 33 | } 34 | 35 | void esExit(void) { 36 | serviceClose(&g_esSrv); 37 | } 38 | 39 | Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize) { 40 | return serviceDispatch(&g_esSrv, 1, 41 | .buffer_attrs = { 42 | SfBufferAttr_HipcMapAlias | SfBufferAttr_In, 43 | SfBufferAttr_HipcMapAlias | SfBufferAttr_In, 44 | }, 45 | .buffers = { 46 | { tikBuf, tikSize }, 47 | { certBuf, certSize }, 48 | }, 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /source/nx/ipc/ns_ext.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "nx/ipc/ns_ext.h" 24 | 25 | #include 26 | 27 | Service g_nsAppManSrv; 28 | 29 | Result nsextInitialize(void) { 30 | Result rc = nsInitialize(); 31 | 32 | if (R_SUCCEEDED(rc)) { 33 | if(hosversionBefore(3,0,0)) { 34 | g_nsAppManSrv = *nsGetServiceSession_ApplicationManagerInterface(); 35 | } else { 36 | rc = nsGetApplicationManagerInterface(&g_nsAppManSrv); 37 | } 38 | } 39 | 40 | return rc; 41 | } 42 | 43 | void nsextExit(void) { 44 | if(hosversionAtLeast(3,0,0)) 45 | serviceClose(&g_nsAppManSrv); 46 | nsExit(); 47 | } 48 | 49 | Result nsPushApplicationRecord(u64 application_id, NsApplicationRecordType last_modified_event, ContentStorageRecord *content_records, u32 count) { 50 | struct { 51 | u8 last_modified_event; 52 | u64 application_id; 53 | } in = { last_modified_event, application_id }; 54 | 55 | return serviceDispatchIn(&g_nsAppManSrv, 16, in, 56 | .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, 57 | .buffers = { { content_records, count * sizeof(*content_records) } 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /source/nx/ncm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "nx/ncm.hpp" 24 | #include "util/error.hpp" 25 | 26 | namespace nx::ncm 27 | { 28 | ContentStorage::ContentStorage(NcmStorageId storageId) 29 | { 30 | ASSERT_OK(ncmOpenContentStorage(&m_contentStorage, storageId), "Failed to open NCM ContentStorage"); 31 | } 32 | 33 | ContentStorage::~ContentStorage() 34 | { 35 | serviceClose(&m_contentStorage.s); 36 | } 37 | 38 | void ContentStorage::CreatePlaceholder(const NcmContentId &placeholderId, const NcmPlaceHolderId ®isteredId, size_t size) 39 | { 40 | ASSERT_OK(ncmContentStorageCreatePlaceHolder(&m_contentStorage, &placeholderId, ®isteredId, size), "Failed to create placeholder"); 41 | } 42 | 43 | void ContentStorage::DeletePlaceholder(const NcmPlaceHolderId &placeholderId) 44 | { 45 | ASSERT_OK(ncmContentStorageDeletePlaceHolder(&m_contentStorage, &placeholderId), "Failed to delete placeholder"); 46 | } 47 | 48 | void ContentStorage::WritePlaceholder(const NcmPlaceHolderId &placeholderId, u64 offset, void *buffer, size_t bufSize) 49 | { 50 | ASSERT_OK(ncmContentStorageWritePlaceHolder(&m_contentStorage, &placeholderId, offset, buffer, bufSize), "Failed to write to placeholder"); 51 | } 52 | 53 | void ContentStorage::Register(const NcmPlaceHolderId &placeholderId, const NcmContentId ®isteredId) 54 | { 55 | ASSERT_OK(ncmContentStorageRegister(&m_contentStorage, ®isteredId, &placeholderId), "Failed to register placeholder NCA"); 56 | } 57 | 58 | void ContentStorage::Delete(const NcmContentId ®isteredId) 59 | { 60 | ASSERT_OK(ncmContentStorageDelete(&m_contentStorage, ®isteredId), "Failed to delete registered NCA"); 61 | } 62 | 63 | bool ContentStorage::Has(const NcmContentId ®isteredId) 64 | { 65 | bool hasNCA = false; 66 | ASSERT_OK(ncmContentStorageHas(&m_contentStorage, &hasNCA, ®isteredId), "Failed to check if NCA is present"); 67 | return hasNCA; 68 | } 69 | 70 | std::string ContentStorage::GetPath(const NcmContentId ®isteredId) 71 | { 72 | char pathBuf[FS_MAX_PATH] = {0}; 73 | ASSERT_OK(ncmContentStorageGetPath(&m_contentStorage, pathBuf, FS_MAX_PATH, ®isteredId), "Failed to get installed NCA path"); 74 | return std::string(pathBuf); 75 | } 76 | } -------------------------------------------------------------------------------- /source/sigInstall.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "util/error.hpp" 3 | #include "ui/MainApplication.hpp" 4 | #include "util/curl.hpp" 5 | #include "util/util.hpp" 6 | #include "util/unzip.hpp" 7 | #include "util/config.hpp" 8 | #include "util/lang.hpp" 9 | 10 | namespace inst::ui { 11 | extern MainApplication *mainApp; 12 | } 13 | 14 | namespace sig { 15 | void installSigPatches () { 16 | bpcInitialize(); 17 | try { 18 | std::string patchesVersion = inst::util::readTextFromFile("sdmc:/atmosphere/exefs_patches/es_patches/patches.txt"); 19 | std::string versionText = ""; 20 | std::string installButtonText = "sig.install"_lang; 21 | if (patchesVersion != "") { 22 | versionText = "\n\n" + "sig.version_text"_lang + patchesVersion + "."; 23 | installButtonText = "sig.update"_lang; 24 | } 25 | int ourResult = inst::ui::mainApp->CreateShowDialog("sig.title0"_lang, "sig.desc0"_lang + versionText, {installButtonText, "sig.uninstall"_lang, "common.cancel"_lang}, true); 26 | if (ourResult == 0) { 27 | if (inst::util::getIPAddress() == "1.0.0.127") { 28 | inst::ui::mainApp->CreateShowDialog("main.net.title"_lang, "main.net.desc"_lang, {"common.ok"_lang}, true); 29 | return; 30 | } 31 | if (!inst::util::copyFile("sdmc:/bootloader/patches.ini", inst::config::appDir + "/patches.ini.old")) { 32 | if (inst::ui::mainApp->CreateShowDialog("sig.backup_failed"_lang, "sig.backup_failed_desc"_lang, {"common.yes"_lang, "common.no"_lang}, false)) return; 33 | } 34 | std::string ourPath = inst::config::appDir + "/patches.zip"; 35 | bool didDownload = inst::curl::downloadFile(inst::config::sigPatchesUrl, ourPath.c_str()); 36 | bool didExtract = false; 37 | if (didDownload) didExtract = inst::zip::extractFile(ourPath, "sdmc:/"); 38 | else { 39 | inst::ui::mainApp->CreateShowDialog("sig.download_failed"_lang, "sig.download_failed_desc"_lang, {"common.ok"_lang}, true); 40 | return; 41 | } 42 | std::filesystem::remove(ourPath); 43 | if (didExtract) { 44 | patchesVersion = inst::util::readTextFromFile("sdmc:/atmosphere/exefs_patches/es_patches/patches.txt"); 45 | versionText = ""; 46 | if (patchesVersion != "") versionText = "sig.version_text2"_lang + patchesVersion + "! "; 47 | if (inst::ui::mainApp->CreateShowDialog("sig.install_complete"_lang, versionText + "\n\n" + "sig.complete_desc"_lang, {"sig.restart"_lang, "sig.later"_lang}, false) == 0) bpcRebootSystem(); 48 | } 49 | else { 50 | inst::ui::mainApp->CreateShowDialog("sig.extract_failed"_lang, "", {"common.ok"_lang}, true); 51 | return; 52 | } 53 | return; 54 | } else if (ourResult == 1) { 55 | if (!inst::util::copyFile( inst::config::appDir + "/patches.ini.old", "sdmc:/bootloader/patches.ini")) { 56 | if (inst::ui::mainApp->CreateShowDialog("sig.restore_failed"_lang, "", {"common.yes"_lang, "common.no"_lang}, false)) return; 57 | } else std::filesystem::remove(inst::config::appDir + "/patches.ini.old"); 58 | if (inst::util::removeDirectory("sdmc:/atmosphere/exefs_patches/es_patches")) { 59 | if (inst::ui::mainApp->CreateShowDialog("sig.uninstall_complete"_lang, "sig.complete_desc"_lang, {"sig.restart"_lang, "sig.later"_lang}, false) == 0) bpcRebootSystem(); 60 | } 61 | else inst::ui::mainApp->CreateShowDialog("sig.remove_failed"_lang, "sig.remove_failed_desc"_lang, {"common.ok"_lang}, true); 62 | } else return; 63 | } 64 | catch (std::exception& e) 65 | { 66 | LOG_DEBUG("Failed to install Signature Patches"); 67 | LOG_DEBUG("%s", e.what()); 68 | fprintf(stdout, "%s", e.what()); 69 | inst::ui::mainApp->CreateShowDialog("sig.generic_error"_lang, (std::string)e.what(), {"common.ok"_lang}, true); 70 | } 71 | bpcExit(); 72 | } 73 | } -------------------------------------------------------------------------------- /source/ui/MainApplication.cpp: -------------------------------------------------------------------------------- 1 | #include "ui/MainApplication.hpp" 2 | #include "util/lang.hpp" 3 | 4 | namespace inst::ui { 5 | MainApplication *mainApp; 6 | 7 | void MainApplication::OnLoad() { 8 | mainApp = this; 9 | 10 | Language::Load(); 11 | 12 | this->mainPage = MainPage::New(); 13 | this->netinstPage = netInstPage::New(); 14 | this->sdinstPage = sdInstPage::New(); 15 | this->usbinstPage = usbInstPage::New(); 16 | this->instpage = instPage::New(); 17 | this->optionspage = optionsPage::New(); 18 | this->mainPage->SetOnInput(std::bind(&MainPage::onInput, this->mainPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); 19 | this->netinstPage->SetOnInput(std::bind(&netInstPage::onInput, this->netinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); 20 | this->sdinstPage->SetOnInput(std::bind(&sdInstPage::onInput, this->sdinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); 21 | this->usbinstPage->SetOnInput(std::bind(&usbInstPage::onInput, this->usbinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); 22 | this->instpage->SetOnInput(std::bind(&instPage::onInput, this->instpage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); 23 | this->optionspage->SetOnInput(std::bind(&optionsPage::onInput, this->optionspage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); 24 | this->LoadLayout(this->mainPage); 25 | } 26 | } -------------------------------------------------------------------------------- /source/ui/instPage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ui/MainApplication.hpp" 3 | #include "ui/instPage.hpp" 4 | #include "util/config.hpp" 5 | 6 | #define COLOR(hex) pu::ui::Color::FromHex(hex) 7 | 8 | namespace inst::ui { 9 | extern MainApplication *mainApp; 10 | 11 | instPage::instPage() : Layout::Layout() { 12 | this->SetBackgroundColor(COLOR("#670000FF")); 13 | if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png"); 14 | else this->SetBackgroundImage("romfs:/images/background.jpg"); 15 | this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF")); 16 | this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980")); 17 | if (inst::config::gayMode) { 18 | this->titleImage = Image::New(-113, 0, "romfs:/images/logo.png"); 19 | this->appVersionText = TextBlock::New(367, 49, "v" + inst::config::appVersion, 22); 20 | } 21 | else { 22 | this->titleImage = Image::New(0, 0, "romfs:/images/logo.png"); 23 | this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion, 22); 24 | } 25 | this->appVersionText->SetColor(COLOR("#FFFFFFFF")); 26 | this->pageInfoText = TextBlock::New(10, 109, "", 30); 27 | this->pageInfoText->SetColor(COLOR("#FFFFFFFF")); 28 | this->installInfoText = TextBlock::New(15, 568, "", 22); 29 | this->installInfoText->SetColor(COLOR("#FFFFFFFF")); 30 | this->installBar = pu::ui::elm::ProgressBar::New(10, 600, 850, 40, 100.0f); 31 | this->installBar->SetColor(COLOR("#222222FF")); 32 | if (std::filesystem::exists(inst::config::appDir + "/awoo_inst.png")) this->awooImage = Image::New(410, 190, inst::config::appDir + "/awoo_inst.png"); 33 | else this->awooImage = Image::New(510, 166, "romfs:/images/awoos/7d8a05cddfef6da4901b20d2698d5a71.png"); 34 | this->Add(this->topRect); 35 | this->Add(this->infoRect); 36 | this->Add(this->titleImage); 37 | this->Add(this->appVersionText); 38 | this->Add(this->pageInfoText); 39 | this->Add(this->installInfoText); 40 | this->Add(this->installBar); 41 | this->Add(this->awooImage); 42 | if (inst::config::gayMode) this->awooImage->SetVisible(false); 43 | } 44 | 45 | void instPage::setTopInstInfoText(std::string ourText){ 46 | mainApp->instpage->pageInfoText->SetText(ourText); 47 | mainApp->CallForRender(); 48 | } 49 | 50 | void instPage::setInstInfoText(std::string ourText){ 51 | mainApp->instpage->installInfoText->SetText(ourText); 52 | mainApp->CallForRender(); 53 | } 54 | 55 | void instPage::setInstBarPerc(double ourPercent){ 56 | mainApp->instpage->installBar->SetVisible(true); 57 | mainApp->instpage->installBar->SetProgress(ourPercent); 58 | mainApp->CallForRender(); 59 | } 60 | 61 | void instPage::loadMainMenu(){ 62 | mainApp->LoadLayout(mainApp->mainPage); 63 | } 64 | 65 | void instPage::loadInstallScreen(){ 66 | mainApp->instpage->pageInfoText->SetText(""); 67 | mainApp->instpage->installInfoText->SetText(""); 68 | mainApp->instpage->installBar->SetProgress(0); 69 | mainApp->instpage->installBar->SetVisible(false); 70 | mainApp->instpage->awooImage->SetVisible(!inst::config::gayMode); 71 | mainApp->LoadLayout(mainApp->instpage); 72 | mainApp->CallForRender(); 73 | } 74 | 75 | void instPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) { 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /source/ui/usbInstPage.cpp: -------------------------------------------------------------------------------- 1 | #include "ui/usbInstPage.hpp" 2 | #include "ui/MainApplication.hpp" 3 | #include "util/util.hpp" 4 | #include "util/config.hpp" 5 | #include "util/lang.hpp" 6 | #include "util/usb_util.hpp" 7 | #include "usbInstall.hpp" 8 | 9 | 10 | #define COLOR(hex) pu::ui::Color::FromHex(hex) 11 | 12 | namespace inst::ui { 13 | extern MainApplication *mainApp; 14 | 15 | usbInstPage::usbInstPage() : Layout::Layout() { 16 | this->SetBackgroundColor(COLOR("#670000FF")); 17 | if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png"); 18 | else this->SetBackgroundImage("romfs:/images/background.jpg"); 19 | this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF")); 20 | this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980")); 21 | this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980")); 22 | if (inst::config::gayMode) { 23 | this->titleImage = Image::New(-113, 0, "romfs:/images/logo.png"); 24 | this->appVersionText = TextBlock::New(367, 49, "v" + inst::config::appVersion, 22); 25 | } 26 | else { 27 | this->titleImage = Image::New(0, 0, "romfs:/images/logo.png"); 28 | this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion, 22); 29 | } 30 | this->appVersionText->SetColor(COLOR("#FFFFFFFF")); 31 | this->pageInfoText = TextBlock::New(10, 109, "", 30); 32 | this->pageInfoText->SetColor(COLOR("#FFFFFFFF")); 33 | this->butText = TextBlock::New(10, 678, "", 24); 34 | this->butText->SetColor(COLOR("#FFFFFFFF")); 35 | this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84)); 36 | this->menu->SetOnFocusColor(COLOR("#00000033")); 37 | this->menu->SetScrollbarColor(COLOR("#17090980")); 38 | this->infoImage = Image::New(460, 332, "romfs:/images/icons/usb-connection-waiting.png"); 39 | this->Add(this->topRect); 40 | this->Add(this->infoRect); 41 | this->Add(this->botRect); 42 | this->Add(this->titleImage); 43 | this->Add(this->appVersionText); 44 | this->Add(this->butText); 45 | this->Add(this->pageInfoText); 46 | this->Add(this->menu); 47 | this->Add(this->infoImage); 48 | } 49 | 50 | void usbInstPage::drawMenuItems(bool clearItems) { 51 | if (clearItems) this->selectedTitles = {}; 52 | this->menu->ClearItems(); 53 | for (auto& url: this->ourTitles) { 54 | std::string itm = inst::util::shortenString(inst::util::formatUrlString(url), 56, true); 55 | auto ourEntry = pu::ui::elm::MenuItem::New(itm); 56 | ourEntry->SetColor(COLOR("#FFFFFFFF")); 57 | ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png"); 58 | for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) { 59 | if (this->selectedTitles[i] == url) { 60 | ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png"); 61 | } 62 | } 63 | this->menu->AddItem(ourEntry); 64 | } 65 | } 66 | 67 | void usbInstPage::selectTitle(int selectedIndex) { 68 | if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") { 69 | for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) { 70 | if (this->selectedTitles[i] == this->ourTitles[selectedIndex]) this->selectedTitles.erase(this->selectedTitles.begin() + i); 71 | } 72 | } else this->selectedTitles.push_back(this->ourTitles[selectedIndex]); 73 | this->drawMenuItems(false); 74 | } 75 | 76 | void usbInstPage::startUsb() { 77 | this->pageInfoText->SetText("inst.usb.top_info"_lang); 78 | this->butText->SetText("inst.usb.buttons"_lang); 79 | this->menu->SetVisible(false); 80 | this->menu->ClearItems(); 81 | this->infoImage->SetVisible(true); 82 | mainApp->LoadLayout(mainApp->usbinstPage); 83 | mainApp->CallForRender(); 84 | this->ourTitles = usbInstStuff::OnSelected(); 85 | if (!this->ourTitles.size()) { 86 | mainApp->LoadLayout(mainApp->mainPage); 87 | return; 88 | } else { 89 | mainApp->CallForRender(); // If we re-render a few times during this process the main screen won't flicker 90 | this->pageInfoText->SetText("inst.usb.top_info2"_lang); 91 | this->butText->SetText("inst.usb.buttons2"_lang); 92 | this->drawMenuItems(true); 93 | this->menu->SetSelectedIndex(0); 94 | mainApp->CallForRender(); 95 | this->infoImage->SetVisible(false); 96 | this->menu->SetVisible(true); 97 | } 98 | return; 99 | } 100 | 101 | void usbInstPage::startInstall() { 102 | int dialogResult = -1; 103 | if (this->selectedTitles.size() == 1) dialogResult = mainApp->CreateShowDialog("inst.target.desc0"_lang + inst::util::shortenString(inst::util::formatUrlString(this->selectedTitles[0]), 32, true) + "inst.target.desc1"_lang, "common.cancel_desc"_lang, {"inst.target.opt0"_lang, "inst.target.opt1"_lang}, false); 104 | else dialogResult = mainApp->CreateShowDialog("inst.target.desc00"_lang + std::to_string(this->selectedTitles.size()) + "inst.target.desc01"_lang, "common.cancel_desc"_lang, {"inst.target.opt0"_lang, "inst.target.opt1"_lang}, false); 105 | if (dialogResult == -1) return; 106 | usbInstStuff::installTitleUsb(this->selectedTitles, dialogResult); 107 | return; 108 | } 109 | 110 | void usbInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) { 111 | if (Down & HidNpadButton_B) { 112 | tin::util::USBCmdManager::SendExitCmd(); 113 | mainApp->LoadLayout(mainApp->mainPage); 114 | } 115 | if ((Down & HidNpadButton_A) || (Up & TouchPseudoKey)) { 116 | this->selectTitle(this->menu->GetSelectedIndex()); 117 | if (this->menu->GetItems().size() == 1 && this->selectedTitles.size() == 1) { 118 | this->startInstall(); 119 | } 120 | } 121 | if ((Down & HidNpadButton_Y)) { 122 | if (this->selectedTitles.size() == this->menu->GetItems().size()) this->drawMenuItems(true); 123 | else { 124 | for (long unsigned int i = 0; i < this->menu->GetItems().size(); i++) { 125 | if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue; 126 | else this->selectTitle(i); 127 | } 128 | this->drawMenuItems(false); 129 | } 130 | } 131 | if (Down & HidNpadButton_Plus) { 132 | if (this->selectedTitles.size() == 0) { 133 | this->selectTitle(this->menu->GetSelectedIndex()); 134 | this->startInstall(); 135 | return; 136 | } 137 | this->startInstall(); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /source/util/config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util/config.hpp" 4 | #include "util/json.hpp" 5 | 6 | namespace inst::config { 7 | std::string gAuthKey; 8 | std::string sigPatchesUrl; 9 | std::string lastNetUrl; 10 | std::vector updateInfo; 11 | int languageSetting; 12 | bool autoUpdate; 13 | bool deletePrompt; 14 | bool gayMode; 15 | bool ignoreReqVers; 16 | bool overClock; 17 | bool usbAck; 18 | bool validateNCAs; 19 | 20 | void setConfig() { 21 | nlohmann::json j = { 22 | {"autoUpdate", autoUpdate}, 23 | {"deletePrompt", deletePrompt}, 24 | {"gAuthKey", gAuthKey}, 25 | {"gayMode", gayMode}, 26 | {"ignoreReqVers", ignoreReqVers}, 27 | {"languageSetting", languageSetting}, 28 | {"overClock", overClock}, 29 | {"sigPatchesUrl", sigPatchesUrl}, 30 | {"usbAck", usbAck}, 31 | {"validateNCAs", validateNCAs}, 32 | {"lastNetUrl", lastNetUrl} 33 | }; 34 | std::ofstream file(inst::config::configPath); 35 | file << std::setw(4) << j << std::endl; 36 | } 37 | 38 | void parseConfig() { 39 | try { 40 | std::ifstream file(inst::config::configPath); 41 | nlohmann::json j; 42 | file >> j; 43 | autoUpdate = j["autoUpdate"].get(); 44 | deletePrompt = j["deletePrompt"].get(); 45 | gAuthKey = j["gAuthKey"].get(); 46 | gayMode = j["gayMode"].get(); 47 | ignoreReqVers = j["ignoreReqVers"].get(); 48 | languageSetting = j["languageSetting"].get(); 49 | overClock = j["overClock"].get(); 50 | sigPatchesUrl = j["sigPatchesUrl"].get(); 51 | usbAck = j["usbAck"].get(); 52 | validateNCAs = j["validateNCAs"].get(); 53 | lastNetUrl = j["lastNetUrl"].get(); 54 | } 55 | catch (...) { 56 | // If loading values from the config fails, we just load the defaults and overwrite the old config 57 | gAuthKey = {0x41,0x49,0x7a,0x61,0x53,0x79,0x42,0x4d,0x71,0x76,0x34,0x64,0x58,0x6e,0x54,0x4a,0x4f,0x47,0x51,0x74,0x5a,0x5a,0x53,0x33,0x43,0x42,0x6a,0x76,0x66,0x37,0x34,0x38,0x51,0x76,0x78,0x53,0x7a,0x46,0x30}; 58 | sigPatchesUrl = "https://sigmapatches.coomer.party/sigpatches.zip"; 59 | languageSetting = 99; 60 | autoUpdate = true; 61 | deletePrompt = true; 62 | gayMode = false; 63 | ignoreReqVers = true; 64 | overClock = false; 65 | usbAck = false; 66 | validateNCAs = true; 67 | lastNetUrl = "https://"; 68 | setConfig(); 69 | } 70 | if (sigPatchesUrl == "https://github.com/Huntereb/Awoo-Installer/releases/download/SignaturePatches/patches.zip") 71 | sigPatchesUrl = "https://sigmapatches.coomer.party/sigpatches.zip"; 72 | } 73 | } -------------------------------------------------------------------------------- /source/util/crypto.cpp: -------------------------------------------------------------------------------- 1 | #include "util/crypto.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void Crypto::calculateMGF1andXOR(unsigned char* data, size_t data_size, const void* source, size_t source_size) { 8 | unsigned char h_buf[RSA_2048_BYTES] = {0}; 9 | memcpy(h_buf, source, source_size); 10 | 11 | unsigned char mgf1_buf[0x20]; 12 | size_t ofs = 0; 13 | unsigned int seed = 0; 14 | while (ofs < data_size) { 15 | for (unsigned int i = 0; i < sizeof(seed); i++) { 16 | h_buf[source_size + 3 - i] = (seed >> (8 * i)) & 0xFF; 17 | } 18 | sha256CalculateHash(mgf1_buf, h_buf, source_size + 4); 19 | for (unsigned int i = ofs; i < data_size && i < ofs + 0x20; i++) { 20 | data[i] ^= mgf1_buf[i - ofs]; 21 | } 22 | seed++; 23 | ofs += 0x20; 24 | } 25 | } 26 | 27 | bool Crypto::rsa2048PssVerify(const void *data, size_t len, const unsigned char *signature, const unsigned char *modulus) { 28 | mbedtls_mpi signature_mpi; 29 | mbedtls_mpi modulus_mpi; 30 | mbedtls_mpi e_mpi; 31 | mbedtls_mpi message_mpi; 32 | 33 | mbedtls_mpi_init(&signature_mpi); 34 | mbedtls_mpi_init(&modulus_mpi); 35 | mbedtls_mpi_init(&e_mpi); 36 | mbedtls_mpi_init(&message_mpi); 37 | mbedtls_mpi_lset(&message_mpi, RSA_2048_BITS); 38 | 39 | unsigned char m_buf[RSA_2048_BYTES]; 40 | unsigned char h_buf[0x24]; 41 | const unsigned char E[3] = {1, 0, 1}; 42 | 43 | mbedtls_mpi_read_binary(&e_mpi, E, 3); 44 | mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES); 45 | mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES); 46 | mbedtls_mpi_exp_mod(&message_mpi, &signature_mpi, &e_mpi, &modulus_mpi, NULL); 47 | 48 | if (mbedtls_mpi_write_binary(&message_mpi, m_buf, RSA_2048_BYTES) != 0) { 49 | throw std::runtime_error("Failed to export exponentiated RSA message!"); 50 | } 51 | 52 | mbedtls_mpi_free(&signature_mpi); 53 | mbedtls_mpi_free(&modulus_mpi); 54 | mbedtls_mpi_free(&e_mpi); 55 | mbedtls_mpi_free(&message_mpi); 56 | 57 | /* There's no automated PSS verification as far as I can tell. */ 58 | if (m_buf[RSA_2048_BYTES-1] != 0xBC) { 59 | return false; 60 | } 61 | 62 | memset(h_buf, 0, 0x24); 63 | memcpy(h_buf, m_buf + RSA_2048_BYTES - 0x20 - 0x1, 0x20); 64 | 65 | /* Decrypt maskedDB. */ 66 | calculateMGF1andXOR(m_buf, RSA_2048_BYTES - 0x20 - 1, h_buf, 0x20); 67 | 68 | m_buf[0] &= 0x7F; /* Constant lmask for rsa-2048-pss. */ 69 | 70 | /* Validate DB. */ 71 | for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) { 72 | if (m_buf[i] != 0) { 73 | return false; 74 | } 75 | } 76 | if (m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) { 77 | return false; 78 | } 79 | 80 | /* Check hash correctness. */ 81 | unsigned char validate_buf[8 + 0x20 + 0x20]; 82 | unsigned char validate_hash[0x20]; 83 | memset(validate_buf, 0, 0x48); 84 | 85 | sha256CalculateHash(&validate_buf[8], data, len); 86 | memcpy(&validate_buf[0x28], &m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20); 87 | sha256CalculateHash(validate_hash, validate_buf, 0x48); 88 | 89 | return memcmp(h_buf, validate_hash, 0x20) == 0; 90 | } -------------------------------------------------------------------------------- /source/util/curl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "util/curl.hpp" 6 | #include "util/config.hpp" 7 | #include "util/error.hpp" 8 | #include "ui/instPage.hpp" 9 | 10 | static size_t writeDataFile(void *ptr, size_t size, size_t nmemb, void *stream) { 11 | size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); 12 | return written; 13 | } 14 | 15 | size_t writeDataBuffer(char *ptr, size_t size, size_t nmemb, void *userdata) { 16 | std::ostringstream *stream = (std::ostringstream*)userdata; 17 | size_t count = size * nmemb; 18 | stream->write(ptr, count); 19 | return count; 20 | } 21 | 22 | int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { 23 | if (ultotal) { 24 | int uploadProgress = (int)(((double)ulnow / (double)ultotal) * 100.0); 25 | inst::ui::instPage::setInstBarPerc(uploadProgress); 26 | } else if (dltotal) { 27 | int downloadProgress = (int)(((double)dlnow / (double)dltotal) * 100.0); 28 | inst::ui::instPage::setInstBarPerc(downloadProgress); 29 | } 30 | return 0; 31 | } 32 | 33 | namespace inst::curl { 34 | bool downloadFile (const std::string ourUrl, const char *pagefilename, long timeout, bool writeProgress) { 35 | CURL *curl_handle; 36 | CURLcode result; 37 | FILE *pagefile; 38 | 39 | curl_global_init(CURL_GLOBAL_ALL); 40 | curl_handle = curl_easy_init(); 41 | 42 | curl_easy_setopt(curl_handle, CURLOPT_URL, ourUrl.c_str()); 43 | curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); 44 | curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); 45 | curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Awoo-Installer"); 46 | curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); 47 | curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L); 48 | curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout); 49 | curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, timeout); 50 | curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeDataFile); 51 | if (writeProgress) curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, progress_callback); 52 | 53 | pagefile = fopen(pagefilename, "wb"); 54 | curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile); 55 | result = curl_easy_perform(curl_handle); 56 | 57 | curl_easy_cleanup(curl_handle); 58 | curl_global_cleanup(); 59 | fclose(pagefile); 60 | 61 | if (result == CURLE_OK) return true; 62 | else { 63 | LOG_DEBUG(curl_easy_strerror(result)); 64 | return false; 65 | } 66 | } 67 | 68 | std::string downloadToBuffer (const std::string ourUrl, int firstRange, int secondRange, long timeout) { 69 | CURL *curl_handle; 70 | CURLcode result; 71 | std::ostringstream stream; 72 | 73 | curl_global_init(CURL_GLOBAL_ALL); 74 | curl_handle = curl_easy_init(); 75 | 76 | curl_easy_setopt(curl_handle, CURLOPT_URL, ourUrl.c_str()); 77 | curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); 78 | curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); 79 | curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Awoo-Installer"); 80 | curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); 81 | curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L); 82 | curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout); 83 | curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, timeout); 84 | curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeDataBuffer); 85 | if (firstRange && secondRange) { 86 | const char * ourRange = (std::to_string(firstRange) + "-" + std::to_string(secondRange)).c_str(); 87 | curl_easy_setopt(curl_handle, CURLOPT_RANGE, ourRange); 88 | } 89 | 90 | curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &stream); 91 | result = curl_easy_perform(curl_handle); 92 | 93 | curl_easy_cleanup(curl_handle); 94 | curl_global_cleanup(); 95 | 96 | if (result == CURLE_OK) return stream.str(); 97 | else { 98 | LOG_DEBUG(curl_easy_strerror(result)); 99 | return ""; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /source/util/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "util/debug.h" 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | void printBytes(u8 *bytes, size_t size, bool includeHeader) 33 | { 34 | #ifdef NXLINK_DEBUG 35 | int count = 0; 36 | 37 | if (includeHeader) 38 | { 39 | printf("\n\n00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 40 | printf("-----------------------------------------------\n"); 41 | } 42 | 43 | for (int i = 0; i < size; i++) 44 | { 45 | printf("%02x ", bytes[i]); 46 | count++; 47 | if ((count % 16) == 0) 48 | printf("\n"); 49 | } 50 | 51 | printf("\n"); 52 | #endif 53 | } -------------------------------------------------------------------------------- /source/util/file_util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "util/file_util.hpp" 24 | 25 | #include 26 | 27 | #include "install/simple_filesystem.hpp" 28 | #include "nx/fs.hpp" 29 | #include "data/byte_buffer.hpp" 30 | #include "util/title_util.hpp" 31 | 32 | namespace tin::util 33 | { 34 | // TODO: do this manually so we don't have to "install" the cnmt's 35 | nx::ncm::ContentMeta GetContentMetaFromNCA(const std::string& ncaPath) 36 | { 37 | // Create the cnmt filesystem 38 | nx::fs::IFileSystem cnmtNCAFileSystem; 39 | cnmtNCAFileSystem.OpenFileSystemWithId(ncaPath, FsFileSystemType_ContentMeta, 0); 40 | tin::install::nsp::SimpleFileSystem cnmtNCASimpleFileSystem(cnmtNCAFileSystem, "/", ncaPath + "/"); 41 | 42 | // Find and read the cnmt file 43 | auto cnmtName = cnmtNCASimpleFileSystem.GetFileNameFromExtension("", "cnmt"); 44 | auto cnmtFile = cnmtNCASimpleFileSystem.OpenFile(cnmtName); 45 | u64 cnmtSize = cnmtFile.GetSize(); 46 | 47 | tin::data::ByteBuffer cnmtBuf; 48 | cnmtBuf.Resize(cnmtSize); 49 | cnmtFile.Read(0x0, cnmtBuf.GetData(), cnmtSize); 50 | 51 | return nx::ncm::ContentMeta(cnmtBuf.GetData(), cnmtBuf.GetSize()); 52 | } 53 | } -------------------------------------------------------------------------------- /source/util/lang.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "util/lang.hpp" 6 | #include "util/config.hpp" 7 | 8 | namespace Language { 9 | json lang; 10 | 11 | void Load() { 12 | std::ifstream ifs; 13 | std::string languagePath; 14 | int langInt = inst::config::languageSetting; 15 | if (langInt == 99) { 16 | SetLanguage ourLang; 17 | u64 lcode = 0; 18 | setInitialize(); 19 | setGetSystemLanguage(&lcode); 20 | setMakeLanguage(lcode, &ourLang); 21 | setExit(); 22 | langInt = (int)ourLang; 23 | } 24 | switch (langInt) { 25 | case SetLanguage_JA: 26 | languagePath = "romfs:/lang/jp.json"; 27 | break; 28 | case SetLanguage_FR: 29 | case SetLanguage_FRCA: 30 | languagePath = "romfs:/lang/fr.json"; 31 | break; 32 | case SetLanguage_DE: 33 | languagePath = "romfs:/lang/de.json"; 34 | break; 35 | case SetLanguage_IT: 36 | languagePath = "romfs:/lang/it.json"; 37 | break; 38 | case SetLanguage_ES: 39 | case SetLanguage_ES419: 40 | languagePath = "romfs:/lang/es-419.json"; 41 | break; 42 | case SetLanguage_ZHCN: 43 | case SetLanguage_ZHHANS: 44 | languagePath = "romfs:/lang/zh-CN.json"; 45 | // the default font will miss some chinese character, so use a chinese font (simplified) 46 | pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::ChineseSimplified); 47 | break; 48 | case SetLanguage_KO: 49 | languagePath = "romfs:/lang/ko.json"; 50 | pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::Korean); 51 | break; 52 | case SetLanguage_NL: 53 | languagePath = "romfs:/lang/nl.json"; 54 | break; 55 | case SetLanguage_PT: 56 | case SetLanguage_PTBR: 57 | languagePath = "romfs:/lang/pt.json"; 58 | break; 59 | case SetLanguage_RU: 60 | languagePath = "romfs:/lang/ru.json"; 61 | break; 62 | case SetLanguage_ZHTW: 63 | languagePath = "romfs:/lang/zh-TW.json"; 64 | // the default font will miss some chinese character, so use a chinese font (traditional) 65 | pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::ChineseTraditional); 66 | break; 67 | case SetLanguage_ZHHANT: 68 | languagePath = "romfs:/lang/zh-Hant.json"; 69 | pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::ChineseTraditional); 70 | break; 71 | case SetLanguage_ENUS: 72 | default: 73 | languagePath = "romfs:/lang/en.json"; 74 | } 75 | if (std::filesystem::exists(languagePath)) ifs = std::ifstream(languagePath); 76 | else ifs = std::ifstream("romfs:/lang/en.json"); 77 | if (!ifs.good()) { 78 | std::cout << "[FAILED TO LOAD LANGUAGE FILE]" << std::endl; 79 | return; 80 | } 81 | lang = json::parse(ifs); 82 | ifs.close(); 83 | } 84 | 85 | std::string LanguageEntry(std::string key) { 86 | json j = GetRelativeJson(lang, key); 87 | if (j == nullptr) { 88 | return "didn't find: " + key; 89 | } 90 | return j.get(); 91 | } 92 | 93 | std::string GetRandomMsg() { 94 | json j = Language::GetRelativeJson(lang, "inst.finished"); 95 | srand(time(NULL)); 96 | return(j[rand() % j.size()]); 97 | } 98 | } -------------------------------------------------------------------------------- /source/util/title_util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "util/title_util.hpp" 24 | 25 | #include 26 | #include "util/error.hpp" 27 | 28 | namespace tin::util 29 | { 30 | u64 GetRightsIdTid(FsRightsId rightsId) 31 | { 32 | return __bswap64(*(u64 *)rightsId.c); 33 | } 34 | 35 | u64 GetRightsIdKeyGen(FsRightsId rightsId) 36 | { 37 | return __bswap64(*(u64 *)(rightsId.c + 8)); 38 | } 39 | 40 | std::string GetNcaIdString(const NcmContentId& ncaId) 41 | { 42 | char ncaIdStr[FS_MAX_PATH] = {0}; 43 | u64 ncaIdLower = __bswap64(*(u64 *)ncaId.c); 44 | u64 ncaIdUpper = __bswap64(*(u64 *)(ncaId.c + 0x8)); 45 | snprintf(ncaIdStr, FS_MAX_PATH, "%016lx%016lx", ncaIdLower, ncaIdUpper); 46 | return std::string(ncaIdStr); 47 | } 48 | 49 | NcmContentId GetNcaIdFromString(std::string ncaIdStr) 50 | { 51 | NcmContentId ncaId = {0}; 52 | char lowerU64[17] = {0}; 53 | char upperU64[17] = {0}; 54 | memcpy(lowerU64, ncaIdStr.c_str(), 16); 55 | memcpy(upperU64, ncaIdStr.c_str() + 16, 16); 56 | 57 | *(u64 *)ncaId.c = __bswap64(strtoul(lowerU64, NULL, 16)); 58 | *(u64 *)(ncaId.c + 8) = __bswap64(strtoul(upperU64, NULL, 16)); 59 | 60 | return ncaId; 61 | } 62 | 63 | u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType) 64 | { 65 | switch (contentMetaType) 66 | { 67 | case NcmContentMetaType_Patch: 68 | return titleId ^ 0x800; 69 | 70 | case NcmContentMetaType_AddOnContent: 71 | return (titleId ^ 0x1000) & ~0xFFF; 72 | 73 | default: 74 | return titleId; 75 | } 76 | } 77 | 78 | std::string GetBaseTitleName(u64 baseTitleId) 79 | { 80 | Result rc = 0; 81 | NsApplicationControlData appControlData; 82 | size_t sizeRead; 83 | 84 | if (R_FAILED(rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, baseTitleId, &appControlData, sizeof(NsApplicationControlData), &sizeRead))) 85 | { 86 | LOG_DEBUG("Failed to get application control data. Error code: 0x%08x\n", rc); 87 | return "Unknown"; 88 | } 89 | 90 | if (sizeRead < sizeof(appControlData.nacp)) 91 | { 92 | LOG_DEBUG("Incorrect size for nacp\n"); 93 | return "Unknown"; 94 | } 95 | 96 | NacpLanguageEntry *languageEntry; 97 | 98 | if (R_FAILED(rc = nacpGetLanguageEntry(&appControlData.nacp, &languageEntry))) 99 | { 100 | LOG_DEBUG("Failed to get language entry. Error code: 0x%08x\n", rc); 101 | return "Unknown"; 102 | } 103 | 104 | if (languageEntry == NULL) 105 | { 106 | LOG_DEBUG("Language entry is null! Error code: 0x%08x\n", rc); 107 | return "Unknown"; 108 | } 109 | 110 | return languageEntry->name; 111 | } 112 | 113 | std::string GetTitleName(u64 titleId, NcmContentMetaType contentMetaType) 114 | { 115 | u64 baseTitleId = GetBaseTitleId(titleId, contentMetaType); 116 | std::string titleName = GetBaseTitleName(baseTitleId); 117 | 118 | switch (contentMetaType) 119 | { 120 | case NcmContentMetaType_Patch: 121 | titleName += " (Update)"; 122 | break; 123 | 124 | case NcmContentMetaType_AddOnContent: 125 | titleName += " (DLC)"; 126 | break; 127 | 128 | default: 129 | break; 130 | } 131 | 132 | return titleName; 133 | } 134 | } -------------------------------------------------------------------------------- /source/util/unzip.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // https://github.com/AtlasNX/Kosmos-Updater/blob/master/source/FileManager.cpp 11 | 12 | unz_file_info_s * _getFileInfo(unzFile unz) { 13 | unz_file_info_s * fileInfo = (unz_file_info_s*) malloc(sizeof(unz_file_info_s)); 14 | unzGetCurrentFileInfo(unz, fileInfo, NULL, 0, NULL, 0, NULL, 0); 15 | return fileInfo; 16 | } 17 | 18 | std::string _getFullFileName(unzFile unz, unz_file_info_s * fileInfo) { 19 | char filePath[fileInfo->size_filename + 1]; 20 | 21 | unzGetCurrentFileInfo(unz, fileInfo, filePath, fileInfo->size_filename, NULL, 0, NULL, 0); 22 | filePath[fileInfo->size_filename] = '\0'; 23 | 24 | std::string path(filePath); 25 | path.resize(fileInfo->size_filename); 26 | 27 | return path; 28 | } 29 | 30 | bool _makeDirectoryParents(std::string path) 31 | { 32 | bool bSuccess = false; 33 | int nRC = ::mkdir(path.c_str(), 0775); 34 | if(nRC == -1) 35 | { 36 | switch(errno) 37 | { 38 | case ENOENT: 39 | //parent didn't exist, try to create it 40 | if( _makeDirectoryParents(path.substr(0, path.find_last_of('/')))) 41 | //Now, try to create again. 42 | bSuccess = 0 == ::mkdir(path.c_str(), 0775); 43 | else 44 | bSuccess = false; 45 | break; 46 | case EEXIST: 47 | //Done! 48 | bSuccess = true; 49 | break; 50 | default: 51 | bSuccess = false; 52 | break; 53 | } 54 | } 55 | else 56 | bSuccess = true; 57 | 58 | return bSuccess; 59 | } 60 | 61 | int _extractFile(const char * path, unzFile unz, unz_file_info_s * fileInfo) { 62 | //check to make sure filepath or fileInfo isnt null 63 | if (path == NULL || fileInfo == NULL) 64 | return -1; 65 | 66 | if (unzOpenCurrentFile(unz) != UNZ_OK) 67 | return -2; 68 | 69 | char folderPath[strlen(path) + 1]; 70 | strcpy(folderPath, path); 71 | char * pos = strrchr(folderPath, '/'); 72 | if (pos != NULL) { 73 | *pos = '\0'; 74 | _makeDirectoryParents(std::string(folderPath)); 75 | } 76 | 77 | u32 blocksize = 0x8000; 78 | u8 * buffer = (u8*) malloc(blocksize); 79 | if (buffer == NULL) 80 | return -3; 81 | u32 done = 0; 82 | int writeBytes = 0; 83 | FILE * fp = fopen(path, "w"); 84 | if (fp == NULL) { 85 | free(buffer); 86 | return -4; 87 | } 88 | 89 | while (done < fileInfo->uncompressed_size) { 90 | if (done + blocksize > fileInfo->uncompressed_size) { 91 | blocksize = fileInfo->uncompressed_size - done; 92 | } 93 | unzReadCurrentFile(unz, buffer, blocksize); 94 | writeBytes = write(fileno(fp), buffer, blocksize); 95 | if (writeBytes <= 0) { 96 | break; 97 | } 98 | done += writeBytes; 99 | } 100 | 101 | fflush(fp); 102 | fsync(fileno(fp)); 103 | fclose(fp); 104 | 105 | free(buffer); 106 | if (done != fileInfo->uncompressed_size) 107 | return -4; 108 | 109 | unzCloseCurrentFile(unz); 110 | return 0; 111 | } 112 | 113 | namespace inst::zip { 114 | bool extractFile(const std::string filename, const std::string destination) { 115 | unzFile unz = unzOpen(filename.c_str()); 116 | 117 | int i = 0; 118 | for (;;) { 119 | int code; 120 | if (i == 0) { 121 | code = unzGoToFirstFile(unz); 122 | } else { 123 | code = unzGoToNextFile(unz); 124 | } 125 | i++; 126 | 127 | if (code == UNZ_END_OF_LIST_OF_FILE) { 128 | break; 129 | } else { 130 | unz_file_pos pos; 131 | unzGetFilePos(unz, &pos); 132 | } 133 | 134 | unz_file_info_s * fileInfo = _getFileInfo(unz); 135 | 136 | std::string fileName = destination; 137 | fileName += _getFullFileName(unz, fileInfo); 138 | 139 | if (fileName.back() != '/') { 140 | int result = _extractFile(fileName.c_str(), unz, fileInfo); 141 | if (result < 0) { 142 | free(fileInfo); 143 | unzClose(unz); 144 | return false; 145 | } 146 | } 147 | 148 | free(fileInfo); 149 | } 150 | 151 | if (i <= 0) { 152 | unzClose(unz); 153 | return false; 154 | } 155 | 156 | unzClose(unz); 157 | return true; 158 | } 159 | } -------------------------------------------------------------------------------- /source/util/usb_util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2018 Adubbz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "util/usb_util.hpp" 24 | #include "util/usb_comms_awoo.h" 25 | 26 | #include "data/byte_buffer.hpp" 27 | #include "debug.h" 28 | #include "error.hpp" 29 | 30 | namespace tin::util 31 | { 32 | void USBCmdManager::SendCmdHeader(u32 cmdId, size_t dataSize) 33 | { 34 | USBCmdHeader header; 35 | header.magic = 0x30435554; // TUC0 (Tinfoil USB Command 0) 36 | header.type = USBCmdType::REQUEST; 37 | header.cmdId = cmdId; 38 | header.dataSize = dataSize; 39 | 40 | USBWrite(&header, sizeof(USBCmdHeader)); 41 | } 42 | 43 | void USBCmdManager::SendExitCmd() 44 | { 45 | USBCmdManager::SendCmdHeader(0, 0); 46 | } 47 | 48 | USBCmdHeader USBCmdManager::SendFileRangeCmd(std::string nspName, u64 offset, u64 size) 49 | { 50 | struct FileRangeCmdHeader 51 | { 52 | u64 size; 53 | u64 offset; 54 | u64 nspNameLen; 55 | u64 padding; 56 | } fRangeHeader; 57 | 58 | fRangeHeader.size = size; 59 | fRangeHeader.offset = offset; 60 | fRangeHeader.nspNameLen = nspName.size(); 61 | fRangeHeader.padding = 0; 62 | 63 | USBCmdManager::SendCmdHeader(1, sizeof(FileRangeCmdHeader) + fRangeHeader.nspNameLen); 64 | USBWrite(&fRangeHeader, sizeof(FileRangeCmdHeader)); 65 | USBWrite(nspName.c_str(), fRangeHeader.nspNameLen); 66 | 67 | USBCmdHeader responseHeader; 68 | USBRead(&responseHeader, sizeof(USBCmdHeader)); 69 | return responseHeader; 70 | } 71 | 72 | size_t USBRead(void* out, size_t len, u64 timeout) 73 | { 74 | u8* tmpBuf = (u8*)out; 75 | size_t sizeRemaining = len; 76 | size_t tmpSizeRead = 0; 77 | 78 | while (sizeRemaining) 79 | { 80 | tmpSizeRead = awoo_usbCommsRead(tmpBuf, sizeRemaining, timeout); 81 | if (tmpSizeRead == 0) return 0; 82 | tmpBuf += tmpSizeRead; 83 | sizeRemaining -= tmpSizeRead; 84 | } 85 | 86 | return len; 87 | } 88 | 89 | size_t USBWrite(const void* in, size_t len, u64 timeout) 90 | { 91 | const u8 *bufptr = (const u8 *)in; 92 | size_t cursize = len; 93 | size_t tmpsize = 0; 94 | 95 | while (cursize) 96 | { 97 | tmpsize = awoo_usbCommsWrite(bufptr, cursize, timeout); 98 | if (tmpsize == 0) return 0; 99 | bufptr += tmpsize; 100 | cursize -= tmpsize; 101 | } 102 | 103 | return len; 104 | } 105 | } --------------------------------------------------------------------------------