reformat code
This commit is contained in:
parent
ba57710eb1
commit
48015449c2
@ -24,5 +24,5 @@ SOFTWARE.
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
namespace nspInstStuff_B {
|
namespace nspInstStuff_B {
|
||||||
void installNspFromFile(std::vector<std::filesystem::path> ourNspList, int whereToInstall);
|
void installNspFromFile(std::vector<std::filesystem::path> ourNspList, int whereToInstall);
|
||||||
}
|
}
|
||||||
|
@ -31,59 +31,59 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::data
|
namespace tin::data
|
||||||
{
|
{
|
||||||
static const size_t BUFFER_SEGMENT_DATA_SIZE = 0x800000; // Approximately 8MB
|
static const size_t BUFFER_SEGMENT_DATA_SIZE = 0x800000; // Approximately 8MB
|
||||||
extern int NUM_BUFFER_SEGMENTS;
|
extern int NUM_BUFFER_SEGMENTS;
|
||||||
|
|
||||||
struct BufferSegment
|
struct BufferSegment
|
||||||
{
|
{
|
||||||
std::atomic_bool isFinalized = false;
|
std::atomic_bool isFinalized = false;
|
||||||
u64 writeOffset = 0;
|
u64 writeOffset = 0;
|
||||||
u8 data[BUFFER_SEGMENT_DATA_SIZE] = {0};
|
u8 data[BUFFER_SEGMENT_DATA_SIZE] = { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
// Receives data in a circular buffer split into 8MB segments
|
// Receives data in a circular buffer split into 8MB segments
|
||||||
class BufferedPlaceholderWriter
|
class BufferedPlaceholderWriter
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
size_t m_totalDataSize = 0;
|
size_t m_totalDataSize = 0;
|
||||||
size_t m_sizeBuffered = 0;
|
size_t m_sizeBuffered = 0;
|
||||||
size_t m_sizeWrittenToPlaceholder = 0;
|
size_t m_sizeWrittenToPlaceholder = 0;
|
||||||
|
|
||||||
// The current segment to which further data will be appended
|
// The current segment to which further data will be appended
|
||||||
u64 m_currentFreeSegment = 0;
|
u64 m_currentFreeSegment = 0;
|
||||||
BufferSegment* m_currentFreeSegmentPtr = NULL;
|
BufferSegment* m_currentFreeSegmentPtr = NULL;
|
||||||
// The current segment that will be written to the placeholder
|
// The current segment that will be written to the placeholder
|
||||||
u64 m_currentSegmentToWrite = 0;
|
u64 m_currentSegmentToWrite = 0;
|
||||||
BufferSegment* m_currentSegmentToWritePtr = NULL;
|
BufferSegment* m_currentSegmentToWritePtr = NULL;
|
||||||
|
|
||||||
std::unique_ptr<BufferSegment[]> m_bufferSegments;
|
std::unique_ptr<BufferSegment[]> m_bufferSegments;
|
||||||
|
|
||||||
std::shared_ptr<nx::ncm::ContentStorage> m_contentStorage;
|
std::shared_ptr<nx::ncm::ContentStorage> m_contentStorage;
|
||||||
NcmContentId m_ncaId;
|
NcmContentId m_ncaId;
|
||||||
NcaWriter m_writer;
|
NcaWriter m_writer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BufferedPlaceholderWriter(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId, size_t totalDataSize);
|
BufferedPlaceholderWriter(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId, size_t totalDataSize);
|
||||||
|
|
||||||
void AppendData(void* source, size_t length);
|
void AppendData(void* source, size_t length);
|
||||||
bool CanAppendData(size_t length);
|
bool CanAppendData(size_t length);
|
||||||
|
|
||||||
void WriteSegmentToPlaceholder();
|
void WriteSegmentToPlaceholder();
|
||||||
bool CanWriteSegmentToPlaceholder();
|
bool CanWriteSegmentToPlaceholder();
|
||||||
|
|
||||||
// Determine the number of segments required to fit data of this size
|
// Determine the number of segments required to fit data of this size
|
||||||
u32 CalcNumSegmentsRequired(size_t size);
|
u32 CalcNumSegmentsRequired(size_t size);
|
||||||
|
|
||||||
// Check if there are enough free segments to fit data of this size
|
// Check if there are enough free segments to fit data of this size
|
||||||
bool IsSizeAvailable(size_t size);
|
bool IsSizeAvailable(size_t size);
|
||||||
|
|
||||||
bool IsBufferDataComplete();
|
bool IsBufferDataComplete();
|
||||||
bool IsPlaceholderComplete();
|
bool IsPlaceholderComplete();
|
||||||
|
|
||||||
size_t GetTotalDataSize();
|
size_t GetTotalDataSize();
|
||||||
size_t GetSizeBuffered();
|
size_t GetSizeBuffered();
|
||||||
size_t GetSizeWrittenToPlaceholder();
|
size_t GetSizeWrittenToPlaceholder();
|
||||||
|
|
||||||
void DebugPrintBuffers();
|
void DebugPrintBuffers();
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -28,45 +28,45 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::data
|
namespace tin::data
|
||||||
{
|
{
|
||||||
class ByteBuffer
|
class ByteBuffer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<u8> m_buffer;
|
std::vector<u8> m_buffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ByteBuffer(size_t reserveSize=0);
|
ByteBuffer(size_t reserveSize = 0);
|
||||||
|
|
||||||
size_t GetSize();
|
size_t GetSize();
|
||||||
u8* GetData(); // TODO: Remove this, it shouldn't be needed
|
u8* GetData(); // TODO: Remove this, it shouldn't be needed
|
||||||
void Resize(size_t size);
|
void Resize(size_t size);
|
||||||
|
|
||||||
void DebugPrintContents();
|
void DebugPrintContents();
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Read(u64 offset)
|
T Read(u64 offset)
|
||||||
{
|
{
|
||||||
if (offset + sizeof(T) <= m_buffer.size())
|
if (offset + sizeof(T) <= m_buffer.size())
|
||||||
return *((T*)&m_buffer.data()[offset]);
|
return *((T*)&m_buffer.data()[offset]);
|
||||||
|
|
||||||
T def;
|
T def;
|
||||||
memset(&def, 0, sizeof(T));
|
memset(&def, 0, sizeof(T));
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void Write(T data, u64 offset)
|
|
||||||
{
|
|
||||||
size_t requiredSize = offset + sizeof(T);
|
|
||||||
|
|
||||||
if (requiredSize > m_buffer.size())
|
template <typename T>
|
||||||
m_buffer.resize(requiredSize, 0);
|
void Write(T data, u64 offset)
|
||||||
|
{
|
||||||
memcpy(m_buffer.data() + offset, &data, sizeof(T));
|
size_t requiredSize = offset + sizeof(T);
|
||||||
}
|
|
||||||
template <typename T>
|
if (requiredSize > m_buffer.size())
|
||||||
void Append(T data)
|
m_buffer.resize(requiredSize, 0);
|
||||||
{
|
|
||||||
this->Write(data, this->GetSize());
|
memcpy(m_buffer.data() + offset, &data, sizeof(T));
|
||||||
}
|
}
|
||||||
};
|
template <typename T>
|
||||||
|
void Append(T data)
|
||||||
|
{
|
||||||
|
this->Write(data, this->GetSize());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
@ -27,25 +27,25 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::data
|
namespace tin::data
|
||||||
{
|
{
|
||||||
class ByteStream
|
class ByteStream
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
u64 m_offset = 0;
|
u64 m_offset = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void ReadBytes(void* dest, size_t length) = 0;
|
virtual void ReadBytes(void* dest, size_t length) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: This isn't generally useful, it's mainly for things like libpng
|
// NOTE: This isn't generally useful, it's mainly for things like libpng
|
||||||
// which rely on streams
|
// which rely on streams
|
||||||
class BufferedByteStream : public ByteStream
|
class BufferedByteStream : public ByteStream
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ByteBuffer m_byteBuffer;
|
ByteBuffer m_byteBuffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BufferedByteStream(ByteBuffer buffer);
|
BufferedByteStream(ByteBuffer buffer);
|
||||||
|
|
||||||
void ReadBytes(void* dest, size_t length) override;
|
void ReadBytes(void* dest, size_t length) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -6,52 +6,52 @@
|
|||||||
|
|
||||||
namespace tin::install
|
namespace tin::install
|
||||||
{
|
{
|
||||||
struct HFS0FileEntry
|
struct HFS0FileEntry
|
||||||
{
|
{
|
||||||
u64 dataOffset;
|
u64 dataOffset;
|
||||||
u64 fileSize;
|
u64 fileSize;
|
||||||
u32 stringTableOffset;
|
u32 stringTableOffset;
|
||||||
u32 hashedSize;
|
u32 hashedSize;
|
||||||
u64 padding;
|
u64 padding;
|
||||||
unsigned char hash[0x20];
|
unsigned char hash[0x20];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(HFS0FileEntry) == 0x40, "HFS0FileEntry must be 0x18");
|
static_assert(sizeof(HFS0FileEntry) == 0x40, "HFS0FileEntry must be 0x18");
|
||||||
|
|
||||||
struct HFS0BaseHeader
|
struct HFS0BaseHeader
|
||||||
{
|
{
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u32 numFiles;
|
u32 numFiles;
|
||||||
u32 stringTableSize;
|
u32 stringTableSize;
|
||||||
u32 reserved;
|
u32 reserved;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(HFS0BaseHeader) == 0x10, "HFS0BaseHeader must be 0x10");
|
static_assert(sizeof(HFS0BaseHeader) == 0x10, "HFS0BaseHeader must be 0x10");
|
||||||
|
|
||||||
NX_INLINE const HFS0FileEntry *hfs0GetFileEntry(const HFS0BaseHeader *header, u32 i)
|
NX_INLINE const HFS0FileEntry* hfs0GetFileEntry(const HFS0BaseHeader* header, u32 i)
|
||||||
{
|
{
|
||||||
if (i >= header->numFiles)
|
if (i >= header->numFiles)
|
||||||
return NULL;
|
return NULL;
|
||||||
return (const HFS0FileEntry*)(header + 0x1 + i * 0x4);
|
return (const HFS0FileEntry*)(header + 0x1 + i * 0x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE const char *hfs0GetStringTable(const HFS0BaseHeader *header)
|
NX_INLINE const char* hfs0GetStringTable(const HFS0BaseHeader* header)
|
||||||
{
|
{
|
||||||
return (const char*)(header + 0x1 + header->numFiles * 0x4);
|
return (const char*)(header + 0x1 + header->numFiles * 0x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE u64 hfs0GetHeaderSize(const HFS0BaseHeader *header)
|
NX_INLINE u64 hfs0GetHeaderSize(const HFS0BaseHeader* header)
|
||||||
{
|
{
|
||||||
return 0x1 + header->numFiles * 0x4 + header->stringTableSize;
|
return 0x1 + header->numFiles * 0x4 + header->stringTableSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE const char *hfs0GetFileName(const HFS0BaseHeader *header, u32 i)
|
NX_INLINE const char* hfs0GetFileName(const HFS0BaseHeader* header, u32 i)
|
||||||
{
|
{
|
||||||
return hfs0GetStringTable(header) + hfs0GetFileEntry(header, i)->stringTableOffset;
|
return hfs0GetStringTable(header) + hfs0GetFileEntry(header, i)->stringTableOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE const char *hfs0GetFileName(const HFS0BaseHeader *header, const HFS0FileEntry *entry)
|
NX_INLINE const char* hfs0GetFileName(const HFS0BaseHeader* header, const HFS0FileEntry* entry)
|
||||||
{
|
{
|
||||||
return hfs0GetStringTable(header) + entry->stringTableOffset;
|
return hfs0GetStringTable(header) + entry->stringTableOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,14 +27,14 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
class HTTPNSP : public NSP
|
class HTTPNSP : public NSP
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tin::network::HTTPDownload m_download;
|
tin::network::HTTPDownload m_download;
|
||||||
|
|
||||||
HTTPNSP(std::string url);
|
HTTPNSP(std::string url);
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -28,14 +28,14 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
class HTTPXCI : public XCI
|
class HTTPXCI : public XCI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tin::network::HTTPDownload m_download;
|
tin::network::HTTPDownload m_download;
|
||||||
|
|
||||||
HTTPXCI(std::string url);
|
HTTPXCI(std::string url);
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -39,31 +39,31 @@ extern "C"
|
|||||||
|
|
||||||
namespace tin::install
|
namespace tin::install
|
||||||
{
|
{
|
||||||
class Install
|
class Install
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const NcmStorageId m_destStorageId;
|
const NcmStorageId m_destStorageId;
|
||||||
bool m_ignoreReqFirmVersion = false;
|
bool m_ignoreReqFirmVersion = false;
|
||||||
bool m_declinedValidation = false;
|
bool m_declinedValidation = false;
|
||||||
|
|
||||||
std::vector<nx::ncm::ContentMeta> m_contentMeta;
|
std::vector<nx::ncm::ContentMeta> m_contentMeta;
|
||||||
|
|
||||||
Install(NcmStorageId destStorageId, bool ignoreReqFirmVersion);
|
Install(NcmStorageId destStorageId, bool ignoreReqFirmVersion);
|
||||||
|
|
||||||
virtual std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> ReadCNMT() = 0;
|
virtual std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> ReadCNMT() = 0;
|
||||||
|
|
||||||
virtual void InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf, int i);
|
virtual void InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf, int i);
|
||||||
virtual void InstallApplicationRecord(int i);
|
virtual void InstallApplicationRecord(int i);
|
||||||
virtual void InstallTicketCert() = 0;
|
virtual void InstallTicketCert() = 0;
|
||||||
virtual void InstallNCA(const NcmContentId &ncaId) = 0;
|
virtual void InstallNCA(const NcmContentId& ncaId) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Install();
|
virtual ~Install();
|
||||||
|
|
||||||
virtual void Prepare();
|
virtual void Prepare();
|
||||||
virtual void Begin();
|
virtual void Begin();
|
||||||
|
|
||||||
virtual u64 GetTitleId(int i = 0);
|
virtual u64 GetTitleId(int i = 0);
|
||||||
virtual NcmContentMetaType GetContentMetaType(int i = 0);
|
virtual NcmContentMetaType GetContentMetaType(int i = 0);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -29,17 +29,17 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
class NSPInstall : public Install
|
class NSPInstall : public Install
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const std::shared_ptr<NSP> m_NSP;
|
const std::shared_ptr<NSP> m_NSP;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> ReadCNMT() override;
|
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> ReadCNMT() override;
|
||||||
void InstallNCA(const NcmContentId& ncaId) override;
|
void InstallNCA(const NcmContentId& ncaId) override;
|
||||||
void InstallTicketCert() override;
|
void InstallTicketCert() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NSPInstall(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<NSP>& remoteNSP);
|
NSPInstall(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<NSP>& remoteNSP);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -30,18 +30,18 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
class XCIInstallTask : public Install
|
class XCIInstallTask : public Install
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const std::shared_ptr<tin::install::xci::XCI> m_xci;
|
const std::shared_ptr<tin::install::xci::XCI> m_xci;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> ReadCNMT() override;
|
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> ReadCNMT() override;
|
||||||
void InstallNCA(const NcmContentId& ncaId) override;
|
void InstallNCA(const NcmContentId& ncaId) override;
|
||||||
void InstallTicketCert() override;
|
void InstallTicketCert() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
XCIInstallTask(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<XCI>& xci);
|
XCIInstallTask(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<XCI>& xci);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,72 +6,72 @@
|
|||||||
#define MAGIC_NCA3 0x3341434E /* "NCA3" */
|
#define MAGIC_NCA3 0x3341434E /* "NCA3" */
|
||||||
namespace tin::install
|
namespace tin::install
|
||||||
{
|
{
|
||||||
struct NcaFsHeader
|
struct NcaFsHeader
|
||||||
{
|
{
|
||||||
u8 _0x0;
|
u8 _0x0;
|
||||||
u8 _0x1;
|
u8 _0x1;
|
||||||
u8 partition_type;
|
u8 partition_type;
|
||||||
u8 fs_type;
|
u8 fs_type;
|
||||||
u8 crypt_type;
|
u8 crypt_type;
|
||||||
u8 _0x5[0x3];
|
u8 _0x5[0x3];
|
||||||
u8 superblock_data[0x138];
|
u8 superblock_data[0x138];
|
||||||
/*union {
|
/*union {
|
||||||
pfs0_superblock_t pfs0_superblock;
|
pfs0_superblock_t pfs0_superblock;
|
||||||
romfs_superblock_t romfs_superblock;
|
romfs_superblock_t romfs_superblock;
|
||||||
//nca0_romfs_superblock_t nca0_romfs_superblock;
|
//nca0_romfs_superblock_t nca0_romfs_superblock;
|
||||||
bktr_superblock_t bktr_superblock;
|
bktr_superblock_t bktr_superblock;
|
||||||
};*/
|
};*/
|
||||||
union {
|
union {
|
||||||
u64 section_ctr;
|
u64 section_ctr;
|
||||||
struct {
|
struct {
|
||||||
u32 section_ctr_low;
|
u32 section_ctr_low;
|
||||||
u32 section_ctr_high;
|
u32 section_ctr_high;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
u8 _0x148[0xB8]; /* Padding. */
|
u8 _0x148[0xB8]; /* Padding. */
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(NcaFsHeader) == 0x200, "NcaFsHeader must be 0x200");
|
static_assert(sizeof(NcaFsHeader) == 0x200, "NcaFsHeader must be 0x200");
|
||||||
|
|
||||||
struct NcaSectionEntry
|
struct NcaSectionEntry
|
||||||
{
|
{
|
||||||
u32 media_start_offset;
|
u32 media_start_offset;
|
||||||
u32 media_end_offset;
|
u32 media_end_offset;
|
||||||
u8 _0x8[0x8]; /* Padding. */
|
u8 _0x8[0x8]; /* Padding. */
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(NcaSectionEntry) == 0x10, "NcaSectionEntry must be 0x10");
|
static_assert(sizeof(NcaSectionEntry) == 0x10, "NcaSectionEntry must be 0x10");
|
||||||
|
|
||||||
struct NcaHeader
|
struct NcaHeader
|
||||||
{
|
{
|
||||||
u8 fixed_key_sig[0x100]; /* RSA-PSS signature over header with fixed key. */
|
u8 fixed_key_sig[0x100]; /* RSA-PSS signature over header with fixed key. */
|
||||||
u8 npdm_key_sig[0x100]; /* RSA-PSS signature over header with key in NPDM. */
|
u8 npdm_key_sig[0x100]; /* RSA-PSS signature over header with key in NPDM. */
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u8 distribution; /* System vs gamecard. */
|
u8 distribution; /* System vs gamecard. */
|
||||||
u8 content_type;
|
u8 content_type;
|
||||||
u8 m_cryptoType; /* Which keyblob (field 1) */
|
u8 m_cryptoType; /* Which keyblob (field 1) */
|
||||||
u8 m_kaekIndex; /* Which kaek index? */
|
u8 m_kaekIndex; /* Which kaek index? */
|
||||||
u64 nca_size; /* Entire archive size. */
|
u64 nca_size; /* Entire archive size. */
|
||||||
u64 m_titleId;
|
u64 m_titleId;
|
||||||
u8 _0x218[0x4]; /* Padding. */
|
u8 _0x218[0x4]; /* Padding. */
|
||||||
union {
|
union {
|
||||||
uint32_t sdk_version; /* What SDK was this built with? */
|
uint32_t sdk_version; /* What SDK was this built with? */
|
||||||
struct {
|
struct {
|
||||||
u8 sdk_revision;
|
u8 sdk_revision;
|
||||||
u8 sdk_micro;
|
u8 sdk_micro;
|
||||||
u8 sdk_minor;
|
u8 sdk_minor;
|
||||||
u8 sdk_major;
|
u8 sdk_major;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
u8 m_cryptoType2; /* Which keyblob (field 2) */
|
u8 m_cryptoType2; /* Which keyblob (field 2) */
|
||||||
u8 _0x221[0xF]; /* Padding. */
|
u8 _0x221[0xF]; /* Padding. */
|
||||||
u64 m_rightsId[2]; /* Rights ID (for titlekey crypto). */
|
u64 m_rightsId[2]; /* Rights ID (for titlekey crypto). */
|
||||||
NcaSectionEntry section_entries[4]; /* Section entry metadata. */
|
NcaSectionEntry section_entries[4]; /* Section entry metadata. */
|
||||||
u8 section_hashes[4 * 0x20]; /* SHA-256 hashes for each section header. */
|
u8 section_hashes[4 * 0x20]; /* SHA-256 hashes for each section header. */
|
||||||
u8 m_keys[4 * 0x10]; /* Encrypted key area. */
|
u8 m_keys[4 * 0x10]; /* Encrypted key area. */
|
||||||
u8 _0x340[0xC0]; /* Padding. */
|
u8 _0x340[0xC0]; /* Padding. */
|
||||||
NcaFsHeader fs_headers[4]; /* FS section headers. */
|
NcaFsHeader fs_headers[4]; /* FS section headers. */
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(NcaHeader) == 0xc00, "NcaHeader must be 0xc00");
|
static_assert(sizeof(NcaHeader) == 0xc00, "NcaHeader must be 0xc00");
|
||||||
}
|
}
|
@ -32,26 +32,26 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
class NSP
|
class NSP
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<u8> m_headerBytes;
|
std::vector<u8> m_headerBytes;
|
||||||
|
|
||||||
NSP();
|
NSP();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) = 0;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) = 0;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) = 0;
|
virtual void BufferData(void* buf, off_t offset, size_t size) = 0;
|
||||||
|
|
||||||
virtual void RetrieveHeader();
|
virtual void RetrieveHeader();
|
||||||
virtual const PFS0BaseHeader* GetBaseHeader();
|
virtual const PFS0BaseHeader* GetBaseHeader();
|
||||||
virtual u64 GetDataOffset();
|
virtual u64 GetDataOffset();
|
||||||
|
|
||||||
virtual const PFS0FileEntry* GetFileEntry(unsigned int index);
|
virtual const PFS0FileEntry* GetFileEntry(unsigned int index);
|
||||||
virtual const PFS0FileEntry* GetFileEntryByName(std::string name);
|
virtual const PFS0FileEntry* GetFileEntryByName(std::string name);
|
||||||
virtual const PFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId);
|
virtual const PFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId);
|
||||||
virtual std::vector<const PFS0FileEntry*> GetFileEntriesByExtension(std::string extension);
|
virtual std::vector<const PFS0FileEntry*> GetFileEntriesByExtension(std::string extension);
|
||||||
|
|
||||||
virtual const char* GetFileEntryName(const PFS0FileEntry* fileEntry);
|
virtual const char* GetFileEntryName(const PFS0FileEntry* fileEntry);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -26,23 +26,23 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install
|
namespace tin::install
|
||||||
{
|
{
|
||||||
struct PFS0FileEntry
|
struct PFS0FileEntry
|
||||||
{
|
{
|
||||||
u64 dataOffset;
|
u64 dataOffset;
|
||||||
u64 fileSize;
|
u64 fileSize;
|
||||||
u32 stringTableOffset;
|
u32 stringTableOffset;
|
||||||
u32 padding;
|
u32 padding;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(PFS0FileEntry) == 0x18, "PFS0FileEntry must be 0x18");
|
static_assert(sizeof(PFS0FileEntry) == 0x18, "PFS0FileEntry must be 0x18");
|
||||||
|
|
||||||
struct PFS0BaseHeader
|
struct PFS0BaseHeader
|
||||||
{
|
{
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u32 numFiles;
|
u32 numFiles;
|
||||||
u32 stringTableSize;
|
u32 stringTableSize;
|
||||||
u32 reserved;
|
u32 reserved;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(PFS0BaseHeader) == 0x10, "PFS0BaseHeader must be 0x10");
|
static_assert(sizeof(PFS0BaseHeader) == 0x10, "PFS0BaseHeader must be 0x10");
|
||||||
}
|
}
|
@ -26,15 +26,15 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
class SDMCNSP : public NSP
|
class SDMCNSP : public NSP
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SDMCNSP(std::string path);
|
SDMCNSP(std::string path);
|
||||||
~SDMCNSP();
|
~SDMCNSP();
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId) override;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId) override;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
||||||
private:
|
private:
|
||||||
FILE* m_nspFile;
|
FILE* m_nspFile;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -26,15 +26,15 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
class SDMCXCI : public XCI
|
class SDMCXCI : public XCI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SDMCXCI(std::string path);
|
SDMCXCI(std::string path);
|
||||||
~SDMCXCI();
|
~SDMCXCI();
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId) override;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId) override;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
||||||
private:
|
private:
|
||||||
FILE* m_xciFile;
|
FILE* m_xciFile;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -27,20 +27,20 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
class SimpleFileSystem final
|
class SimpleFileSystem final
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
nx::fs::IFileSystem* m_fileSystem;
|
nx::fs::IFileSystem* m_fileSystem;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const std::string m_rootPath;
|
const std::string m_rootPath;
|
||||||
const std::string m_absoluteRootPath;
|
const std::string m_absoluteRootPath;
|
||||||
|
|
||||||
SimpleFileSystem(nx::fs::IFileSystem& fileSystem, std::string rootPath, std::string absoluteRootPath);
|
SimpleFileSystem(nx::fs::IFileSystem& fileSystem, std::string rootPath, std::string absoluteRootPath);
|
||||||
~SimpleFileSystem();
|
~SimpleFileSystem();
|
||||||
|
|
||||||
nx::fs::IFile OpenFile(std::string path);
|
nx::fs::IFile OpenFile(std::string path);
|
||||||
bool HasFile(std::string path);
|
bool HasFile(std::string path);
|
||||||
std::string GetFileNameFromExtension(std::string path, std::string extension);
|
std::string GetFileNameFromExtension(std::string path, std::string extension);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -27,15 +27,15 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
class USBNSP : public NSP
|
class USBNSP : public NSP
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string m_nspName;
|
std::string m_nspName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
USBNSP(std::string nspName);
|
USBNSP(std::string nspName);
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -27,15 +27,15 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
class USBXCI : public XCI
|
class USBXCI : public XCI
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string m_xciName;
|
std::string m_xciName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
USBXCI(std::string xciName);
|
USBXCI(std::string xciName);
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) override;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -32,27 +32,27 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
class XCI
|
class XCI
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
u64 m_secureHeaderOffset;
|
u64 m_secureHeaderOffset;
|
||||||
std::vector<u8> m_secureHeaderBytes;
|
std::vector<u8> m_secureHeaderBytes;
|
||||||
|
|
||||||
XCI();
|
XCI();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) = 0;
|
virtual void StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId) = 0;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) = 0;
|
virtual void BufferData(void* buf, off_t offset, size_t size) = 0;
|
||||||
|
|
||||||
virtual void RetrieveHeader();
|
virtual void RetrieveHeader();
|
||||||
virtual const HFS0BaseHeader* GetSecureHeader();
|
virtual const HFS0BaseHeader* GetSecureHeader();
|
||||||
virtual u64 GetDataOffset();
|
virtual u64 GetDataOffset();
|
||||||
|
|
||||||
virtual const HFS0FileEntry* GetFileEntry(unsigned int index);
|
virtual const HFS0FileEntry* GetFileEntry(unsigned int index);
|
||||||
virtual const HFS0FileEntry* GetFileEntryByName(std::string name);
|
virtual const HFS0FileEntry* GetFileEntryByName(std::string name);
|
||||||
virtual const HFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId);
|
virtual const HFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId);
|
||||||
virtual std::vector<const HFS0FileEntry*> GetFileEntriesByExtension(std::string extension);
|
virtual std::vector<const HFS0FileEntry*> GetFileEntriesByExtension(std::string extension);
|
||||||
|
|
||||||
virtual const char* GetFileEntryName(const HFS0FileEntry* fileEntry);
|
virtual const char* GetFileEntryName(const HFS0FileEntry* fileEntry);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -22,8 +22,8 @@ SOFTWARE.
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace netInstStuff {
|
namespace netInstStuff {
|
||||||
void OnUnwound();
|
void OnUnwound();
|
||||||
void sendExitCommands(std::string url);
|
void sendExitCommands(std::string url);
|
||||||
void installTitleNet(std::vector<std::string> ourUrlList, int ourStorage, std::vector<std::string> urlListAltNames, std::string ourSource);
|
void installTitleNet(std::vector<std::string> ourUrlList, int ourStorage, std::vector<std::string> urlListAltNames, std::string ourSource);
|
||||||
std::vector<std::string> OnSelected();
|
std::vector<std::string> OnSelected();
|
||||||
}
|
}
|
@ -24,5 +24,5 @@ SOFTWARE.
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
namespace nspInstStuff {
|
namespace nspInstStuff {
|
||||||
void installNspFromFile(std::vector<std::filesystem::path> ourNspList, int whereToInstall);
|
void installNspFromFile(std::vector<std::filesystem::path> ourNspList, int whereToInstall);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
namespace sig {
|
namespace sig {
|
||||||
void installSigPatches ();
|
void installSigPatches();
|
||||||
}
|
}
|
@ -4,28 +4,28 @@
|
|||||||
|
|
||||||
using namespace pu::ui::elm;
|
using namespace pu::ui::elm;
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class HDInstPage : public pu::ui::Layout
|
class HDInstPage : public pu::ui::Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HDInstPage();
|
HDInstPage();
|
||||||
PU_SMART_CTOR(HDInstPage)
|
PU_SMART_CTOR(HDInstPage)
|
||||||
pu::ui::elm::Menu::Ref menu;
|
pu::ui::elm::Menu::Ref menu;
|
||||||
void startInstall();
|
void startInstall();
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
TextBlock::Ref pageInfoText;
|
TextBlock::Ref pageInfoText;
|
||||||
void drawMenuItems(bool clearItems, std::filesystem::path ourPath);
|
void drawMenuItems(bool clearItems, std::filesystem::path ourPath);
|
||||||
private:
|
private:
|
||||||
std::vector<std::filesystem::path> ourDirectories;
|
std::vector<std::filesystem::path> ourDirectories;
|
||||||
std::vector<std::filesystem::path> ourFiles;
|
std::vector<std::filesystem::path> ourFiles;
|
||||||
std::vector<std::filesystem::path> selectedTitles;
|
std::vector<std::filesystem::path> selectedTitles;
|
||||||
std::filesystem::path currentDir;
|
std::filesystem::path currentDir;
|
||||||
TextBlock::Ref butText;
|
TextBlock::Ref butText;
|
||||||
Rectangle::Ref topRect;
|
Rectangle::Ref topRect;
|
||||||
Rectangle::Ref infoRect;
|
Rectangle::Ref infoRect;
|
||||||
Rectangle::Ref botRect;
|
Rectangle::Ref botRect;
|
||||||
Image::Ref titleImage;
|
Image::Ref titleImage;
|
||||||
TextBlock::Ref appVersionText;
|
TextBlock::Ref appVersionText;
|
||||||
void followDirectory();
|
void followDirectory();
|
||||||
void selectNsp(int selectedIndex);
|
void selectNsp(int selectedIndex);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -9,17 +9,17 @@
|
|||||||
#include "ui/optionsPage.hpp"
|
#include "ui/optionsPage.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class MainApplication : public pu::ui::Application {
|
class MainApplication : public pu::ui::Application {
|
||||||
public:
|
public:
|
||||||
using Application::Application;
|
using Application::Application;
|
||||||
PU_SMART_CTOR(MainApplication)
|
PU_SMART_CTOR(MainApplication)
|
||||||
void OnLoad() override;
|
void OnLoad() override;
|
||||||
MainPage::Ref mainPage;
|
MainPage::Ref mainPage;
|
||||||
netInstPage::Ref netinstPage;
|
netInstPage::Ref netinstPage;
|
||||||
sdInstPage::Ref sdinstPage;
|
sdInstPage::Ref sdinstPage;
|
||||||
HDInstPage::Ref HDinstPage;
|
HDInstPage::Ref HDinstPage;
|
||||||
usbInstPage::Ref usbinstPage;
|
usbInstPage::Ref usbinstPage;
|
||||||
instPage::Ref instpage;
|
instPage::Ref instpage;
|
||||||
optionsPage::Ref optionspage;
|
optionsPage::Ref optionspage;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -3,25 +3,25 @@
|
|||||||
|
|
||||||
using namespace pu::ui::elm;
|
using namespace pu::ui::elm;
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class instPage : public pu::ui::Layout
|
class instPage : public pu::ui::Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
instPage();
|
instPage();
|
||||||
PU_SMART_CTOR(instPage)
|
PU_SMART_CTOR(instPage)
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
TextBlock::Ref pageInfoText;
|
TextBlock::Ref pageInfoText;
|
||||||
TextBlock::Ref installInfoText;
|
TextBlock::Ref installInfoText;
|
||||||
pu::ui::elm::ProgressBar::Ref installBar;
|
pu::ui::elm::ProgressBar::Ref installBar;
|
||||||
Image::Ref awooImage;
|
Image::Ref awooImage;
|
||||||
Image::Ref titleImage;
|
Image::Ref titleImage;
|
||||||
TextBlock::Ref appVersionText;
|
TextBlock::Ref appVersionText;
|
||||||
static void setTopInstInfoText(std::string ourText);
|
static void setTopInstInfoText(std::string ourText);
|
||||||
static void setInstInfoText(std::string ourText);
|
static void setInstInfoText(std::string ourText);
|
||||||
static void setInstBarPerc(double ourPercent);
|
static void setInstBarPerc(double ourPercent);
|
||||||
static void loadMainMenu();
|
static void loadMainMenu();
|
||||||
static void loadInstallScreen();
|
static void loadInstallScreen();
|
||||||
private:
|
private:
|
||||||
Rectangle::Ref infoRect;
|
Rectangle::Ref infoRect;
|
||||||
Rectangle::Ref topRect;
|
Rectangle::Ref topRect;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -3,36 +3,36 @@
|
|||||||
|
|
||||||
using namespace pu::ui::elm;
|
using namespace pu::ui::elm;
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class MainPage : public pu::ui::Layout
|
class MainPage : public pu::ui::Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MainPage();
|
MainPage();
|
||||||
PU_SMART_CTOR(MainPage)
|
PU_SMART_CTOR(MainPage)
|
||||||
void installMenuItem_Click();
|
void installMenuItem_Click();
|
||||||
void netInstallMenuItem_Click();
|
void netInstallMenuItem_Click();
|
||||||
void usbInstallMenuItem_Click();
|
void usbInstallMenuItem_Click();
|
||||||
void hddInstallMenuItem_Click();
|
void hddInstallMenuItem_Click();
|
||||||
void sigPatchesMenuItem_Click();
|
void sigPatchesMenuItem_Click();
|
||||||
void settingsMenuItem_Click();
|
void settingsMenuItem_Click();
|
||||||
void exitMenuItem_Click();
|
void exitMenuItem_Click();
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
void diskUsage();
|
void diskUsage();
|
||||||
Image::Ref awooImage;
|
Image::Ref awooImage;
|
||||||
Image::Ref titleImage;
|
Image::Ref titleImage;
|
||||||
TextBlock::Ref appVersionText;
|
TextBlock::Ref appVersionText;
|
||||||
private:
|
private:
|
||||||
bool appletFinished;
|
bool appletFinished;
|
||||||
bool updateFinished;
|
bool updateFinished;
|
||||||
TextBlock::Ref butText;
|
TextBlock::Ref butText;
|
||||||
Rectangle::Ref topRect;
|
Rectangle::Ref topRect;
|
||||||
Rectangle::Ref botRect;
|
Rectangle::Ref botRect;
|
||||||
pu::ui::elm::Menu::Ref optionMenu;
|
pu::ui::elm::Menu::Ref optionMenu;
|
||||||
pu::ui::elm::MenuItem::Ref installMenuItem;
|
pu::ui::elm::MenuItem::Ref installMenuItem;
|
||||||
pu::ui::elm::MenuItem::Ref netInstallMenuItem;
|
pu::ui::elm::MenuItem::Ref netInstallMenuItem;
|
||||||
pu::ui::elm::MenuItem::Ref usbInstallMenuItem;
|
pu::ui::elm::MenuItem::Ref usbInstallMenuItem;
|
||||||
pu::ui::elm::MenuItem::Ref hddInstallMenuItem;
|
pu::ui::elm::MenuItem::Ref hddInstallMenuItem;
|
||||||
pu::ui::elm::MenuItem::Ref sigPatchesMenuItem;
|
pu::ui::elm::MenuItem::Ref sigPatchesMenuItem;
|
||||||
pu::ui::elm::MenuItem::Ref settingsMenuItem;
|
pu::ui::elm::MenuItem::Ref settingsMenuItem;
|
||||||
pu::ui::elm::MenuItem::Ref exitMenuItem;
|
pu::ui::elm::MenuItem::Ref exitMenuItem;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -3,28 +3,28 @@
|
|||||||
|
|
||||||
using namespace pu::ui::elm;
|
using namespace pu::ui::elm;
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class netInstPage : public pu::ui::Layout
|
class netInstPage : public pu::ui::Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
netInstPage();
|
netInstPage();
|
||||||
PU_SMART_CTOR(netInstPage)
|
PU_SMART_CTOR(netInstPage)
|
||||||
void startInstall(bool urlMode);
|
void startInstall(bool urlMode);
|
||||||
void startNetwork();
|
void startNetwork();
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
TextBlock::Ref pageInfoText;
|
TextBlock::Ref pageInfoText;
|
||||||
Image::Ref titleImage;
|
Image::Ref titleImage;
|
||||||
TextBlock::Ref appVersionText;
|
TextBlock::Ref appVersionText;
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> ourUrls;
|
std::vector<std::string> ourUrls;
|
||||||
std::vector<std::string> selectedUrls;
|
std::vector<std::string> selectedUrls;
|
||||||
std::vector<std::string> alternativeNames;
|
std::vector<std::string> alternativeNames;
|
||||||
TextBlock::Ref butText;
|
TextBlock::Ref butText;
|
||||||
Rectangle::Ref topRect;
|
Rectangle::Ref topRect;
|
||||||
Rectangle::Ref infoRect;
|
Rectangle::Ref infoRect;
|
||||||
Rectangle::Ref botRect;
|
Rectangle::Ref botRect;
|
||||||
pu::ui::elm::Menu::Ref menu;
|
pu::ui::elm::Menu::Ref menu;
|
||||||
Image::Ref infoImage;
|
Image::Ref infoImage;
|
||||||
void drawMenuItems(bool clearItems);
|
void drawMenuItems(bool clearItems);
|
||||||
void selectTitle(int selectedIndex);
|
void selectTitle(int selectedIndex);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -3,24 +3,24 @@
|
|||||||
|
|
||||||
using namespace pu::ui::elm;
|
using namespace pu::ui::elm;
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class optionsPage : public pu::ui::Layout
|
class optionsPage : public pu::ui::Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
optionsPage();
|
optionsPage();
|
||||||
PU_SMART_CTOR(optionsPage)
|
PU_SMART_CTOR(optionsPage)
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
static void askToUpdate(std::vector<std::string> updateInfo);
|
static void askToUpdate(std::vector<std::string> updateInfo);
|
||||||
Image::Ref titleImage;
|
Image::Ref titleImage;
|
||||||
TextBlock::Ref appVersionText;
|
TextBlock::Ref appVersionText;
|
||||||
private:
|
private:
|
||||||
TextBlock::Ref butText;
|
TextBlock::Ref butText;
|
||||||
Rectangle::Ref topRect;
|
Rectangle::Ref topRect;
|
||||||
Rectangle::Ref infoRect;
|
Rectangle::Ref infoRect;
|
||||||
Rectangle::Ref botRect;
|
Rectangle::Ref botRect;
|
||||||
TextBlock::Ref pageInfoText;
|
TextBlock::Ref pageInfoText;
|
||||||
pu::ui::elm::Menu::Ref menu;
|
pu::ui::elm::Menu::Ref menu;
|
||||||
void setMenuText();
|
void setMenuText();
|
||||||
std::string getMenuOptionIcon(bool ourBool);
|
std::string getMenuOptionIcon(bool ourBool);
|
||||||
std::string getMenuLanguage(int ourLangCode);
|
std::string getMenuLanguage(int ourLangCode);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -4,28 +4,28 @@
|
|||||||
|
|
||||||
using namespace pu::ui::elm;
|
using namespace pu::ui::elm;
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class sdInstPage : public pu::ui::Layout
|
class sdInstPage : public pu::ui::Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
sdInstPage();
|
sdInstPage();
|
||||||
PU_SMART_CTOR(sdInstPage)
|
PU_SMART_CTOR(sdInstPage)
|
||||||
pu::ui::elm::Menu::Ref menu;
|
pu::ui::elm::Menu::Ref menu;
|
||||||
void startInstall();
|
void startInstall();
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
TextBlock::Ref pageInfoText;
|
TextBlock::Ref pageInfoText;
|
||||||
void drawMenuItems(bool clearItems, std::filesystem::path ourPath);
|
void drawMenuItems(bool clearItems, std::filesystem::path ourPath);
|
||||||
Image::Ref titleImage;
|
Image::Ref titleImage;
|
||||||
TextBlock::Ref appVersionText;
|
TextBlock::Ref appVersionText;
|
||||||
private:
|
private:
|
||||||
std::vector<std::filesystem::path> ourDirectories;
|
std::vector<std::filesystem::path> ourDirectories;
|
||||||
std::vector<std::filesystem::path> ourFiles;
|
std::vector<std::filesystem::path> ourFiles;
|
||||||
std::vector<std::filesystem::path> selectedTitles;
|
std::vector<std::filesystem::path> selectedTitles;
|
||||||
std::filesystem::path currentDir;
|
std::filesystem::path currentDir;
|
||||||
TextBlock::Ref butText;
|
TextBlock::Ref butText;
|
||||||
Rectangle::Ref topRect;
|
Rectangle::Ref topRect;
|
||||||
Rectangle::Ref infoRect;
|
Rectangle::Ref infoRect;
|
||||||
Rectangle::Ref botRect;
|
Rectangle::Ref botRect;
|
||||||
void followDirectory();
|
void followDirectory();
|
||||||
void selectNsp(int selectedIndex);
|
void selectNsp(int selectedIndex);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -3,29 +3,29 @@
|
|||||||
|
|
||||||
using namespace pu::ui::elm;
|
using namespace pu::ui::elm;
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
class usbInstPage : public pu::ui::Layout
|
class usbInstPage : public pu::ui::Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
usbInstPage();
|
usbInstPage();
|
||||||
PU_SMART_CTOR(usbInstPage)
|
PU_SMART_CTOR(usbInstPage)
|
||||||
void startInstall();
|
void startInstall();
|
||||||
void startUsb();
|
void startUsb();
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
TextBlock::Ref pageInfoText;
|
TextBlock::Ref pageInfoText;
|
||||||
Image::Ref titleImage;
|
Image::Ref titleImage;
|
||||||
TextBlock::Ref appVersionText;
|
TextBlock::Ref appVersionText;
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> ourTitles;
|
std::vector<std::string> ourTitles;
|
||||||
std::vector<std::string> selectedTitles;
|
std::vector<std::string> selectedTitles;
|
||||||
std::string lastUrl;
|
std::string lastUrl;
|
||||||
std::string lastFileID;
|
std::string lastFileID;
|
||||||
TextBlock::Ref butText;
|
TextBlock::Ref butText;
|
||||||
Rectangle::Ref topRect;
|
Rectangle::Ref topRect;
|
||||||
Rectangle::Ref infoRect;
|
Rectangle::Ref infoRect;
|
||||||
Rectangle::Ref botRect;
|
Rectangle::Ref botRect;
|
||||||
pu::ui::elm::Menu::Ref menu;
|
pu::ui::elm::Menu::Ref menu;
|
||||||
Image::Ref infoImage;
|
Image::Ref infoImage;
|
||||||
void drawMenuItems(bool clearItems);
|
void drawMenuItems(bool clearItems);
|
||||||
void selectTitle(int selectedIndex);
|
void selectTitle(int selectedIndex);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -3,6 +3,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace usbInstStuff {
|
namespace usbInstStuff {
|
||||||
std::vector<std::string> OnSelected();
|
std::vector<std::string> OnSelected();
|
||||||
void installTitleUsb(std::vector<std::string> ourNspList, int ourStorage);
|
void installTitleUsb(std::vector<std::string> ourNspList, int ourStorage);
|
||||||
}
|
}
|
@ -3,23 +3,23 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace inst::config {
|
namespace inst::config {
|
||||||
static const std::string appDir = "sdmc:/switch/Awoo-Installer";
|
static const std::string appDir = "sdmc:/switch/Awoo-Installer";
|
||||||
static const std::string configPath = appDir + "/config.json";
|
static const std::string configPath = appDir + "/config.json";
|
||||||
static const std::string appVersion = "1.3.4";
|
static const std::string appVersion = "1.3.4";
|
||||||
|
|
||||||
extern std::string gAuthKey;
|
extern std::string gAuthKey;
|
||||||
extern std::string sigPatchesUrl;
|
extern std::string sigPatchesUrl;
|
||||||
extern std::string lastNetUrl;
|
extern std::string lastNetUrl;
|
||||||
extern std::vector<std::string> updateInfo;
|
extern std::vector<std::string> updateInfo;
|
||||||
extern int languageSetting;
|
extern int languageSetting;
|
||||||
extern bool ignoreReqVers;
|
extern bool ignoreReqVers;
|
||||||
extern bool validateNCAs;
|
extern bool validateNCAs;
|
||||||
extern bool overClock;
|
extern bool overClock;
|
||||||
extern bool deletePrompt;
|
extern bool deletePrompt;
|
||||||
extern bool autoUpdate;
|
extern bool autoUpdate;
|
||||||
extern bool gayMode;
|
extern bool gayMode;
|
||||||
extern bool usbAck;
|
extern bool usbAck;
|
||||||
|
|
||||||
void setConfig();
|
void setConfig();
|
||||||
void parseConfig();
|
void parseConfig();
|
||||||
}
|
}
|
@ -5,150 +5,150 @@
|
|||||||
|
|
||||||
namespace Crypto
|
namespace Crypto
|
||||||
{
|
{
|
||||||
#define RSA_2048_BYTES 0x100
|
#define RSA_2048_BYTES 0x100
|
||||||
#define RSA_2048_BITS (RSA_2048_BYTES*8)
|
#define RSA_2048_BITS (RSA_2048_BYTES*8)
|
||||||
static const unsigned char NCAHeaderSignature[0x100] = { /* Fixed RSA key used to validate NCA signature 0. */
|
static const unsigned char NCAHeaderSignature[0x100] = { /* Fixed RSA key used to validate NCA signature 0. */
|
||||||
0xBF, 0xBE, 0x40, 0x6C, 0xF4, 0xA7, 0x80, 0xE9, 0xF0, 0x7D, 0x0C, 0x99, 0x61, 0x1D, 0x77, 0x2F,
|
0xBF, 0xBE, 0x40, 0x6C, 0xF4, 0xA7, 0x80, 0xE9, 0xF0, 0x7D, 0x0C, 0x99, 0x61, 0x1D, 0x77, 0x2F,
|
||||||
0x96, 0xBC, 0x4B, 0x9E, 0x58, 0x38, 0x1B, 0x03, 0xAB, 0xB1, 0x75, 0x49, 0x9F, 0x2B, 0x4D, 0x58,
|
0x96, 0xBC, 0x4B, 0x9E, 0x58, 0x38, 0x1B, 0x03, 0xAB, 0xB1, 0x75, 0x49, 0x9F, 0x2B, 0x4D, 0x58,
|
||||||
0x34, 0xB0, 0x05, 0xA3, 0x75, 0x22, 0xBE, 0x1A, 0x3F, 0x03, 0x73, 0xAC, 0x70, 0x68, 0xD1, 0x16,
|
0x34, 0xB0, 0x05, 0xA3, 0x75, 0x22, 0xBE, 0x1A, 0x3F, 0x03, 0x73, 0xAC, 0x70, 0x68, 0xD1, 0x16,
|
||||||
0xB9, 0x04, 0x46, 0x5E, 0xB7, 0x07, 0x91, 0x2F, 0x07, 0x8B, 0x26, 0xDE, 0xF6, 0x00, 0x07, 0xB2,
|
0xB9, 0x04, 0x46, 0x5E, 0xB7, 0x07, 0x91, 0x2F, 0x07, 0x8B, 0x26, 0xDE, 0xF6, 0x00, 0x07, 0xB2,
|
||||||
0xB4, 0x51, 0xF8, 0x0D, 0x0A, 0x5E, 0x58, 0xAD, 0xEB, 0xBC, 0x9A, 0xD6, 0x49, 0xB9, 0x64, 0xEF,
|
0xB4, 0x51, 0xF8, 0x0D, 0x0A, 0x5E, 0x58, 0xAD, 0xEB, 0xBC, 0x9A, 0xD6, 0x49, 0xB9, 0x64, 0xEF,
|
||||||
0xA7, 0x82, 0xB5, 0xCF, 0x6D, 0x70, 0x13, 0xB0, 0x0F, 0x85, 0xF6, 0xA9, 0x08, 0xAA, 0x4D, 0x67,
|
0xA7, 0x82, 0xB5, 0xCF, 0x6D, 0x70, 0x13, 0xB0, 0x0F, 0x85, 0xF6, 0xA9, 0x08, 0xAA, 0x4D, 0x67,
|
||||||
0x66, 0x87, 0xFA, 0x89, 0xFF, 0x75, 0x90, 0x18, 0x1E, 0x6B, 0x3D, 0xE9, 0x8A, 0x68, 0xC9, 0x26,
|
0x66, 0x87, 0xFA, 0x89, 0xFF, 0x75, 0x90, 0x18, 0x1E, 0x6B, 0x3D, 0xE9, 0x8A, 0x68, 0xC9, 0x26,
|
||||||
0x04, 0xD9, 0x80, 0xCE, 0x3F, 0x5E, 0x92, 0xCE, 0x01, 0xFF, 0x06, 0x3B, 0xF2, 0xC1, 0xA9, 0x0C,
|
0x04, 0xD9, 0x80, 0xCE, 0x3F, 0x5E, 0x92, 0xCE, 0x01, 0xFF, 0x06, 0x3B, 0xF2, 0xC1, 0xA9, 0x0C,
|
||||||
0xCE, 0x02, 0x6F, 0x16, 0xBC, 0x92, 0x42, 0x0A, 0x41, 0x64, 0xCD, 0x52, 0xB6, 0x34, 0x4D, 0xAE,
|
0xCE, 0x02, 0x6F, 0x16, 0xBC, 0x92, 0x42, 0x0A, 0x41, 0x64, 0xCD, 0x52, 0xB6, 0x34, 0x4D, 0xAE,
|
||||||
0xC0, 0x2E, 0xDE, 0xA4, 0xDF, 0x27, 0x68, 0x3C, 0xC1, 0xA0, 0x60, 0xAD, 0x43, 0xF3, 0xFC, 0x86,
|
0xC0, 0x2E, 0xDE, 0xA4, 0xDF, 0x27, 0x68, 0x3C, 0xC1, 0xA0, 0x60, 0xAD, 0x43, 0xF3, 0xFC, 0x86,
|
||||||
0xC1, 0x3E, 0x6C, 0x46, 0xF7, 0x7C, 0x29, 0x9F, 0xFA, 0xFD, 0xF0, 0xE3, 0xCE, 0x64, 0xE7, 0x35,
|
0xC1, 0x3E, 0x6C, 0x46, 0xF7, 0x7C, 0x29, 0x9F, 0xFA, 0xFD, 0xF0, 0xE3, 0xCE, 0x64, 0xE7, 0x35,
|
||||||
0xF2, 0xF6, 0x56, 0x56, 0x6F, 0x6D, 0xF1, 0xE2, 0x42, 0xB0, 0x83, 0x40, 0xA5, 0xC3, 0x20, 0x2B,
|
0xF2, 0xF6, 0x56, 0x56, 0x6F, 0x6D, 0xF1, 0xE2, 0x42, 0xB0, 0x83, 0x40, 0xA5, 0xC3, 0x20, 0x2B,
|
||||||
0xCC, 0x9A, 0xAE, 0xCA, 0xED, 0x4D, 0x70, 0x30, 0xA8, 0x70, 0x1C, 0x70, 0xFD, 0x13, 0x63, 0x29,
|
0xCC, 0x9A, 0xAE, 0xCA, 0xED, 0x4D, 0x70, 0x30, 0xA8, 0x70, 0x1C, 0x70, 0xFD, 0x13, 0x63, 0x29,
|
||||||
0x02, 0x79, 0xEA, 0xD2, 0xA7, 0xAF, 0x35, 0x28, 0x32, 0x1C, 0x7B, 0xE6, 0x2F, 0x1A, 0xAA, 0x40,
|
0x02, 0x79, 0xEA, 0xD2, 0xA7, 0xAF, 0x35, 0x28, 0x32, 0x1C, 0x7B, 0xE6, 0x2F, 0x1A, 0xAA, 0x40,
|
||||||
0x7E, 0x32, 0x8C, 0x27, 0x42, 0xFE, 0x82, 0x78, 0xEC, 0x0D, 0xEB, 0xE6, 0x83, 0x4B, 0x6D, 0x81,
|
0x7E, 0x32, 0x8C, 0x27, 0x42, 0xFE, 0x82, 0x78, 0xEC, 0x0D, 0xEB, 0xE6, 0x83, 0x4B, 0x6D, 0x81,
|
||||||
0x04, 0x40, 0x1A, 0x9E, 0x9A, 0x67, 0xF6, 0x72, 0x29, 0xFA, 0x04, 0xF0, 0x9D, 0xE4, 0xF4, 0x03
|
0x04, 0x40, 0x1A, 0x9E, 0x9A, 0x67, 0xF6, 0x72, 0x29, 0xFA, 0x04, 0xF0, 0x9D, 0xE4, 0xF4, 0x03
|
||||||
};
|
};
|
||||||
|
|
||||||
class Keys
|
class Keys
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Keys()
|
Keys()
|
||||||
{
|
{
|
||||||
u8 kek[0x10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
u8 kek[0x10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
splCryptoGenerateAesKek(headerKekSource, 0, 0, kek);
|
splCryptoGenerateAesKek(headerKekSource, 0, 0, kek);
|
||||||
splCryptoGenerateAesKey(kek, headerKeySource, headerKey);
|
splCryptoGenerateAesKey(kek, headerKeySource, headerKey);
|
||||||
splCryptoGenerateAesKey(kek, headerKeySource + 0x10, headerKey + 0x10);
|
splCryptoGenerateAesKey(kek, headerKeySource + 0x10, headerKey + 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 headerKekSource[0x10] = { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A };
|
u8 headerKekSource[0x10] = { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A };
|
||||||
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 };
|
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 };
|
||||||
|
|
||||||
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 };
|
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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
void calculateMGF1andXOR(unsigned char* data, size_t data_size, const void* source, size_t source_size);
|
void calculateMGF1andXOR(unsigned char* data, size_t data_size, const void* source, size_t source_size);
|
||||||
bool rsa2048PssVerify(const void *data, size_t len, const unsigned char *signature, const unsigned char *modulus);
|
bool rsa2048PssVerify(const void* data, size_t len, const unsigned char* signature, const unsigned char* modulus);
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T swapEndian(T s)
|
T swapEndian(T s)
|
||||||
{
|
{
|
||||||
T result;
|
T result;
|
||||||
u8* dest = (u8*)&result;
|
u8* dest = (u8*)&result;
|
||||||
u8* src = (u8*)&s;
|
u8* src = (u8*)&s;
|
||||||
for (unsigned int i = 0; i < sizeof(s); i++)
|
for (unsigned int i = 0; i < sizeof(s); i++)
|
||||||
{
|
{
|
||||||
dest[i] = src[sizeof(s) - i - 1];
|
dest[i] = src[sizeof(s) - i - 1];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
class AesCtr
|
class AesCtr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AesCtr() : m_high(0), m_low(0)
|
AesCtr() : m_high(0), m_low(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AesCtr(u64 iv) : m_high(swapEndian(iv)), m_low(0)
|
AesCtr(u64 iv) : m_high(swapEndian(iv)), m_low(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
u64& high() { return m_high; }
|
u64& high() { return m_high; }
|
||||||
u64& low() { return m_low; }
|
u64& low() { return m_low; }
|
||||||
private:
|
private:
|
||||||
u64 m_high;
|
u64 m_high;
|
||||||
u64 m_low;
|
u64 m_low;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Aes128Ctr
|
class Aes128Ctr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Aes128Ctr(const u8* key, const AesCtr& iv)
|
Aes128Ctr(const u8* key, const AesCtr& iv)
|
||||||
{
|
{
|
||||||
counter = iv;
|
counter = iv;
|
||||||
aes128CtrContextCreate(&ctx, key, &iv);
|
aes128CtrContextCreate(&ctx, key, &iv);
|
||||||
seek(0);
|
seek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Aes128Ctr()
|
virtual ~Aes128Ctr()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek(u64 offset)
|
void seek(u64 offset)
|
||||||
{
|
{
|
||||||
counter.low() = swapEndian(offset >> 4);
|
counter.low() = swapEndian(offset >> 4);
|
||||||
aes128CtrContextResetCtr(&ctx, &counter);
|
aes128CtrContextResetCtr(&ctx, &counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void encrypt(void *dst, const void *src, size_t l)
|
void encrypt(void* dst, const void* src, size_t l)
|
||||||
{
|
{
|
||||||
aes128CtrCrypt(&ctx, dst, src, l);
|
aes128CtrCrypt(&ctx, dst, src, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void decrypt(void *dst, const void *src, size_t l)
|
void decrypt(void* dst, const void* src, size_t l)
|
||||||
{
|
{
|
||||||
encrypt(dst, src, l);
|
encrypt(dst, src, l);
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
AesCtr counter;
|
AesCtr counter;
|
||||||
|
|
||||||
Aes128CtrContext ctx;
|
Aes128CtrContext ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AesXtr
|
class AesXtr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AesXtr(const u8* key, bool is_encryptor)
|
AesXtr(const u8* key, bool is_encryptor)
|
||||||
{
|
{
|
||||||
aes128XtsContextCreate(&ctx, key, key + 0x10, is_encryptor);
|
aes128XtsContextCreate(&ctx, key, key + 0x10, is_encryptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~AesXtr()
|
virtual ~AesXtr()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void encrypt(void *dst, const void *src, size_t l, size_t sector, size_t sector_size)
|
void encrypt(void* dst, const void* src, size_t l, size_t sector, size_t sector_size)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < l; i += sector_size)
|
for (size_t i = 0; i < l; i += sector_size)
|
||||||
{
|
{
|
||||||
aes128XtsContextResetSector(&ctx, sector++, true);
|
aes128XtsContextResetSector(&ctx, sector++, true);
|
||||||
aes128XtsEncrypt(&ctx, dst, src, sector_size);
|
aes128XtsEncrypt(&ctx, dst, src, sector_size);
|
||||||
|
|
||||||
dst = (u8*)dst + sector_size;
|
dst = (u8*)dst + sector_size;
|
||||||
src = (const u8*)src + sector_size;
|
src = (const u8*)src + sector_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decrypt(void *dst, const void *src, size_t l, size_t sector, size_t sector_size)
|
void decrypt(void* dst, const void* src, size_t l, size_t sector, size_t sector_size)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < l; i += sector_size)
|
for (size_t i = 0; i < l; i += sector_size)
|
||||||
{
|
{
|
||||||
aes128XtsContextResetSector(&ctx, sector++, true);
|
aes128XtsContextResetSector(&ctx, sector++, true);
|
||||||
aes128XtsDecrypt(&ctx, dst, src, sector_size);
|
aes128XtsDecrypt(&ctx, dst, src, sector_size);
|
||||||
|
|
||||||
dst = (u8*)dst + sector_size;
|
dst = (u8*)dst + sector_size;
|
||||||
src = (const u8*)src + sector_size;
|
src = (const u8*)src + sector_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
Aes128XtsContext ctx;
|
Aes128XtsContext ctx;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace inst::curl {
|
namespace inst::curl {
|
||||||
bool downloadFile(const std::string ourUrl, const char *pagefilename, long timeout = 5000, bool writeProgress = false);
|
bool downloadFile(const std::string ourUrl, const char* pagefilename, long timeout = 5000, bool writeProgress = false);
|
||||||
std::string downloadToBuffer (const std::string ourUrl, int firstRange = -1, int secondRange = -1, long timeout = 5000);
|
std::string downloadToBuffer(const std::string ourUrl, int firstRange = -1, int secondRange = -1, long timeout = 5000);
|
||||||
}
|
}
|
@ -29,7 +29,7 @@ extern "C" {
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <switch/types.h>
|
#include <switch/types.h>
|
||||||
|
|
||||||
void printBytes(u8 *bytes, size_t size, bool includeHeader);
|
void printBytes(u8* bytes, size_t size, bool includeHeader);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::util
|
namespace tin::util
|
||||||
{
|
{
|
||||||
NcmContentInfo CreateNSPCNMTContentRecord(const std::string& nspPath);
|
NcmContentInfo CreateNSPCNMTContentRecord(const std::string& nspPath);
|
||||||
nx::ncm::ContentMeta GetContentMetaFromNCA(const std::string& ncaPath);
|
nx::ncm::ContentMeta GetContentMetaFromNCA(const std::string& ncaPath);
|
||||||
std::vector<std::string> GetNSPList();
|
std::vector<std::string> GetNSPList();
|
||||||
}
|
}
|
39733
include/util/json.hpp
39733
include/util/json.hpp
File diff suppressed because it is too large
Load Diff
@ -8,21 +8,21 @@
|
|||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
namespace Language {
|
namespace Language {
|
||||||
void Load();
|
void Load();
|
||||||
std::string LanguageEntry(std::string key);
|
std::string LanguageEntry(std::string key);
|
||||||
std::string GetRandomMsg();
|
std::string GetRandomMsg();
|
||||||
inline json GetRelativeJson(json j, std::string key) {
|
inline json GetRelativeJson(json j, std::string key) {
|
||||||
std::istringstream ss(key);
|
std::istringstream ss(key);
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
while (std::getline(ss, token, '.') && j != nullptr) {
|
while (std::getline(ss, token, '.') && j != nullptr) {
|
||||||
j = j[token];
|
j = j[token];
|
||||||
}
|
}
|
||||||
|
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string operator ""_lang (const char* key, size_t size) {
|
inline std::string operator ""_lang(const char* key, size_t size) {
|
||||||
return Language::LanguageEntry(std::string(key, size));
|
return Language::LanguageEntry(std::string(key, size));
|
||||||
}
|
}
|
@ -45,41 +45,41 @@ extern "C" {
|
|||||||
|
|
||||||
namespace tin::network
|
namespace tin::network
|
||||||
{
|
{
|
||||||
class HTTPHeader
|
class HTTPHeader
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string m_url;
|
std::string m_url;
|
||||||
std::map<std::string, std::string> m_values;
|
std::map<std::string, std::string> m_values;
|
||||||
|
|
||||||
static size_t ParseHTMLHeader(char* bytes, size_t size, size_t numItems, void* userData);
|
static size_t ParseHTMLHeader(char* bytes, size_t size, size_t numItems, void* userData);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HTTPHeader(std::string url);
|
HTTPHeader(std::string url);
|
||||||
|
|
||||||
void PerformRequest();
|
void PerformRequest();
|
||||||
|
|
||||||
bool HasValue(std::string key);
|
bool HasValue(std::string key);
|
||||||
std::string GetValue(std::string key);
|
std::string GetValue(std::string key);
|
||||||
};
|
};
|
||||||
|
|
||||||
class HTTPDownload
|
class HTTPDownload
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string m_url;
|
std::string m_url;
|
||||||
HTTPHeader m_header;
|
HTTPHeader m_header;
|
||||||
bool m_rangesSupported = false;
|
bool m_rangesSupported = false;
|
||||||
|
|
||||||
static size_t ParseHTMLData(char* bytes, size_t size, size_t numItems, void* userData);
|
static size_t ParseHTMLData(char* bytes, size_t size, size_t numItems, void* userData);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HTTPDownload(std::string url);
|
HTTPDownload(std::string url);
|
||||||
|
|
||||||
void BufferDataRange(void* buffer, size_t offset, size_t size, std::function<void (size_t sizeRead)> progressFunc);
|
|
||||||
int StreamDataRange(size_t offset, size_t size, std::function<size_t (u8* bytes, size_t size)> streamFunc);
|
|
||||||
};
|
|
||||||
|
|
||||||
void NSULDrop(std::string url);
|
void BufferDataRange(void* buffer, size_t offset, size_t size, std::function<void(size_t sizeRead)> progressFunc);
|
||||||
|
int StreamDataRange(size_t offset, size_t size, std::function<size_t(u8* bytes, size_t size)> streamFunc);
|
||||||
|
};
|
||||||
|
|
||||||
size_t WaitReceiveNetworkData(int sockfd, void* buf, size_t len);
|
void NSULDrop(std::string url);
|
||||||
size_t WaitSendNetworkData(int sockfd, void* buf, size_t len);
|
|
||||||
|
size_t WaitReceiveNetworkData(int sockfd, void* buf, size_t len);
|
||||||
|
size_t WaitSendNetworkData(int sockfd, void* buf, size_t len);
|
||||||
}
|
}
|
@ -29,13 +29,13 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::util
|
namespace tin::util
|
||||||
{
|
{
|
||||||
u64 GetRightsIdTid(FsRightsId rightsId);
|
u64 GetRightsIdTid(FsRightsId rightsId);
|
||||||
u64 GetRightsIdKeyGen(FsRightsId rightsId);
|
u64 GetRightsIdKeyGen(FsRightsId rightsId);
|
||||||
|
|
||||||
std::string GetNcaIdString(const NcmContentId& ncaId);
|
std::string GetNcaIdString(const NcmContentId& ncaId);
|
||||||
NcmContentId GetNcaIdFromString(std::string ncaIdStr);
|
NcmContentId GetNcaIdFromString(std::string ncaIdStr);
|
||||||
|
|
||||||
u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType);
|
u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType);
|
||||||
std::string GetBaseTitleName(u64 baseTitleId);
|
std::string GetBaseTitleName(u64 baseTitleId);
|
||||||
std::string GetTitleName(u64 titleId, NcmContentMetaType contentMetaType);
|
std::string GetTitleName(u64 titleId, NcmContentMetaType contentMetaType);
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
namespace inst::zip {
|
namespace inst::zip {
|
||||||
bool extractFile(const std::string filename, const std::string destination);
|
bool extractFile(const std::string filename, const std::string destination);
|
||||||
}
|
}
|
@ -12,35 +12,35 @@ extern "C" {
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "switch/types.h"
|
#include "switch/types.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 bInterfaceClass;
|
u8 bInterfaceClass;
|
||||||
u8 bInterfaceSubClass;
|
u8 bInterfaceSubClass;
|
||||||
u8 bInterfaceProtocol;
|
u8 bInterfaceProtocol;
|
||||||
} awoo_UsbCommsInterfaceInfo;
|
} awoo_UsbCommsInterfaceInfo;
|
||||||
|
|
||||||
/// Initializes usbComms with the default number of interfaces (1)
|
/// Initializes usbComms with the default number of interfaces (1)
|
||||||
Result awoo_usbCommsInitialize(void);
|
Result awoo_usbCommsInitialize(void);
|
||||||
|
|
||||||
/// Initializes usbComms with a specific number of interfaces.
|
/// Initializes usbComms with a specific number of interfaces.
|
||||||
Result awoo_usbCommsInitializeEx(u32 num_interfaces, const awoo_UsbCommsInterfaceInfo *infos);
|
Result awoo_usbCommsInitializeEx(u32 num_interfaces, const awoo_UsbCommsInterfaceInfo* infos);
|
||||||
|
|
||||||
/// Exits usbComms.
|
/// Exits usbComms.
|
||||||
void awoo_usbCommsExit(void);
|
void awoo_usbCommsExit(void);
|
||||||
|
|
||||||
/// 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.
|
/// 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.
|
||||||
void awoo_usbCommsSetErrorHandling(bool flag);
|
void awoo_usbCommsSetErrorHandling(bool flag);
|
||||||
|
|
||||||
/// Read data with the default interface.
|
/// Read data with the default interface.
|
||||||
size_t awoo_usbCommsRead(void* buffer, size_t size, u64 timeout);
|
size_t awoo_usbCommsRead(void* buffer, size_t size, u64 timeout);
|
||||||
|
|
||||||
/// Write data with the default interface.
|
/// Write data with the default interface.
|
||||||
size_t awoo_usbCommsWrite(const void* buffer, size_t size, u64 timeout);
|
size_t awoo_usbCommsWrite(const void* buffer, size_t size, u64 timeout);
|
||||||
|
|
||||||
/// Same as usbCommsRead except with the specified interface.
|
/// Same as usbCommsRead except with the specified interface.
|
||||||
size_t awoo_usbCommsReadEx(void* buffer, size_t size, u32 interface, u64 timeout);
|
size_t awoo_usbCommsReadEx(void* buffer, size_t size, u32 interface, u64 timeout);
|
||||||
|
|
||||||
/// Same as usbCommsWrite except with the specified interface.
|
/// Same as usbCommsWrite except with the specified interface.
|
||||||
size_t awoo_usbCommsWriteEx(const void* buffer, size_t size, u32 interface, u64 timeout);
|
size_t awoo_usbCommsWriteEx(const void* buffer, size_t size, u32 interface, u64 timeout);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -27,33 +27,33 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::util
|
namespace tin::util
|
||||||
{
|
{
|
||||||
enum USBCmdType : u8
|
enum USBCmdType : u8
|
||||||
{
|
{
|
||||||
REQUEST = 0,
|
REQUEST = 0,
|
||||||
RESPONSE = 1
|
RESPONSE = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct USBCmdHeader
|
struct USBCmdHeader
|
||||||
{
|
{
|
||||||
u32 magic;
|
u32 magic;
|
||||||
USBCmdType type;
|
USBCmdType type;
|
||||||
u8 padding[0x3] = {0};
|
u8 padding[0x3] = { 0 };
|
||||||
u32 cmdId;
|
u32 cmdId;
|
||||||
u64 dataSize;
|
u64 dataSize;
|
||||||
u8 reserved[0xC] = {0};
|
u8 reserved[0xC] = { 0 };
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
static_assert(sizeof(USBCmdHeader) == 0x20, "USBCmdHeader must be 0x20!");
|
static_assert(sizeof(USBCmdHeader) == 0x20, "USBCmdHeader must be 0x20!");
|
||||||
|
|
||||||
class USBCmdManager
|
class USBCmdManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void SendCmdHeader(u32 cmdId, size_t dataSize);
|
static void SendCmdHeader(u32 cmdId, size_t dataSize);
|
||||||
|
|
||||||
static void SendExitCmd();
|
static void SendExitCmd();
|
||||||
static USBCmdHeader SendFileRangeCmd(std::string nspName, u64 offset, u64 size);
|
static USBCmdHeader SendFileRangeCmd(std::string nspName, u64 offset, u64 size);
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t USBRead(void* out, size_t len, u64 timeout = 5000000000);
|
size_t USBRead(void* out, size_t len, u64 timeout = 5000000000);
|
||||||
size_t USBWrite(const void* in, size_t len, u64 timeout = 5000000000);
|
size_t USBWrite(const void* in, size_t len, u64 timeout = 5000000000);
|
||||||
}
|
}
|
@ -2,27 +2,27 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
namespace inst::util {
|
namespace inst::util {
|
||||||
void initApp ();
|
void initApp();
|
||||||
void deinitApp ();
|
void deinitApp();
|
||||||
void initInstallServices();
|
void initInstallServices();
|
||||||
void deinitInstallServices();
|
void deinitInstallServices();
|
||||||
bool ignoreCaseCompare(const std::string &a, const std::string &b);
|
bool ignoreCaseCompare(const std::string& a, const std::string& b);
|
||||||
std::vector<std::filesystem::path> getDirectoryFiles(const std::string & dir, const std::vector<std::string> & extensions);
|
std::vector<std::filesystem::path> getDirectoryFiles(const std::string& dir, const std::vector<std::string>& extensions);
|
||||||
std::vector<std::filesystem::path> getDirsAtPath(const std::string & dir);
|
std::vector<std::filesystem::path> getDirsAtPath(const std::string& dir);
|
||||||
bool removeDirectory(std::string dir);
|
bool removeDirectory(std::string dir);
|
||||||
bool copyFile(std::string inFile, std::string outFile);
|
bool copyFile(std::string inFile, std::string outFile);
|
||||||
std::string formatUrlString(std::string ourString);
|
std::string formatUrlString(std::string ourString);
|
||||||
std::string formatUrlLink(std::string ourString);
|
std::string formatUrlLink(std::string ourString);
|
||||||
std::string shortenString(std::string ourString, int ourLength, bool isFile);
|
std::string shortenString(std::string ourString, int ourLength, bool isFile);
|
||||||
std::string readTextFromFile(std::string ourFile);
|
std::string readTextFromFile(std::string ourFile);
|
||||||
std::string softwareKeyboard(std::string guideText, std::string initialText, int LenMax);
|
std::string softwareKeyboard(std::string guideText, std::string initialText, int LenMax);
|
||||||
std::string getDriveFileName(std::string fileId);
|
std::string getDriveFileName(std::string fileId);
|
||||||
std::vector<uint32_t> setClockSpeed(int deviceToClock, uint32_t clockSpeed);
|
std::vector<uint32_t> setClockSpeed(int deviceToClock, uint32_t clockSpeed);
|
||||||
std::string getIPAddress();
|
std::string getIPAddress();
|
||||||
bool usbIsConnected();
|
bool usbIsConnected();
|
||||||
void playAudio(std::string audioPath);
|
void playAudio(std::string audioPath);
|
||||||
std::vector<std::string> checkForAppUpdate();
|
std::vector<std::string> checkForAppUpdate();
|
||||||
double GetAvailableSpace(const char* path);
|
double GetAvailableSpace(const char* path);
|
||||||
double amountOfDiskSpaceUsed(const char* path);
|
double amountOfDiskSpaceUsed(const char* path);
|
||||||
double totalsize(const char* path);
|
double totalsize(const char* path);
|
||||||
}
|
}
|
@ -43,108 +43,112 @@ SOFTWARE.
|
|||||||
#include "ui/instPage.hpp"
|
#include "ui/instPage.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace nspInstStuff_B {
|
namespace nspInstStuff_B {
|
||||||
|
|
||||||
void installNspFromFile(std::vector<std::filesystem::path> ourTitleList, int whereToInstall)
|
void installNspFromFile(std::vector<std::filesystem::path> ourTitleList, int whereToInstall)
|
||||||
{
|
{
|
||||||
inst::util::initInstallServices();
|
inst::util::initInstallServices();
|
||||||
inst::ui::instPage::loadInstallScreen();
|
inst::ui::instPage::loadInstallScreen();
|
||||||
bool nspInstalled = true;
|
bool nspInstalled = true;
|
||||||
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
||||||
|
|
||||||
if (whereToInstall) m_destStorageId = NcmStorageId_BuiltInUser;
|
if (whereToInstall) m_destStorageId = NcmStorageId_BuiltInUser;
|
||||||
unsigned int titleItr;
|
unsigned int titleItr;
|
||||||
|
|
||||||
std::vector<int> previousClockValues;
|
std::vector<int> previousClockValues;
|
||||||
if (inst::config::overClock) {
|
if (inst::config::overClock) {
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (titleItr = 0; titleItr < ourTitleList.size(); titleItr++) {
|
for (titleItr = 0; titleItr < ourTitleList.size(); titleItr++) {
|
||||||
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 40, true) + "inst.hd.source_string"_lang);
|
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 40, true) + "inst.hd.source_string"_lang);
|
||||||
std::unique_ptr<tin::install::Install> installTask;
|
std::unique_ptr<tin::install::Install> installTask;
|
||||||
|
|
||||||
if (ourTitleList[titleItr].extension() == ".xci" || ourTitleList[titleItr].extension() == ".xcz") {
|
if (ourTitleList[titleItr].extension() == ".xci" || ourTitleList[titleItr].extension() == ".xcz") {
|
||||||
auto sdmcXCI = std::make_shared<tin::install::xci::SDMCXCI>(ourTitleList[titleItr]);
|
auto sdmcXCI = std::make_shared<tin::install::xci::SDMCXCI>(ourTitleList[titleItr]);
|
||||||
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, sdmcXCI);
|
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, sdmcXCI);
|
||||||
} else {
|
}
|
||||||
auto sdmcNSP = std::make_shared<tin::install::nsp::SDMCNSP>(ourTitleList[titleItr]);
|
else {
|
||||||
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, sdmcNSP);
|
auto sdmcNSP = std::make_shared<tin::install::nsp::SDMCNSP>(ourTitleList[titleItr]);
|
||||||
}
|
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, sdmcNSP);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("%s\n", "Preparing installation");
|
LOG_DEBUG("%s\n", "Preparing installation");
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
installTask->Prepare();
|
installTask->Prepare();
|
||||||
installTask->Begin();
|
installTask->Begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Failed to install");
|
LOG_DEBUG("Failed to install");
|
||||||
LOG_DEBUG("%s", e.what());
|
LOG_DEBUG("%s", e.what());
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true));
|
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true));
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
std::string audioPath = "";
|
std::string audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/sounds/OHNO.WAV")) {
|
if (std::filesystem::exists(inst::config::appDir + "/sounds/OHNO.WAV")) {
|
||||||
audioPath = (inst::config::appDir + "/sounds/OHNO.WAV");
|
audioPath = (inst::config::appDir + "/sounds/OHNO.WAV");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
audioPath = "romfs:/audio/bark.wav";
|
audioPath = "romfs:/audio/bark.wav";
|
||||||
}
|
}
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true) + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true) + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), { "common.ok"_lang }, true);
|
||||||
audioThread.join();
|
audioThread.join();
|
||||||
nspInstalled = false;
|
nspInstalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousClockValues.size() > 0) {
|
if (previousClockValues.size() > 0) {
|
||||||
inst::util::setClockSpeed(0, previousClockValues[0]);
|
inst::util::setClockSpeed(0, previousClockValues[0]);
|
||||||
inst::util::setClockSpeed(1, previousClockValues[1]);
|
inst::util::setClockSpeed(1, previousClockValues[1]);
|
||||||
inst::util::setClockSpeed(2, previousClockValues[2]);
|
inst::util::setClockSpeed(2, previousClockValues[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nspInstalled) {
|
if (nspInstalled) {
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
std::string audioPath = "";
|
std::string audioPath = "";
|
||||||
|
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/sounds/YIPPEE.WAV")) {
|
|
||||||
audioPath = (inst::config::appDir + "/sounds/YIPPEE.WAV");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
audioPath = "romfs:/audio/ameizing.mp3";
|
|
||||||
}
|
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
|
||||||
|
|
||||||
if (ourTitleList.size() > 1) {
|
if (std::filesystem::exists(inst::config::appDir + "/sounds/YIPPEE.WAV")) {
|
||||||
if (inst::config::deletePrompt) {
|
audioPath = (inst::config::appDir + "/sounds/YIPPEE.WAV");
|
||||||
if(inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.hd.delete_info_multi"_lang, "inst.hd.delete_desc"_lang, {"common.no"_lang,"common.yes"_lang}, false) == 1) {
|
}
|
||||||
for (long unsigned int i = 0; i < ourTitleList.size(); i++) {
|
else {
|
||||||
if (std::filesystem::exists(ourTitleList[i])) std::filesystem::remove(ourTitleList[i]);
|
audioPath = "romfs:/audio/ameizing.mp3";
|
||||||
}
|
}
|
||||||
}
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
} else inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
|
||||||
} else {
|
|
||||||
if (inst::config::deletePrompt) {
|
|
||||||
if(inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 32, true) + "inst.hd.delete_info"_lang, "inst.hd.delete_desc"_lang, {"common.no"_lang,"common.yes"_lang}, false) == 1) if (std::filesystem::exists(ourTitleList[0])) std::filesystem::remove(ourTitleList[0]);
|
|
||||||
} else inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 42, true) + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
audioThread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("Done");
|
if (ourTitleList.size() > 1) {
|
||||||
inst::ui::instPage::loadMainMenu();
|
if (inst::config::deletePrompt) {
|
||||||
inst::util::deinitInstallServices();
|
if (inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.hd.delete_info_multi"_lang, "inst.hd.delete_desc"_lang, { "common.no"_lang,"common.yes"_lang }, false) == 1) {
|
||||||
return;
|
for (long unsigned int i = 0; i < ourTitleList.size(); i++) {
|
||||||
}
|
if (std::filesystem::exists(ourTitleList[i])) std::filesystem::remove(ourTitleList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (inst::config::deletePrompt) {
|
||||||
|
if (inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 32, true) + "inst.hd.delete_info"_lang, "inst.hd.delete_desc"_lang, { "common.no"_lang,"common.yes"_lang }, false) == 1) if (std::filesystem::exists(ourTitleList[0])) std::filesystem::remove(ourTitleList[0]);
|
||||||
|
}
|
||||||
|
else inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 42, true) + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
audioThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("Done");
|
||||||
|
inst::ui::instPage::loadMainMenu();
|
||||||
|
inst::util::deinitInstallServices();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,182 +31,182 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::data
|
namespace tin::data
|
||||||
{
|
{
|
||||||
int NUM_BUFFER_SEGMENTS;
|
int NUM_BUFFER_SEGMENTS;
|
||||||
|
|
||||||
BufferedPlaceholderWriter::BufferedPlaceholderWriter(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId, size_t totalDataSize) :
|
BufferedPlaceholderWriter::BufferedPlaceholderWriter(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId, size_t totalDataSize) :
|
||||||
m_totalDataSize(totalDataSize), m_contentStorage(contentStorage), m_ncaId(ncaId), m_writer(ncaId, contentStorage)
|
m_totalDataSize(totalDataSize), m_contentStorage(contentStorage), m_ncaId(ncaId), m_writer(ncaId, contentStorage)
|
||||||
{
|
{
|
||||||
// Though currently the number of segments is fixed, we want them allocated on the heap, not the stack
|
// Though currently the number of segments is fixed, we want them allocated on the heap, not the stack
|
||||||
m_bufferSegments = std::make_unique<BufferSegment[]>(NUM_BUFFER_SEGMENTS);
|
m_bufferSegments = std::make_unique<BufferSegment[]>(NUM_BUFFER_SEGMENTS);
|
||||||
|
|
||||||
if (m_bufferSegments == nullptr)
|
if (m_bufferSegments == nullptr)
|
||||||
THROW_FORMAT("Failed to allocated buffer segments!\n");
|
THROW_FORMAT("Failed to allocated buffer segments!\n");
|
||||||
|
|
||||||
m_currentFreeSegmentPtr = &m_bufferSegments[m_currentFreeSegment];
|
m_currentFreeSegmentPtr = &m_bufferSegments[m_currentFreeSegment];
|
||||||
m_currentSegmentToWritePtr = &m_bufferSegments[m_currentSegmentToWrite];
|
m_currentSegmentToWritePtr = &m_bufferSegments[m_currentSegmentToWrite];
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferedPlaceholderWriter::AppendData(void* source, size_t length)
|
void BufferedPlaceholderWriter::AppendData(void* source, size_t length)
|
||||||
{
|
{
|
||||||
if (m_sizeBuffered + length > m_totalDataSize)
|
if (m_sizeBuffered + length > m_totalDataSize)
|
||||||
THROW_FORMAT("Cannot append data as it would exceed the expected total.\n");
|
THROW_FORMAT("Cannot append data as it would exceed the expected total.\n");
|
||||||
|
|
||||||
size_t dataSizeRemaining = length;
|
size_t dataSizeRemaining = length;
|
||||||
u64 sourceOffset = 0;
|
u64 sourceOffset = 0;
|
||||||
|
|
||||||
while (dataSizeRemaining > 0)
|
while (dataSizeRemaining > 0)
|
||||||
{
|
{
|
||||||
size_t bufferSegmentSizeRemaining = BUFFER_SEGMENT_DATA_SIZE - m_currentFreeSegmentPtr->writeOffset;
|
size_t bufferSegmentSizeRemaining = BUFFER_SEGMENT_DATA_SIZE - m_currentFreeSegmentPtr->writeOffset;
|
||||||
|
|
||||||
if (m_currentFreeSegmentPtr->isFinalized)
|
if (m_currentFreeSegmentPtr->isFinalized)
|
||||||
THROW_FORMAT("Current buffer segment is already finalized!\n");
|
THROW_FORMAT("Current buffer segment is already finalized!\n");
|
||||||
|
|
||||||
if (dataSizeRemaining < bufferSegmentSizeRemaining)
|
if (dataSizeRemaining < bufferSegmentSizeRemaining)
|
||||||
{
|
{
|
||||||
memcpy(m_currentFreeSegmentPtr->data + m_currentFreeSegmentPtr->writeOffset, (u8*)source + sourceOffset, dataSizeRemaining);
|
memcpy(m_currentFreeSegmentPtr->data + m_currentFreeSegmentPtr->writeOffset, (u8*)source + sourceOffset, dataSizeRemaining);
|
||||||
sourceOffset += dataSizeRemaining;
|
sourceOffset += dataSizeRemaining;
|
||||||
m_currentFreeSegmentPtr->writeOffset += dataSizeRemaining;
|
m_currentFreeSegmentPtr->writeOffset += dataSizeRemaining;
|
||||||
dataSizeRemaining = 0;
|
dataSizeRemaining = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(m_currentFreeSegmentPtr->data + m_currentFreeSegmentPtr->writeOffset, (u8*)source + sourceOffset, bufferSegmentSizeRemaining);
|
memcpy(m_currentFreeSegmentPtr->data + m_currentFreeSegmentPtr->writeOffset, (u8*)source + sourceOffset, bufferSegmentSizeRemaining);
|
||||||
dataSizeRemaining -= bufferSegmentSizeRemaining;
|
dataSizeRemaining -= bufferSegmentSizeRemaining;
|
||||||
sourceOffset += bufferSegmentSizeRemaining;
|
sourceOffset += bufferSegmentSizeRemaining;
|
||||||
m_currentFreeSegmentPtr->writeOffset += bufferSegmentSizeRemaining;
|
m_currentFreeSegmentPtr->writeOffset += bufferSegmentSizeRemaining;
|
||||||
m_currentFreeSegmentPtr->isFinalized = true;
|
m_currentFreeSegmentPtr->isFinalized = true;
|
||||||
|
|
||||||
m_currentFreeSegment = (m_currentFreeSegment + 1) % NUM_BUFFER_SEGMENTS;
|
m_currentFreeSegment = (m_currentFreeSegment + 1) % NUM_BUFFER_SEGMENTS;
|
||||||
m_currentFreeSegmentPtr = &m_bufferSegments[m_currentFreeSegment];
|
m_currentFreeSegmentPtr = &m_bufferSegments[m_currentFreeSegment];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sizeBuffered += length;
|
m_sizeBuffered += length;
|
||||||
|
|
||||||
if (m_sizeBuffered == m_totalDataSize)
|
if (m_sizeBuffered == m_totalDataSize)
|
||||||
{
|
{
|
||||||
m_currentFreeSegmentPtr->isFinalized = true;
|
m_currentFreeSegmentPtr->isFinalized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferedPlaceholderWriter::CanAppendData(size_t length)
|
bool BufferedPlaceholderWriter::CanAppendData(size_t length)
|
||||||
{
|
{
|
||||||
if (m_sizeBuffered + length > m_totalDataSize)
|
if (m_sizeBuffered + length > m_totalDataSize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!this->IsSizeAvailable(length))
|
if (!this->IsSizeAvailable(length))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferedPlaceholderWriter::WriteSegmentToPlaceholder()
|
void BufferedPlaceholderWriter::WriteSegmentToPlaceholder()
|
||||||
{
|
{
|
||||||
if (m_sizeWrittenToPlaceholder >= m_totalDataSize)
|
if (m_sizeWrittenToPlaceholder >= m_totalDataSize)
|
||||||
THROW_FORMAT("Cannot write segment as end of data has already been reached!\n");
|
THROW_FORMAT("Cannot write segment as end of data has already been reached!\n");
|
||||||
|
|
||||||
if (!m_currentSegmentToWritePtr->isFinalized)
|
if (!m_currentSegmentToWritePtr->isFinalized)
|
||||||
THROW_FORMAT("Cannot write segment as it hasn't been finalized!\n");
|
THROW_FORMAT("Cannot write segment as it hasn't been finalized!\n");
|
||||||
|
|
||||||
// NOTE: The final segment will have leftover data from previous writes, however
|
// NOTE: The final segment will have leftover data from previous writes, however
|
||||||
// this will be accounted for by this size
|
// this will be accounted for by this size
|
||||||
size_t sizeToWriteToPlaceholder = std::min(m_totalDataSize - m_sizeWrittenToPlaceholder, BUFFER_SEGMENT_DATA_SIZE);
|
size_t sizeToWriteToPlaceholder = std::min(m_totalDataSize - m_sizeWrittenToPlaceholder, BUFFER_SEGMENT_DATA_SIZE);
|
||||||
m_writer.write(m_currentSegmentToWritePtr->data, sizeToWriteToPlaceholder);
|
m_writer.write(m_currentSegmentToWritePtr->data, sizeToWriteToPlaceholder);
|
||||||
|
|
||||||
m_currentSegmentToWritePtr->isFinalized = false;
|
m_currentSegmentToWritePtr->isFinalized = false;
|
||||||
m_currentSegmentToWritePtr->writeOffset = 0;
|
m_currentSegmentToWritePtr->writeOffset = 0;
|
||||||
m_currentSegmentToWrite = (m_currentSegmentToWrite + 1) % NUM_BUFFER_SEGMENTS;
|
m_currentSegmentToWrite = (m_currentSegmentToWrite + 1) % NUM_BUFFER_SEGMENTS;
|
||||||
m_currentSegmentToWritePtr = &m_bufferSegments[m_currentSegmentToWrite];
|
m_currentSegmentToWritePtr = &m_bufferSegments[m_currentSegmentToWrite];
|
||||||
m_sizeWrittenToPlaceholder += sizeToWriteToPlaceholder;
|
m_sizeWrittenToPlaceholder += sizeToWriteToPlaceholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferedPlaceholderWriter::CanWriteSegmentToPlaceholder()
|
bool BufferedPlaceholderWriter::CanWriteSegmentToPlaceholder()
|
||||||
{
|
{
|
||||||
if (m_sizeWrittenToPlaceholder >= m_totalDataSize)
|
if (m_sizeWrittenToPlaceholder >= m_totalDataSize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_currentSegmentToWritePtr->isFinalized)
|
if (!m_currentSegmentToWritePtr->isFinalized)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 BufferedPlaceholderWriter::CalcNumSegmentsRequired(size_t size)
|
u32 BufferedPlaceholderWriter::CalcNumSegmentsRequired(size_t size)
|
||||||
{
|
{
|
||||||
if (m_currentFreeSegmentPtr->isFinalized)
|
if (m_currentFreeSegmentPtr->isFinalized)
|
||||||
return INT_MAX;
|
return INT_MAX;
|
||||||
|
|
||||||
size_t bufferSegmentSizeRemaining = BUFFER_SEGMENT_DATA_SIZE - m_currentFreeSegmentPtr->writeOffset;
|
size_t bufferSegmentSizeRemaining = BUFFER_SEGMENT_DATA_SIZE - m_currentFreeSegmentPtr->writeOffset;
|
||||||
|
|
||||||
if (size <= bufferSegmentSizeRemaining) return 1;
|
if (size <= bufferSegmentSizeRemaining) return 1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double numSegmentsReq = 1 + (double)(size - bufferSegmentSizeRemaining) / (double)BUFFER_SEGMENT_DATA_SIZE;
|
double numSegmentsReq = 1 + (double)(size - bufferSegmentSizeRemaining) / (double)BUFFER_SEGMENT_DATA_SIZE;
|
||||||
return ceil(numSegmentsReq);
|
return ceil(numSegmentsReq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferedPlaceholderWriter::IsSizeAvailable(size_t size)
|
bool BufferedPlaceholderWriter::IsSizeAvailable(size_t size)
|
||||||
{
|
{
|
||||||
u32 numSegmentsRequired = this->CalcNumSegmentsRequired(size);
|
u32 numSegmentsRequired = this->CalcNumSegmentsRequired(size);
|
||||||
|
|
||||||
if ((int)numSegmentsRequired > NUM_BUFFER_SEGMENTS)
|
if ((int)numSegmentsRequired > NUM_BUFFER_SEGMENTS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < numSegmentsRequired; i++)
|
for (unsigned int i = 0; i < numSegmentsRequired; i++)
|
||||||
{
|
{
|
||||||
unsigned int segmentIndex = m_currentFreeSegment + i;
|
unsigned int segmentIndex = m_currentFreeSegment + i;
|
||||||
BufferSegment* bufferSegment = &m_bufferSegments[segmentIndex % NUM_BUFFER_SEGMENTS];
|
BufferSegment* bufferSegment = &m_bufferSegments[segmentIndex % NUM_BUFFER_SEGMENTS];
|
||||||
|
|
||||||
if (bufferSegment->isFinalized)
|
if (bufferSegment->isFinalized)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (i != 0 && bufferSegment->writeOffset != 0)
|
if (i != 0 && bufferSegment->writeOffset != 0)
|
||||||
THROW_FORMAT("Unexpected non-zero write offset at segment %u (%lu)\n", segmentIndex, bufferSegment->writeOffset);
|
THROW_FORMAT("Unexpected non-zero write offset at segment %u (%lu)\n", segmentIndex, bufferSegment->writeOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferedPlaceholderWriter::IsBufferDataComplete()
|
bool BufferedPlaceholderWriter::IsBufferDataComplete()
|
||||||
{
|
{
|
||||||
if (m_sizeBuffered > m_totalDataSize)
|
if (m_sizeBuffered > m_totalDataSize)
|
||||||
THROW_FORMAT("Size buffered cannot exceed total data size!\n");
|
THROW_FORMAT("Size buffered cannot exceed total data size!\n");
|
||||||
|
|
||||||
return m_sizeBuffered == m_totalDataSize;
|
return m_sizeBuffered == m_totalDataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferedPlaceholderWriter::IsPlaceholderComplete()
|
bool BufferedPlaceholderWriter::IsPlaceholderComplete()
|
||||||
{
|
{
|
||||||
if (m_sizeWrittenToPlaceholder > m_totalDataSize)
|
if (m_sizeWrittenToPlaceholder > m_totalDataSize)
|
||||||
THROW_FORMAT("Size written to placeholder cannot exceed total data size!\n");
|
THROW_FORMAT("Size written to placeholder cannot exceed total data size!\n");
|
||||||
|
|
||||||
return m_sizeWrittenToPlaceholder == m_totalDataSize;
|
return m_sizeWrittenToPlaceholder == m_totalDataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t BufferedPlaceholderWriter::GetTotalDataSize()
|
size_t BufferedPlaceholderWriter::GetTotalDataSize()
|
||||||
{
|
{
|
||||||
return m_totalDataSize;
|
return m_totalDataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t BufferedPlaceholderWriter::GetSizeBuffered()
|
size_t BufferedPlaceholderWriter::GetSizeBuffered()
|
||||||
{
|
{
|
||||||
return m_sizeBuffered;
|
return m_sizeBuffered;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t BufferedPlaceholderWriter::GetSizeWrittenToPlaceholder()
|
size_t BufferedPlaceholderWriter::GetSizeWrittenToPlaceholder()
|
||||||
{
|
{
|
||||||
return m_sizeWrittenToPlaceholder;
|
return m_sizeWrittenToPlaceholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferedPlaceholderWriter::DebugPrintBuffers()
|
void BufferedPlaceholderWriter::DebugPrintBuffers()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("BufferedPlaceholderWriter Buffers: \n");
|
LOG_DEBUG("BufferedPlaceholderWriter Buffers: \n");
|
||||||
|
|
||||||
for (int i = 0; i < NUM_BUFFER_SEGMENTS; i++)
|
for (int i = 0; i < NUM_BUFFER_SEGMENTS; i++)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Buffer %u:\n", i);
|
LOG_DEBUG("Buffer %u:\n", i);
|
||||||
printBytes(m_bufferSegments[i].data, BUFFER_SEGMENT_DATA_SIZE, true);
|
printBytes(m_bufferSegments[i].data, BUFFER_SEGMENT_DATA_SIZE, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,29 +27,29 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::data
|
namespace tin::data
|
||||||
{
|
{
|
||||||
ByteBuffer::ByteBuffer(size_t reserveSize)
|
ByteBuffer::ByteBuffer(size_t reserveSize)
|
||||||
{
|
{
|
||||||
m_buffer.resize(reserveSize);
|
m_buffer.resize(reserveSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ByteBuffer::GetSize()
|
size_t ByteBuffer::GetSize()
|
||||||
{
|
{
|
||||||
return m_buffer.size();
|
return m_buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* ByteBuffer::GetData()
|
u8* ByteBuffer::GetData()
|
||||||
{
|
{
|
||||||
return m_buffer.data();
|
return m_buffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteBuffer::Resize(size_t size)
|
void ByteBuffer::Resize(size_t size)
|
||||||
{
|
{
|
||||||
m_buffer.resize(size, 0);
|
m_buffer.resize(size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteBuffer::DebugPrintContents()
|
void ByteBuffer::DebugPrintContents()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Buffer Size: 0x%lx\n", this->GetSize());
|
LOG_DEBUG("Buffer Size: 0x%lx\n", this->GetSize());
|
||||||
printBytes(this->GetData(), this->GetSize(), true);
|
printBytes(this->GetData(), this->GetSize(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,18 +24,18 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::data
|
namespace tin::data
|
||||||
{
|
{
|
||||||
BufferedByteStream::BufferedByteStream(ByteBuffer buffer) :
|
BufferedByteStream::BufferedByteStream(ByteBuffer buffer) :
|
||||||
m_byteBuffer(buffer)
|
m_byteBuffer(buffer)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferedByteStream::ReadBytes(void* dest, size_t length)
|
void BufferedByteStream::ReadBytes(void* dest, size_t length)
|
||||||
{
|
{
|
||||||
if (m_offset + length > m_byteBuffer.GetSize())
|
if (m_offset + length > m_byteBuffer.GetSize())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memcpy(dest, m_byteBuffer.GetData() + m_offset, length);
|
memcpy(dest, m_byteBuffer.GetData() + m_offset, length);
|
||||||
m_offset += length;
|
m_offset += length;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -34,121 +34,121 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
bool stopThreadsHttpNsp;
|
bool stopThreadsHttpNsp;
|
||||||
|
|
||||||
HTTPNSP::HTTPNSP(std::string url) :
|
HTTPNSP::HTTPNSP(std::string url) :
|
||||||
m_download(url)
|
m_download(url)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StreamFuncArgs
|
struct StreamFuncArgs
|
||||||
{
|
{
|
||||||
tin::network::HTTPDownload* download;
|
tin::network::HTTPDownload* download;
|
||||||
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
||||||
u64 pfs0Offset;
|
u64 pfs0Offset;
|
||||||
u64 ncaSize;
|
u64 ncaSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
int CurlStreamFunc(void* in)
|
int CurlStreamFunc(void* in)
|
||||||
{
|
{
|
||||||
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
||||||
|
|
||||||
auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t
|
auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanAppendData(streamBufSize))
|
if (args->bufferedPlaceholderWriter->CanAppendData(streamBufSize))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
args->bufferedPlaceholderWriter->AppendData(streamBuf, streamBufSize);
|
args->bufferedPlaceholderWriter->AppendData(streamBuf, streamBufSize);
|
||||||
return streamBufSize;
|
return streamBufSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (args->download->StreamDataRange(args->pfs0Offset, args->ncaSize, streamFunc) == 1) stopThreadsHttpNsp = true;
|
if (args->download->StreamDataRange(args->pfs0Offset, args->ncaSize, streamFunc) == 1) stopThreadsHttpNsp = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlaceholderWriteFunc(void* in)
|
int PlaceholderWriteFunc(void* in)
|
||||||
{
|
{
|
||||||
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
||||||
|
|
||||||
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsHttpNsp)
|
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsHttpNsp)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
||||||
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPNSP::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId)
|
void HTTPNSP::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize);
|
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize);
|
||||||
StreamFuncArgs args;
|
StreamFuncArgs args;
|
||||||
args.download = &m_download;
|
args.download = &m_download;
|
||||||
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
||||||
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
||||||
args.ncaSize = ncaSize;
|
args.ncaSize = ncaSize;
|
||||||
thrd_t curlThread;
|
thrd_t curlThread;
|
||||||
thrd_t writeThread;
|
thrd_t writeThread;
|
||||||
|
|
||||||
stopThreadsHttpNsp = false;
|
stopThreadsHttpNsp = false;
|
||||||
thrd_create(&curlThread, CurlStreamFunc, &args);
|
thrd_create(&curlThread, CurlStreamFunc, &args);
|
||||||
thrd_create(&writeThread, PlaceholderWriteFunc, &args);
|
thrd_create(&writeThread, PlaceholderWriteFunc, &args);
|
||||||
|
|
||||||
u64 freq = armGetSystemTickFreq();
|
u64 freq = armGetSystemTickFreq();
|
||||||
u64 startTime = armGetSystemTick();
|
u64 startTime = armGetSystemTick();
|
||||||
size_t startSizeBuffered = 0;
|
size_t startSizeBuffered = 0;
|
||||||
double speed = 0.0;
|
double speed = 0.0;
|
||||||
|
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsHttpNsp)
|
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsHttpNsp)
|
||||||
{
|
{
|
||||||
u64 newTime = armGetSystemTick();
|
u64 newTime = armGetSystemTick();
|
||||||
|
|
||||||
if (newTime - startTime >= freq * 0.5)
|
if (newTime - startTime >= freq * 0.5)
|
||||||
{
|
{
|
||||||
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
||||||
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
||||||
double duration = ((double)(newTime - startTime) / (double)freq);
|
double duration = ((double)(newTime - startTime) / (double)freq);
|
||||||
speed = mbBuffered / duration;
|
speed = mbBuffered / duration;
|
||||||
|
|
||||||
startTime = newTime;
|
startTime = newTime;
|
||||||
startSizeBuffered = newSizeBuffered;
|
startSizeBuffered = newSizeBuffered;
|
||||||
|
|
||||||
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
|
|
||||||
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");
|
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");
|
||||||
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsHttpNsp)
|
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsHttpNsp)
|
||||||
{
|
{
|
||||||
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
|
|
||||||
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
thrd_join(curlThread, NULL);
|
thrd_join(curlThread, NULL);
|
||||||
thrd_join(writeThread, NULL);
|
thrd_join(writeThread, NULL);
|
||||||
if (stopThreadsHttpNsp) THROW_FORMAT(("inst.net.transfer_interput"_lang).c_str());
|
if (stopThreadsHttpNsp) THROW_FORMAT(("inst.net.transfer_interput"_lang).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPNSP::BufferData(void* buf, off_t offset, size_t size)
|
void HTTPNSP::BufferData(void* buf, off_t offset, size_t size)
|
||||||
{
|
{
|
||||||
m_download.BufferDataRange(buf, offset, size, nullptr);
|
m_download.BufferDataRange(buf, offset, size, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,132 +31,132 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
bool stopThreadsHttpXci;
|
bool stopThreadsHttpXci;
|
||||||
|
|
||||||
HTTPXCI::HTTPXCI(std::string url) :
|
HTTPXCI::HTTPXCI(std::string url) :
|
||||||
m_download(url)
|
m_download(url)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StreamFuncArgs
|
struct StreamFuncArgs
|
||||||
{
|
{
|
||||||
tin::network::HTTPDownload* download;
|
tin::network::HTTPDownload* download;
|
||||||
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
||||||
u64 pfs0Offset;
|
u64 pfs0Offset;
|
||||||
u64 ncaSize;
|
u64 ncaSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
int CurlStreamFunc(void* in)
|
int CurlStreamFunc(void* in)
|
||||||
{
|
{
|
||||||
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
||||||
|
|
||||||
auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t
|
auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanAppendData(streamBufSize))
|
if (args->bufferedPlaceholderWriter->CanAppendData(streamBufSize))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
args->bufferedPlaceholderWriter->AppendData(streamBuf, streamBufSize);
|
args->bufferedPlaceholderWriter->AppendData(streamBuf, streamBufSize);
|
||||||
return streamBufSize;
|
return streamBufSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (args->download->StreamDataRange(args->pfs0Offset, args->ncaSize, streamFunc) == 1) stopThreadsHttpXci = true;
|
if (args->download->StreamDataRange(args->pfs0Offset, args->ncaSize, streamFunc) == 1) stopThreadsHttpXci = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlaceholderWriteFunc(void* in)
|
int PlaceholderWriteFunc(void* in)
|
||||||
{
|
{
|
||||||
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
||||||
|
|
||||||
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsHttpXci)
|
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsHttpXci)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
||||||
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPXCI::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId)
|
void HTTPXCI::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId)
|
||||||
{
|
{
|
||||||
const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId);
|
const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId);
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, ncaId, ncaSize);
|
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, ncaId, ncaSize);
|
||||||
StreamFuncArgs args;
|
StreamFuncArgs args;
|
||||||
args.download = &m_download;
|
args.download = &m_download;
|
||||||
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
||||||
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
||||||
args.ncaSize = ncaSize;
|
args.ncaSize = ncaSize;
|
||||||
thrd_t curlThread;
|
thrd_t curlThread;
|
||||||
thrd_t writeThread;
|
thrd_t writeThread;
|
||||||
|
|
||||||
stopThreadsHttpXci = false;
|
stopThreadsHttpXci = false;
|
||||||
thrd_create(&curlThread, CurlStreamFunc, &args);
|
thrd_create(&curlThread, CurlStreamFunc, &args);
|
||||||
thrd_create(&writeThread, PlaceholderWriteFunc, &args);
|
thrd_create(&writeThread, PlaceholderWriteFunc, &args);
|
||||||
|
|
||||||
u64 freq = armGetSystemTickFreq();
|
u64 freq = armGetSystemTickFreq();
|
||||||
u64 startTime = armGetSystemTick();
|
u64 startTime = armGetSystemTick();
|
||||||
size_t startSizeBuffered = 0;
|
size_t startSizeBuffered = 0;
|
||||||
double speed = 0.0;
|
double speed = 0.0;
|
||||||
|
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsHttpXci)
|
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsHttpXci)
|
||||||
{
|
{
|
||||||
u64 newTime = armGetSystemTick();
|
u64 newTime = armGetSystemTick();
|
||||||
|
|
||||||
if (newTime - startTime >= freq * 0.5)
|
if (newTime - startTime >= freq * 0.5)
|
||||||
{
|
{
|
||||||
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
||||||
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
||||||
double duration = ((double)(newTime - startTime) / (double)freq);
|
double duration = ((double)(newTime - startTime) / (double)freq);
|
||||||
speed = mbBuffered / duration;
|
speed = mbBuffered / duration;
|
||||||
|
|
||||||
startTime = newTime;
|
startTime = newTime;
|
||||||
startSizeBuffered = newSizeBuffered;
|
startSizeBuffered = newSizeBuffered;
|
||||||
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
||||||
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
|
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
|
||||||
LOG_DEBUG("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
LOG_DEBUG("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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");
|
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");
|
||||||
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
#ifdef NXLINK_DEBUG
|
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
#ifdef NXLINK_DEBUG
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
||||||
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsHttpXci)
|
#endif
|
||||||
{
|
|
||||||
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
|
||||||
#ifdef NXLINK_DEBUG
|
|
||||||
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
|
|
||||||
LOG_DEBUG("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
|
||||||
#endif
|
|
||||||
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
|
||||||
}
|
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
|
||||||
|
|
||||||
thrd_join(curlThread, NULL);
|
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
||||||
thrd_join(writeThread, NULL);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
if (stopThreadsHttpXci) THROW_FORMAT(("inst.net.transfer_interput"_lang).c_str());
|
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsHttpXci)
|
||||||
}
|
{
|
||||||
|
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
|
#ifdef NXLINK_DEBUG
|
||||||
|
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
|
||||||
|
LOG_DEBUG("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
||||||
|
#endif
|
||||||
|
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
||||||
|
}
|
||||||
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
void HTTPXCI::BufferData(void* buf, off_t offset, size_t size)
|
thrd_join(curlThread, NULL);
|
||||||
{
|
thrd_join(writeThread, NULL);
|
||||||
m_download.BufferDataRange(buf, offset, size, nullptr);
|
if (stopThreadsHttpXci) THROW_FORMAT(("inst.net.transfer_interput"_lang).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPXCI::BufferData(void* buf, off_t offset, size_t size)
|
||||||
|
{
|
||||||
|
m_download.BufferDataRange(buf, offset, size, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
@ -35,117 +35,117 @@ SOFTWARE.
|
|||||||
// TODO: Check tik/cert is present
|
// TODO: Check tik/cert is present
|
||||||
namespace tin::install
|
namespace tin::install
|
||||||
{
|
{
|
||||||
Install::Install(NcmStorageId destStorageId, bool ignoreReqFirmVersion) :
|
Install::Install(NcmStorageId destStorageId, bool ignoreReqFirmVersion) :
|
||||||
m_destStorageId(destStorageId), m_ignoreReqFirmVersion(ignoreReqFirmVersion), m_contentMeta()
|
m_destStorageId(destStorageId), m_ignoreReqFirmVersion(ignoreReqFirmVersion), m_contentMeta()
|
||||||
{
|
{
|
||||||
appletSetMediaPlaybackState(true);
|
appletSetMediaPlaybackState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Install::~Install()
|
Install::~Install()
|
||||||
{
|
{
|
||||||
appletSetMediaPlaybackState(false);
|
appletSetMediaPlaybackState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement RAII on NcmContentMetaDatabase
|
// TODO: Implement RAII on NcmContentMetaDatabase
|
||||||
void Install::InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf, int i)
|
void Install::InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf, int i)
|
||||||
{
|
{
|
||||||
NcmContentMetaDatabase contentMetaDatabase;
|
NcmContentMetaDatabase contentMetaDatabase;
|
||||||
NcmContentMetaKey contentMetaKey = m_contentMeta[i].GetContentMetaKey();
|
NcmContentMetaKey contentMetaKey = m_contentMeta[i].GetContentMetaKey();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ASSERT_OK(ncmOpenContentMetaDatabase(&contentMetaDatabase, m_destStorageId), "Failed to open content meta database");
|
ASSERT_OK(ncmOpenContentMetaDatabase(&contentMetaDatabase, m_destStorageId), "Failed to open content meta database");
|
||||||
ASSERT_OK(ncmContentMetaDatabaseSet(&contentMetaDatabase, &contentMetaKey, (NcmContentMetaHeader*)installContentMetaBuf.GetData(), installContentMetaBuf.GetSize()), "Failed to set content records");
|
ASSERT_OK(ncmContentMetaDatabaseSet(&contentMetaDatabase, &contentMetaKey, (NcmContentMetaHeader*)installContentMetaBuf.GetData(), installContentMetaBuf.GetSize()), "Failed to set content records");
|
||||||
ASSERT_OK(ncmContentMetaDatabaseCommit(&contentMetaDatabase), "Failed to commit content records");
|
ASSERT_OK(ncmContentMetaDatabaseCommit(&contentMetaDatabase), "Failed to commit content records");
|
||||||
}
|
}
|
||||||
catch (std::runtime_error& e)
|
catch (std::runtime_error& e)
|
||||||
{
|
{
|
||||||
serviceClose(&contentMetaDatabase.s);
|
serviceClose(&contentMetaDatabase.s);
|
||||||
THROW_FORMAT(e.what());
|
THROW_FORMAT(e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceClose(&contentMetaDatabase.s);
|
serviceClose(&contentMetaDatabase.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Install::InstallApplicationRecord(int i)
|
void Install::InstallApplicationRecord(int i)
|
||||||
{
|
{
|
||||||
const u64 baseTitleId = tin::util::GetBaseTitleId(this->GetTitleId(i), this->GetContentMetaType(i));
|
const u64 baseTitleId = tin::util::GetBaseTitleId(this->GetTitleId(i), this->GetContentMetaType(i));
|
||||||
|
|
||||||
// Add our new content meta
|
// Add our new content meta
|
||||||
ContentStorageRecord storageRecord;
|
ContentStorageRecord storageRecord;
|
||||||
storageRecord.metaRecord = m_contentMeta[i].GetContentMetaKey();
|
storageRecord.metaRecord = m_contentMeta[i].GetContentMetaKey();
|
||||||
storageRecord.storageId = m_destStorageId;
|
storageRecord.storageId = m_destStorageId;
|
||||||
|
|
||||||
LOG_DEBUG("Pushing application record...\n");
|
LOG_DEBUG("Pushing application record...\n");
|
||||||
ASSERT_OK(nsPushApplicationRecord(baseTitleId, NsApplicationRecordType_Installed, &storageRecord, 1), "Failed to push application record");
|
ASSERT_OK(nsPushApplicationRecord(baseTitleId, NsApplicationRecordType_Installed, &storageRecord, 1), "Failed to push application record");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and obtain all data needed for install
|
// Validate and obtain all data needed for install
|
||||||
void Install::Prepare()
|
void Install::Prepare()
|
||||||
{
|
{
|
||||||
tin::data::ByteBuffer cnmtBuf;
|
tin::data::ByteBuffer cnmtBuf;
|
||||||
|
|
||||||
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> tupelList = this->ReadCNMT();
|
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> tupelList = this->ReadCNMT();
|
||||||
|
|
||||||
for (size_t i = 0; i < tupelList.size(); i++) {
|
|
||||||
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> cnmtTuple = tupelList[i];
|
|
||||||
|
|
||||||
m_contentMeta.push_back(std::get<0>(cnmtTuple));
|
|
||||||
NcmContentInfo cnmtContentRecord = std::get<1>(cnmtTuple);
|
|
||||||
|
|
||||||
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
for (size_t i = 0; i < tupelList.size(); i++) {
|
||||||
|
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> cnmtTuple = tupelList[i];
|
||||||
|
|
||||||
if (!contentStorage.Has(cnmtContentRecord.content_id))
|
m_contentMeta.push_back(std::get<0>(cnmtTuple));
|
||||||
{
|
NcmContentInfo cnmtContentRecord = std::get<1>(cnmtTuple);
|
||||||
LOG_DEBUG("Installing CNMT NCA...\n");
|
|
||||||
this->InstallNCA(cnmtContentRecord.content_id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_DEBUG("CNMT NCA already installed. Proceeding...\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse data and create install content meta
|
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
||||||
if (m_ignoreReqFirmVersion)
|
|
||||||
LOG_DEBUG("WARNING: Required system firmware version is being IGNORED!\n");
|
|
||||||
|
|
||||||
tin::data::ByteBuffer installContentMetaBuf;
|
if (!contentStorage.Has(cnmtContentRecord.content_id))
|
||||||
m_contentMeta[i].GetInstallContentMeta(installContentMetaBuf, cnmtContentRecord, m_ignoreReqFirmVersion);
|
{
|
||||||
|
LOG_DEBUG("Installing CNMT NCA...\n");
|
||||||
|
this->InstallNCA(cnmtContentRecord.content_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_DEBUG("CNMT NCA already installed. Proceeding...\n");
|
||||||
|
}
|
||||||
|
|
||||||
this->InstallContentMetaRecords(installContentMetaBuf, i);
|
// Parse data and create install content meta
|
||||||
this->InstallApplicationRecord(i);
|
if (m_ignoreReqFirmVersion)
|
||||||
}
|
LOG_DEBUG("WARNING: Required system firmware version is being IGNORED!\n");
|
||||||
}
|
|
||||||
|
|
||||||
void Install::Begin()
|
tin::data::ByteBuffer installContentMetaBuf;
|
||||||
{
|
m_contentMeta[i].GetInstallContentMeta(installContentMetaBuf, cnmtContentRecord, m_ignoreReqFirmVersion);
|
||||||
LOG_DEBUG("Installing ticket and cert...\n");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this->InstallTicketCert();
|
|
||||||
}
|
|
||||||
catch (std::runtime_error& e)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("WARNING: Ticket installation failed! This may not be an issue, depending on your use case.\nProceed with caution!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (nx::ncm::ContentMeta contentMeta: m_contentMeta) {
|
this->InstallContentMetaRecords(installContentMetaBuf, i);
|
||||||
LOG_DEBUG("Installing NCAs...\n");
|
this->InstallApplicationRecord(i);
|
||||||
for (auto& record : contentMeta.GetContentInfos())
|
}
|
||||||
{
|
}
|
||||||
LOG_DEBUG("Installing from %s\n", tin::util::GetNcaIdString(record.content_id).c_str());
|
|
||||||
this->InstallNCA(record.content_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Install::GetTitleId(int i)
|
void Install::Begin()
|
||||||
{
|
{
|
||||||
return m_contentMeta[i].GetContentMetaKey().id;
|
LOG_DEBUG("Installing ticket and cert...\n");
|
||||||
}
|
try
|
||||||
|
{
|
||||||
|
this->InstallTicketCert();
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& e)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("WARNING: Ticket installation failed! This may not be an issue, depending on your use case.\nProceed with caution!\n");
|
||||||
|
}
|
||||||
|
|
||||||
NcmContentMetaType Install::GetContentMetaType(int i)
|
for (nx::ncm::ContentMeta contentMeta : m_contentMeta) {
|
||||||
{
|
LOG_DEBUG("Installing NCAs...\n");
|
||||||
return static_cast<NcmContentMetaType>(m_contentMeta[i].GetContentMetaKey().type);
|
for (auto& record : contentMeta.GetContentInfos())
|
||||||
}
|
{
|
||||||
|
LOG_DEBUG("Installing from %s\n", tin::util::GetNcaIdString(record.content_id).c_str());
|
||||||
|
this->InstallNCA(record.content_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 Install::GetTitleId(int i)
|
||||||
|
{
|
||||||
|
return m_contentMeta[i].GetContentMetaKey().id;
|
||||||
|
}
|
||||||
|
|
||||||
|
NcmContentMetaType Install::GetContentMetaType(int i)
|
||||||
|
{
|
||||||
|
return static_cast<NcmContentMetaType>(m_contentMeta[i].GetContentMetaKey().type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,142 +39,142 @@ SOFTWARE.
|
|||||||
#include "ui/MainApplication.hpp"
|
#include "ui/MainApplication.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
NSPInstall::NSPInstall(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<NSP>& remoteNSP) :
|
NSPInstall::NSPInstall(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<NSP>& remoteNSP) :
|
||||||
Install(destStorageId, ignoreReqFirmVersion), m_NSP(remoteNSP)
|
Install(destStorageId, ignoreReqFirmVersion), m_NSP(remoteNSP)
|
||||||
{
|
{
|
||||||
m_NSP->RetrieveHeader();
|
m_NSP->RetrieveHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> NSPInstall::ReadCNMT()
|
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> NSPInstall::ReadCNMT()
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> CNMTList;
|
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> CNMTList;
|
||||||
|
|
||||||
for (const PFS0FileEntry* fileEntry : m_NSP->GetFileEntriesByExtension("cnmt.nca")) {
|
for (const PFS0FileEntry* fileEntry : m_NSP->GetFileEntriesByExtension("cnmt.nca")) {
|
||||||
std::string cnmtNcaName(m_NSP->GetFileEntryName(fileEntry));
|
std::string cnmtNcaName(m_NSP->GetFileEntryName(fileEntry));
|
||||||
NcmContentId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
|
NcmContentId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
|
||||||
size_t cnmtNcaSize = fileEntry->fileSize;
|
size_t cnmtNcaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
||||||
|
|
||||||
LOG_DEBUG("CNMT Name: %s\n", cnmtNcaName.c_str());
|
LOG_DEBUG("CNMT Name: %s\n", cnmtNcaName.c_str());
|
||||||
|
|
||||||
// We install the cnmt nca early to read from it later
|
// We install the cnmt nca early to read from it later
|
||||||
this->InstallNCA(cnmtContentId);
|
this->InstallNCA(cnmtContentId);
|
||||||
std::string cnmtNCAFullPath = contentStorage.GetPath(cnmtContentId);
|
std::string cnmtNCAFullPath = contentStorage.GetPath(cnmtContentId);
|
||||||
|
|
||||||
NcmContentInfo cnmtContentInfo;
|
NcmContentInfo cnmtContentInfo;
|
||||||
cnmtContentInfo.content_id = cnmtContentId;
|
cnmtContentInfo.content_id = cnmtContentId;
|
||||||
*(u64*)&cnmtContentInfo.size = cnmtNcaSize & 0xFFFFFFFFFFFF;
|
*(u64*)&cnmtContentInfo.size = cnmtNcaSize & 0xFFFFFFFFFFFF;
|
||||||
cnmtContentInfo.content_type = NcmContentType_Meta;
|
cnmtContentInfo.content_type = NcmContentType_Meta;
|
||||||
|
|
||||||
CNMTList.push_back( { tin::util::GetContentMetaFromNCA(cnmtNCAFullPath), cnmtContentInfo } );
|
CNMTList.push_back({ tin::util::GetContentMetaFromNCA(cnmtNCAFullPath), cnmtContentInfo });
|
||||||
}
|
}
|
||||||
|
|
||||||
return CNMTList;
|
return CNMTList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NSPInstall::InstallNCA(const NcmContentId& ncaId)
|
void NSPInstall::InstallNCA(const NcmContentId& ncaId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = m_NSP->GetFileEntryByNcaId(ncaId);
|
const PFS0FileEntry* fileEntry = m_NSP->GetFileEntryByNcaId(ncaId);
|
||||||
std::string ncaFileName = m_NSP->GetFileEntryName(fileEntry);
|
std::string ncaFileName = m_NSP->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
LOG_DEBUG("Installing %s to storage Id %u\n", ncaFileName.c_str(), m_destStorageId);
|
LOG_DEBUG("Installing %s to storage Id %u\n", ncaFileName.c_str(), m_destStorageId);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::shared_ptr<nx::ncm::ContentStorage> contentStorage(new nx::ncm::ContentStorage(m_destStorageId));
|
std::shared_ptr<nx::ncm::ContentStorage> contentStorage(new nx::ncm::ContentStorage(m_destStorageId));
|
||||||
|
|
||||||
// Attempt to delete any leftover placeholders
|
// Attempt to delete any leftover placeholders
|
||||||
try {
|
try {
|
||||||
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
||||||
}
|
}
|
||||||
catch (...) {}
|
catch (...) {}
|
||||||
|
|
||||||
LOG_DEBUG("Size: 0x%lx\n", ncaSize);
|
LOG_DEBUG("Size: 0x%lx\n", ncaSize);
|
||||||
|
|
||||||
if (inst::config::validateNCAs && !m_declinedValidation)
|
if (inst::config::validateNCAs && !m_declinedValidation)
|
||||||
{
|
{
|
||||||
tin::install::NcaHeader* header = new NcaHeader;
|
tin::install::NcaHeader* header = new NcaHeader;
|
||||||
m_NSP->BufferData(header, m_NSP->GetDataOffset() + fileEntry->dataOffset, sizeof(tin::install::NcaHeader));
|
m_NSP->BufferData(header, m_NSP->GetDataOffset() + fileEntry->dataOffset, sizeof(tin::install::NcaHeader));
|
||||||
|
|
||||||
Crypto::AesXtr crypto(Crypto::Keys().headerKey, false);
|
Crypto::AesXtr crypto(Crypto::Keys().headerKey, false);
|
||||||
crypto.decrypt(header, header, sizeof(tin::install::NcaHeader), 0, 0x200);
|
crypto.decrypt(header, header, sizeof(tin::install::NcaHeader), 0, 0x200);
|
||||||
|
|
||||||
if (header->magic != MAGIC_NCA3)
|
if (header->magic != MAGIC_NCA3)
|
||||||
THROW_FORMAT("Invalid NCA magic");
|
THROW_FORMAT("Invalid NCA magic");
|
||||||
|
|
||||||
if (!Crypto::rsa2048PssVerify(&header->magic, 0x200, header->fixed_key_sig, Crypto::NCAHeaderSignature))
|
if (!Crypto::rsa2048PssVerify(&header->magic, 0x200, header->fixed_key_sig, Crypto::NCAHeaderSignature))
|
||||||
{
|
{
|
||||||
std::string audioPath = "romfs:/audio/bark.wav";
|
std::string audioPath = "romfs:/audio/bark.wav";
|
||||||
if (inst::config::gayMode) audioPath = "";
|
if (inst::config::gayMode) audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
int rc = inst::ui::mainApp->CreateShowDialog("inst.nca_verify.title"_lang, "inst.nca_verify.desc"_lang, {"common.cancel"_lang, "inst.nca_verify.opt1"_lang}, false);
|
int rc = inst::ui::mainApp->CreateShowDialog("inst.nca_verify.title"_lang, "inst.nca_verify.desc"_lang, { "common.cancel"_lang, "inst.nca_verify.opt1"_lang }, false);
|
||||||
audioThread.join();
|
audioThread.join();
|
||||||
if (rc != 1)
|
if (rc != 1)
|
||||||
THROW_FORMAT(("inst.nca_verify.error"_lang + tin::util::GetNcaIdString(ncaId)).c_str());
|
THROW_FORMAT(("inst.nca_verify.error"_lang + tin::util::GetNcaIdString(ncaId)).c_str());
|
||||||
m_declinedValidation = true;
|
m_declinedValidation = true;
|
||||||
}
|
}
|
||||||
delete header;
|
delete header;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_NSP->StreamToPlaceholder(contentStorage, ncaId);
|
m_NSP->StreamToPlaceholder(contentStorage, ncaId);
|
||||||
|
|
||||||
LOG_DEBUG("Registering placeholder...\n");
|
LOG_DEBUG("Registering placeholder...\n");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
contentStorage->Register(*(NcmPlaceHolderId*)&ncaId, ncaId);
|
contentStorage->Register(*(NcmPlaceHolderId*)&ncaId, ncaId);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(("Failed to register " + ncaFileName + ". It may already exist.\n").c_str());
|
LOG_DEBUG(("Failed to register " + ncaFileName + ". It may already exist.\n").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
||||||
}
|
}
|
||||||
catch (...) {}
|
catch (...) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NSPInstall::InstallTicketCert()
|
void NSPInstall::InstallTicketCert()
|
||||||
{
|
{
|
||||||
// Read the tik files and put it into a buffer
|
// Read the tik files and put it into a buffer
|
||||||
std::vector<const PFS0FileEntry*> tikFileEntries = m_NSP->GetFileEntriesByExtension("tik");
|
std::vector<const PFS0FileEntry*> tikFileEntries = m_NSP->GetFileEntriesByExtension("tik");
|
||||||
std::vector<const PFS0FileEntry*> certFileEntries = m_NSP->GetFileEntriesByExtension("cert");
|
std::vector<const PFS0FileEntry*> certFileEntries = m_NSP->GetFileEntriesByExtension("cert");
|
||||||
|
|
||||||
for (size_t i = 0; i < tikFileEntries.size(); i++)
|
for (size_t i = 0; i < tikFileEntries.size(); i++)
|
||||||
{
|
{
|
||||||
if (tikFileEntries[i] == nullptr) {
|
if (tikFileEntries[i] == nullptr) {
|
||||||
LOG_DEBUG("Remote tik file is missing.\n");
|
LOG_DEBUG("Remote tik file is missing.\n");
|
||||||
THROW_FORMAT("Remote tik file is not present!");
|
THROW_FORMAT("Remote tik file is not present!");
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 tikSize = tikFileEntries[i]->fileSize;
|
u64 tikSize = tikFileEntries[i]->fileSize;
|
||||||
auto tikBuf = std::make_unique<u8[]>(tikSize);
|
auto tikBuf = std::make_unique<u8[]>(tikSize);
|
||||||
LOG_DEBUG("> Reading tik\n");
|
LOG_DEBUG("> Reading tik\n");
|
||||||
m_NSP->BufferData(tikBuf.get(), m_NSP->GetDataOffset() + tikFileEntries[i]->dataOffset, tikSize);
|
m_NSP->BufferData(tikBuf.get(), m_NSP->GetDataOffset() + tikFileEntries[i]->dataOffset, tikSize);
|
||||||
|
|
||||||
if (certFileEntries[i] == nullptr)
|
if (certFileEntries[i] == nullptr)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Remote cert file is missing.\n");
|
LOG_DEBUG("Remote cert file is missing.\n");
|
||||||
THROW_FORMAT("Remote cert file is not present!");
|
THROW_FORMAT("Remote cert file is not present!");
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 certSize = certFileEntries[i]->fileSize;
|
u64 certSize = certFileEntries[i]->fileSize;
|
||||||
auto certBuf = std::make_unique<u8[]>(certSize);
|
auto certBuf = std::make_unique<u8[]>(certSize);
|
||||||
LOG_DEBUG("> Reading cert\n");
|
LOG_DEBUG("> Reading cert\n");
|
||||||
m_NSP->BufferData(certBuf.get(), m_NSP->GetDataOffset() + certFileEntries[i]->dataOffset, certSize);
|
m_NSP->BufferData(certBuf.get(), m_NSP->GetDataOffset() + certFileEntries[i]->dataOffset, certSize);
|
||||||
|
|
||||||
// Finally, let's actually import the ticket
|
// Finally, let's actually import the ticket
|
||||||
ASSERT_OK(esImportTicket(tikBuf.get(), tikSize, certBuf.get(), certSize), "Failed to import ticket");
|
ASSERT_OK(esImportTicket(tikBuf.get(), tikSize, certBuf.get(), certSize), "Failed to import ticket");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -35,145 +35,145 @@ SOFTWARE.
|
|||||||
#include "ui/MainApplication.hpp"
|
#include "ui/MainApplication.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
XCIInstallTask::XCIInstallTask(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<XCI>& xci) :
|
XCIInstallTask::XCIInstallTask(NcmStorageId destStorageId, bool ignoreReqFirmVersion, const std::shared_ptr<XCI>& xci) :
|
||||||
Install(destStorageId, ignoreReqFirmVersion), m_xci(xci)
|
Install(destStorageId, ignoreReqFirmVersion), m_xci(xci)
|
||||||
{
|
{
|
||||||
m_xci->RetrieveHeader();
|
m_xci->RetrieveHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> XCIInstallTask::ReadCNMT()
|
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> XCIInstallTask::ReadCNMT()
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> CNMTList;
|
std::vector<std::tuple<nx::ncm::ContentMeta, NcmContentInfo>> CNMTList;
|
||||||
|
|
||||||
for (const HFS0FileEntry* fileEntry : m_xci->GetFileEntriesByExtension("cnmt.nca")) {
|
for (const HFS0FileEntry* fileEntry : m_xci->GetFileEntriesByExtension("cnmt.nca")) {
|
||||||
std::string cnmtNcaName(m_xci->GetFileEntryName(fileEntry));
|
std::string cnmtNcaName(m_xci->GetFileEntryName(fileEntry));
|
||||||
NcmContentId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
|
NcmContentId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
|
||||||
size_t cnmtNcaSize = fileEntry->fileSize;
|
size_t cnmtNcaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
||||||
|
|
||||||
LOG_DEBUG("CNMT Name: %s\n", cnmtNcaName.c_str());
|
LOG_DEBUG("CNMT Name: %s\n", cnmtNcaName.c_str());
|
||||||
|
|
||||||
// We install the cnmt nca early to read from it later
|
// We install the cnmt nca early to read from it later
|
||||||
this->InstallNCA(cnmtContentId);
|
this->InstallNCA(cnmtContentId);
|
||||||
std::string cnmtNCAFullPath = contentStorage.GetPath(cnmtContentId);
|
std::string cnmtNCAFullPath = contentStorage.GetPath(cnmtContentId);
|
||||||
|
|
||||||
NcmContentInfo cnmtContentInfo;
|
NcmContentInfo cnmtContentInfo;
|
||||||
cnmtContentInfo.content_id = cnmtContentId;
|
cnmtContentInfo.content_id = cnmtContentId;
|
||||||
*(u64*)&cnmtContentInfo.size = cnmtNcaSize & 0xFFFFFFFFFFFF;
|
*(u64*)&cnmtContentInfo.size = cnmtNcaSize & 0xFFFFFFFFFFFF;
|
||||||
cnmtContentInfo.content_type = NcmContentType_Meta;
|
cnmtContentInfo.content_type = NcmContentType_Meta;
|
||||||
|
|
||||||
CNMTList.push_back( { tin::util::GetContentMetaFromNCA(cnmtNCAFullPath), cnmtContentInfo } );
|
CNMTList.push_back({ tin::util::GetContentMetaFromNCA(cnmtNCAFullPath), cnmtContentInfo });
|
||||||
}
|
}
|
||||||
|
|
||||||
return CNMTList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XCIInstallTask::InstallNCA(const NcmContentId& ncaId)
|
return CNMTList;
|
||||||
{
|
}
|
||||||
const HFS0FileEntry* fileEntry = m_xci->GetFileEntryByNcaId(ncaId);
|
|
||||||
std::string ncaFileName = m_xci->GetFileEntryName(fileEntry);
|
|
||||||
|
|
||||||
#ifdef NXLINK_DEBUG
|
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
|
||||||
LOG_DEBUG("Installing %s to storage Id %u\n", ncaFileName.c_str(), m_destStorageId);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::shared_ptr<nx::ncm::ContentStorage> contentStorage(new nx::ncm::ContentStorage(m_destStorageId));
|
void XCIInstallTask::InstallNCA(const NcmContentId& ncaId)
|
||||||
|
{
|
||||||
|
const HFS0FileEntry* fileEntry = m_xci->GetFileEntryByNcaId(ncaId);
|
||||||
|
std::string ncaFileName = m_xci->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
// Attempt to delete any leftover placeholders
|
#ifdef NXLINK_DEBUG
|
||||||
try {
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
LOG_DEBUG("Installing %s to storage Id %u\n", ncaFileName.c_str(), m_destStorageId);
|
||||||
}
|
#endif
|
||||||
catch (...) {}
|
|
||||||
|
|
||||||
LOG_DEBUG("Size: 0x%lx\n", ncaSize);
|
std::shared_ptr<nx::ncm::ContentStorage> contentStorage(new nx::ncm::ContentStorage(m_destStorageId));
|
||||||
|
|
||||||
if (inst::config::validateNCAs && !m_declinedValidation)
|
// Attempt to delete any leftover placeholders
|
||||||
{
|
try {
|
||||||
tin::install::NcaHeader* header = new NcaHeader;
|
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
||||||
m_xci->BufferData(header, m_xci->GetDataOffset() + fileEntry->dataOffset, sizeof(tin::install::NcaHeader));
|
}
|
||||||
|
catch (...) {}
|
||||||
|
|
||||||
Crypto::AesXtr crypto(Crypto::Keys().headerKey, false);
|
LOG_DEBUG("Size: 0x%lx\n", ncaSize);
|
||||||
crypto.decrypt(header, header, sizeof(tin::install::NcaHeader), 0, 0x200);
|
|
||||||
|
|
||||||
if (header->magic != MAGIC_NCA3)
|
if (inst::config::validateNCAs && !m_declinedValidation)
|
||||||
THROW_FORMAT("Invalid NCA magic");
|
{
|
||||||
|
tin::install::NcaHeader* header = new NcaHeader;
|
||||||
|
m_xci->BufferData(header, m_xci->GetDataOffset() + fileEntry->dataOffset, sizeof(tin::install::NcaHeader));
|
||||||
|
|
||||||
if (!Crypto::rsa2048PssVerify(&header->magic, 0x200, header->fixed_key_sig, Crypto::NCAHeaderSignature))
|
Crypto::AesXtr crypto(Crypto::Keys().headerKey, false);
|
||||||
{
|
crypto.decrypt(header, header, sizeof(tin::install::NcaHeader), 0, 0x200);
|
||||||
std::string audioPath = "romfs:/audio/bark.wav";
|
|
||||||
if (inst::config::gayMode) audioPath = "";
|
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
|
||||||
int rc = inst::ui::mainApp->CreateShowDialog("inst.nca_verify.title"_lang, "inst.nca_verify.desc"_lang, {"common.cancel"_lang, "inst.nca_verify.opt1"_lang}, false);
|
|
||||||
audioThread.join();
|
|
||||||
if (rc != 1)
|
|
||||||
THROW_FORMAT(("inst.nca_verify.error"_lang + tin::util::GetNcaIdString(ncaId)).c_str());
|
|
||||||
m_declinedValidation = true;
|
|
||||||
}
|
|
||||||
delete header;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_xci->StreamToPlaceholder(contentStorage, ncaId);
|
if (header->magic != MAGIC_NCA3)
|
||||||
|
THROW_FORMAT("Invalid NCA magic");
|
||||||
|
|
||||||
// Clean up the line for whatever comes next
|
if (!Crypto::rsa2048PssVerify(&header->magic, 0x200, header->fixed_key_sig, Crypto::NCAHeaderSignature))
|
||||||
LOG_DEBUG(" \r");
|
{
|
||||||
LOG_DEBUG("Registering placeholder...\n");
|
std::string audioPath = "romfs:/audio/bark.wav";
|
||||||
|
if (inst::config::gayMode) audioPath = "";
|
||||||
|
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
||||||
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
|
int rc = inst::ui::mainApp->CreateShowDialog("inst.nca_verify.title"_lang, "inst.nca_verify.desc"_lang, { "common.cancel"_lang, "inst.nca_verify.opt1"_lang }, false);
|
||||||
|
audioThread.join();
|
||||||
|
if (rc != 1)
|
||||||
|
THROW_FORMAT(("inst.nca_verify.error"_lang + tin::util::GetNcaIdString(ncaId)).c_str());
|
||||||
|
m_declinedValidation = true;
|
||||||
|
}
|
||||||
|
delete header;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
m_xci->StreamToPlaceholder(contentStorage, ncaId);
|
||||||
{
|
|
||||||
contentStorage->Register(*(NcmPlaceHolderId*)&ncaId, ncaId);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
LOG_DEBUG(("Failed to register " + ncaFileName + ". It may already exist.\n").c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
// Clean up the line for whatever comes next
|
||||||
{
|
LOG_DEBUG(" \r");
|
||||||
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
LOG_DEBUG("Registering placeholder...\n");
|
||||||
}
|
|
||||||
catch (...) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XCIInstallTask::InstallTicketCert()
|
try
|
||||||
{
|
{
|
||||||
// Read the tik files and put it into a buffer
|
contentStorage->Register(*(NcmPlaceHolderId*)&ncaId, ncaId);
|
||||||
std::vector<const HFS0FileEntry*> tikFileEntries = m_xci->GetFileEntriesByExtension("tik");
|
}
|
||||||
std::vector<const HFS0FileEntry*> certFileEntries = m_xci->GetFileEntriesByExtension("cert");
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_DEBUG(("Failed to register " + ncaFileName + ". It may already exist.\n").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < tikFileEntries.size(); i++)
|
try
|
||||||
{
|
{
|
||||||
if (tikFileEntries[i] == nullptr)
|
contentStorage->DeletePlaceholder(*(NcmPlaceHolderId*)&ncaId);
|
||||||
{
|
}
|
||||||
LOG_DEBUG("Remote tik file is missing.\n");
|
catch (...) {}
|
||||||
THROW_FORMAT("Remote tik file is not present!");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
u64 tikSize = tikFileEntries[i]->fileSize;
|
void XCIInstallTask::InstallTicketCert()
|
||||||
auto tikBuf = std::make_unique<u8[]>(tikSize);
|
{
|
||||||
LOG_DEBUG("> Reading tik\n");
|
// Read the tik files and put it into a buffer
|
||||||
m_xci->BufferData(tikBuf.get(), m_xci->GetDataOffset() + tikFileEntries[i]->dataOffset, tikSize);
|
std::vector<const HFS0FileEntry*> tikFileEntries = m_xci->GetFileEntriesByExtension("tik");
|
||||||
|
std::vector<const HFS0FileEntry*> certFileEntries = m_xci->GetFileEntriesByExtension("cert");
|
||||||
|
|
||||||
if (certFileEntries[i] == nullptr)
|
for (size_t i = 0; i < tikFileEntries.size(); i++)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Remote cert file is missing.\n");
|
if (tikFileEntries[i] == nullptr)
|
||||||
THROW_FORMAT("Remote cert file is not present!");
|
{
|
||||||
}
|
LOG_DEBUG("Remote tik file is missing.\n");
|
||||||
|
THROW_FORMAT("Remote tik file is not present!");
|
||||||
|
}
|
||||||
|
|
||||||
u64 certSize = certFileEntries[i]->fileSize;
|
u64 tikSize = tikFileEntries[i]->fileSize;
|
||||||
auto certBuf = std::make_unique<u8[]>(certSize);
|
auto tikBuf = std::make_unique<u8[]>(tikSize);
|
||||||
LOG_DEBUG("> Reading cert\n");
|
LOG_DEBUG("> Reading tik\n");
|
||||||
m_xci->BufferData(certBuf.get(), m_xci->GetDataOffset() + certFileEntries[i]->dataOffset, certSize);
|
m_xci->BufferData(tikBuf.get(), m_xci->GetDataOffset() + tikFileEntries[i]->dataOffset, tikSize);
|
||||||
|
|
||||||
// Finally, let's actually import the ticket
|
if (certFileEntries[i] == nullptr)
|
||||||
ASSERT_OK(esImportTicket(tikBuf.get(), tikSize, certBuf.get(), certSize), "Failed to import ticket");
|
{
|
||||||
}
|
LOG_DEBUG("Remote cert file is missing.\n");
|
||||||
}
|
THROW_FORMAT("Remote cert file is not present!");
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 certSize = certFileEntries[i]->fileSize;
|
||||||
|
auto certBuf = std::make_unique<u8[]>(certSize);
|
||||||
|
LOG_DEBUG("> Reading cert\n");
|
||||||
|
m_xci->BufferData(certBuf.get(), m_xci->GetDataOffset() + certFileEntries[i]->dataOffset, certSize);
|
||||||
|
|
||||||
|
// Finally, let's actually import the ticket
|
||||||
|
ASSERT_OK(esImportTicket(tikBuf.get(), tikSize, certBuf.get(), certSize), "Failed to import ticket");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -30,114 +30,114 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
NSP::NSP() {}
|
NSP::NSP() {}
|
||||||
|
|
||||||
// TODO: Do verification: PFS0 magic, sizes not zero
|
// TODO: Do verification: PFS0 magic, sizes not zero
|
||||||
void NSP::RetrieveHeader()
|
void NSP::RetrieveHeader()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Retrieving remote NSP header...\n");
|
LOG_DEBUG("Retrieving remote NSP header...\n");
|
||||||
|
|
||||||
// Retrieve the base header
|
// Retrieve the base header
|
||||||
m_headerBytes.resize(sizeof(PFS0BaseHeader), 0);
|
m_headerBytes.resize(sizeof(PFS0BaseHeader), 0);
|
||||||
this->BufferData(m_headerBytes.data(), 0x0, sizeof(PFS0BaseHeader));
|
this->BufferData(m_headerBytes.data(), 0x0, sizeof(PFS0BaseHeader));
|
||||||
|
|
||||||
LOG_DEBUG("Base header: \n");
|
LOG_DEBUG("Base header: \n");
|
||||||
printBytes(m_headerBytes.data(), sizeof(PFS0BaseHeader), true);
|
printBytes(m_headerBytes.data(), sizeof(PFS0BaseHeader), true);
|
||||||
|
|
||||||
// Retrieve the full header
|
// Retrieve the full header
|
||||||
size_t remainingHeaderSize = this->GetBaseHeader()->numFiles * sizeof(PFS0FileEntry) + this->GetBaseHeader()->stringTableSize;
|
size_t remainingHeaderSize = this->GetBaseHeader()->numFiles * sizeof(PFS0FileEntry) + this->GetBaseHeader()->stringTableSize;
|
||||||
m_headerBytes.resize(sizeof(PFS0BaseHeader) + remainingHeaderSize, 0);
|
m_headerBytes.resize(sizeof(PFS0BaseHeader) + remainingHeaderSize, 0);
|
||||||
this->BufferData(m_headerBytes.data() + sizeof(PFS0BaseHeader), sizeof(PFS0BaseHeader), remainingHeaderSize);
|
this->BufferData(m_headerBytes.data() + sizeof(PFS0BaseHeader), sizeof(PFS0BaseHeader), remainingHeaderSize);
|
||||||
|
|
||||||
LOG_DEBUG("Full header: \n");
|
LOG_DEBUG("Full header: \n");
|
||||||
printBytes(m_headerBytes.data(), m_headerBytes.size(), true);
|
printBytes(m_headerBytes.data(), m_headerBytes.size(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PFS0FileEntry* NSP::GetFileEntry(unsigned int index)
|
const PFS0FileEntry* NSP::GetFileEntry(unsigned int index)
|
||||||
{
|
{
|
||||||
if (index >= this->GetBaseHeader()->numFiles)
|
if (index >= this->GetBaseHeader()->numFiles)
|
||||||
THROW_FORMAT("File entry index is out of bounds\n");
|
THROW_FORMAT("File entry index is out of bounds\n");
|
||||||
|
|
||||||
size_t fileEntryOffset = sizeof(PFS0BaseHeader) + index * sizeof(PFS0FileEntry);
|
size_t fileEntryOffset = sizeof(PFS0BaseHeader) + index * sizeof(PFS0FileEntry);
|
||||||
|
|
||||||
if (m_headerBytes.size() < fileEntryOffset + sizeof(PFS0FileEntry))
|
if (m_headerBytes.size() < fileEntryOffset + sizeof(PFS0FileEntry))
|
||||||
THROW_FORMAT("Header bytes is too small to get file entry!");
|
THROW_FORMAT("Header bytes is too small to get file entry!");
|
||||||
|
|
||||||
return reinterpret_cast<PFS0FileEntry*>(m_headerBytes.data() + fileEntryOffset);
|
return reinterpret_cast<PFS0FileEntry*>(m_headerBytes.data() + fileEntryOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const PFS0FileEntry*> NSP::GetFileEntriesByExtension(std::string extension)
|
std::vector<const PFS0FileEntry*> NSP::GetFileEntriesByExtension(std::string extension)
|
||||||
{
|
{
|
||||||
std::vector<const PFS0FileEntry*> entryList;
|
std::vector<const PFS0FileEntry*> entryList;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->GetBaseHeader()->numFiles; i++)
|
for (unsigned int i = 0; i < this->GetBaseHeader()->numFiles; i++)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
const PFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
||||||
std::string name(this->GetFileEntryName(fileEntry));
|
std::string name(this->GetFileEntryName(fileEntry));
|
||||||
auto foundExtension = name.substr(name.find(".") + 1);
|
auto foundExtension = name.substr(name.find(".") + 1);
|
||||||
|
|
||||||
if (foundExtension == extension)
|
if (foundExtension == extension)
|
||||||
entryList.push_back(fileEntry);
|
entryList.push_back(fileEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryList;
|
return entryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PFS0FileEntry* NSP::GetFileEntryByName(std::string name)
|
const PFS0FileEntry* NSP::GetFileEntryByName(std::string name)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < this->GetBaseHeader()->numFiles; i++)
|
for (unsigned int i = 0; i < this->GetBaseHeader()->numFiles; i++)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
const PFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
||||||
std::string foundName(this->GetFileEntryName(fileEntry));
|
std::string foundName(this->GetFileEntryName(fileEntry));
|
||||||
|
|
||||||
if (foundName == name)
|
if (foundName == name)
|
||||||
return fileEntry;
|
return fileEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PFS0FileEntry* NSP::GetFileEntryByNcaId(const NcmContentId& ncaId)
|
const PFS0FileEntry* NSP::GetFileEntryByNcaId(const NcmContentId& ncaId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = nullptr;
|
const PFS0FileEntry* fileEntry = nullptr;
|
||||||
std::string ncaIdStr = tin::util::GetNcaIdString(ncaId);
|
std::string ncaIdStr = tin::util::GetNcaIdString(ncaId);
|
||||||
|
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".nca")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".nca")) == nullptr)
|
||||||
{
|
{
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.nca")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.nca")) == nullptr)
|
||||||
{
|
{
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".ncz")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".ncz")) == nullptr)
|
||||||
{
|
{
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.ncz")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.ncz")) == nullptr)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileEntry;
|
return fileEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* NSP::GetFileEntryName(const PFS0FileEntry* fileEntry)
|
const char* NSP::GetFileEntryName(const PFS0FileEntry* fileEntry)
|
||||||
{
|
{
|
||||||
u64 stringTableStart = sizeof(PFS0BaseHeader) + this->GetBaseHeader()->numFiles * sizeof(PFS0FileEntry);
|
u64 stringTableStart = sizeof(PFS0BaseHeader) + this->GetBaseHeader()->numFiles * sizeof(PFS0FileEntry);
|
||||||
return reinterpret_cast<const char*>(m_headerBytes.data() + stringTableStart + fileEntry->stringTableOffset);
|
return reinterpret_cast<const char*>(m_headerBytes.data() + stringTableStart + fileEntry->stringTableOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PFS0BaseHeader* NSP::GetBaseHeader()
|
const PFS0BaseHeader* NSP::GetBaseHeader()
|
||||||
{
|
{
|
||||||
if (m_headerBytes.empty())
|
if (m_headerBytes.empty())
|
||||||
THROW_FORMAT("Cannot retrieve header as header bytes are empty. Have you retrieved it yet?\n");
|
THROW_FORMAT("Cannot retrieve header as header bytes are empty. Have you retrieved it yet?\n");
|
||||||
|
|
||||||
return reinterpret_cast<PFS0BaseHeader*>(m_headerBytes.data());
|
return reinterpret_cast<PFS0BaseHeader*>(m_headerBytes.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NSP::GetDataOffset()
|
u64 NSP::GetDataOffset()
|
||||||
{
|
{
|
||||||
if (m_headerBytes.empty())
|
if (m_headerBytes.empty())
|
||||||
THROW_FORMAT("Cannot get data offset as header is empty. Have you retrieved it yet?\n");
|
THROW_FORMAT("Cannot get data offset as header is empty. Have you retrieved it yet?\n");
|
||||||
|
|
||||||
return m_headerBytes.size();
|
return m_headerBytes.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,68 +7,68 @@
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
SDMCNSP::SDMCNSP(std::string path)
|
SDMCNSP::SDMCNSP(std::string path)
|
||||||
{
|
{
|
||||||
m_nspFile = fopen((path).c_str(), "rb");
|
m_nspFile = fopen((path).c_str(), "rb");
|
||||||
if (!m_nspFile)
|
if (!m_nspFile)
|
||||||
THROW_FORMAT("can't open file at %s\n", path.c_str());
|
THROW_FORMAT("can't open file at %s\n", path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
SDMCNSP::~SDMCNSP()
|
SDMCNSP::~SDMCNSP()
|
||||||
{
|
{
|
||||||
fclose(m_nspFile);
|
fclose(m_nspFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDMCNSP::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId)
|
void SDMCNSP::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId);
|
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId);
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
NcaWriter writer(ncaId, contentStorage);
|
NcaWriter writer(ncaId, contentStorage);
|
||||||
|
|
||||||
float progress;
|
float progress;
|
||||||
|
|
||||||
u64 fileStart = GetDataOffset() + fileEntry->dataOffset;
|
u64 fileStart = GetDataOffset() + fileEntry->dataOffset;
|
||||||
u64 fileOff = 0;
|
u64 fileOff = 0;
|
||||||
size_t readSize = 0x400000; // 4MB buff
|
size_t readSize = 0x400000; // 4MB buff
|
||||||
auto readBuffer = std::make_unique<u8[]>(readSize);
|
auto readBuffer = std::make_unique<u8[]>(readSize);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (fileOff < ncaSize)
|
while (fileOff < ncaSize)
|
||||||
{
|
{
|
||||||
progress = (float) fileOff / (float) ncaSize;
|
progress = (float)fileOff / (float)ncaSize;
|
||||||
|
|
||||||
if (fileOff % (0x400000 * 3) == 0) {
|
if (fileOff % (0x400000 * 3) == 0) {
|
||||||
LOG_DEBUG("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%");
|
LOG_DEBUG("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%");
|
||||||
inst::ui::instPage::setInstBarPerc((double)(progress * 100.0));
|
inst::ui::instPage::setInstBarPerc((double)(progress * 100.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff;
|
if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff;
|
||||||
|
|
||||||
this->BufferData(readBuffer.get(), fileOff + fileStart, readSize);
|
this->BufferData(readBuffer.get(), fileOff + fileStart, readSize);
|
||||||
writer.write(readBuffer.get(), readSize);
|
writer.write(readBuffer.get(), readSize);
|
||||||
|
|
||||||
fileOff += readSize;
|
fileOff += readSize;
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("something went wrong: %s\n", e.what());
|
LOG_DEBUG("something went wrong: %s\n", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDMCNSP::BufferData(void* buf, off_t offset, size_t size)
|
void SDMCNSP::BufferData(void* buf, off_t offset, size_t size)
|
||||||
{
|
{
|
||||||
fseeko(m_nspFile, offset, SEEK_SET);
|
fseeko(m_nspFile, offset, SEEK_SET);
|
||||||
fread(buf, 1, size, m_nspFile);
|
fread(buf, 1, size, m_nspFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,68 +7,68 @@
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
SDMCXCI::SDMCXCI(std::string path)
|
SDMCXCI::SDMCXCI(std::string path)
|
||||||
{
|
{
|
||||||
m_xciFile = fopen((path).c_str(), "rb");
|
m_xciFile = fopen((path).c_str(), "rb");
|
||||||
if (!m_xciFile)
|
if (!m_xciFile)
|
||||||
THROW_FORMAT("can't open file at %s\n", path.c_str());
|
THROW_FORMAT("can't open file at %s\n", path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
SDMCXCI::~SDMCXCI()
|
SDMCXCI::~SDMCXCI()
|
||||||
{
|
{
|
||||||
fclose(m_xciFile);
|
fclose(m_xciFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDMCXCI::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId)
|
void SDMCXCI::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId ncaId)
|
||||||
{
|
{
|
||||||
const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId);
|
const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(ncaId);
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
NcaWriter writer(ncaId, contentStorage);
|
NcaWriter writer(ncaId, contentStorage);
|
||||||
|
|
||||||
float progress;
|
float progress;
|
||||||
|
|
||||||
u64 fileStart = GetDataOffset() + fileEntry->dataOffset;
|
u64 fileStart = GetDataOffset() + fileEntry->dataOffset;
|
||||||
u64 fileOff = 0;
|
u64 fileOff = 0;
|
||||||
size_t readSize = 0x400000; // 4MB buff
|
size_t readSize = 0x400000; // 4MB buff
|
||||||
auto readBuffer = std::make_unique<u8[]>(readSize);
|
auto readBuffer = std::make_unique<u8[]>(readSize);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (fileOff < ncaSize)
|
while (fileOff < ncaSize)
|
||||||
{
|
{
|
||||||
progress = (float) fileOff / (float) ncaSize;
|
progress = (float)fileOff / (float)ncaSize;
|
||||||
|
|
||||||
if (fileOff % (0x400000 * 3) == 0) {
|
if (fileOff % (0x400000 * 3) == 0) {
|
||||||
LOG_DEBUG("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%");
|
LOG_DEBUG("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%");
|
||||||
inst::ui::instPage::setInstBarPerc((double)(progress * 100.0));
|
inst::ui::instPage::setInstBarPerc((double)(progress * 100.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff;
|
if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff;
|
||||||
|
|
||||||
this->BufferData(readBuffer.get(), fileOff + fileStart, readSize);
|
this->BufferData(readBuffer.get(), fileOff + fileStart, readSize);
|
||||||
writer.write(readBuffer.get(), readSize);
|
writer.write(readBuffer.get(), readSize);
|
||||||
|
|
||||||
fileOff += readSize;
|
fileOff += readSize;
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("something went wrong: %s\n", e.what());
|
LOG_DEBUG("something went wrong: %s\n", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDMCXCI::BufferData(void* buf, off_t offset, size_t size)
|
void SDMCXCI::BufferData(void* buf, off_t offset, size_t size)
|
||||||
{
|
{
|
||||||
fseeko(m_xciFile, offset, SEEK_SET);
|
fseeko(m_xciFile, offset, SEEK_SET);
|
||||||
fread(buf, 1, size, m_xciFile);
|
fread(buf, 1, size, m_xciFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,61 +29,61 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
SimpleFileSystem::SimpleFileSystem(nx::fs::IFileSystem& fileSystem, std::string rootPath, std::string absoluteRootPath) :
|
SimpleFileSystem::SimpleFileSystem(nx::fs::IFileSystem& fileSystem, std::string rootPath, std::string absoluteRootPath) :
|
||||||
m_fileSystem(&fileSystem) , m_rootPath(rootPath), m_absoluteRootPath(absoluteRootPath)
|
m_fileSystem(&fileSystem), m_rootPath(rootPath), m_absoluteRootPath(absoluteRootPath)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SimpleFileSystem::~SimpleFileSystem() {}
|
SimpleFileSystem::~SimpleFileSystem() {}
|
||||||
|
|
||||||
nx::fs::IFile SimpleFileSystem::OpenFile(std::string path)
|
nx::fs::IFile SimpleFileSystem::OpenFile(std::string path)
|
||||||
{
|
{
|
||||||
return m_fileSystem->OpenFile(m_rootPath + path);
|
return m_fileSystem->OpenFile(m_rootPath + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimpleFileSystem::HasFile(std::string path)
|
bool SimpleFileSystem::HasFile(std::string path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LOG_DEBUG(("Attempting to find file at " + m_rootPath + path + "\n").c_str());
|
LOG_DEBUG(("Attempting to find file at " + m_rootPath + path + "\n").c_str());
|
||||||
m_fileSystem->OpenFile(m_rootPath + path);
|
m_fileSystem->OpenFile(m_rootPath + path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (std::exception& e) {}
|
catch (std::exception& e) {}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SimpleFileSystem::GetFileNameFromExtension(std::string path, std::string extension)
|
std::string SimpleFileSystem::GetFileNameFromExtension(std::string path, std::string extension)
|
||||||
{
|
{
|
||||||
nx::fs::IDirectory dir = m_fileSystem->OpenDirectory(m_rootPath + path, FsDirOpenMode_ReadFiles | FsDirOpenMode_ReadDirs);
|
nx::fs::IDirectory dir = m_fileSystem->OpenDirectory(m_rootPath + path, FsDirOpenMode_ReadFiles | FsDirOpenMode_ReadDirs);
|
||||||
|
|
||||||
u64 entryCount = dir.GetEntryCount();
|
u64 entryCount = dir.GetEntryCount();
|
||||||
auto dirEntries = std::make_unique<FsDirectoryEntry[]>(entryCount);
|
auto dirEntries = std::make_unique<FsDirectoryEntry[]>(entryCount);
|
||||||
|
|
||||||
dir.Read(0, dirEntries.get(), entryCount);
|
dir.Read(0, dirEntries.get(), entryCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < entryCount; i++)
|
for (unsigned int i = 0; i < entryCount; i++)
|
||||||
{
|
{
|
||||||
FsDirectoryEntry dirEntry = dirEntries[i];
|
FsDirectoryEntry dirEntry = dirEntries[i];
|
||||||
std::string dirEntryName = dirEntry.name;
|
std::string dirEntryName = dirEntry.name;
|
||||||
|
|
||||||
if (dirEntry.type == FsDirEntryType_Dir)
|
if (dirEntry.type == FsDirEntryType_Dir)
|
||||||
{
|
{
|
||||||
auto subdirPath = path + dirEntryName + "/";
|
auto subdirPath = path + dirEntryName + "/";
|
||||||
auto subdirFound = this->GetFileNameFromExtension(subdirPath, extension);
|
auto subdirFound = this->GetFileNameFromExtension(subdirPath, extension);
|
||||||
|
|
||||||
if (subdirFound != "")
|
if (subdirFound != "")
|
||||||
return subdirFound;
|
return subdirFound;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (dirEntry.type == FsDirEntryType_File)
|
else if (dirEntry.type == FsDirEntryType_File)
|
||||||
{
|
{
|
||||||
auto foundExtension = dirEntryName.substr(dirEntryName.find(".") + 1);
|
auto foundExtension = dirEntryName.substr(dirEntryName.find(".") + 1);
|
||||||
|
|
||||||
if (foundExtension == extension)
|
if (foundExtension == extension)
|
||||||
return dirEntryName;
|
return dirEntryName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -39,155 +39,155 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
bool stopThreadsUsbNsp;
|
bool stopThreadsUsbNsp;
|
||||||
std::string errorMessageUsbNsp;
|
std::string errorMessageUsbNsp;
|
||||||
|
|
||||||
USBNSP::USBNSP(std::string nspName) :
|
USBNSP::USBNSP(std::string nspName) :
|
||||||
m_nspName(nspName)
|
m_nspName(nspName)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct USBFuncArgs
|
struct USBFuncArgs
|
||||||
{
|
{
|
||||||
std::string nspName;
|
std::string nspName;
|
||||||
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
||||||
u64 pfs0Offset;
|
u64 pfs0Offset;
|
||||||
u64 ncaSize;
|
u64 ncaSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
int USBThreadFunc(void* in)
|
int USBThreadFunc(void* in)
|
||||||
{
|
{
|
||||||
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
||||||
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(args->nspName, args->pfs0Offset, args->ncaSize);
|
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(args->nspName, args->pfs0Offset, args->ncaSize);
|
||||||
|
|
||||||
u8* buf = (u8*)memalign(0x1000, 0x800000);
|
u8* buf = (u8*)memalign(0x1000, 0x800000);
|
||||||
u64 sizeRemaining = header.dataSize;
|
u64 sizeRemaining = header.dataSize;
|
||||||
size_t tmpSizeRead = 0;
|
size_t tmpSizeRead = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (sizeRemaining && !stopThreadsUsbNsp)
|
while (sizeRemaining && !stopThreadsUsbNsp)
|
||||||
{
|
{
|
||||||
tmpSizeRead = awoo_usbCommsRead(buf, std::min(sizeRemaining, (u64)0x800000), 5000000000);
|
tmpSizeRead = awoo_usbCommsRead(buf, std::min(sizeRemaining, (u64)0x800000), 5000000000);
|
||||||
if (tmpSizeRead == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
if (tmpSizeRead == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
||||||
sizeRemaining -= tmpSizeRead;
|
sizeRemaining -= tmpSizeRead;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanAppendData(tmpSizeRead))
|
if (args->bufferedPlaceholderWriter->CanAppendData(tmpSizeRead))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
args->bufferedPlaceholderWriter->AppendData(buf, tmpSizeRead);
|
args->bufferedPlaceholderWriter->AppendData(buf, tmpSizeRead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
stopThreadsUsbNsp = true;
|
stopThreadsUsbNsp = true;
|
||||||
errorMessageUsbNsp = e.what();
|
errorMessageUsbNsp = e.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int USBPlaceholderWriteFunc(void* in)
|
int USBPlaceholderWriteFunc(void* in)
|
||||||
{
|
{
|
||||||
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
||||||
|
|
||||||
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsUsbNsp)
|
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsUsbNsp)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
||||||
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBNSP::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId)
|
void USBNSP::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize);
|
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize);
|
||||||
USBFuncArgs args;
|
USBFuncArgs args;
|
||||||
args.nspName = m_nspName;
|
args.nspName = m_nspName;
|
||||||
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
||||||
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
||||||
args.ncaSize = ncaSize;
|
args.ncaSize = ncaSize;
|
||||||
thrd_t usbThread;
|
thrd_t usbThread;
|
||||||
thrd_t writeThread;
|
thrd_t writeThread;
|
||||||
|
|
||||||
stopThreadsUsbNsp = false;
|
stopThreadsUsbNsp = false;
|
||||||
thrd_create(&usbThread, USBThreadFunc, &args);
|
thrd_create(&usbThread, USBThreadFunc, &args);
|
||||||
thrd_create(&writeThread, USBPlaceholderWriteFunc, &args);
|
thrd_create(&writeThread, USBPlaceholderWriteFunc, &args);
|
||||||
|
|
||||||
u64 freq = armGetSystemTickFreq();
|
u64 freq = armGetSystemTickFreq();
|
||||||
u64 startTime = armGetSystemTick();
|
u64 startTime = armGetSystemTick();
|
||||||
size_t startSizeBuffered = 0;
|
size_t startSizeBuffered = 0;
|
||||||
double speed = 0.0;
|
double speed = 0.0;
|
||||||
|
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsUsbNsp)
|
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsUsbNsp)
|
||||||
{
|
{
|
||||||
u64 newTime = armGetSystemTick();
|
u64 newTime = armGetSystemTick();
|
||||||
|
|
||||||
if (newTime - startTime >= freq)
|
if (newTime - startTime >= freq)
|
||||||
{
|
{
|
||||||
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
||||||
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
||||||
double duration = ((double)(newTime - startTime) / (double)freq);
|
double duration = ((double)(newTime - startTime) / (double)freq);
|
||||||
speed = mbBuffered / duration;
|
speed = mbBuffered / duration;
|
||||||
|
|
||||||
startTime = newTime;
|
startTime = newTime;
|
||||||
startSizeBuffered = newSizeBuffered;
|
startSizeBuffered = newSizeBuffered;
|
||||||
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
||||||
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
|
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
|
||||||
LOG_DEBUG("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
LOG_DEBUG("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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");
|
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");
|
||||||
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsUsbNsp)
|
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsUsbNsp)
|
||||||
{
|
{
|
||||||
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
|
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
|
||||||
LOG_DEBUG("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
LOG_DEBUG("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
||||||
#endif
|
#endif
|
||||||
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
thrd_join(usbThread, NULL);
|
thrd_join(usbThread, NULL);
|
||||||
thrd_join(writeThread, NULL);
|
thrd_join(writeThread, NULL);
|
||||||
if (stopThreadsUsbNsp) throw std::runtime_error(errorMessageUsbNsp.c_str());
|
if (stopThreadsUsbNsp) throw std::runtime_error(errorMessageUsbNsp.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBNSP::BufferData(void* buf, off_t offset, size_t size)
|
void USBNSP::BufferData(void* buf, off_t offset, size_t size)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("buffering 0x%lx-0x%lx\n", offset, offset + size);
|
LOG_DEBUG("buffering 0x%lx-0x%lx\n", offset, offset + size);
|
||||||
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(m_nspName, offset, size);
|
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(m_nspName, offset, size);
|
||||||
u8* tempBuffer = (u8*)memalign(0x1000, header.dataSize);
|
u8* tempBuffer = (u8*)memalign(0x1000, header.dataSize);
|
||||||
if (tin::util::USBRead(tempBuffer, header.dataSize) == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
if (tin::util::USBRead(tempBuffer, header.dataSize) == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
||||||
memcpy(buf, tempBuffer, header.dataSize);
|
memcpy(buf, tempBuffer, header.dataSize);
|
||||||
free(tempBuffer);
|
free(tempBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -38,155 +38,155 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
bool stopThreadsUsbXci;
|
bool stopThreadsUsbXci;
|
||||||
std::string errorMessageUsbXci;
|
std::string errorMessageUsbXci;
|
||||||
|
|
||||||
USBXCI::USBXCI(std::string xciName) :
|
USBXCI::USBXCI(std::string xciName) :
|
||||||
m_xciName(xciName)
|
m_xciName(xciName)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct USBFuncArgs
|
struct USBFuncArgs
|
||||||
{
|
{
|
||||||
std::string xciName;
|
std::string xciName;
|
||||||
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
||||||
u64 hfs0Offset;
|
u64 hfs0Offset;
|
||||||
u64 ncaSize;
|
u64 ncaSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
int USBThreadFunc(void* in)
|
int USBThreadFunc(void* in)
|
||||||
{
|
{
|
||||||
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
||||||
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(args->xciName, args->hfs0Offset, args->ncaSize);
|
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(args->xciName, args->hfs0Offset, args->ncaSize);
|
||||||
|
|
||||||
u8* buf = (u8*)memalign(0x1000, 0x800000);
|
u8* buf = (u8*)memalign(0x1000, 0x800000);
|
||||||
u64 sizeRemaining = header.dataSize;
|
u64 sizeRemaining = header.dataSize;
|
||||||
size_t tmpSizeRead = 0;
|
size_t tmpSizeRead = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (sizeRemaining && !stopThreadsUsbXci)
|
while (sizeRemaining && !stopThreadsUsbXci)
|
||||||
{
|
{
|
||||||
tmpSizeRead = awoo_usbCommsRead(buf, std::min(sizeRemaining, (u64)0x800000), 5000000000);
|
tmpSizeRead = awoo_usbCommsRead(buf, std::min(sizeRemaining, (u64)0x800000), 5000000000);
|
||||||
if (tmpSizeRead == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
if (tmpSizeRead == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
||||||
sizeRemaining -= tmpSizeRead;
|
sizeRemaining -= tmpSizeRead;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanAppendData(tmpSizeRead))
|
if (args->bufferedPlaceholderWriter->CanAppendData(tmpSizeRead))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
args->bufferedPlaceholderWriter->AppendData(buf, tmpSizeRead);
|
args->bufferedPlaceholderWriter->AppendData(buf, tmpSizeRead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
stopThreadsUsbXci = true;
|
stopThreadsUsbXci = true;
|
||||||
errorMessageUsbXci = e.what();
|
errorMessageUsbXci = e.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int USBPlaceholderWriteFunc(void* in)
|
int USBPlaceholderWriteFunc(void* in)
|
||||||
{
|
{
|
||||||
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
||||||
|
|
||||||
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsUsbXci)
|
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsUsbXci)
|
||||||
{
|
{
|
||||||
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
||||||
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBXCI::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId)
|
void USBXCI::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId)
|
||||||
{
|
{
|
||||||
const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
const HFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
||||||
|
|
||||||
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
size_t ncaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize);
|
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize);
|
||||||
USBFuncArgs args;
|
USBFuncArgs args;
|
||||||
args.xciName = m_xciName;
|
args.xciName = m_xciName;
|
||||||
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
||||||
args.hfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
args.hfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
||||||
args.ncaSize = ncaSize;
|
args.ncaSize = ncaSize;
|
||||||
thrd_t usbThread;
|
thrd_t usbThread;
|
||||||
thrd_t writeThread;
|
thrd_t writeThread;
|
||||||
|
|
||||||
stopThreadsUsbXci = false;
|
stopThreadsUsbXci = false;
|
||||||
thrd_create(&usbThread, USBThreadFunc, &args);
|
thrd_create(&usbThread, USBThreadFunc, &args);
|
||||||
thrd_create(&writeThread, USBPlaceholderWriteFunc, &args);
|
thrd_create(&writeThread, USBPlaceholderWriteFunc, &args);
|
||||||
|
|
||||||
u64 freq = armGetSystemTickFreq();
|
u64 freq = armGetSystemTickFreq();
|
||||||
u64 startTime = armGetSystemTick();
|
u64 startTime = armGetSystemTick();
|
||||||
size_t startSizeBuffered = 0;
|
size_t startSizeBuffered = 0;
|
||||||
double speed = 0.0;
|
double speed = 0.0;
|
||||||
|
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsUsbXci)
|
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsUsbXci)
|
||||||
{
|
{
|
||||||
u64 newTime = armGetSystemTick();
|
u64 newTime = armGetSystemTick();
|
||||||
|
|
||||||
if (newTime - startTime >= freq)
|
if (newTime - startTime >= freq)
|
||||||
{
|
{
|
||||||
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
||||||
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
||||||
double duration = ((double)(newTime - startTime) / (double)freq);
|
double duration = ((double)(newTime - startTime) / (double)freq);
|
||||||
speed = mbBuffered / duration;
|
speed = mbBuffered / duration;
|
||||||
|
|
||||||
startTime = newTime;
|
startTime = newTime;
|
||||||
startSizeBuffered = newSizeBuffered;
|
startSizeBuffered = newSizeBuffered;
|
||||||
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
||||||
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
|
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
|
||||||
LOG_DEBUG("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
LOG_DEBUG("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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");
|
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");
|
||||||
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsUsbXci)
|
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsUsbXci)
|
||||||
{
|
{
|
||||||
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
|
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
|
||||||
LOG_DEBUG("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
LOG_DEBUG("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
||||||
#endif
|
#endif
|
||||||
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
||||||
}
|
}
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
|
|
||||||
thrd_join(usbThread, NULL);
|
thrd_join(usbThread, NULL);
|
||||||
thrd_join(writeThread, NULL);
|
thrd_join(writeThread, NULL);
|
||||||
if (stopThreadsUsbXci) throw std::runtime_error(errorMessageUsbXci.c_str());
|
if (stopThreadsUsbXci) throw std::runtime_error(errorMessageUsbXci.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBXCI::BufferData(void* buf, off_t offset, size_t size)
|
void USBXCI::BufferData(void* buf, off_t offset, size_t size)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("buffering 0x%lx-0x%lx\n", offset, offset + size);
|
LOG_DEBUG("buffering 0x%lx-0x%lx\n", offset, offset + size);
|
||||||
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(m_xciName, offset, size);
|
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(m_xciName, offset, size);
|
||||||
u8* tempBuffer = (u8*)memalign(0x1000, header.dataSize);
|
u8* tempBuffer = (u8*)memalign(0x1000, header.dataSize);
|
||||||
if (tin::util::USBRead(tempBuffer, header.dataSize) == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
if (tin::util::USBRead(tempBuffer, header.dataSize) == 0) THROW_FORMAT(("inst.usb.error"_lang).c_str());
|
||||||
memcpy(buf, tempBuffer, header.dataSize);
|
memcpy(buf, tempBuffer, header.dataSize);
|
||||||
free(tempBuffer);
|
free(tempBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,148 +27,148 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::install::xci
|
namespace tin::install::xci
|
||||||
{
|
{
|
||||||
XCI::XCI()
|
XCI::XCI()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void XCI::RetrieveHeader()
|
void XCI::RetrieveHeader()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Retrieving HFS0 header...\n");
|
LOG_DEBUG("Retrieving HFS0 header...\n");
|
||||||
|
|
||||||
// Retrieve hfs0 offset
|
// Retrieve hfs0 offset
|
||||||
u64 hfs0Offset = 0xf000;
|
u64 hfs0Offset = 0xf000;
|
||||||
|
|
||||||
// Retrieve main hfs0 header
|
// Retrieve main hfs0 header
|
||||||
std::vector<u8> m_headerBytes;
|
std::vector<u8> m_headerBytes;
|
||||||
m_headerBytes.resize(sizeof(HFS0BaseHeader), 0);
|
m_headerBytes.resize(sizeof(HFS0BaseHeader), 0);
|
||||||
this->BufferData(m_headerBytes.data(), hfs0Offset, sizeof(HFS0BaseHeader));
|
this->BufferData(m_headerBytes.data(), hfs0Offset, sizeof(HFS0BaseHeader));
|
||||||
|
|
||||||
LOG_DEBUG("Base header: \n");
|
LOG_DEBUG("Base header: \n");
|
||||||
printBytes(m_headerBytes.data(), sizeof(HFS0BaseHeader), true);
|
printBytes(m_headerBytes.data(), sizeof(HFS0BaseHeader), true);
|
||||||
|
|
||||||
// Retrieve full header
|
// Retrieve full header
|
||||||
HFS0BaseHeader *header = reinterpret_cast<HFS0BaseHeader*>(m_headerBytes.data());
|
HFS0BaseHeader* header = reinterpret_cast<HFS0BaseHeader*>(m_headerBytes.data());
|
||||||
if (header->magic != MAGIC_HFS0)
|
if (header->magic != MAGIC_HFS0)
|
||||||
THROW_FORMAT("hfs0 magic doesn't match at 0x%lx\n", hfs0Offset);
|
THROW_FORMAT("hfs0 magic doesn't match at 0x%lx\n", hfs0Offset);
|
||||||
|
|
||||||
size_t remainingHeaderSize = header->numFiles * sizeof(HFS0FileEntry) + header->stringTableSize;
|
size_t remainingHeaderSize = header->numFiles * sizeof(HFS0FileEntry) + header->stringTableSize;
|
||||||
m_headerBytes.resize(sizeof(HFS0BaseHeader) + remainingHeaderSize, 0);
|
m_headerBytes.resize(sizeof(HFS0BaseHeader) + remainingHeaderSize, 0);
|
||||||
this->BufferData(m_headerBytes.data() + sizeof(HFS0BaseHeader), hfs0Offset + sizeof(HFS0BaseHeader), remainingHeaderSize);
|
this->BufferData(m_headerBytes.data() + sizeof(HFS0BaseHeader), hfs0Offset + sizeof(HFS0BaseHeader), remainingHeaderSize);
|
||||||
|
|
||||||
LOG_DEBUG("Base header: \n");
|
LOG_DEBUG("Base header: \n");
|
||||||
printBytes(m_headerBytes.data(), sizeof(HFS0BaseHeader) + remainingHeaderSize, true);
|
printBytes(m_headerBytes.data(), sizeof(HFS0BaseHeader) + remainingHeaderSize, true);
|
||||||
|
|
||||||
// Find Secure partition
|
// Find Secure partition
|
||||||
header = reinterpret_cast<HFS0BaseHeader*>(m_headerBytes.data());
|
header = reinterpret_cast<HFS0BaseHeader*>(m_headerBytes.data());
|
||||||
for (unsigned int i = 0; i < header->numFiles; i++)
|
for (unsigned int i = 0; i < header->numFiles; i++)
|
||||||
{
|
{
|
||||||
const HFS0FileEntry *entry = hfs0GetFileEntry(header, i);
|
const HFS0FileEntry* entry = hfs0GetFileEntry(header, i);
|
||||||
std::string entryName(hfs0GetFileName(header, entry));
|
std::string entryName(hfs0GetFileName(header, entry));
|
||||||
|
|
||||||
if (entryName != "secure")
|
if (entryName != "secure")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_secureHeaderOffset = hfs0Offset + remainingHeaderSize + 0x10 + entry->dataOffset;
|
m_secureHeaderOffset = hfs0Offset + remainingHeaderSize + 0x10 + entry->dataOffset;
|
||||||
m_secureHeaderBytes.resize(sizeof(HFS0BaseHeader), 0);
|
m_secureHeaderBytes.resize(sizeof(HFS0BaseHeader), 0);
|
||||||
this->BufferData(m_secureHeaderBytes.data(), m_secureHeaderOffset, sizeof(HFS0BaseHeader));
|
this->BufferData(m_secureHeaderBytes.data(), m_secureHeaderOffset, sizeof(HFS0BaseHeader));
|
||||||
|
|
||||||
LOG_DEBUG("Secure header: \n");
|
LOG_DEBUG("Secure header: \n");
|
||||||
printBytes(m_secureHeaderBytes.data(), sizeof(HFS0BaseHeader), true);
|
printBytes(m_secureHeaderBytes.data(), sizeof(HFS0BaseHeader), true);
|
||||||
|
|
||||||
if (this->GetSecureHeader()->magic != MAGIC_HFS0)
|
if (this->GetSecureHeader()->magic != MAGIC_HFS0)
|
||||||
THROW_FORMAT("hfs0 magic doesn't match at 0x%lx\n", m_secureHeaderOffset);
|
THROW_FORMAT("hfs0 magic doesn't match at 0x%lx\n", m_secureHeaderOffset);
|
||||||
|
|
||||||
// Retrieve full header
|
// Retrieve full header
|
||||||
remainingHeaderSize = this->GetSecureHeader()->numFiles * sizeof(HFS0FileEntry) + this->GetSecureHeader()->stringTableSize;
|
remainingHeaderSize = this->GetSecureHeader()->numFiles * sizeof(HFS0FileEntry) + this->GetSecureHeader()->stringTableSize;
|
||||||
m_secureHeaderBytes.resize(sizeof(HFS0BaseHeader) + remainingHeaderSize, 0);
|
m_secureHeaderBytes.resize(sizeof(HFS0BaseHeader) + remainingHeaderSize, 0);
|
||||||
this->BufferData(m_secureHeaderBytes.data() + sizeof(HFS0BaseHeader), m_secureHeaderOffset + sizeof(HFS0BaseHeader), remainingHeaderSize);
|
this->BufferData(m_secureHeaderBytes.data() + sizeof(HFS0BaseHeader), m_secureHeaderOffset + sizeof(HFS0BaseHeader), remainingHeaderSize);
|
||||||
|
|
||||||
LOG_DEBUG("Base header: \n");
|
LOG_DEBUG("Base header: \n");
|
||||||
printBytes(m_secureHeaderBytes.data(), sizeof(HFS0BaseHeader) + remainingHeaderSize, true);
|
printBytes(m_secureHeaderBytes.data(), sizeof(HFS0BaseHeader) + remainingHeaderSize, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
THROW_FORMAT("couldn't optain secure hfs0 header\n");
|
THROW_FORMAT("couldn't optain secure hfs0 header\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const HFS0BaseHeader* XCI::GetSecureHeader()
|
const HFS0BaseHeader* XCI::GetSecureHeader()
|
||||||
{
|
{
|
||||||
if (m_secureHeaderBytes.empty())
|
if (m_secureHeaderBytes.empty())
|
||||||
THROW_FORMAT("Cannot retrieve header as header bytes are empty. Have you retrieved it yet?\n");
|
THROW_FORMAT("Cannot retrieve header as header bytes are empty. Have you retrieved it yet?\n");
|
||||||
|
|
||||||
return reinterpret_cast<HFS0BaseHeader*>(m_secureHeaderBytes.data());
|
return reinterpret_cast<HFS0BaseHeader*>(m_secureHeaderBytes.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 XCI::GetDataOffset()
|
u64 XCI::GetDataOffset()
|
||||||
{
|
{
|
||||||
if (m_secureHeaderBytes.empty())
|
if (m_secureHeaderBytes.empty())
|
||||||
THROW_FORMAT("Cannot get data offset as header is empty. Have you retrieved it yet?\n");
|
THROW_FORMAT("Cannot get data offset as header is empty. Have you retrieved it yet?\n");
|
||||||
|
|
||||||
return m_secureHeaderOffset + m_secureHeaderBytes.size();
|
return m_secureHeaderOffset + m_secureHeaderBytes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const HFS0FileEntry* XCI::GetFileEntry(unsigned int index)
|
const HFS0FileEntry* XCI::GetFileEntry(unsigned int index)
|
||||||
{
|
{
|
||||||
if (index >= this->GetSecureHeader()->numFiles)
|
if (index >= this->GetSecureHeader()->numFiles)
|
||||||
THROW_FORMAT("File entry index is out of bounds\n");
|
THROW_FORMAT("File entry index is out of bounds\n");
|
||||||
|
|
||||||
return hfs0GetFileEntry(this->GetSecureHeader(), index);
|
return hfs0GetFileEntry(this->GetSecureHeader(), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const HFS0FileEntry* XCI::GetFileEntryByName(std::string name)
|
const HFS0FileEntry* XCI::GetFileEntryByName(std::string name)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < this->GetSecureHeader()->numFiles; i++)
|
for (unsigned int i = 0; i < this->GetSecureHeader()->numFiles; i++)
|
||||||
{
|
{
|
||||||
const HFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
const HFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
||||||
std::string foundName(this->GetFileEntryName(fileEntry));
|
std::string foundName(this->GetFileEntryName(fileEntry));
|
||||||
|
|
||||||
if (foundName == name)
|
if (foundName == name)
|
||||||
return fileEntry;
|
return fileEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HFS0FileEntry* XCI::GetFileEntryByNcaId(const NcmContentId& ncaId)
|
const HFS0FileEntry* XCI::GetFileEntryByNcaId(const NcmContentId& ncaId)
|
||||||
{
|
{
|
||||||
const HFS0FileEntry* fileEntry = nullptr;
|
const HFS0FileEntry* fileEntry = nullptr;
|
||||||
std::string ncaIdStr = tin::util::GetNcaIdString(ncaId);
|
std::string ncaIdStr = tin::util::GetNcaIdString(ncaId);
|
||||||
|
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".nca")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".nca")) == nullptr)
|
||||||
{
|
{
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.nca")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.nca")) == nullptr)
|
||||||
{
|
{
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".ncz")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".ncz")) == nullptr)
|
||||||
{
|
{
|
||||||
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.ncz")) == nullptr)
|
if ((fileEntry = this->GetFileEntryByName(ncaIdStr + ".cnmt.ncz")) == nullptr)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileEntry;
|
return fileEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const HFS0FileEntry*> XCI::GetFileEntriesByExtension(std::string extension)
|
std::vector<const HFS0FileEntry*> XCI::GetFileEntriesByExtension(std::string extension)
|
||||||
{
|
{
|
||||||
std::vector<const HFS0FileEntry*> entryList;
|
std::vector<const HFS0FileEntry*> entryList;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->GetSecureHeader()->numFiles; i++)
|
for (unsigned int i = 0; i < this->GetSecureHeader()->numFiles; i++)
|
||||||
{
|
{
|
||||||
const HFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
const HFS0FileEntry* fileEntry = this->GetFileEntry(i);
|
||||||
std::string name(this->GetFileEntryName(fileEntry));
|
std::string name(this->GetFileEntryName(fileEntry));
|
||||||
auto foundExtension = name.substr(name.find(".") + 1);
|
auto foundExtension = name.substr(name.find(".") + 1);
|
||||||
|
|
||||||
if (foundExtension == extension)
|
if (foundExtension == extension)
|
||||||
entryList.push_back(fileEntry);
|
entryList.push_back(fileEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryList;
|
return entryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* XCI::GetFileEntryName(const HFS0FileEntry* fileEntry)
|
const char* XCI::GetFileEntryName(const HFS0FileEntry* fileEntry)
|
||||||
{
|
{
|
||||||
return hfs0GetFileName(this->GetSecureHeader(), fileEntry);
|
return hfs0GetFileName(this->GetSecureHeader(), fileEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,18 +8,19 @@
|
|||||||
using namespace pu::ui::render;
|
using namespace pu::ui::render;
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
inst::util::initApp();
|
inst::util::initApp();
|
||||||
try {
|
try {
|
||||||
auto renderer = Renderer::New(RendererInitOptions(SDL_INIT_EVERYTHING, RendererHardwareFlags).WithIMG(IMGAllFlags).WithMixer(MixerAllFlags).WithTTF());
|
auto renderer = Renderer::New(RendererInitOptions(SDL_INIT_EVERYTHING, RendererHardwareFlags).WithIMG(IMGAllFlags).WithMixer(MixerAllFlags).WithTTF());
|
||||||
auto main = inst::ui::MainApplication::New(renderer);
|
auto main = inst::ui::MainApplication::New(renderer);
|
||||||
std::thread updateThread;
|
std::thread updateThread;
|
||||||
if (inst::config::autoUpdate && inst::util::getIPAddress() != "1.0.0.127") updateThread = std::thread(inst::util::checkForAppUpdate);
|
if (inst::config::autoUpdate && inst::util::getIPAddress() != "1.0.0.127") updateThread = std::thread(inst::util::checkForAppUpdate);
|
||||||
main->Prepare();
|
main->Prepare();
|
||||||
main->ShowWithFadeIn();
|
main->ShowWithFadeIn();
|
||||||
updateThread.join();
|
updateThread.join();
|
||||||
} catch (std::exception& e) {
|
}
|
||||||
LOG_DEBUG("An error occurred:\n%s", e.what());
|
catch (std::exception& e) {
|
||||||
}
|
LOG_DEBUG("An error occurred:\n%s", e.what());
|
||||||
inst::util::deinitApp();
|
}
|
||||||
return 0;
|
inst::util::deinitApp();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -50,269 +50,271 @@ static int m_serverSocket = 0;
|
|||||||
static int m_clientSocket = 0;
|
static int m_clientSocket = 0;
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace netInstStuff{
|
namespace netInstStuff {
|
||||||
|
|
||||||
void InitializeServerSocket() try
|
void InitializeServerSocket() try
|
||||||
{
|
{
|
||||||
// Create a socket
|
// Create a socket
|
||||||
m_serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
m_serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||||
|
|
||||||
if (m_serverSocket < -1)
|
if (m_serverSocket < -1)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to create a server socket. Error code: %u\n", errno);
|
THROW_FORMAT("Failed to create a server socket. Error code: %u\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_in server;
|
struct sockaddr_in server;
|
||||||
server.sin_family = AF_INET;
|
server.sin_family = AF_INET;
|
||||||
server.sin_port = htons(REMOTE_INSTALL_PORT);
|
server.sin_port = htons(REMOTE_INSTALL_PORT);
|
||||||
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
if (bind(m_serverSocket, (struct sockaddr*) &server, sizeof(server)) < 0)
|
if (bind(m_serverSocket, (struct sockaddr*)&server, sizeof(server)) < 0)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to bind server socket. Error code: %u\n", errno);
|
THROW_FORMAT("Failed to bind server socket. Error code: %u\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set as non-blocking
|
// Set as non-blocking
|
||||||
fcntl(m_serverSocket, F_SETFL, fcntl(m_serverSocket, F_GETFL, 0) | O_NONBLOCK);
|
fcntl(m_serverSocket, F_SETFL, fcntl(m_serverSocket, F_GETFL, 0) | O_NONBLOCK);
|
||||||
|
|
||||||
if (listen(m_serverSocket, 5) < 0)
|
if (listen(m_serverSocket, 5) < 0)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to listen on server socket. Error code: %u\n", errno);
|
THROW_FORMAT("Failed to listen on server socket. Error code: %u\n", errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Failed to initialize server socket!\n");
|
LOG_DEBUG("Failed to initialize server socket!\n");
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
|
|
||||||
if (m_serverSocket != 0)
|
if (m_serverSocket != 0)
|
||||||
{
|
{
|
||||||
close(m_serverSocket);
|
close(m_serverSocket);
|
||||||
m_serverSocket = 0;
|
m_serverSocket = 0;
|
||||||
}
|
}
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to initialize server socket!", (std::string)e.what(), {"OK"}, true);
|
inst::ui::mainApp->CreateShowDialog("Failed to initialize server socket!", (std::string)e.what(), { "OK" }, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnUnwound()
|
void OnUnwound()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("unwinding view\n");
|
LOG_DEBUG("unwinding view\n");
|
||||||
if (m_clientSocket != 0)
|
if (m_clientSocket != 0)
|
||||||
{
|
{
|
||||||
close(m_clientSocket);
|
close(m_clientSocket);
|
||||||
m_clientSocket = 0;
|
m_clientSocket = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendExitCommands(std::string url)
|
void sendExitCommands(std::string url)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Telling the server we're done installing\n");
|
LOG_DEBUG("Telling the server we're done installing\n");
|
||||||
// Send 1 byte ack to close the server, OG tinfoil compatibility
|
// Send 1 byte ack to close the server, OG tinfoil compatibility
|
||||||
u8 ack = 0;
|
u8 ack = 0;
|
||||||
tin::network::WaitSendNetworkData(m_clientSocket, &ack, sizeof(u8));
|
tin::network::WaitSendNetworkData(m_clientSocket, &ack, sizeof(u8));
|
||||||
// Send 'DROP' header so ns-usbloader knows we're done
|
// Send 'DROP' header so ns-usbloader knows we're done
|
||||||
tin::network::NSULDrop(url);
|
tin::network::NSULDrop(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void installTitleNet(std::vector<std::string> ourUrlList, int ourStorage, std::vector<std::string> urlListAltNames, std::string ourSource)
|
void installTitleNet(std::vector<std::string> ourUrlList, int ourStorage, std::vector<std::string> urlListAltNames, std::string ourSource)
|
||||||
{
|
{
|
||||||
inst::util::initInstallServices();
|
inst::util::initInstallServices();
|
||||||
inst::ui::instPage::loadInstallScreen();
|
inst::ui::instPage::loadInstallScreen();
|
||||||
bool nspInstalled = true;
|
bool nspInstalled = true;
|
||||||
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
||||||
|
|
||||||
if (ourStorage) m_destStorageId = NcmStorageId_BuiltInUser;
|
if (ourStorage) m_destStorageId = NcmStorageId_BuiltInUser;
|
||||||
unsigned int urlItr;
|
unsigned int urlItr;
|
||||||
|
|
||||||
std::vector<std::string> urlNames;
|
std::vector<std::string> urlNames;
|
||||||
if (urlListAltNames.size() > 0) {
|
if (urlListAltNames.size() > 0) {
|
||||||
for (long unsigned int i = 0; i < urlListAltNames.size(); i++) {
|
for (long unsigned int i = 0; i < urlListAltNames.size(); i++) {
|
||||||
urlNames.push_back(inst::util::shortenString(urlListAltNames[i], 38, true));
|
urlNames.push_back(inst::util::shortenString(urlListAltNames[i], 38, true));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
for (long unsigned int i = 0; i < ourUrlList.size(); i++) {
|
else {
|
||||||
urlNames.push_back(inst::util::shortenString(inst::util::formatUrlString(ourUrlList[i]), 38, true));
|
for (long unsigned int i = 0; i < ourUrlList.size(); i++) {
|
||||||
}
|
urlNames.push_back(inst::util::shortenString(inst::util::formatUrlString(ourUrlList[i]), 38, true));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> previousClockValues;
|
std::vector<int> previousClockValues;
|
||||||
if (inst::config::overClock) {
|
if (inst::config::overClock) {
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (urlItr = 0; urlItr < ourUrlList.size(); urlItr++) {
|
for (urlItr = 0; urlItr < ourUrlList.size(); urlItr++) {
|
||||||
LOG_DEBUG("%s %s\n", "Install request from", ourUrlList[urlItr].c_str());
|
LOG_DEBUG("%s %s\n", "Install request from", ourUrlList[urlItr].c_str());
|
||||||
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + urlNames[urlItr] + ourSource);
|
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + urlNames[urlItr] + ourSource);
|
||||||
std::unique_ptr<tin::install::Install> installTask;
|
std::unique_ptr<tin::install::Install> installTask;
|
||||||
|
|
||||||
if (inst::curl::downloadToBuffer(ourUrlList[urlItr], 0x100, 0x103) == "HEAD") {
|
if (inst::curl::downloadToBuffer(ourUrlList[urlItr], 0x100, 0x103) == "HEAD") {
|
||||||
auto httpXCI = std::make_shared<tin::install::xci::HTTPXCI>(ourUrlList[urlItr]);
|
auto httpXCI = std::make_shared<tin::install::xci::HTTPXCI>(ourUrlList[urlItr]);
|
||||||
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, httpXCI);
|
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, httpXCI);
|
||||||
} else {
|
}
|
||||||
auto httpNSP = std::make_shared<tin::install::nsp::HTTPNSP>(ourUrlList[urlItr]);
|
else {
|
||||||
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, httpNSP);
|
auto httpNSP = std::make_shared<tin::install::nsp::HTTPNSP>(ourUrlList[urlItr]);
|
||||||
}
|
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, httpNSP);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("%s\n", "Preparing installation");
|
LOG_DEBUG("%s\n", "Preparing installation");
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
installTask->Prepare();
|
installTask->Prepare();
|
||||||
installTask->Begin();
|
installTask->Begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e) {
|
catch (std::exception& e) {
|
||||||
LOG_DEBUG("Failed to install");
|
LOG_DEBUG("Failed to install");
|
||||||
LOG_DEBUG("%s", e.what());
|
LOG_DEBUG("%s", e.what());
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + urlNames[urlItr]);
|
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + urlNames[urlItr]);
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
std::string audioPath = "romfs:/audio/bark.wav";
|
std::string audioPath = "romfs:/audio/bark.wav";
|
||||||
if (inst::config::gayMode) audioPath = "";
|
if (inst::config::gayMode) audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + urlNames[urlItr] + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + urlNames[urlItr] + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), { "common.ok"_lang }, true);
|
||||||
audioThread.join();
|
audioThread.join();
|
||||||
nspInstalled = false;
|
nspInstalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousClockValues.size() > 0) {
|
if (previousClockValues.size() > 0) {
|
||||||
inst::util::setClockSpeed(0, previousClockValues[0]);
|
inst::util::setClockSpeed(0, previousClockValues[0]);
|
||||||
inst::util::setClockSpeed(1, previousClockValues[1]);
|
inst::util::setClockSpeed(1, previousClockValues[1]);
|
||||||
inst::util::setClockSpeed(2, previousClockValues[2]);
|
inst::util::setClockSpeed(2, previousClockValues[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendExitCommands(inst::util::formatUrlLink(ourUrlList[0]));
|
sendExitCommands(inst::util::formatUrlLink(ourUrlList[0]));
|
||||||
OnUnwound();
|
OnUnwound();
|
||||||
|
|
||||||
if(nspInstalled) {
|
if (nspInstalled) {
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
std::string audioPath = "romfs:/audio/awoo.wav";
|
std::string audioPath = "romfs:/audio/awoo.wav";
|
||||||
if (inst::config::gayMode) audioPath = "";
|
if (inst::config::gayMode) audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/awoo.wav")) audioPath = inst::config::appDir + "/awoo.wav";
|
if (std::filesystem::exists(inst::config::appDir + "/awoo.wav")) audioPath = inst::config::appDir + "/awoo.wav";
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
if (ourUrlList.size() > 1) inst::ui::mainApp->CreateShowDialog(std::to_string(ourUrlList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
if (ourUrlList.size() > 1) inst::ui::mainApp->CreateShowDialog(std::to_string(ourUrlList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
else inst::ui::mainApp->CreateShowDialog(urlNames[0] + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
else inst::ui::mainApp->CreateShowDialog(urlNames[0] + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
audioThread.join();
|
audioThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Done");
|
|
||||||
inst::ui::instPage::loadMainMenu();
|
|
||||||
inst::util::deinitInstallServices();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> OnSelected()
|
LOG_DEBUG("Done");
|
||||||
{
|
inst::ui::instPage::loadMainMenu();
|
||||||
u64 freq = armGetSystemTickFreq();
|
inst::util::deinitInstallServices();
|
||||||
u64 startTime = armGetSystemTick();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
std::vector<std::string> OnSelected()
|
||||||
{
|
{
|
||||||
ASSERT_OK(curl_global_init(CURL_GLOBAL_ALL), "Curl failed to initialized");
|
u64 freq = armGetSystemTickFreq();
|
||||||
|
u64 startTime = armGetSystemTick();
|
||||||
|
|
||||||
// Initialize the server socket if it hasn't already been
|
try
|
||||||
if (m_serverSocket == 0)
|
{
|
||||||
{
|
ASSERT_OK(curl_global_init(CURL_GLOBAL_ALL), "Curl failed to initialized");
|
||||||
InitializeServerSocket();
|
|
||||||
|
|
||||||
if (m_serverSocket <= 0)
|
// Initialize the server socket if it hasn't already been
|
||||||
{
|
if (m_serverSocket == 0)
|
||||||
THROW_FORMAT("Server socket failed to initialize.\n");
|
{
|
||||||
}
|
InitializeServerSocket();
|
||||||
}
|
|
||||||
|
|
||||||
std::string ourIPAddress = inst::util::getIPAddress();
|
if (m_serverSocket <= 0)
|
||||||
inst::ui::mainApp->netinstPage->pageInfoText->SetText("inst.net.top_info1"_lang + ourIPAddress);
|
{
|
||||||
inst::ui::mainApp->CallForRender();
|
THROW_FORMAT("Server socket failed to initialize.\n");
|
||||||
LOG_DEBUG("%s %s\n", "Switch IP is ", ourIPAddress.c_str());
|
}
|
||||||
LOG_DEBUG("%s\n", "Waiting for network");
|
}
|
||||||
LOG_DEBUG("%s\n", "B to cancel");
|
|
||||||
|
|
||||||
std::vector<std::string> urls;
|
|
||||||
|
|
||||||
while (true)
|
std::string ourIPAddress = inst::util::getIPAddress();
|
||||||
{
|
inst::ui::mainApp->netinstPage->pageInfoText->SetText("inst.net.top_info1"_lang + ourIPAddress);
|
||||||
// If we don't update the UI occasionally the Switch basically crashes on this screen if you press the home button
|
inst::ui::mainApp->CallForRender();
|
||||||
u64 newTime = armGetSystemTick();
|
LOG_DEBUG("%s %s\n", "Switch IP is ", ourIPAddress.c_str());
|
||||||
if (newTime - startTime >= freq * 0.25) {
|
LOG_DEBUG("%s\n", "Waiting for network");
|
||||||
startTime = newTime;
|
LOG_DEBUG("%s\n", "B to cancel");
|
||||||
inst::ui::mainApp->CallForRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Break on input pressed
|
std::vector<std::string> urls;
|
||||||
u64 kDown = inst::ui::mainApp->GetButtonsDown();
|
|
||||||
|
|
||||||
if (kDown & HidNpadButton_B)
|
while (true)
|
||||||
{
|
{
|
||||||
break;
|
// If we don't update the UI occasionally the Switch basically crashes on this screen if you press the home button
|
||||||
}
|
u64 newTime = armGetSystemTick();
|
||||||
if (kDown & HidNpadButton_Y)
|
if (newTime - startTime >= freq * 0.25) {
|
||||||
{
|
startTime = newTime;
|
||||||
return {"supplyUrl"};
|
inst::ui::mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
if (kDown & HidNpadButton_X)
|
|
||||||
{
|
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.net.help.title"_lang, "inst.net.help.desc"_lang, {"common.ok"_lang}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in client;
|
// Break on input pressed
|
||||||
socklen_t clientLen = sizeof(client);
|
u64 kDown = inst::ui::mainApp->GetButtonsDown();
|
||||||
|
|
||||||
m_clientSocket = accept(m_serverSocket, (struct sockaddr*)&client, &clientLen);
|
if (kDown & HidNpadButton_B)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (kDown & HidNpadButton_Y)
|
||||||
|
{
|
||||||
|
return { "supplyUrl" };
|
||||||
|
}
|
||||||
|
if (kDown & HidNpadButton_X)
|
||||||
|
{
|
||||||
|
inst::ui::mainApp->CreateShowDialog("inst.net.help.title"_lang, "inst.net.help.desc"_lang, { "common.ok"_lang }, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_clientSocket >= 0)
|
struct sockaddr_in client;
|
||||||
{
|
socklen_t clientLen = sizeof(client);
|
||||||
LOG_DEBUG("%s\n", "Server accepted");
|
|
||||||
u32 size = 0;
|
|
||||||
tin::network::WaitReceiveNetworkData(m_clientSocket, &size, sizeof(u32));
|
|
||||||
size = ntohl(size);
|
|
||||||
|
|
||||||
LOG_DEBUG("Received url buf size: 0x%x\n", size);
|
m_clientSocket = accept(m_serverSocket, (struct sockaddr*)&client, &clientLen);
|
||||||
|
|
||||||
if (size > MAX_URL_SIZE * MAX_URLS)
|
if (m_clientSocket >= 0)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("URL size %x is too large!\n", size);
|
LOG_DEBUG("%s\n", "Server accepted");
|
||||||
}
|
u32 size = 0;
|
||||||
|
tin::network::WaitReceiveNetworkData(m_clientSocket, &size, sizeof(u32));
|
||||||
|
size = ntohl(size);
|
||||||
|
|
||||||
// Make sure the last string is null terminated
|
LOG_DEBUG("Received url buf size: 0x%x\n", size);
|
||||||
auto urlBuf = std::make_unique<char[]>(size+1);
|
|
||||||
memset(urlBuf.get(), 0, size+1);
|
|
||||||
|
|
||||||
tin::network::WaitReceiveNetworkData(m_clientSocket, urlBuf.get(), size);
|
if (size > MAX_URL_SIZE * MAX_URLS)
|
||||||
|
{
|
||||||
|
THROW_FORMAT("URL size %x is too large!\n", size);
|
||||||
|
}
|
||||||
|
|
||||||
// Split the string up into individual URLs
|
// Make sure the last string is null terminated
|
||||||
std::stringstream urlStream(urlBuf.get());
|
auto urlBuf = std::make_unique<char[]>(size + 1);
|
||||||
std::string segment;
|
memset(urlBuf.get(), 0, size + 1);
|
||||||
|
|
||||||
while (std::getline(urlStream, segment, '\n')) urls.push_back(segment);
|
tin::network::WaitReceiveNetworkData(m_clientSocket, urlBuf.get(), size);
|
||||||
std::sort(urls.begin(), urls.end(), inst::util::ignoreCaseCompare);
|
|
||||||
|
|
||||||
break;
|
// Split the string up into individual URLs
|
||||||
}
|
std::stringstream urlStream(urlBuf.get());
|
||||||
else if (errno != EAGAIN)
|
std::string segment;
|
||||||
{
|
|
||||||
THROW_FORMAT("Failed to open client socket with code %u\n", errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return urls;
|
while (std::getline(urlStream, segment, '\n')) urls.push_back(segment);
|
||||||
|
std::sort(urls.begin(), urls.end(), inst::util::ignoreCaseCompare);
|
||||||
|
|
||||||
}
|
break;
|
||||||
catch (std::runtime_error& e)
|
}
|
||||||
{
|
else if (errno != EAGAIN)
|
||||||
LOG_DEBUG("Failed to perform remote install!\n");
|
{
|
||||||
LOG_DEBUG("%s", e.what());
|
THROW_FORMAT("Failed to open client socket with code %u\n", errno);
|
||||||
fprintf(stdout, "%s", e.what());
|
}
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.net.failed"_lang, (std::string)e.what(), {"common.ok"_lang}, true);
|
}
|
||||||
return {};
|
|
||||||
}
|
return urls;
|
||||||
}
|
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& e)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Failed to perform remote install!\n");
|
||||||
|
LOG_DEBUG("%s", e.what());
|
||||||
|
fprintf(stdout, "%s", e.what());
|
||||||
|
inst::ui::mainApp->CreateShowDialog("inst.net.failed"_lang, (std::string)e.what(), { "common.ok"_lang }, true);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,22 +29,22 @@ SOFTWARE.
|
|||||||
static Service g_esSrv;
|
static Service g_esSrv;
|
||||||
|
|
||||||
Result esInitialize(void) {
|
Result esInitialize(void) {
|
||||||
return smGetService(&g_esSrv, "es");
|
return smGetService(&g_esSrv, "es");
|
||||||
}
|
}
|
||||||
|
|
||||||
void esExit(void) {
|
void esExit(void) {
|
||||||
serviceClose(&g_esSrv);
|
serviceClose(&g_esSrv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize) {
|
Result esImportTicket(void const* tikBuf, size_t tikSize, void const* certBuf, size_t certSize) {
|
||||||
return serviceDispatch(&g_esSrv, 1,
|
return serviceDispatch(&g_esSrv, 1,
|
||||||
.buffer_attrs = {
|
.buffer_attrs = {
|
||||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||||
},
|
},
|
||||||
.buffers = {
|
.buffers = {
|
||||||
{ tikBuf, tikSize },
|
{ tikBuf, tikSize },
|
||||||
{ certBuf, certSize },
|
{ certBuf, certSize },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -27,33 +27,34 @@ SOFTWARE.
|
|||||||
Service g_nsAppManSrv;
|
Service g_nsAppManSrv;
|
||||||
|
|
||||||
Result nsextInitialize(void) {
|
Result nsextInitialize(void) {
|
||||||
Result rc = nsInitialize();
|
Result rc = nsInitialize();
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
if(hosversionBefore(3,0,0)) {
|
if (hosversionBefore(3, 0, 0)) {
|
||||||
g_nsAppManSrv = *nsGetServiceSession_ApplicationManagerInterface();
|
g_nsAppManSrv = *nsGetServiceSession_ApplicationManagerInterface();
|
||||||
} else {
|
}
|
||||||
rc = nsGetApplicationManagerInterface(&g_nsAppManSrv);
|
else {
|
||||||
}
|
rc = nsGetApplicationManagerInterface(&g_nsAppManSrv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsextExit(void) {
|
void nsextExit(void) {
|
||||||
if(hosversionAtLeast(3,0,0))
|
if (hosversionAtLeast(3, 0, 0))
|
||||||
serviceClose(&g_nsAppManSrv);
|
serviceClose(&g_nsAppManSrv);
|
||||||
nsExit();
|
nsExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsPushApplicationRecord(u64 application_id, NsApplicationRecordType last_modified_event, ContentStorageRecord *content_records, u32 count) {
|
Result nsPushApplicationRecord(u64 application_id, NsApplicationRecordType last_modified_event, ContentStorageRecord* content_records, u32 count) {
|
||||||
struct {
|
struct {
|
||||||
u8 last_modified_event;
|
u8 last_modified_event;
|
||||||
u64 application_id;
|
u64 application_id;
|
||||||
} in = { last_modified_event, application_id };
|
} in = { last_modified_event, application_id };
|
||||||
|
|
||||||
return serviceDispatchIn(&g_nsAppManSrv, 16, in,
|
return serviceDispatchIn(&g_nsAppManSrv, 16, in,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
||||||
.buffers = { { content_records, count * sizeof(*content_records) }
|
.buffers = { { content_records, count * sizeof(*content_records) }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -42,107 +42,113 @@ SOFTWARE.
|
|||||||
#include "ui/instPage.hpp"
|
#include "ui/instPage.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace nspInstStuff {
|
namespace nspInstStuff {
|
||||||
|
|
||||||
void installNspFromFile(std::vector<std::filesystem::path> ourTitleList, int whereToInstall)
|
void installNspFromFile(std::vector<std::filesystem::path> ourTitleList, int whereToInstall)
|
||||||
{
|
{
|
||||||
inst::util::initInstallServices();
|
inst::util::initInstallServices();
|
||||||
inst::ui::instPage::loadInstallScreen();
|
inst::ui::instPage::loadInstallScreen();
|
||||||
bool nspInstalled = true;
|
bool nspInstalled = true;
|
||||||
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
||||||
|
|
||||||
if (whereToInstall) m_destStorageId = NcmStorageId_BuiltInUser;
|
if (whereToInstall) m_destStorageId = NcmStorageId_BuiltInUser;
|
||||||
unsigned int titleItr;
|
unsigned int titleItr;
|
||||||
|
|
||||||
std::vector<int> previousClockValues;
|
std::vector<int> previousClockValues;
|
||||||
if (inst::config::overClock) {
|
if (inst::config::overClock) {
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (titleItr = 0; titleItr < ourTitleList.size(); titleItr++) {
|
for (titleItr = 0; titleItr < ourTitleList.size(); titleItr++) {
|
||||||
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 40, true) + "inst.sd.source_string"_lang);
|
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 40, true) + "inst.sd.source_string"_lang);
|
||||||
std::unique_ptr<tin::install::Install> installTask;
|
std::unique_ptr<tin::install::Install> installTask;
|
||||||
|
|
||||||
if (ourTitleList[titleItr].extension() == ".xci" || ourTitleList[titleItr].extension() == ".xcz") {
|
if (ourTitleList[titleItr].extension() == ".xci" || ourTitleList[titleItr].extension() == ".xcz") {
|
||||||
auto sdmcXCI = std::make_shared<tin::install::xci::SDMCXCI>(ourTitleList[titleItr]);
|
auto sdmcXCI = std::make_shared<tin::install::xci::SDMCXCI>(ourTitleList[titleItr]);
|
||||||
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, sdmcXCI);
|
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, sdmcXCI);
|
||||||
} else {
|
}
|
||||||
auto sdmcNSP = std::make_shared<tin::install::nsp::SDMCNSP>(ourTitleList[titleItr]);
|
else {
|
||||||
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, sdmcNSP);
|
auto sdmcNSP = std::make_shared<tin::install::nsp::SDMCNSP>(ourTitleList[titleItr]);
|
||||||
}
|
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, sdmcNSP);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("%s\n", "Preparing installation");
|
LOG_DEBUG("%s\n", "Preparing installation");
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
installTask->Prepare();
|
installTask->Prepare();
|
||||||
installTask->Begin();
|
installTask->Begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Failed to install");
|
LOG_DEBUG("Failed to install");
|
||||||
LOG_DEBUG("%s", e.what());
|
LOG_DEBUG("%s", e.what());
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true));
|
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true));
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
std::string audioPath = "romfs:/audio/bark.wav";
|
std::string audioPath = "romfs:/audio/bark.wav";
|
||||||
if (inst::config::gayMode) audioPath = "";
|
if (inst::config::gayMode) audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true) + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + inst::util::shortenString(ourTitleList[titleItr].filename().string(), 42, true) + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), { "common.ok"_lang }, true);
|
||||||
audioThread.join();
|
audioThread.join();
|
||||||
nspInstalled = false;
|
nspInstalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousClockValues.size() > 0) {
|
if (previousClockValues.size() > 0) {
|
||||||
inst::util::setClockSpeed(0, previousClockValues[0]);
|
inst::util::setClockSpeed(0, previousClockValues[0]);
|
||||||
inst::util::setClockSpeed(1, previousClockValues[1]);
|
inst::util::setClockSpeed(1, previousClockValues[1]);
|
||||||
inst::util::setClockSpeed(2, previousClockValues[2]);
|
inst::util::setClockSpeed(2, previousClockValues[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nspInstalled) {
|
if (nspInstalled) {
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
std::string audioPath = "romfs:/audio/awoo.wav";
|
std::string audioPath = "romfs:/audio/awoo.wav";
|
||||||
if (inst::config::gayMode) audioPath = "";
|
if (inst::config::gayMode) audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/awoo.wav")) audioPath = inst::config::appDir + "/awoo.wav";
|
if (std::filesystem::exists(inst::config::appDir + "/awoo.wav")) audioPath = inst::config::appDir + "/awoo.wav";
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
if (ourTitleList.size() > 1) {
|
if (ourTitleList.size() > 1) {
|
||||||
if (inst::config::deletePrompt) {
|
if (inst::config::deletePrompt) {
|
||||||
if(inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.sd.delete_info_multi"_lang, "inst.sd.delete_desc"_lang, {"common.no"_lang,"common.yes"_lang}, false) == 1) {
|
if (inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.sd.delete_info_multi"_lang, "inst.sd.delete_desc"_lang, { "common.no"_lang,"common.yes"_lang }, false) == 1) {
|
||||||
for (long unsigned int i = 0; i < ourTitleList.size(); i++) {
|
for (long unsigned int i = 0; i < ourTitleList.size(); i++) {
|
||||||
if (std::filesystem::exists(ourTitleList[i])) {
|
if (std::filesystem::exists(ourTitleList[i])) {
|
||||||
try {
|
try {
|
||||||
std::filesystem::remove(ourTitleList[i]);
|
std::filesystem::remove(ourTitleList[i]);
|
||||||
} catch (...){ };
|
}
|
||||||
}
|
catch (...) {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
}
|
||||||
} else {
|
}
|
||||||
if (inst::config::deletePrompt) {
|
else inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
if(inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 32, true) + "inst.sd.delete_info"_lang, "inst.sd.delete_desc"_lang, {"common.no"_lang,"common.yes"_lang}, false) == 1) {
|
}
|
||||||
if (std::filesystem::exists(ourTitleList[0])) {
|
else {
|
||||||
try {
|
if (inst::config::deletePrompt) {
|
||||||
std::filesystem::remove(ourTitleList[0]);
|
if (inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 32, true) + "inst.sd.delete_info"_lang, "inst.sd.delete_desc"_lang, { "common.no"_lang,"common.yes"_lang }, false) == 1) {
|
||||||
} catch (...){ };
|
if (std::filesystem::exists(ourTitleList[0])) {
|
||||||
}
|
try {
|
||||||
}
|
std::filesystem::remove(ourTitleList[0]);
|
||||||
} else inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 42, true) + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
}
|
||||||
}
|
catch (...) {};
|
||||||
audioThread.join();
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else inst::ui::mainApp->CreateShowDialog(inst::util::shortenString(ourTitleList[0].filename().string(), 42, true) + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
|
}
|
||||||
|
audioThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Done");
|
LOG_DEBUG("Done");
|
||||||
inst::ui::instPage::loadMainMenu();
|
inst::ui::instPage::loadMainMenu();
|
||||||
inst::util::deinitInstallServices();
|
inst::util::deinitInstallServices();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,66 +8,69 @@
|
|||||||
#include "util/lang.hpp"
|
#include "util/lang.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace sig {
|
namespace sig {
|
||||||
void installSigPatches () {
|
void installSigPatches() {
|
||||||
bpcInitialize();
|
bpcInitialize();
|
||||||
try {
|
try {
|
||||||
std::string patchesVersion = inst::util::readTextFromFile("sdmc:/atmosphere/exefs_patches/es_patches/patches.txt");
|
std::string patchesVersion = inst::util::readTextFromFile("sdmc:/atmosphere/exefs_patches/es_patches/patches.txt");
|
||||||
std::string versionText = "";
|
std::string versionText = "";
|
||||||
std::string installButtonText = "sig.install"_lang;
|
std::string installButtonText = "sig.install"_lang;
|
||||||
if (patchesVersion != "") {
|
if (patchesVersion != "") {
|
||||||
versionText = "\n\n" + "sig.version_text"_lang + patchesVersion + ".";
|
versionText = "\n\n" + "sig.version_text"_lang + patchesVersion + ".";
|
||||||
installButtonText = "sig.update"_lang;
|
installButtonText = "sig.update"_lang;
|
||||||
}
|
}
|
||||||
int ourResult = inst::ui::mainApp->CreateShowDialog("sig.title0"_lang, "sig.desc0"_lang + versionText, {installButtonText, "sig.uninstall"_lang, "common.cancel"_lang}, true);
|
int ourResult = inst::ui::mainApp->CreateShowDialog("sig.title0"_lang, "sig.desc0"_lang + versionText, { installButtonText, "sig.uninstall"_lang, "common.cancel"_lang }, true);
|
||||||
if (ourResult == 0) {
|
if (ourResult == 0) {
|
||||||
if (inst::util::getIPAddress() == "1.0.0.127") {
|
if (inst::util::getIPAddress() == "1.0.0.127") {
|
||||||
inst::ui::mainApp->CreateShowDialog("main.net.title"_lang, "main.net.desc"_lang, {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("main.net.title"_lang, "main.net.desc"_lang, { "common.ok"_lang }, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!inst::util::copyFile("sdmc:/bootloader/patches.ini", inst::config::appDir + "/patches.ini.old")) {
|
if (!inst::util::copyFile("sdmc:/bootloader/patches.ini", inst::config::appDir + "/patches.ini.old")) {
|
||||||
if (inst::ui::mainApp->CreateShowDialog("sig.backup_failed"_lang, "sig.backup_failed_desc"_lang, {"common.yes"_lang, "common.no"_lang}, false)) return;
|
if (inst::ui::mainApp->CreateShowDialog("sig.backup_failed"_lang, "sig.backup_failed_desc"_lang, { "common.yes"_lang, "common.no"_lang }, false)) return;
|
||||||
}
|
}
|
||||||
std::string ourPath = inst::config::appDir + "/patches.zip";
|
std::string ourPath = inst::config::appDir + "/patches.zip";
|
||||||
bool didDownload = inst::curl::downloadFile(inst::config::sigPatchesUrl, ourPath.c_str());
|
bool didDownload = inst::curl::downloadFile(inst::config::sigPatchesUrl, ourPath.c_str());
|
||||||
bool didExtract = false;
|
bool didExtract = false;
|
||||||
if (didDownload) didExtract = inst::zip::extractFile(ourPath, "sdmc:/");
|
if (didDownload) didExtract = inst::zip::extractFile(ourPath, "sdmc:/");
|
||||||
else {
|
else {
|
||||||
inst::ui::mainApp->CreateShowDialog("sig.download_failed"_lang, "sig.download_failed_desc"_lang, {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("sig.download_failed"_lang, "sig.download_failed_desc"_lang, { "common.ok"_lang }, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::filesystem::remove(ourPath);
|
std::filesystem::remove(ourPath);
|
||||||
if (didExtract) {
|
if (didExtract) {
|
||||||
patchesVersion = inst::util::readTextFromFile("sdmc:/atmosphere/exefs_patches/es_patches/patches.txt");
|
patchesVersion = inst::util::readTextFromFile("sdmc:/atmosphere/exefs_patches/es_patches/patches.txt");
|
||||||
versionText = "";
|
versionText = "";
|
||||||
if (patchesVersion != "") versionText = "sig.version_text2"_lang + patchesVersion + "! ";
|
if (patchesVersion != "") versionText = "sig.version_text2"_lang + patchesVersion + "! ";
|
||||||
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();
|
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();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
inst::ui::mainApp->CreateShowDialog("sig.extract_failed"_lang, "", {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("sig.extract_failed"_lang, "", { "common.ok"_lang }, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (ourResult == 1) {
|
}
|
||||||
if (!inst::util::copyFile( inst::config::appDir + "/patches.ini.old", "sdmc:/bootloader/patches.ini")) {
|
else if (ourResult == 1) {
|
||||||
if (inst::ui::mainApp->CreateShowDialog("sig.restore_failed"_lang, "", {"common.yes"_lang, "common.no"_lang}, false)) return;
|
if (!inst::util::copyFile(inst::config::appDir + "/patches.ini.old", "sdmc:/bootloader/patches.ini")) {
|
||||||
} else std::filesystem::remove(inst::config::appDir + "/patches.ini.old");
|
if (inst::ui::mainApp->CreateShowDialog("sig.restore_failed"_lang, "", { "common.yes"_lang, "common.no"_lang }, false)) return;
|
||||||
if (inst::util::removeDirectory("sdmc:/atmosphere/exefs_patches/es_patches")) {
|
}
|
||||||
if (inst::ui::mainApp->CreateShowDialog("sig.uninstall_complete"_lang, "sig.complete_desc"_lang, {"sig.restart"_lang, "sig.later"_lang}, false) == 0) bpcRebootSystem();
|
else std::filesystem::remove(inst::config::appDir + "/patches.ini.old");
|
||||||
}
|
if (inst::util::removeDirectory("sdmc:/atmosphere/exefs_patches/es_patches")) {
|
||||||
else inst::ui::mainApp->CreateShowDialog("sig.remove_failed"_lang, "sig.remove_failed_desc"_lang, {"common.ok"_lang}, true);
|
if (inst::ui::mainApp->CreateShowDialog("sig.uninstall_complete"_lang, "sig.complete_desc"_lang, { "sig.restart"_lang, "sig.later"_lang }, false) == 0) bpcRebootSystem();
|
||||||
} else return;
|
}
|
||||||
}
|
else inst::ui::mainApp->CreateShowDialog("sig.remove_failed"_lang, "sig.remove_failed_desc"_lang, { "common.ok"_lang }, true);
|
||||||
catch (std::exception& e)
|
}
|
||||||
{
|
else return;
|
||||||
LOG_DEBUG("Failed to install Signature Patches");
|
}
|
||||||
LOG_DEBUG("%s", e.what());
|
catch (std::exception& e)
|
||||||
fprintf(stdout, "%s", e.what());
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("sig.generic_error"_lang, (std::string)e.what(), {"common.ok"_lang}, true);
|
LOG_DEBUG("Failed to install Signature Patches");
|
||||||
}
|
LOG_DEBUG("%s", e.what());
|
||||||
bpcExit();
|
fprintf(stdout, "%s", e.what());
|
||||||
}
|
inst::ui::mainApp->CreateShowDialog("sig.generic_error"_lang, (std::string)e.what(), { "common.ok"_lang }, true);
|
||||||
|
}
|
||||||
|
bpcExit();
|
||||||
|
}
|
||||||
}
|
}
|
@ -10,156 +10,160 @@
|
|||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
|
|
||||||
HDInstPage::HDInstPage() : Layout::Layout() {
|
HDInstPage::HDInstPage() : Layout::Layout() {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
||||||
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
||||||
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
||||||
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
||||||
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
||||||
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
||||||
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->pageInfoText = TextBlock::New(10, 109, "");
|
this->pageInfoText = TextBlock::New(10, 109, "");
|
||||||
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->butText = TextBlock::New(10, 678, "inst.hd.buttons"_lang);
|
this->butText = TextBlock::New(10, 678, "inst.hd.buttons"_lang);
|
||||||
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
||||||
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
||||||
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
||||||
this->Add(this->topRect);
|
this->Add(this->topRect);
|
||||||
this->Add(this->infoRect);
|
this->Add(this->infoRect);
|
||||||
this->Add(this->botRect);
|
this->Add(this->botRect);
|
||||||
this->Add(this->titleImage);
|
this->Add(this->titleImage);
|
||||||
this->Add(this->appVersionText);
|
this->Add(this->appVersionText);
|
||||||
this->Add(this->butText);
|
this->Add(this->butText);
|
||||||
this->Add(this->pageInfoText);
|
this->Add(this->pageInfoText);
|
||||||
this->Add(this->menu);
|
this->Add(this->menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HDInstPage::drawMenuItems(bool clearItems, std::filesystem::path ourPath) {
|
void HDInstPage::drawMenuItems(bool clearItems, std::filesystem::path ourPath) {
|
||||||
if (clearItems) this->selectedTitles = {};
|
if (clearItems) this->selectedTitles = {};
|
||||||
this->currentDir = ourPath;
|
this->currentDir = ourPath;
|
||||||
|
|
||||||
auto pathStr = this->currentDir.string();
|
auto pathStr = this->currentDir.string();
|
||||||
if(pathStr.length())
|
if (pathStr.length())
|
||||||
{
|
{
|
||||||
if(pathStr[pathStr.length() - 1] == ':')
|
if (pathStr[pathStr.length() - 1] == ':')
|
||||||
{
|
{
|
||||||
this->currentDir = this->currentDir / "";
|
this->currentDir = this->currentDir / "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->menu->ClearItems();
|
this->menu->ClearItems();
|
||||||
try {
|
try {
|
||||||
this->ourDirectories = util::getDirsAtPath(this->currentDir);
|
this->ourDirectories = util::getDirsAtPath(this->currentDir);
|
||||||
this->ourFiles = util::getDirectoryFiles(this->currentDir, {".nsp", ".nsz", ".xci", ".xcz"});
|
this->ourFiles = util::getDirectoryFiles(this->currentDir, { ".nsp", ".nsz", ".xci", ".xcz" });
|
||||||
} catch (std::exception& e) {
|
}
|
||||||
this->drawMenuItems(false, this->currentDir.parent_path());
|
catch (std::exception& e) {
|
||||||
return;
|
this->drawMenuItems(false, this->currentDir.parent_path());
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string itm = "..";
|
std::string itm = "..";
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
ourEntry->SetIcon("romfs:/images/icons/folder-upload.png");
|
ourEntry->SetIcon("romfs:/images/icons/folder-upload.png");
|
||||||
this->menu->AddItem(ourEntry);
|
this->menu->AddItem(ourEntry);
|
||||||
|
|
||||||
for (auto& file: this->ourDirectories) {
|
for (auto& file : this->ourDirectories) {
|
||||||
if (file == "..") break;
|
if (file == "..") break;
|
||||||
std::string itm = file.filename().string();
|
std::string itm = file.filename().string();
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
ourEntry->SetIcon("romfs:/images/icons/folder.png");
|
ourEntry->SetIcon("romfs:/images/icons/folder.png");
|
||||||
this->menu->AddItem(ourEntry);
|
this->menu->AddItem(ourEntry);
|
||||||
}
|
}
|
||||||
for (auto& file: this->ourFiles) {
|
for (auto& file : this->ourFiles) {
|
||||||
std::string itm = file.filename().string();
|
std::string itm = file.filename().string();
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
||||||
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
||||||
if (this->selectedTitles[i] == file) {
|
if (this->selectedTitles[i] == file) {
|
||||||
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->menu->AddItem(ourEntry);
|
this->menu->AddItem(ourEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HDInstPage::followDirectory() {
|
void HDInstPage::followDirectory() {
|
||||||
int selectedIndex = this->menu->GetSelectedIndex();
|
int selectedIndex = this->menu->GetSelectedIndex();
|
||||||
int dirListSize = this->ourDirectories.size();
|
int dirListSize = this->ourDirectories.size();
|
||||||
|
|
||||||
dirListSize++;
|
dirListSize++;
|
||||||
selectedIndex--;
|
selectedIndex--;
|
||||||
|
|
||||||
if (selectedIndex < dirListSize) {
|
if (selectedIndex < dirListSize) {
|
||||||
if (this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetName() == ".." && this->menu->GetSelectedIndex() == 0) {
|
if (this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetName() == ".." && this->menu->GetSelectedIndex() == 0) {
|
||||||
this->drawMenuItems(true, this->currentDir.parent_path());
|
this->drawMenuItems(true, this->currentDir.parent_path());
|
||||||
} else {
|
}
|
||||||
this->drawMenuItems(true, this->ourDirectories[selectedIndex]);
|
else {
|
||||||
}
|
this->drawMenuItems(true, this->ourDirectories[selectedIndex]);
|
||||||
this->menu->SetSelectedIndex(0);
|
}
|
||||||
}
|
this->menu->SetSelectedIndex(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HDInstPage::selectNsp(int selectedIndex) {
|
void HDInstPage::selectNsp(int selectedIndex) {
|
||||||
int dirListSize = this->ourDirectories.size();
|
int dirListSize = this->ourDirectories.size();
|
||||||
dirListSize++;
|
dirListSize++;
|
||||||
|
|
||||||
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
||||||
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
||||||
if (this->selectedTitles[i] == this->ourFiles[selectedIndex - dirListSize]) this->selectedTitles.erase(this->selectedTitles.begin() + i);
|
if (this->selectedTitles[i] == this->ourFiles[selectedIndex - dirListSize]) this->selectedTitles.erase(this->selectedTitles.begin() + i);
|
||||||
}
|
}
|
||||||
} else if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") this->selectedTitles.push_back(this->ourFiles[selectedIndex - dirListSize]);
|
}
|
||||||
else {
|
else if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") this->selectedTitles.push_back(this->ourFiles[selectedIndex - dirListSize]);
|
||||||
this->followDirectory();
|
else {
|
||||||
return;
|
this->followDirectory();
|
||||||
}
|
return;
|
||||||
this->drawMenuItems(false, currentDir);
|
}
|
||||||
}
|
this->drawMenuItems(false, currentDir);
|
||||||
|
}
|
||||||
|
|
||||||
void HDInstPage::startInstall() {
|
void HDInstPage::startInstall() {
|
||||||
int dialogResult = -1;
|
int dialogResult = -1;
|
||||||
if (this->selectedTitles.size() == 1) {
|
if (this->selectedTitles.size() == 1) {
|
||||||
dialogResult = mainApp->CreateShowDialog("inst.target.desc0"_lang + inst::util::shortenString(std::filesystem::path(this->selectedTitles[0]).filename().string(), 32, true) + "inst.target.desc1"_lang, "common.cancel_desc"_lang, {"inst.target.opt0"_lang, "inst.target.opt1"_lang}, false);
|
dialogResult = mainApp->CreateShowDialog("inst.target.desc0"_lang + inst::util::shortenString(std::filesystem::path(this->selectedTitles[0]).filename().string(), 32, true) + "inst.target.desc1"_lang, "common.cancel_desc"_lang, { "inst.target.opt0"_lang, "inst.target.opt1"_lang }, false);
|
||||||
} 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);
|
}
|
||||||
if (dialogResult == -1) return;
|
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);
|
||||||
nspInstStuff_B::installNspFromFile(this->selectedTitles, dialogResult);
|
if (dialogResult == -1) return;
|
||||||
}
|
nspInstStuff_B::installNspFromFile(this->selectedTitles, dialogResult);
|
||||||
|
}
|
||||||
|
|
||||||
void HDInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void HDInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
if (Down & HidNpadButton_B) {
|
if (Down & HidNpadButton_B) {
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_A)) {
|
if ((Down & HidNpadButton_A)) {
|
||||||
this->selectNsp(this->menu->GetSelectedIndex());
|
this->selectNsp(this->menu->GetSelectedIndex());
|
||||||
if (this->ourFiles.size() == 1 && this->selectedTitles.size() == 1) {
|
if (this->ourFiles.size() == 1 && this->selectedTitles.size() == 1) {
|
||||||
this->startInstall();
|
this->startInstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_Y)) {
|
if ((Down & HidNpadButton_Y)) {
|
||||||
if (this->selectedTitles.size() == this->ourFiles.size()) this->drawMenuItems(true, currentDir);
|
if (this->selectedTitles.size() == this->ourFiles.size()) this->drawMenuItems(true, currentDir);
|
||||||
else {
|
else {
|
||||||
int topDir = 0;
|
int topDir = 0;
|
||||||
topDir++;
|
topDir++;
|
||||||
for (long unsigned int i = this->ourDirectories.size() + topDir; i < this->menu->GetItems().size(); i++) {
|
for (long unsigned int i = this->ourDirectories.size() + topDir; i < this->menu->GetItems().size(); i++) {
|
||||||
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
||||||
else this->selectNsp(i);
|
else this->selectNsp(i);
|
||||||
}
|
}
|
||||||
this->drawMenuItems(false, currentDir);
|
this->drawMenuItems(false, currentDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_X)) {
|
if ((Down & HidNpadButton_X)) {
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.hd.help.title"_lang, "inst.hd.help.desc"_lang, {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("inst.hd.help.title"_lang, "inst.hd.help.desc"_lang, { "common.ok"_lang }, true);
|
||||||
}
|
}
|
||||||
if (Down & HidNpadButton_Plus) {
|
if (Down & HidNpadButton_Plus) {
|
||||||
if (this->selectedTitles.size() == 0 && this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") {
|
if (this->selectedTitles.size() == 0 && this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") {
|
||||||
this->selectNsp(this->menu->GetSelectedIndex());
|
this->selectNsp(this->menu->GetSelectedIndex());
|
||||||
}
|
}
|
||||||
if (this->selectedTitles.size() > 0) this->startInstall();
|
if (this->selectedTitles.size() > 0) this->startInstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,27 +2,27 @@
|
|||||||
#include "util/lang.hpp"
|
#include "util/lang.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
MainApplication *mainApp;
|
MainApplication* mainApp;
|
||||||
|
|
||||||
void MainApplication::OnLoad() {
|
void MainApplication::OnLoad() {
|
||||||
mainApp = this;
|
mainApp = this;
|
||||||
|
|
||||||
Language::Load();
|
Language::Load();
|
||||||
|
|
||||||
this->mainPage = MainPage::New();
|
this->mainPage = MainPage::New();
|
||||||
this->netinstPage = netInstPage::New();
|
this->netinstPage = netInstPage::New();
|
||||||
this->sdinstPage = sdInstPage::New();
|
this->sdinstPage = sdInstPage::New();
|
||||||
this->HDinstPage = HDInstPage::New();
|
this->HDinstPage = HDInstPage::New();
|
||||||
this->usbinstPage = usbInstPage::New();
|
this->usbinstPage = usbInstPage::New();
|
||||||
this->instpage = instPage::New();
|
this->instpage = instPage::New();
|
||||||
this->optionspage = optionsPage::New();
|
this->optionspage = optionsPage::New();
|
||||||
this->mainPage->SetOnInput(std::bind(&MainPage::onInput, this->mainPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
this->mainPage->SetOnInput(std::bind(&MainPage::onInput, this->mainPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
this->netinstPage->SetOnInput(std::bind(&netInstPage::onInput, this->netinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
this->netinstPage->SetOnInput(std::bind(&netInstPage::onInput, this->netinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
this->sdinstPage->SetOnInput(std::bind(&sdInstPage::onInput, this->sdinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
this->sdinstPage->SetOnInput(std::bind(&sdInstPage::onInput, this->sdinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
this->HDinstPage->SetOnInput(std::bind(&HDInstPage::onInput, this->HDinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
this->HDinstPage->SetOnInput(std::bind(&HDInstPage::onInput, this->HDinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
this->usbinstPage->SetOnInput(std::bind(&usbInstPage::onInput, this->usbinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
this->usbinstPage->SetOnInput(std::bind(&usbInstPage::onInput, this->usbinstPage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
this->instpage->SetOnInput(std::bind(&instPage::onInput, this->instpage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
this->instpage->SetOnInput(std::bind(&instPage::onInput, this->instpage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
this->optionspage->SetOnInput(std::bind(&optionsPage::onInput, this->optionspage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
this->optionspage->SetOnInput(std::bind(&optionsPage::onInput, this->optionspage, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
this->LoadLayout(this->mainPage);
|
this->LoadLayout(this->mainPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,66 +6,66 @@
|
|||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
|
|
||||||
instPage::instPage() : Layout::Layout() {
|
instPage::instPage() : Layout::Layout() {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
||||||
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
||||||
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
||||||
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
||||||
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
||||||
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
||||||
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->pageInfoText = TextBlock::New(10, 109, "");
|
this->pageInfoText = TextBlock::New(10, 109, "");
|
||||||
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->installInfoText = TextBlock::New(15, 568, "");
|
this->installInfoText = TextBlock::New(15, 568, "");
|
||||||
this->installInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->installInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->installBar = pu::ui::elm::ProgressBar::New(10, 600, 850, 40, 100.0f);
|
this->installBar = pu::ui::elm::ProgressBar::New(10, 600, 850, 40, 100.0f);
|
||||||
this->installBar->SetColor(COLOR("#222222FF"));
|
this->installBar->SetColor(COLOR("#222222FF"));
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/awoo_inst.png")) this->awooImage = Image::New(410, 190, inst::config::appDir + "/awoo_inst.png");
|
if (std::filesystem::exists(inst::config::appDir + "/awoo_inst.png")) this->awooImage = Image::New(410, 190, inst::config::appDir + "/awoo_inst.png");
|
||||||
else this->awooImage = Image::New(510, 166, "romfs:/images/awoos/7d8a05cddfef6da4901b20d2698d5a71.png");
|
else this->awooImage = Image::New(510, 166, "romfs:/images/awoos/7d8a05cddfef6da4901b20d2698d5a71.png");
|
||||||
this->Add(this->topRect);
|
this->Add(this->topRect);
|
||||||
this->Add(this->infoRect);
|
this->Add(this->infoRect);
|
||||||
this->Add(this->titleImage);
|
this->Add(this->titleImage);
|
||||||
this->Add(this->appVersionText);
|
this->Add(this->appVersionText);
|
||||||
this->Add(this->pageInfoText);
|
this->Add(this->pageInfoText);
|
||||||
this->Add(this->installInfoText);
|
this->Add(this->installInfoText);
|
||||||
this->Add(this->installBar);
|
this->Add(this->installBar);
|
||||||
this->Add(this->awooImage);
|
this->Add(this->awooImage);
|
||||||
if (inst::config::gayMode) this->awooImage->SetVisible(false);
|
if (inst::config::gayMode) this->awooImage->SetVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instPage::setTopInstInfoText(std::string ourText){
|
void instPage::setTopInstInfoText(std::string ourText) {
|
||||||
mainApp->instpage->pageInfoText->SetText(ourText);
|
mainApp->instpage->pageInfoText->SetText(ourText);
|
||||||
mainApp->CallForRender();
|
mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
void instPage::setInstInfoText(std::string ourText){
|
void instPage::setInstInfoText(std::string ourText) {
|
||||||
mainApp->instpage->installInfoText->SetText(ourText);
|
mainApp->instpage->installInfoText->SetText(ourText);
|
||||||
mainApp->CallForRender();
|
mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
void instPage::setInstBarPerc(double ourPercent){
|
void instPage::setInstBarPerc(double ourPercent) {
|
||||||
mainApp->instpage->installBar->SetVisible(true);
|
mainApp->instpage->installBar->SetVisible(true);
|
||||||
mainApp->instpage->installBar->SetProgress(ourPercent);
|
mainApp->instpage->installBar->SetProgress(ourPercent);
|
||||||
mainApp->CallForRender();
|
mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
void instPage::loadMainMenu(){
|
void instPage::loadMainMenu() {
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instPage::loadInstallScreen(){
|
void instPage::loadInstallScreen() {
|
||||||
mainApp->instpage->pageInfoText->SetText("");
|
mainApp->instpage->pageInfoText->SetText("");
|
||||||
mainApp->instpage->installInfoText->SetText("");
|
mainApp->instpage->installInfoText->SetText("");
|
||||||
mainApp->instpage->installBar->SetProgress(0);
|
mainApp->instpage->installBar->SetProgress(0);
|
||||||
mainApp->instpage->installBar->SetVisible(false);
|
mainApp->instpage->installBar->SetVisible(false);
|
||||||
mainApp->instpage->awooImage->SetVisible(!inst::config::gayMode);
|
mainApp->instpage->awooImage->SetVisible(!inst::config::gayMode);
|
||||||
mainApp->LoadLayout(mainApp->instpage);
|
mainApp->LoadLayout(mainApp->instpage);
|
||||||
mainApp->CallForRender();
|
mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
void instPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void instPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,227 +14,229 @@
|
|||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
bool appletFinished = false;
|
bool appletFinished = false;
|
||||||
bool updateFinished = false;
|
bool updateFinished = false;
|
||||||
|
|
||||||
void mainMenuThread() {
|
|
||||||
bool menuLoaded = mainApp->IsShown();
|
|
||||||
if (!appletFinished && appletGetAppletType() == AppletType_LibraryApplet) {
|
|
||||||
tin::data::NUM_BUFFER_SEGMENTS = 2;
|
|
||||||
if (menuLoaded) {
|
|
||||||
inst::ui::appletFinished = true;
|
|
||||||
mainApp->CreateShowDialog("main.applet.title"_lang, "main.applet.desc"_lang, {"common.ok"_lang}, true);
|
|
||||||
}
|
|
||||||
} else if (!appletFinished) {
|
|
||||||
inst::ui::appletFinished = true;
|
|
||||||
tin::data::NUM_BUFFER_SEGMENTS = 128;
|
|
||||||
}
|
|
||||||
if (!updateFinished && (!inst::config::autoUpdate || inst::util::getIPAddress() == "1.0.0.127")) updateFinished = true;
|
|
||||||
if (!updateFinished && menuLoaded && inst::config::updateInfo.size()) {
|
|
||||||
updateFinished = true;
|
|
||||||
optionsPage::askToUpdate(inst::config::updateInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MainPage::MainPage() : Layout::Layout() {
|
void mainMenuThread() {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
bool menuLoaded = mainApp->IsShown();
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
if (!appletFinished && appletGetAppletType() == AppletType_LibraryApplet) {
|
||||||
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
tin::data::NUM_BUFFER_SEGMENTS = 2;
|
||||||
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
if (menuLoaded) {
|
||||||
this->botRect = Rectangle::New(0, 659, 1280, 61, COLOR("#17090980"));
|
inst::ui::appletFinished = true;
|
||||||
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
mainApp->CreateShowDialog("main.applet.title"_lang, "main.applet.desc"_lang, { "common.ok"_lang }, true);
|
||||||
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
}
|
||||||
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
}
|
||||||
this->butText = TextBlock::New(10, 678, "main.buttons"_lang);
|
else if (!appletFinished) {
|
||||||
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
inst::ui::appletFinished = true;
|
||||||
this->optionMenu = pu::ui::elm::Menu::New(0, 95, 1280, COLOR("#67000000"), 94, 6);
|
tin::data::NUM_BUFFER_SEGMENTS = 128;
|
||||||
this->optionMenu->SetOnFocusColor(COLOR("#00000033"));
|
}
|
||||||
this->optionMenu->SetScrollbarColor(COLOR("#170909FF"));
|
if (!updateFinished && (!inst::config::autoUpdate || inst::util::getIPAddress() == "1.0.0.127")) updateFinished = true;
|
||||||
this->installMenuItem = pu::ui::elm::MenuItem::New("main.menu.sd"_lang);
|
if (!updateFinished && menuLoaded && inst::config::updateInfo.size()) {
|
||||||
this->installMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
updateFinished = true;
|
||||||
this->installMenuItem->SetIcon("romfs:/images/icons/micro-sd.png");
|
optionsPage::askToUpdate(inst::config::updateInfo);
|
||||||
this->netInstallMenuItem = pu::ui::elm::MenuItem::New("main.menu.net"_lang);
|
}
|
||||||
this->netInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
}
|
||||||
this->netInstallMenuItem->SetIcon("romfs:/images/icons/cloud-download.png");
|
|
||||||
this->usbInstallMenuItem = pu::ui::elm::MenuItem::New("main.menu.usb"_lang);
|
|
||||||
this->usbInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
|
||||||
this->usbInstallMenuItem->SetIcon("romfs:/images/icons/usb-port.png");
|
|
||||||
this->hddInstallMenuItem = pu::ui::elm::MenuItem::New("main.menu.hdd"_lang);
|
|
||||||
this->hddInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
|
||||||
this->hddInstallMenuItem->SetIcon("romfs:/images/icons/usb-hd.png");
|
|
||||||
this->sigPatchesMenuItem = pu::ui::elm::MenuItem::New("main.menu.sig"_lang);
|
|
||||||
this->sigPatchesMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
|
||||||
this->sigPatchesMenuItem->SetIcon("romfs:/images/icons/wrench.png");
|
|
||||||
this->settingsMenuItem = pu::ui::elm::MenuItem::New("main.menu.set"_lang);
|
|
||||||
this->settingsMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
|
||||||
this->settingsMenuItem->SetIcon("romfs:/images/icons/settings.png");
|
|
||||||
this->exitMenuItem = pu::ui::elm::MenuItem::New("main.menu.exit"_lang);
|
|
||||||
this->exitMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
|
||||||
this->exitMenuItem->SetIcon("romfs:/images/icons/exit-run.png");
|
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/awoo_main.png")) this->awooImage = Image::New(410, 190, inst::config::appDir + "/awoo_main.png");
|
|
||||||
else this->awooImage = Image::New(410, 190, "romfs:/images/awoos/5bbdbcf9a5625cd307c9e9bc360d78bd.png");
|
|
||||||
this->Add(this->topRect);
|
|
||||||
this->Add(this->botRect);
|
|
||||||
this->Add(this->titleImage);
|
|
||||||
this->Add(this->appVersionText);
|
|
||||||
this->Add(this->butText);
|
|
||||||
this->optionMenu->AddItem(this->installMenuItem);
|
|
||||||
this->optionMenu->AddItem(this->netInstallMenuItem);
|
|
||||||
this->optionMenu->AddItem(this->usbInstallMenuItem);
|
|
||||||
this->optionMenu->AddItem(this->hddInstallMenuItem);
|
|
||||||
this->optionMenu->AddItem(this->settingsMenuItem);
|
|
||||||
this->optionMenu->AddItem(this->exitMenuItem);
|
|
||||||
this->Add(this->optionMenu);
|
|
||||||
this->Add(this->awooImage);
|
|
||||||
this->awooImage->SetVisible(!inst::config::gayMode);
|
|
||||||
this->AddThread(mainMenuThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainPage::installMenuItem_Click() {
|
MainPage::MainPage() : Layout::Layout() {
|
||||||
mainApp->sdinstPage->drawMenuItems(true, "sdmc:/");
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
mainApp->sdinstPage->menu->SetSelectedIndex(0);
|
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
||||||
mainApp->LoadLayout(mainApp->sdinstPage);
|
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
||||||
}
|
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
||||||
|
this->botRect = Rectangle::New(0, 659, 1280, 61, COLOR("#17090980"));
|
||||||
|
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
||||||
|
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
||||||
|
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->butText = TextBlock::New(10, 678, "main.buttons"_lang);
|
||||||
|
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->optionMenu = pu::ui::elm::Menu::New(0, 95, 1280, COLOR("#67000000"), 94, 6);
|
||||||
|
this->optionMenu->SetOnFocusColor(COLOR("#00000033"));
|
||||||
|
this->optionMenu->SetScrollbarColor(COLOR("#170909FF"));
|
||||||
|
this->installMenuItem = pu::ui::elm::MenuItem::New("main.menu.sd"_lang);
|
||||||
|
this->installMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->installMenuItem->SetIcon("romfs:/images/icons/micro-sd.png");
|
||||||
|
this->netInstallMenuItem = pu::ui::elm::MenuItem::New("main.menu.net"_lang);
|
||||||
|
this->netInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->netInstallMenuItem->SetIcon("romfs:/images/icons/cloud-download.png");
|
||||||
|
this->usbInstallMenuItem = pu::ui::elm::MenuItem::New("main.menu.usb"_lang);
|
||||||
|
this->usbInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->usbInstallMenuItem->SetIcon("romfs:/images/icons/usb-port.png");
|
||||||
|
this->hddInstallMenuItem = pu::ui::elm::MenuItem::New("main.menu.hdd"_lang);
|
||||||
|
this->hddInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->hddInstallMenuItem->SetIcon("romfs:/images/icons/usb-hd.png");
|
||||||
|
this->sigPatchesMenuItem = pu::ui::elm::MenuItem::New("main.menu.sig"_lang);
|
||||||
|
this->sigPatchesMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->sigPatchesMenuItem->SetIcon("romfs:/images/icons/wrench.png");
|
||||||
|
this->settingsMenuItem = pu::ui::elm::MenuItem::New("main.menu.set"_lang);
|
||||||
|
this->settingsMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->settingsMenuItem->SetIcon("romfs:/images/icons/settings.png");
|
||||||
|
this->exitMenuItem = pu::ui::elm::MenuItem::New("main.menu.exit"_lang);
|
||||||
|
this->exitMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->exitMenuItem->SetIcon("romfs:/images/icons/exit-run.png");
|
||||||
|
if (std::filesystem::exists(inst::config::appDir + "/awoo_main.png")) this->awooImage = Image::New(410, 190, inst::config::appDir + "/awoo_main.png");
|
||||||
|
else this->awooImage = Image::New(410, 190, "romfs:/images/awoos/5bbdbcf9a5625cd307c9e9bc360d78bd.png");
|
||||||
|
this->Add(this->topRect);
|
||||||
|
this->Add(this->botRect);
|
||||||
|
this->Add(this->titleImage);
|
||||||
|
this->Add(this->appVersionText);
|
||||||
|
this->Add(this->butText);
|
||||||
|
this->optionMenu->AddItem(this->installMenuItem);
|
||||||
|
this->optionMenu->AddItem(this->netInstallMenuItem);
|
||||||
|
this->optionMenu->AddItem(this->usbInstallMenuItem);
|
||||||
|
this->optionMenu->AddItem(this->hddInstallMenuItem);
|
||||||
|
this->optionMenu->AddItem(this->settingsMenuItem);
|
||||||
|
this->optionMenu->AddItem(this->exitMenuItem);
|
||||||
|
this->Add(this->optionMenu);
|
||||||
|
this->Add(this->awooImage);
|
||||||
|
this->awooImage->SetVisible(!inst::config::gayMode);
|
||||||
|
this->AddThread(mainMenuThread);
|
||||||
|
}
|
||||||
|
|
||||||
void MainPage::netInstallMenuItem_Click() {
|
void MainPage::installMenuItem_Click() {
|
||||||
if (inst::util::getIPAddress() == "1.0.0.127") {
|
mainApp->sdinstPage->drawMenuItems(true, "sdmc:/");
|
||||||
inst::ui::mainApp->CreateShowDialog("main.net.title"_lang, "main.net.desc"_lang, {"common.ok"_lang}, true);
|
mainApp->sdinstPage->menu->SetSelectedIndex(0);
|
||||||
return;
|
mainApp->LoadLayout(mainApp->sdinstPage);
|
||||||
}
|
}
|
||||||
mainApp->netinstPage->startNetwork();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainPage::usbInstallMenuItem_Click() {
|
void MainPage::netInstallMenuItem_Click() {
|
||||||
if (!inst::config::usbAck) {
|
if (inst::util::getIPAddress() == "1.0.0.127") {
|
||||||
if (mainApp->CreateShowDialog("main.usb.warn.title"_lang, "main.usb.warn.desc"_lang, {"common.ok"_lang, "main.usb.warn.opt1"_lang}, false) == 1) {
|
inst::ui::mainApp->CreateShowDialog("main.net.title"_lang, "main.net.desc"_lang, { "common.ok"_lang }, true);
|
||||||
inst::config::usbAck = true;
|
return;
|
||||||
inst::config::setConfig();
|
}
|
||||||
}
|
mainApp->netinstPage->startNetwork();
|
||||||
}
|
}
|
||||||
if (inst::util::usbIsConnected()) mainApp->usbinstPage->startUsb();
|
|
||||||
else mainApp->CreateShowDialog("main.usb.error.title"_lang, "main.usb.error.desc"_lang, {"common.ok"_lang}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainPage::sigPatchesMenuItem_Click() {
|
void MainPage::usbInstallMenuItem_Click() {
|
||||||
sig::installSigPatches();
|
if (!inst::config::usbAck) {
|
||||||
}
|
if (mainApp->CreateShowDialog("main.usb.warn.title"_lang, "main.usb.warn.desc"_lang, { "common.ok"_lang, "main.usb.warn.opt1"_lang }, false) == 1) {
|
||||||
|
inst::config::usbAck = true;
|
||||||
void MainPage::hddInstallMenuItem_Click() {
|
inst::config::setConfig();
|
||||||
if(nx::hdd::count() && nx::hdd::rootPath()) {
|
}
|
||||||
|
}
|
||||||
|
if (inst::util::usbIsConnected()) mainApp->usbinstPage->startUsb();
|
||||||
|
else mainApp->CreateShowDialog("main.usb.error.title"_lang, "main.usb.error.desc"_lang, { "common.ok"_lang }, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainPage::sigPatchesMenuItem_Click() {
|
||||||
|
sig::installSigPatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainPage::hddInstallMenuItem_Click() {
|
||||||
|
if (nx::hdd::count() && nx::hdd::rootPath()) {
|
||||||
mainApp->HDinstPage->drawMenuItems(true, nx::hdd::rootPath());
|
mainApp->HDinstPage->drawMenuItems(true, nx::hdd::rootPath());
|
||||||
mainApp->HDinstPage->menu->SetSelectedIndex(0);
|
mainApp->HDinstPage->menu->SetSelectedIndex(0);
|
||||||
mainApp->LoadLayout(mainApp->HDinstPage);
|
mainApp->LoadLayout(mainApp->HDinstPage);
|
||||||
} else {
|
|
||||||
inst::ui::mainApp->CreateShowDialog("main.hdd.title"_lang, "main.hdd.notfound"_lang, {"common.ok"_lang}, true);
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
inst::ui::mainApp->CreateShowDialog("main.hdd.title"_lang, "main.hdd.notfound"_lang, { "common.ok"_lang }, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainPage::exitMenuItem_Click() {
|
void MainPage::exitMenuItem_Click() {
|
||||||
mainApp->FadeOut();
|
mainApp->FadeOut();
|
||||||
mainApp->Close();
|
mainApp->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainPage::settingsMenuItem_Click() {
|
void MainPage::settingsMenuItem_Click() {
|
||||||
mainApp->LoadLayout(mainApp->optionspage);
|
mainApp->LoadLayout(mainApp->optionspage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void MainPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
if (((Down & HidNpadButton_Plus) || (Down & HidNpadButton_Minus) || (Down & HidNpadButton_B)) && mainApp->IsShown()) {
|
if (((Down & HidNpadButton_Plus) || (Down & HidNpadButton_Minus) || (Down & HidNpadButton_B)) && mainApp->IsShown()) {
|
||||||
mainApp->FadeOut();
|
mainApp->FadeOut();
|
||||||
mainApp->Close();
|
mainApp->Close();
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_A)) {
|
if ((Down & HidNpadButton_A)) {
|
||||||
switch (this->optionMenu->GetSelectedIndex()) {
|
switch (this->optionMenu->GetSelectedIndex()) {
|
||||||
case 0:
|
case 0:
|
||||||
this->installMenuItem_Click();
|
this->installMenuItem_Click();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
this->netInstallMenuItem_Click();
|
this->netInstallMenuItem_Click();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
MainPage::usbInstallMenuItem_Click();
|
MainPage::usbInstallMenuItem_Click();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
MainPage::hddInstallMenuItem_Click();
|
MainPage::hddInstallMenuItem_Click();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
MainPage::settingsMenuItem_Click();
|
MainPage::settingsMenuItem_Click();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
MainPage::exitMenuItem_Click();
|
MainPage::exitMenuItem_Click();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Down & HidNpadButton_Y) {
|
if (Down & HidNpadButton_Y) {
|
||||||
this->diskUsage();
|
this->diskUsage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainPage::diskUsage() {
|
void MainPage::diskUsage() {
|
||||||
double math = (inst::util::GetAvailableSpace("./") / 1024) / 1024; //megabytes
|
double math = (inst::util::GetAvailableSpace("./") / 1024) / 1024; //megabytes
|
||||||
float math2 = ((float)math / 1024); //gigabytes
|
float math2 = ((float)math / 1024); //gigabytes
|
||||||
|
|
||||||
double used = (inst::util::amountOfDiskSpaceUsed("./")); //same file path as sdmc
|
double used = (inst::util::amountOfDiskSpaceUsed("./")); //same file path as sdmc
|
||||||
|
|
||||||
double total = (inst::util::totalsize("sdmc:/") / 1024) / 1024; //megabytes
|
double total = (inst::util::totalsize("sdmc:/") / 1024) / 1024; //megabytes
|
||||||
float total2 = ((float)total / 1024); //gigabytes
|
float total2 = ((float)total / 1024); //gigabytes
|
||||||
//
|
//
|
||||||
float GB = math2;
|
float GB = math2;
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << std::fixed << std::setprecision(2) << GB; //only show 2 decimal places
|
stream << std::fixed << std::setprecision(2) << GB; //only show 2 decimal places
|
||||||
std::string freespace = stream.str();
|
std::string freespace = stream.str();
|
||||||
|
|
||||||
|
|
||||||
float GB2 = total2;
|
float GB2 = total2;
|
||||||
std::stringstream stream2;
|
std::stringstream stream2;
|
||||||
stream2 << std::fixed << std::setprecision(2) << GB2; //only show 2 decimal places
|
stream2 << std::fixed << std::setprecision(2) << GB2; //only show 2 decimal places
|
||||||
std::string sdsize = stream2.str();
|
std::string sdsize = stream2.str();
|
||||||
|
|
||||||
//printf("\nSdCard Free Space in MB: %li", math);
|
//printf("\nSdCard Free Space in MB: %li", math);
|
||||||
//printf("\nSdCard Free Space in GB: %.2f", math2);
|
//printf("\nSdCard Free Space in GB: %.2f", math2);
|
||||||
std::stringstream stream3;
|
std::stringstream stream3;
|
||||||
stream3 << std::fixed << std::setprecision(2) << used; //only show 2 decimal places
|
stream3 << std::fixed << std::setprecision(2) << used; //only show 2 decimal places
|
||||||
std::string percent = stream3.str();
|
std::string percent = stream3.str();
|
||||||
|
|
||||||
//unmount sd here and mount system....
|
//unmount sd here and mount system....
|
||||||
//fsdevUnmountDevice("sdmc");
|
//fsdevUnmountDevice("sdmc");
|
||||||
FsFileSystem nandFS;
|
FsFileSystem nandFS;
|
||||||
fsOpenBisFileSystem(&nandFS, FsBisPartitionId_User, "");
|
fsOpenBisFileSystem(&nandFS, FsBisPartitionId_User, "");
|
||||||
fsdevMountDevice("user", nandFS);
|
fsdevMountDevice("user", nandFS);
|
||||||
|
|
||||||
double math3 = (inst::util::GetAvailableSpace("user:/") / 1024) / 1024; //megabytes
|
double math3 = (inst::util::GetAvailableSpace("user:/") / 1024) / 1024; //megabytes
|
||||||
float math4 = ((float)math3 / 1024); //gigabytes
|
float math4 = ((float)math3 / 1024); //gigabytes
|
||||||
|
|
||||||
double used2 = (inst::util::amountOfDiskSpaceUsed("user:/")); //same file path as sdmc
|
double used2 = (inst::util::amountOfDiskSpaceUsed("user:/")); //same file path as sdmc
|
||||||
|
|
||||||
double total3 = (inst::util::totalsize("user:/") / 1024) / 1024; //megabytes
|
double total3 = (inst::util::totalsize("user:/") / 1024) / 1024; //megabytes
|
||||||
float total4 = ((float)total3 / 1024); //gigabytes
|
float total4 = ((float)total3 / 1024); //gigabytes
|
||||||
//
|
//
|
||||||
float GB3 = math4;
|
float GB3 = math4;
|
||||||
std::stringstream stream4;
|
std::stringstream stream4;
|
||||||
stream4 << std::fixed << std::setprecision(2) << GB3; //only show 2 decimal places
|
stream4 << std::fixed << std::setprecision(2) << GB3; //only show 2 decimal places
|
||||||
std::string freespace2 = stream4.str();
|
std::string freespace2 = stream4.str();
|
||||||
|
|
||||||
|
|
||||||
float GB4 = total4;
|
float GB4 = total4;
|
||||||
std::stringstream stream5;
|
std::stringstream stream5;
|
||||||
stream5 << std::fixed << std::setprecision(2) << GB4; //only show 2 decimal places
|
stream5 << std::fixed << std::setprecision(2) << GB4; //only show 2 decimal places
|
||||||
std::string sdsize2 = stream5.str();
|
std::string sdsize2 = stream5.str();
|
||||||
|
|
||||||
//printf("\nSdCard Free Space in MB: %li", math);
|
//printf("\nSdCard Free Space in MB: %li", math);
|
||||||
//printf("\nSdCard Free Space in GB: %.2f", math2);
|
//printf("\nSdCard Free Space in GB: %.2f", math2);
|
||||||
std::stringstream stream6;
|
std::stringstream stream6;
|
||||||
stream6 << std::fixed << std::setprecision(2) << used2; //only show 2 decimal places
|
stream6 << std::fixed << std::setprecision(2) << used2; //only show 2 decimal places
|
||||||
std::string percent2 = stream6.str();
|
std::string percent2 = stream6.str();
|
||||||
|
|
||||||
//unmount user now as we already know how much space we have
|
//unmount user now as we already know how much space we have
|
||||||
fsdevUnmountDevice("user");
|
fsdevUnmountDevice("user");
|
||||||
|
|
||||||
|
|
||||||
std::string Info = ("System total size: " + sdsize2 + " GB" + "\nSystem free space: " + freespace2 + " GB" + "\nSystem percent used: " + percent2 + "%" + "\n\n" + "SD card total size: " + sdsize + " GB" + "\nSD card free space: " + freespace + " GB" + "\nSD card percent used: " + percent + "%");
|
std::string Info = ("System total size: " + sdsize2 + " GB" + "\nSystem free space: " + freespace2 + " GB" + "\nSystem percent used: " + percent2 + "%" + "\n\n" + "SD card total size: " + sdsize + " GB" + "\nSD card free space: " + freespace + " GB" + "\nSD card percent used: " + percent + "%");
|
||||||
inst::ui::mainApp->CreateShowDialog("Space Usage Information", Info, { "common.ok"_lang }, true);
|
inst::ui::mainApp->CreateShowDialog("Space Usage Information", Info, { "common.ok"_lang }, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,174 +12,178 @@
|
|||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
|
|
||||||
std::string lastFileID = "";
|
std::string lastFileID = "";
|
||||||
std::string sourceString = "";
|
std::string sourceString = "";
|
||||||
|
|
||||||
netInstPage::netInstPage() : Layout::Layout() {
|
netInstPage::netInstPage() : Layout::Layout() {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
||||||
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
||||||
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
||||||
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
||||||
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
||||||
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
||||||
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
||||||
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->pageInfoText = TextBlock::New(10, 109, "");
|
this->pageInfoText = TextBlock::New(10, 109, "");
|
||||||
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->butText = TextBlock::New(10, 678, "");
|
this->butText = TextBlock::New(10, 678, "");
|
||||||
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
||||||
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
||||||
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
||||||
this->infoImage = Image::New(453, 292, "romfs:/images/icons/lan-connection-waiting.png");
|
this->infoImage = Image::New(453, 292, "romfs:/images/icons/lan-connection-waiting.png");
|
||||||
this->Add(this->topRect);
|
this->Add(this->topRect);
|
||||||
this->Add(this->infoRect);
|
this->Add(this->infoRect);
|
||||||
this->Add(this->botRect);
|
this->Add(this->botRect);
|
||||||
this->Add(this->titleImage);
|
this->Add(this->titleImage);
|
||||||
this->Add(this->appVersionText);
|
this->Add(this->appVersionText);
|
||||||
this->Add(this->butText);
|
this->Add(this->butText);
|
||||||
this->Add(this->pageInfoText);
|
this->Add(this->pageInfoText);
|
||||||
this->Add(this->menu);
|
this->Add(this->menu);
|
||||||
this->Add(this->infoImage);
|
this->Add(this->infoImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void netInstPage::drawMenuItems(bool clearItems) {
|
void netInstPage::drawMenuItems(bool clearItems) {
|
||||||
if (clearItems) this->selectedUrls = {};
|
if (clearItems) this->selectedUrls = {};
|
||||||
if (clearItems) this->alternativeNames = {};
|
if (clearItems) this->alternativeNames = {};
|
||||||
this->menu->ClearItems();
|
this->menu->ClearItems();
|
||||||
for (auto& url: this->ourUrls) {
|
for (auto& url : this->ourUrls) {
|
||||||
std::string itm = inst::util::shortenString(inst::util::formatUrlString(url), 56, true);
|
std::string itm = inst::util::shortenString(inst::util::formatUrlString(url), 56, true);
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
||||||
for (long unsigned int i = 0; i < this->selectedUrls.size(); i++) {
|
for (long unsigned int i = 0; i < this->selectedUrls.size(); i++) {
|
||||||
if (this->selectedUrls[i] == url) {
|
if (this->selectedUrls[i] == url) {
|
||||||
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->menu->AddItem(ourEntry);
|
this->menu->AddItem(ourEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void netInstPage::selectTitle(int selectedIndex) {
|
void netInstPage::selectTitle(int selectedIndex) {
|
||||||
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
||||||
for (long unsigned int i = 0; i < this->selectedUrls.size(); i++) {
|
for (long unsigned int i = 0; i < this->selectedUrls.size(); i++) {
|
||||||
if (this->selectedUrls[i] == this->ourUrls[selectedIndex]) this->selectedUrls.erase(this->selectedUrls.begin() + i);
|
if (this->selectedUrls[i] == this->ourUrls[selectedIndex]) this->selectedUrls.erase(this->selectedUrls.begin() + i);
|
||||||
}
|
}
|
||||||
} else this->selectedUrls.push_back(this->ourUrls[selectedIndex]);
|
}
|
||||||
this->drawMenuItems(false);
|
else this->selectedUrls.push_back(this->ourUrls[selectedIndex]);
|
||||||
}
|
this->drawMenuItems(false);
|
||||||
|
}
|
||||||
|
|
||||||
void netInstPage::startNetwork() {
|
void netInstPage::startNetwork() {
|
||||||
this->butText->SetText("inst.net.buttons"_lang);
|
this->butText->SetText("inst.net.buttons"_lang);
|
||||||
this->menu->SetVisible(false);
|
this->menu->SetVisible(false);
|
||||||
this->menu->ClearItems();
|
this->menu->ClearItems();
|
||||||
this->infoImage->SetVisible(true);
|
this->infoImage->SetVisible(true);
|
||||||
mainApp->LoadLayout(mainApp->netinstPage);
|
mainApp->LoadLayout(mainApp->netinstPage);
|
||||||
this->ourUrls = netInstStuff::OnSelected();
|
this->ourUrls = netInstStuff::OnSelected();
|
||||||
if (!this->ourUrls.size()) {
|
if (!this->ourUrls.size()) {
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
return;
|
return;
|
||||||
} else if (this->ourUrls[0] == "supplyUrl") {
|
}
|
||||||
std::string keyboardResult;
|
else if (this->ourUrls[0] == "supplyUrl") {
|
||||||
switch (mainApp->CreateShowDialog("inst.net.src.title"_lang, "common.cancel_desc"_lang, {"inst.net.src.opt0"_lang, "inst.net.src.opt1"_lang}, false)) {
|
std::string keyboardResult;
|
||||||
case 0:
|
switch (mainApp->CreateShowDialog("inst.net.src.title"_lang, "common.cancel_desc"_lang, { "inst.net.src.opt0"_lang, "inst.net.src.opt1"_lang }, false)) {
|
||||||
keyboardResult = inst::util::softwareKeyboard("inst.net.url.hint"_lang, inst::config::lastNetUrl, 500);
|
case 0:
|
||||||
if (keyboardResult.size() > 0) {
|
keyboardResult = inst::util::softwareKeyboard("inst.net.url.hint"_lang, inst::config::lastNetUrl, 500);
|
||||||
if (inst::util::formatUrlString(keyboardResult) == "" || keyboardResult == "https://" || keyboardResult == "http://") {
|
if (keyboardResult.size() > 0) {
|
||||||
mainApp->CreateShowDialog("inst.net.url.invalid"_lang, "", {"common.ok"_lang}, false);
|
if (inst::util::formatUrlString(keyboardResult) == "" || keyboardResult == "https://" || keyboardResult == "http://") {
|
||||||
break;
|
mainApp->CreateShowDialog("inst.net.url.invalid"_lang, "", { "common.ok"_lang }, false);
|
||||||
}
|
break;
|
||||||
inst::config::lastNetUrl = keyboardResult;
|
}
|
||||||
inst::config::setConfig();
|
inst::config::lastNetUrl = keyboardResult;
|
||||||
sourceString = "inst.net.url.source_string"_lang;
|
inst::config::setConfig();
|
||||||
this->selectedUrls = {keyboardResult};
|
sourceString = "inst.net.url.source_string"_lang;
|
||||||
this->startInstall(true);
|
this->selectedUrls = { keyboardResult };
|
||||||
return;
|
this->startInstall(true);
|
||||||
}
|
return;
|
||||||
break;
|
}
|
||||||
case 1:
|
break;
|
||||||
keyboardResult = inst::util::softwareKeyboard("inst.net.gdrive.hint"_lang, lastFileID, 50);
|
case 1:
|
||||||
if (keyboardResult.size() > 0) {
|
keyboardResult = inst::util::softwareKeyboard("inst.net.gdrive.hint"_lang, lastFileID, 50);
|
||||||
lastFileID = keyboardResult;
|
if (keyboardResult.size() > 0) {
|
||||||
std::string fileName = inst::util::getDriveFileName(keyboardResult);
|
lastFileID = keyboardResult;
|
||||||
if (fileName.size() > 0) this->alternativeNames = {fileName};
|
std::string fileName = inst::util::getDriveFileName(keyboardResult);
|
||||||
else this->alternativeNames = {"inst.net.gdrive.alt_name"_lang};
|
if (fileName.size() > 0) this->alternativeNames = { fileName };
|
||||||
sourceString = "inst.net.gdrive.source_string"_lang;
|
else this->alternativeNames = { "inst.net.gdrive.alt_name"_lang };
|
||||||
this->selectedUrls = {"https://www.googleapis.com/drive/v3/files/" + keyboardResult + "?key=" + inst::config::gAuthKey + "&alt=media"};
|
sourceString = "inst.net.gdrive.source_string"_lang;
|
||||||
this->startInstall(true);
|
this->selectedUrls = { "https://www.googleapis.com/drive/v3/files/" + keyboardResult + "?key=" + inst::config::gAuthKey + "&alt=media" };
|
||||||
return;
|
this->startInstall(true);
|
||||||
}
|
return;
|
||||||
break;
|
}
|
||||||
}
|
break;
|
||||||
this->startNetwork();
|
}
|
||||||
return;
|
this->startNetwork();
|
||||||
} else {
|
return;
|
||||||
mainApp->CallForRender(); // If we re-render a few times during this process the main screen won't flicker
|
}
|
||||||
sourceString = "inst.net.source_string"_lang;
|
else {
|
||||||
this->pageInfoText->SetText("inst.net.top_info"_lang);
|
mainApp->CallForRender(); // If we re-render a few times during this process the main screen won't flicker
|
||||||
this->butText->SetText("inst.net.buttons1"_lang);
|
sourceString = "inst.net.source_string"_lang;
|
||||||
this->drawMenuItems(true);
|
this->pageInfoText->SetText("inst.net.top_info"_lang);
|
||||||
this->menu->SetSelectedIndex(0);
|
this->butText->SetText("inst.net.buttons1"_lang);
|
||||||
mainApp->CallForRender();
|
this->drawMenuItems(true);
|
||||||
this->infoImage->SetVisible(false);
|
this->menu->SetSelectedIndex(0);
|
||||||
this->menu->SetVisible(true);
|
mainApp->CallForRender();
|
||||||
}
|
this->infoImage->SetVisible(false);
|
||||||
return;
|
this->menu->SetVisible(true);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void netInstPage::startInstall(bool urlMode) {
|
void netInstPage::startInstall(bool urlMode) {
|
||||||
int dialogResult = -1;
|
int dialogResult = -1;
|
||||||
if (this->selectedUrls.size() == 1) {
|
if (this->selectedUrls.size() == 1) {
|
||||||
std::string ourUrlString;
|
std::string ourUrlString;
|
||||||
if (this->alternativeNames.size() > 0) ourUrlString = inst::util::shortenString(this->alternativeNames[0], 32, true);
|
if (this->alternativeNames.size() > 0) ourUrlString = inst::util::shortenString(this->alternativeNames[0], 32, true);
|
||||||
else ourUrlString = inst::util::shortenString(inst::util::formatUrlString(this->selectedUrls[0]), 32, true);
|
else ourUrlString = inst::util::shortenString(inst::util::formatUrlString(this->selectedUrls[0]), 32, true);
|
||||||
dialogResult = mainApp->CreateShowDialog("inst.target.desc0"_lang + ourUrlString + "inst.target.desc1"_lang, "common.cancel_desc"_lang, {"inst.target.opt0"_lang, "inst.target.opt1"_lang}, false);
|
dialogResult = mainApp->CreateShowDialog("inst.target.desc0"_lang + ourUrlString + "inst.target.desc1"_lang, "common.cancel_desc"_lang, { "inst.target.opt0"_lang, "inst.target.opt1"_lang }, false);
|
||||||
} else dialogResult = mainApp->CreateShowDialog("inst.target.desc00"_lang + std::to_string(this->selectedUrls.size()) + "inst.target.desc01"_lang, "common.cancel_desc"_lang, {"inst.target.opt0"_lang, "inst.target.opt1"_lang}, false);
|
}
|
||||||
if (dialogResult == -1 && !urlMode) return;
|
else dialogResult = mainApp->CreateShowDialog("inst.target.desc00"_lang + std::to_string(this->selectedUrls.size()) + "inst.target.desc01"_lang, "common.cancel_desc"_lang, { "inst.target.opt0"_lang, "inst.target.opt1"_lang }, false);
|
||||||
else if (dialogResult == -1 && urlMode) {
|
if (dialogResult == -1 && !urlMode) return;
|
||||||
this->startNetwork();
|
else if (dialogResult == -1 && urlMode) {
|
||||||
return;
|
this->startNetwork();
|
||||||
}
|
return;
|
||||||
netInstStuff::installTitleNet(this->selectedUrls, dialogResult, this->alternativeNames, sourceString);
|
}
|
||||||
return;
|
netInstStuff::installTitleNet(this->selectedUrls, dialogResult, this->alternativeNames, sourceString);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void netInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void netInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
if (Down & HidNpadButton_B) {
|
if (Down & HidNpadButton_B) {
|
||||||
if (this->menu->GetItems().size() > 0){
|
if (this->menu->GetItems().size() > 0) {
|
||||||
if (this->selectedUrls.size() == 0) {
|
if (this->selectedUrls.size() == 0) {
|
||||||
this->selectTitle(this->menu->GetSelectedIndex());
|
this->selectTitle(this->menu->GetSelectedIndex());
|
||||||
}
|
}
|
||||||
netInstStuff::sendExitCommands(inst::util::formatUrlLink(this->selectedUrls[0]));
|
netInstStuff::sendExitCommands(inst::util::formatUrlLink(this->selectedUrls[0]));
|
||||||
}
|
}
|
||||||
netInstStuff::OnUnwound();
|
netInstStuff::OnUnwound();
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_A)) {
|
if ((Down & HidNpadButton_A)) {
|
||||||
this->selectTitle(this->menu->GetSelectedIndex());
|
this->selectTitle(this->menu->GetSelectedIndex());
|
||||||
if (this->menu->GetItems().size() == 1 && this->selectedUrls.size() == 1) {
|
if (this->menu->GetItems().size() == 1 && this->selectedUrls.size() == 1) {
|
||||||
this->startInstall(false);
|
this->startInstall(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_Y)) {
|
if ((Down & HidNpadButton_Y)) {
|
||||||
if (this->selectedUrls.size() == this->menu->GetItems().size()) this->drawMenuItems(true);
|
if (this->selectedUrls.size() == this->menu->GetItems().size()) this->drawMenuItems(true);
|
||||||
else {
|
else {
|
||||||
for (long unsigned int i = 0; i < this->menu->GetItems().size(); i++) {
|
for (long unsigned int i = 0; i < this->menu->GetItems().size(); i++) {
|
||||||
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
||||||
else this->selectTitle(i);
|
else this->selectTitle(i);
|
||||||
}
|
}
|
||||||
this->drawMenuItems(false);
|
this->drawMenuItems(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Down & HidNpadButton_Plus) {
|
if (Down & HidNpadButton_Plus) {
|
||||||
if (this->selectedUrls.size() == 0) {
|
if (this->selectedUrls.size() == 0) {
|
||||||
this->selectTitle(this->menu->GetSelectedIndex());
|
this->selectTitle(this->menu->GetSelectedIndex());
|
||||||
}
|
}
|
||||||
this->startInstall(false);
|
this->startInstall(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,263 +14,265 @@
|
|||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
|
|
||||||
std::vector<std::string> languageStrings = {"English", "日本語", "Français", "Deutsch", "Italiano", "Español", "Português", "Русский", "簡体中文","繁體中文"};
|
std::vector<std::string> languageStrings = { "English", "日本語", "Français", "Deutsch", "Italiano", "Español", "Português", "Русский", "簡体中文", "繁體中文" };
|
||||||
|
|
||||||
optionsPage::optionsPage() : Layout::Layout() {
|
optionsPage::optionsPage() : Layout::Layout() {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
||||||
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
||||||
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
||||||
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
||||||
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
||||||
if (inst::config::gayMode) {
|
if (inst::config::gayMode) {
|
||||||
this->titleImage = Image::New(-113, 0, "romfs:/images/logo.png");
|
this->titleImage = Image::New(-113, 0, "romfs:/images/logo.png");
|
||||||
this->appVersionText = TextBlock::New(367, 49, "v" + inst::config::appVersion);
|
this->appVersionText = TextBlock::New(367, 49, "v" + inst::config::appVersion);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
||||||
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
||||||
}
|
}
|
||||||
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->pageInfoText = TextBlock::New(10, 109, "options.title"_lang);
|
this->pageInfoText = TextBlock::New(10, 109, "options.title"_lang);
|
||||||
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->butText = TextBlock::New(10, 678, "options.buttons"_lang);
|
this->butText = TextBlock::New(10, 678, "options.buttons"_lang);
|
||||||
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
||||||
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
||||||
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
||||||
this->Add(this->topRect);
|
this->Add(this->topRect);
|
||||||
this->Add(this->infoRect);
|
this->Add(this->infoRect);
|
||||||
this->Add(this->botRect);
|
this->Add(this->botRect);
|
||||||
this->Add(this->titleImage);
|
this->Add(this->titleImage);
|
||||||
this->Add(this->appVersionText);
|
this->Add(this->appVersionText);
|
||||||
this->Add(this->butText);
|
this->Add(this->butText);
|
||||||
this->Add(this->pageInfoText);
|
this->Add(this->pageInfoText);
|
||||||
this->setMenuText();
|
this->setMenuText();
|
||||||
this->Add(this->menu);
|
this->Add(this->menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void optionsPage::askToUpdate(std::vector<std::string> updateInfo) {
|
void optionsPage::askToUpdate(std::vector<std::string> updateInfo) {
|
||||||
if (!mainApp->CreateShowDialog("options.update.title"_lang, "options.update.desc0"_lang + updateInfo[0] + "options.update.desc1"_lang, {"options.update.opt0"_lang, "common.cancel"_lang}, false)) {
|
if (!mainApp->CreateShowDialog("options.update.title"_lang, "options.update.desc0"_lang + updateInfo[0] + "options.update.desc1"_lang, { "options.update.opt0"_lang, "common.cancel"_lang }, false)) {
|
||||||
inst::ui::instPage::loadInstallScreen();
|
inst::ui::instPage::loadInstallScreen();
|
||||||
inst::ui::instPage::setTopInstInfoText("options.update.top_info"_lang + updateInfo[0]);
|
inst::ui::instPage::setTopInstInfoText("options.update.top_info"_lang + updateInfo[0]);
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
inst::ui::instPage::setInstInfoText("options.update.bot_info"_lang + updateInfo[0]);
|
inst::ui::instPage::setInstInfoText("options.update.bot_info"_lang + updateInfo[0]);
|
||||||
try {
|
try {
|
||||||
std::string downloadName = inst::config::appDir + "/temp_download.zip";
|
std::string downloadName = inst::config::appDir + "/temp_download.zip";
|
||||||
inst::curl::downloadFile(updateInfo[1], downloadName.c_str(), 0, true);
|
inst::curl::downloadFile(updateInfo[1], downloadName.c_str(), 0, true);
|
||||||
romfsExit();
|
romfsExit();
|
||||||
inst::ui::instPage::setInstInfoText("options.update.bot_info2"_lang + updateInfo[0]);
|
inst::ui::instPage::setInstInfoText("options.update.bot_info2"_lang + updateInfo[0]);
|
||||||
inst::zip::extractFile(downloadName, "sdmc:/");
|
inst::zip::extractFile(downloadName, "sdmc:/");
|
||||||
std::filesystem::remove(downloadName);
|
std::filesystem::remove(downloadName);
|
||||||
mainApp->CreateShowDialog("options.update.complete"_lang, "options.update.end_desc"_lang, {"common.ok"_lang}, false);
|
mainApp->CreateShowDialog("options.update.complete"_lang, "options.update.end_desc"_lang, { "common.ok"_lang }, false);
|
||||||
} catch (...) {
|
}
|
||||||
mainApp->CreateShowDialog("options.update.failed"_lang, "options.update.end_desc"_lang, {"common.ok"_lang}, false);
|
catch (...) {
|
||||||
}
|
mainApp->CreateShowDialog("options.update.failed"_lang, "options.update.end_desc"_lang, { "common.ok"_lang }, false);
|
||||||
mainApp->FadeOut();
|
}
|
||||||
mainApp->Close();
|
mainApp->FadeOut();
|
||||||
}
|
mainApp->Close();
|
||||||
return;
|
}
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string optionsPage::getMenuOptionIcon(bool ourBool) {
|
std::string optionsPage::getMenuOptionIcon(bool ourBool) {
|
||||||
if(ourBool) return "romfs:/images/icons/check-box-outline.png";
|
if (ourBool) return "romfs:/images/icons/check-box-outline.png";
|
||||||
else return "romfs:/images/icons/checkbox-blank-outline.png";
|
else return "romfs:/images/icons/checkbox-blank-outline.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string optionsPage::getMenuLanguage(int ourLangCode) {
|
std::string optionsPage::getMenuLanguage(int ourLangCode) {
|
||||||
switch (ourLangCode) {
|
switch (ourLangCode) {
|
||||||
case 1:
|
case 1:
|
||||||
case 12:
|
case 12:
|
||||||
return languageStrings[0];
|
return languageStrings[0];
|
||||||
case 0:
|
case 0:
|
||||||
return languageStrings[1];
|
return languageStrings[1];
|
||||||
case 2:
|
case 2:
|
||||||
case 13:
|
case 13:
|
||||||
return languageStrings[2];
|
return languageStrings[2];
|
||||||
case 3:
|
case 3:
|
||||||
return languageStrings[3];
|
return languageStrings[3];
|
||||||
case 4:
|
case 4:
|
||||||
return languageStrings[4];
|
return languageStrings[4];
|
||||||
case 5:
|
case 5:
|
||||||
case 14:
|
case 14:
|
||||||
return languageStrings[5];
|
return languageStrings[5];
|
||||||
case 9:
|
case 9:
|
||||||
return languageStrings[6];
|
return languageStrings[6];
|
||||||
case 10:
|
case 10:
|
||||||
return languageStrings[7];
|
return languageStrings[7];
|
||||||
case 6:
|
case 6:
|
||||||
return languageStrings[8];
|
return languageStrings[8];
|
||||||
case 11:
|
case 11:
|
||||||
return languageStrings[9];
|
return languageStrings[9];
|
||||||
default:
|
default:
|
||||||
return "options.language.system_language"_lang;
|
return "options.language.system_language"_lang;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void optionsPage::setMenuText() {
|
void optionsPage::setMenuText() {
|
||||||
this->menu->ClearItems();
|
this->menu->ClearItems();
|
||||||
auto ignoreFirmOption = pu::ui::elm::MenuItem::New("options.menu_items.ignore_firm"_lang);
|
auto ignoreFirmOption = pu::ui::elm::MenuItem::New("options.menu_items.ignore_firm"_lang);
|
||||||
ignoreFirmOption->SetColor(COLOR("#FFFFFFFF"));
|
ignoreFirmOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
ignoreFirmOption->SetIcon(this->getMenuOptionIcon(inst::config::ignoreReqVers));
|
ignoreFirmOption->SetIcon(this->getMenuOptionIcon(inst::config::ignoreReqVers));
|
||||||
this->menu->AddItem(ignoreFirmOption);
|
this->menu->AddItem(ignoreFirmOption);
|
||||||
auto validateOption = pu::ui::elm::MenuItem::New("options.menu_items.nca_verify"_lang);
|
auto validateOption = pu::ui::elm::MenuItem::New("options.menu_items.nca_verify"_lang);
|
||||||
validateOption->SetColor(COLOR("#FFFFFFFF"));
|
validateOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
validateOption->SetIcon(this->getMenuOptionIcon(inst::config::validateNCAs));
|
validateOption->SetIcon(this->getMenuOptionIcon(inst::config::validateNCAs));
|
||||||
this->menu->AddItem(validateOption);
|
this->menu->AddItem(validateOption);
|
||||||
auto overclockOption = pu::ui::elm::MenuItem::New("options.menu_items.boost_mode"_lang);
|
auto overclockOption = pu::ui::elm::MenuItem::New("options.menu_items.boost_mode"_lang);
|
||||||
overclockOption->SetColor(COLOR("#FFFFFFFF"));
|
overclockOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
overclockOption->SetIcon(this->getMenuOptionIcon(inst::config::overClock));
|
overclockOption->SetIcon(this->getMenuOptionIcon(inst::config::overClock));
|
||||||
this->menu->AddItem(overclockOption);
|
this->menu->AddItem(overclockOption);
|
||||||
auto deletePromptOption = pu::ui::elm::MenuItem::New("options.menu_items.ask_delete"_lang);
|
auto deletePromptOption = pu::ui::elm::MenuItem::New("options.menu_items.ask_delete"_lang);
|
||||||
deletePromptOption->SetColor(COLOR("#FFFFFFFF"));
|
deletePromptOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
deletePromptOption->SetIcon(this->getMenuOptionIcon(inst::config::deletePrompt));
|
deletePromptOption->SetIcon(this->getMenuOptionIcon(inst::config::deletePrompt));
|
||||||
this->menu->AddItem(deletePromptOption);
|
this->menu->AddItem(deletePromptOption);
|
||||||
auto autoUpdateOption = pu::ui::elm::MenuItem::New("options.menu_items.auto_update"_lang);
|
auto autoUpdateOption = pu::ui::elm::MenuItem::New("options.menu_items.auto_update"_lang);
|
||||||
autoUpdateOption->SetColor(COLOR("#FFFFFFFF"));
|
autoUpdateOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
autoUpdateOption->SetIcon(this->getMenuOptionIcon(inst::config::autoUpdate));
|
autoUpdateOption->SetIcon(this->getMenuOptionIcon(inst::config::autoUpdate));
|
||||||
this->menu->AddItem(autoUpdateOption);
|
this->menu->AddItem(autoUpdateOption);
|
||||||
auto gayModeOption = pu::ui::elm::MenuItem::New("options.menu_items.gay_option"_lang);
|
auto gayModeOption = pu::ui::elm::MenuItem::New("options.menu_items.gay_option"_lang);
|
||||||
gayModeOption->SetColor(COLOR("#FFFFFFFF"));
|
gayModeOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
gayModeOption->SetIcon(this->getMenuOptionIcon(inst::config::gayMode));
|
gayModeOption->SetIcon(this->getMenuOptionIcon(inst::config::gayMode));
|
||||||
this->menu->AddItem(gayModeOption);
|
this->menu->AddItem(gayModeOption);
|
||||||
//auto sigPatchesUrlOption = pu::ui::elm::MenuItem::New("options.menu_items.sig_url"_lang + inst::util::shortenString(inst::config::sigPatchesUrl, 42, false));
|
//auto sigPatchesUrlOption = pu::ui::elm::MenuItem::New("options.menu_items.sig_url"_lang + inst::util::shortenString(inst::config::sigPatchesUrl, 42, false));
|
||||||
//sigPatchesUrlOption->SetColor(COLOR("#FFFFFFFF"));
|
//sigPatchesUrlOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
//this->menu->AddItem(sigPatchesUrlOption);
|
//this->menu->AddItem(sigPatchesUrlOption);
|
||||||
auto languageOption = pu::ui::elm::MenuItem::New("options.menu_items.language"_lang + this->getMenuLanguage(inst::config::languageSetting));
|
auto languageOption = pu::ui::elm::MenuItem::New("options.menu_items.language"_lang + this->getMenuLanguage(inst::config::languageSetting));
|
||||||
languageOption->SetColor(COLOR("#FFFFFFFF"));
|
languageOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu->AddItem(languageOption);
|
this->menu->AddItem(languageOption);
|
||||||
auto updateOption = pu::ui::elm::MenuItem::New("options.menu_items.check_update"_lang);
|
auto updateOption = pu::ui::elm::MenuItem::New("options.menu_items.check_update"_lang);
|
||||||
updateOption->SetColor(COLOR("#FFFFFFFF"));
|
updateOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu->AddItem(updateOption);
|
this->menu->AddItem(updateOption);
|
||||||
auto creditsOption = pu::ui::elm::MenuItem::New("options.menu_items.credits"_lang);
|
auto creditsOption = pu::ui::elm::MenuItem::New("options.menu_items.credits"_lang);
|
||||||
creditsOption->SetColor(COLOR("#FFFFFFFF"));
|
creditsOption->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu->AddItem(creditsOption);
|
this->menu->AddItem(creditsOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
void optionsPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void optionsPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
if (Down & HidNpadButton_B) {
|
if (Down & HidNpadButton_B) {
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_A)) {
|
if ((Down & HidNpadButton_A)) {
|
||||||
std::string keyboardResult;
|
std::string keyboardResult;
|
||||||
int rc;
|
int rc;
|
||||||
std::vector<std::string> downloadUrl;
|
std::vector<std::string> downloadUrl;
|
||||||
switch (this->menu->GetSelectedIndex()) {
|
switch (this->menu->GetSelectedIndex()) {
|
||||||
case 0:
|
case 0:
|
||||||
inst::config::ignoreReqVers = !inst::config::ignoreReqVers;
|
inst::config::ignoreReqVers = !inst::config::ignoreReqVers;
|
||||||
inst::config::setConfig();
|
inst::config::setConfig();
|
||||||
this->setMenuText();
|
this->setMenuText();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (inst::config::validateNCAs) {
|
if (inst::config::validateNCAs) {
|
||||||
if (inst::ui::mainApp->CreateShowDialog("options.nca_warn.title"_lang, "options.nca_warn.desc"_lang, {"common.cancel"_lang, "options.nca_warn.opt1"_lang}, false) == 1) inst::config::validateNCAs = false;
|
if (inst::ui::mainApp->CreateShowDialog("options.nca_warn.title"_lang, "options.nca_warn.desc"_lang, { "common.cancel"_lang, "options.nca_warn.opt1"_lang }, false) == 1) inst::config::validateNCAs = false;
|
||||||
} else inst::config::validateNCAs = true;
|
}
|
||||||
inst::config::setConfig();
|
else inst::config::validateNCAs = true;
|
||||||
this->setMenuText();
|
inst::config::setConfig();
|
||||||
break;
|
this->setMenuText();
|
||||||
case 2:
|
break;
|
||||||
inst::config::overClock = !inst::config::overClock;
|
case 2:
|
||||||
inst::config::setConfig();
|
inst::config::overClock = !inst::config::overClock;
|
||||||
this->setMenuText();
|
inst::config::setConfig();
|
||||||
break;
|
this->setMenuText();
|
||||||
case 3:
|
break;
|
||||||
inst::config::deletePrompt = !inst::config::deletePrompt;
|
case 3:
|
||||||
inst::config::setConfig();
|
inst::config::deletePrompt = !inst::config::deletePrompt;
|
||||||
this->setMenuText();
|
inst::config::setConfig();
|
||||||
break;
|
this->setMenuText();
|
||||||
case 4:
|
break;
|
||||||
inst::config::autoUpdate = !inst::config::autoUpdate;
|
case 4:
|
||||||
inst::config::setConfig();
|
inst::config::autoUpdate = !inst::config::autoUpdate;
|
||||||
this->setMenuText();
|
inst::config::setConfig();
|
||||||
break;
|
this->setMenuText();
|
||||||
case 5:
|
break;
|
||||||
if (inst::config::gayMode) {
|
case 5:
|
||||||
inst::config::gayMode = false;
|
if (inst::config::gayMode) {
|
||||||
mainApp->mainPage->awooImage->SetVisible(true);
|
inst::config::gayMode = false;
|
||||||
mainApp->instpage->awooImage->SetVisible(true);
|
mainApp->mainPage->awooImage->SetVisible(true);
|
||||||
}
|
mainApp->instpage->awooImage->SetVisible(true);
|
||||||
else {
|
}
|
||||||
inst::config::gayMode = true;
|
else {
|
||||||
mainApp->mainPage->awooImage->SetVisible(false);
|
inst::config::gayMode = true;
|
||||||
mainApp->instpage->awooImage->SetVisible(false);
|
mainApp->mainPage->awooImage->SetVisible(false);
|
||||||
}
|
mainApp->instpage->awooImage->SetVisible(false);
|
||||||
inst::config::setConfig();
|
}
|
||||||
this->setMenuText();
|
inst::config::setConfig();
|
||||||
break;
|
this->setMenuText();
|
||||||
/*case 6:
|
break;
|
||||||
keyboardResult = inst::util::softwareKeyboard("options.sig_hint"_lang, inst::config::sigPatchesUrl.c_str(), 500);
|
/*case 6:
|
||||||
if (keyboardResult.size() > 0) {
|
keyboardResult = inst::util::softwareKeyboard("options.sig_hint"_lang, inst::config::sigPatchesUrl.c_str(), 500);
|
||||||
inst::config::sigPatchesUrl = keyboardResult;
|
if (keyboardResult.size() > 0) {
|
||||||
inst::config::setConfig();
|
inst::config::sigPatchesUrl = keyboardResult;
|
||||||
this->setMenuText();
|
inst::config::setConfig();
|
||||||
}
|
this->setMenuText();
|
||||||
break;*/
|
}
|
||||||
case 6:
|
break;*/
|
||||||
{
|
case 6:
|
||||||
std::vector<pu::String> languageList(languageStrings.begin(), languageStrings.end());
|
{
|
||||||
languageList.push_back("options.language.system_language"_lang);
|
std::vector<pu::String> languageList(languageStrings.begin(), languageStrings.end());
|
||||||
rc = inst::ui::mainApp->CreateShowDialog("options.language.title"_lang, "options.language.desc"_lang, languageList, false);
|
languageList.push_back("options.language.system_language"_lang);
|
||||||
if (rc == -1) break;
|
rc = inst::ui::mainApp->CreateShowDialog("options.language.title"_lang, "options.language.desc"_lang, languageList, false);
|
||||||
switch (rc) {
|
if (rc == -1) break;
|
||||||
case 0:
|
switch (rc) {
|
||||||
inst::config::languageSetting = 1;
|
case 0:
|
||||||
break;
|
inst::config::languageSetting = 1;
|
||||||
case 1:
|
break;
|
||||||
inst::config::languageSetting = 0;
|
case 1:
|
||||||
break;
|
inst::config::languageSetting = 0;
|
||||||
case 2:
|
break;
|
||||||
inst::config::languageSetting = 2;
|
case 2:
|
||||||
break;
|
inst::config::languageSetting = 2;
|
||||||
case 3:
|
break;
|
||||||
inst::config::languageSetting = 3;
|
case 3:
|
||||||
break;
|
inst::config::languageSetting = 3;
|
||||||
case 4:
|
break;
|
||||||
inst::config::languageSetting = 4;
|
case 4:
|
||||||
break;
|
inst::config::languageSetting = 4;
|
||||||
case 5:
|
break;
|
||||||
inst::config::languageSetting = 14;
|
case 5:
|
||||||
break;
|
inst::config::languageSetting = 14;
|
||||||
case 6:
|
break;
|
||||||
inst::config::languageSetting = 9;
|
case 6:
|
||||||
break;
|
inst::config::languageSetting = 9;
|
||||||
case 7:
|
break;
|
||||||
inst::config::languageSetting = 10;
|
case 7:
|
||||||
break;
|
inst::config::languageSetting = 10;
|
||||||
case 8:
|
break;
|
||||||
inst::config::languageSetting = 6;
|
case 8:
|
||||||
break;
|
inst::config::languageSetting = 6;
|
||||||
case 9:
|
break;
|
||||||
inst::config::languageSetting = 11;
|
case 9:
|
||||||
break;
|
inst::config::languageSetting = 11;
|
||||||
default:
|
break;
|
||||||
inst::config::languageSetting = 99;
|
default:
|
||||||
}
|
inst::config::languageSetting = 99;
|
||||||
inst::config::setConfig();
|
}
|
||||||
mainApp->FadeOut();
|
inst::config::setConfig();
|
||||||
mainApp->Close();
|
mainApp->FadeOut();
|
||||||
}
|
mainApp->Close();
|
||||||
break;
|
}
|
||||||
case 7:
|
break;
|
||||||
if (inst::util::getIPAddress() == "1.0.0.127") {
|
case 7:
|
||||||
inst::ui::mainApp->CreateShowDialog("main.net.title"_lang, "main.net.desc"_lang, {"common.ok"_lang}, true);
|
if (inst::util::getIPAddress() == "1.0.0.127") {
|
||||||
break;
|
inst::ui::mainApp->CreateShowDialog("main.net.title"_lang, "main.net.desc"_lang, { "common.ok"_lang }, true);
|
||||||
}
|
break;
|
||||||
downloadUrl = inst::util::checkForAppUpdate();
|
}
|
||||||
if (!downloadUrl.size()) {
|
downloadUrl = inst::util::checkForAppUpdate();
|
||||||
mainApp->CreateShowDialog("options.update.title_check_fail"_lang, "options.update.desc_check_fail"_lang, {"common.ok"_lang}, false);
|
if (!downloadUrl.size()) {
|
||||||
break;
|
mainApp->CreateShowDialog("options.update.title_check_fail"_lang, "options.update.desc_check_fail"_lang, { "common.ok"_lang }, false);
|
||||||
}
|
break;
|
||||||
this->askToUpdate(downloadUrl);
|
}
|
||||||
break;
|
this->askToUpdate(downloadUrl);
|
||||||
case 8:
|
break;
|
||||||
inst::ui::mainApp->CreateShowDialog("options.credits.title"_lang, "options.credits.desc"_lang, {"common.close"_lang}, true);
|
case 8:
|
||||||
break;
|
inst::ui::mainApp->CreateShowDialog("options.credits.title"_lang, "options.credits.desc"_lang, { "common.close"_lang }, true);
|
||||||
default:
|
break;
|
||||||
break;
|
default:
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,147 +10,151 @@
|
|||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
|
|
||||||
sdInstPage::sdInstPage() : Layout::Layout() {
|
sdInstPage::sdInstPage() : Layout::Layout() {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
||||||
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
||||||
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
||||||
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
||||||
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
||||||
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
||||||
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
||||||
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->pageInfoText = TextBlock::New(10, 109, "inst.sd.top_info"_lang);
|
this->pageInfoText = TextBlock::New(10, 109, "inst.sd.top_info"_lang);
|
||||||
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->butText = TextBlock::New(10, 678, "inst.sd.buttons"_lang);
|
this->butText = TextBlock::New(10, 678, "inst.sd.buttons"_lang);
|
||||||
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
||||||
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
||||||
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
||||||
this->Add(this->topRect);
|
this->Add(this->topRect);
|
||||||
this->Add(this->infoRect);
|
this->Add(this->infoRect);
|
||||||
this->Add(this->botRect);
|
this->Add(this->botRect);
|
||||||
this->Add(this->titleImage);
|
this->Add(this->titleImage);
|
||||||
this->Add(this->appVersionText);
|
this->Add(this->appVersionText);
|
||||||
this->Add(this->butText);
|
this->Add(this->butText);
|
||||||
this->Add(this->pageInfoText);
|
this->Add(this->pageInfoText);
|
||||||
this->Add(this->menu);
|
this->Add(this->menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdInstPage::drawMenuItems(bool clearItems, std::filesystem::path ourPath) {
|
void sdInstPage::drawMenuItems(bool clearItems, std::filesystem::path ourPath) {
|
||||||
if (clearItems) this->selectedTitles = {};
|
if (clearItems) this->selectedTitles = {};
|
||||||
if (ourPath == "sdmc:") this->currentDir = std::filesystem::path(ourPath.string() + "/");
|
if (ourPath == "sdmc:") this->currentDir = std::filesystem::path(ourPath.string() + "/");
|
||||||
else this->currentDir = ourPath;
|
else this->currentDir = ourPath;
|
||||||
this->menu->ClearItems();
|
this->menu->ClearItems();
|
||||||
try {
|
try {
|
||||||
this->ourDirectories = util::getDirsAtPath(this->currentDir);
|
this->ourDirectories = util::getDirsAtPath(this->currentDir);
|
||||||
this->ourFiles = util::getDirectoryFiles(this->currentDir, {".nsp", ".nsz", ".xci", ".xcz"});
|
this->ourFiles = util::getDirectoryFiles(this->currentDir, { ".nsp", ".nsz", ".xci", ".xcz" });
|
||||||
} catch (std::exception& e) {
|
}
|
||||||
this->drawMenuItems(false, this->currentDir.parent_path());
|
catch (std::exception& e) {
|
||||||
return;
|
this->drawMenuItems(false, this->currentDir.parent_path());
|
||||||
}
|
return;
|
||||||
if (this->currentDir != "sdmc:/") {
|
}
|
||||||
std::string itm = "..";
|
if (this->currentDir != "sdmc:/") {
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
std::string itm = "..";
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetIcon("romfs:/images/icons/folder-upload.png");
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu->AddItem(ourEntry);
|
ourEntry->SetIcon("romfs:/images/icons/folder-upload.png");
|
||||||
}
|
this->menu->AddItem(ourEntry);
|
||||||
for (auto& file: this->ourDirectories) {
|
}
|
||||||
if (file == "..") break;
|
for (auto& file : this->ourDirectories) {
|
||||||
std::string itm = file.filename().string();
|
if (file == "..") break;
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
std::string itm = file.filename().string();
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetIcon("romfs:/images/icons/folder.png");
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu->AddItem(ourEntry);
|
ourEntry->SetIcon("romfs:/images/icons/folder.png");
|
||||||
}
|
this->menu->AddItem(ourEntry);
|
||||||
for (auto& file: this->ourFiles) {
|
}
|
||||||
std::string itm = file.filename().string();
|
for (auto& file : this->ourFiles) {
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
std::string itm = file.filename().string();
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
||||||
if (this->selectedTitles[i] == file) {
|
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
||||||
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
if (this->selectedTitles[i] == file) {
|
||||||
}
|
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
||||||
}
|
}
|
||||||
this->menu->AddItem(ourEntry);
|
}
|
||||||
}
|
this->menu->AddItem(ourEntry);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sdInstPage::followDirectory() {
|
void sdInstPage::followDirectory() {
|
||||||
int selectedIndex = this->menu->GetSelectedIndex();
|
int selectedIndex = this->menu->GetSelectedIndex();
|
||||||
int dirListSize = this->ourDirectories.size();
|
int dirListSize = this->ourDirectories.size();
|
||||||
if (this->currentDir != "sdmc:/") {
|
if (this->currentDir != "sdmc:/") {
|
||||||
dirListSize++;
|
dirListSize++;
|
||||||
selectedIndex--;
|
selectedIndex--;
|
||||||
}
|
}
|
||||||
if (selectedIndex < dirListSize) {
|
if (selectedIndex < dirListSize) {
|
||||||
if (this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetName() == ".." && this->menu->GetSelectedIndex() == 0) {
|
if (this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetName() == ".." && this->menu->GetSelectedIndex() == 0) {
|
||||||
this->drawMenuItems(true, this->currentDir.parent_path());
|
this->drawMenuItems(true, this->currentDir.parent_path());
|
||||||
} else {
|
}
|
||||||
this->drawMenuItems(true, this->ourDirectories[selectedIndex]);
|
else {
|
||||||
}
|
this->drawMenuItems(true, this->ourDirectories[selectedIndex]);
|
||||||
this->menu->SetSelectedIndex(0);
|
}
|
||||||
}
|
this->menu->SetSelectedIndex(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sdInstPage::selectNsp(int selectedIndex) {
|
void sdInstPage::selectNsp(int selectedIndex) {
|
||||||
int dirListSize = this->ourDirectories.size();
|
int dirListSize = this->ourDirectories.size();
|
||||||
if (this->currentDir != "sdmc:/") dirListSize++;
|
if (this->currentDir != "sdmc:/") dirListSize++;
|
||||||
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
||||||
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
||||||
if (this->selectedTitles[i] == this->ourFiles[selectedIndex - dirListSize]) this->selectedTitles.erase(this->selectedTitles.begin() + i);
|
if (this->selectedTitles[i] == this->ourFiles[selectedIndex - dirListSize]) this->selectedTitles.erase(this->selectedTitles.begin() + i);
|
||||||
}
|
}
|
||||||
} else if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") this->selectedTitles.push_back(this->ourFiles[selectedIndex - dirListSize]);
|
}
|
||||||
else {
|
else if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") this->selectedTitles.push_back(this->ourFiles[selectedIndex - dirListSize]);
|
||||||
this->followDirectory();
|
else {
|
||||||
return;
|
this->followDirectory();
|
||||||
}
|
return;
|
||||||
this->drawMenuItems(false, currentDir);
|
}
|
||||||
}
|
this->drawMenuItems(false, currentDir);
|
||||||
|
}
|
||||||
|
|
||||||
void sdInstPage::startInstall() {
|
void sdInstPage::startInstall() {
|
||||||
int dialogResult = -1;
|
int dialogResult = -1;
|
||||||
if (this->selectedTitles.size() == 1) {
|
if (this->selectedTitles.size() == 1) {
|
||||||
dialogResult = mainApp->CreateShowDialog("inst.target.desc0"_lang + inst::util::shortenString(std::filesystem::path(this->selectedTitles[0]).filename().string(), 32, true) + "inst.target.desc1"_lang, "common.cancel_desc"_lang, {"inst.target.opt0"_lang, "inst.target.opt1"_lang}, false);
|
dialogResult = mainApp->CreateShowDialog("inst.target.desc0"_lang + inst::util::shortenString(std::filesystem::path(this->selectedTitles[0]).filename().string(), 32, true) + "inst.target.desc1"_lang, "common.cancel_desc"_lang, { "inst.target.opt0"_lang, "inst.target.opt1"_lang }, false);
|
||||||
} 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);
|
}
|
||||||
if (dialogResult == -1) return;
|
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);
|
||||||
nspInstStuff::installNspFromFile(this->selectedTitles, dialogResult);
|
if (dialogResult == -1) return;
|
||||||
}
|
nspInstStuff::installNspFromFile(this->selectedTitles, dialogResult);
|
||||||
|
}
|
||||||
|
|
||||||
void sdInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void sdInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
if (Down & HidNpadButton_B) {
|
if (Down & HidNpadButton_B) {
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_A)) {
|
if ((Down & HidNpadButton_A)) {
|
||||||
this->selectNsp(this->menu->GetSelectedIndex());
|
this->selectNsp(this->menu->GetSelectedIndex());
|
||||||
if (this->ourFiles.size() == 1 && this->selectedTitles.size() == 1) {
|
if (this->ourFiles.size() == 1 && this->selectedTitles.size() == 1) {
|
||||||
this->startInstall();
|
this->startInstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_Y)) {
|
if ((Down & HidNpadButton_Y)) {
|
||||||
if (this->selectedTitles.size() == this->ourFiles.size()) this->drawMenuItems(true, currentDir);
|
if (this->selectedTitles.size() == this->ourFiles.size()) this->drawMenuItems(true, currentDir);
|
||||||
else {
|
else {
|
||||||
int topDir = 0;
|
int topDir = 0;
|
||||||
if (this->currentDir != "sdmc:/") topDir++;
|
if (this->currentDir != "sdmc:/") topDir++;
|
||||||
for (long unsigned int i = this->ourDirectories.size() + topDir; i < this->menu->GetItems().size(); i++) {
|
for (long unsigned int i = this->ourDirectories.size() + topDir; i < this->menu->GetItems().size(); i++) {
|
||||||
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
||||||
else this->selectNsp(i);
|
else this->selectNsp(i);
|
||||||
}
|
}
|
||||||
this->drawMenuItems(false, currentDir);
|
this->drawMenuItems(false, currentDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_A)) {
|
if ((Down & HidNpadButton_A)) {
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.sd.help.title"_lang, "inst.sd.help.desc"_lang, {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("inst.sd.help.title"_lang, "inst.sd.help.desc"_lang, { "common.ok"_lang }, true);
|
||||||
}
|
}
|
||||||
if (Down & HidNpadButton_Plus) {
|
if (Down & HidNpadButton_Plus) {
|
||||||
if (this->selectedTitles.size() == 0 && this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") {
|
if (this->selectedTitles.size() == 0 && this->menu->GetItems()[this->menu->GetSelectedIndex()]->GetIcon() == "romfs:/images/icons/checkbox-blank-outline.png") {
|
||||||
this->selectNsp(this->menu->GetSelectedIndex());
|
this->selectNsp(this->menu->GetSelectedIndex());
|
||||||
}
|
}
|
||||||
if (this->selectedTitles.size() > 0) this->startInstall();
|
if (this->selectedTitles.size() > 0) this->startInstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,125 +10,127 @@
|
|||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
|
|
||||||
usbInstPage::usbInstPage() : Layout::Layout() {
|
usbInstPage::usbInstPage() : Layout::Layout() {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
if (std::filesystem::exists(inst::config::appDir + "/background.png")) this->SetBackgroundImage(inst::config::appDir + "/background.png");
|
||||||
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
else this->SetBackgroundImage("romfs:/images/background.jpg");
|
||||||
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
this->topRect = Rectangle::New(0, 0, 1280, 94, COLOR("#170909FF"));
|
||||||
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
this->infoRect = Rectangle::New(0, 95, 1280, 60, COLOR("#17090980"));
|
||||||
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
this->botRect = Rectangle::New(0, 660, 1280, 60, COLOR("#17090980"));
|
||||||
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
this->titleImage = Image::New(0, 0, "romfs:/images/logo.png");
|
||||||
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
this->appVersionText = TextBlock::New(480, 49, "v" + inst::config::appVersion);
|
||||||
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
this->appVersionText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->pageInfoText = TextBlock::New(10, 109, "");
|
this->pageInfoText = TextBlock::New(10, 109, "");
|
||||||
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->butText = TextBlock::New(10, 678, "");
|
this->butText = TextBlock::New(10, 678, "");
|
||||||
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
this->butText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
this->menu = pu::ui::elm::Menu::New(0, 156, 1280, COLOR("#FFFFFF00"), 84, (506 / 84));
|
||||||
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
this->menu->SetOnFocusColor(COLOR("#00000033"));
|
||||||
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
this->menu->SetScrollbarColor(COLOR("#17090980"));
|
||||||
this->infoImage = Image::New(460, 332, "romfs:/images/icons/usb-connection-waiting.png");
|
this->infoImage = Image::New(460, 332, "romfs:/images/icons/usb-connection-waiting.png");
|
||||||
this->Add(this->topRect);
|
this->Add(this->topRect);
|
||||||
this->Add(this->infoRect);
|
this->Add(this->infoRect);
|
||||||
this->Add(this->botRect);
|
this->Add(this->botRect);
|
||||||
this->Add(this->titleImage);
|
this->Add(this->titleImage);
|
||||||
this->Add(this->appVersionText);
|
this->Add(this->appVersionText);
|
||||||
this->Add(this->butText);
|
this->Add(this->butText);
|
||||||
this->Add(this->pageInfoText);
|
this->Add(this->pageInfoText);
|
||||||
this->Add(this->menu);
|
this->Add(this->menu);
|
||||||
this->Add(this->infoImage);
|
this->Add(this->infoImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbInstPage::drawMenuItems(bool clearItems) {
|
void usbInstPage::drawMenuItems(bool clearItems) {
|
||||||
if (clearItems) this->selectedTitles = {};
|
if (clearItems) this->selectedTitles = {};
|
||||||
this->menu->ClearItems();
|
this->menu->ClearItems();
|
||||||
for (auto& url: this->ourTitles) {
|
for (auto& url : this->ourTitles) {
|
||||||
std::string itm = inst::util::shortenString(inst::util::formatUrlString(url), 56, true);
|
std::string itm = inst::util::shortenString(inst::util::formatUrlString(url), 56, true);
|
||||||
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
auto ourEntry = pu::ui::elm::MenuItem::New(itm);
|
||||||
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
ourEntry->SetColor(COLOR("#FFFFFFFF"));
|
||||||
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
ourEntry->SetIcon("romfs:/images/icons/checkbox-blank-outline.png");
|
||||||
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
||||||
if (this->selectedTitles[i] == url) {
|
if (this->selectedTitles[i] == url) {
|
||||||
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
ourEntry->SetIcon("romfs:/images/icons/check-box-outline.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->menu->AddItem(ourEntry);
|
this->menu->AddItem(ourEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbInstPage::selectTitle(int selectedIndex) {
|
void usbInstPage::selectTitle(int selectedIndex) {
|
||||||
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
if (this->menu->GetItems()[selectedIndex]->GetIcon() == "romfs:/images/icons/check-box-outline.png") {
|
||||||
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
for (long unsigned int i = 0; i < this->selectedTitles.size(); i++) {
|
||||||
if (this->selectedTitles[i] == this->ourTitles[selectedIndex]) this->selectedTitles.erase(this->selectedTitles.begin() + i);
|
if (this->selectedTitles[i] == this->ourTitles[selectedIndex]) this->selectedTitles.erase(this->selectedTitles.begin() + i);
|
||||||
}
|
}
|
||||||
} else this->selectedTitles.push_back(this->ourTitles[selectedIndex]);
|
}
|
||||||
this->drawMenuItems(false);
|
else this->selectedTitles.push_back(this->ourTitles[selectedIndex]);
|
||||||
}
|
this->drawMenuItems(false);
|
||||||
|
}
|
||||||
|
|
||||||
void usbInstPage::startUsb() {
|
void usbInstPage::startUsb() {
|
||||||
this->pageInfoText->SetText("inst.usb.top_info"_lang);
|
this->pageInfoText->SetText("inst.usb.top_info"_lang);
|
||||||
this->butText->SetText("inst.usb.buttons"_lang);
|
this->butText->SetText("inst.usb.buttons"_lang);
|
||||||
this->menu->SetVisible(false);
|
this->menu->SetVisible(false);
|
||||||
this->menu->ClearItems();
|
this->menu->ClearItems();
|
||||||
this->infoImage->SetVisible(true);
|
this->infoImage->SetVisible(true);
|
||||||
mainApp->LoadLayout(mainApp->usbinstPage);
|
mainApp->LoadLayout(mainApp->usbinstPage);
|
||||||
mainApp->CallForRender();
|
mainApp->CallForRender();
|
||||||
this->ourTitles = usbInstStuff::OnSelected();
|
this->ourTitles = usbInstStuff::OnSelected();
|
||||||
if (!this->ourTitles.size()) {
|
if (!this->ourTitles.size()) {
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
mainApp->CallForRender(); // If we re-render a few times during this process the main screen won't flicker
|
else {
|
||||||
this->pageInfoText->SetText("inst.usb.top_info2"_lang);
|
mainApp->CallForRender(); // If we re-render a few times during this process the main screen won't flicker
|
||||||
this->butText->SetText("inst.usb.buttons2"_lang);
|
this->pageInfoText->SetText("inst.usb.top_info2"_lang);
|
||||||
this->drawMenuItems(true);
|
this->butText->SetText("inst.usb.buttons2"_lang);
|
||||||
this->menu->SetSelectedIndex(0);
|
this->drawMenuItems(true);
|
||||||
mainApp->CallForRender();
|
this->menu->SetSelectedIndex(0);
|
||||||
this->infoImage->SetVisible(false);
|
mainApp->CallForRender();
|
||||||
this->menu->SetVisible(true);
|
this->infoImage->SetVisible(false);
|
||||||
}
|
this->menu->SetVisible(true);
|
||||||
return;
|
}
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void usbInstPage::startInstall() {
|
void usbInstPage::startInstall() {
|
||||||
int dialogResult = -1;
|
int dialogResult = -1;
|
||||||
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);
|
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);
|
||||||
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);
|
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);
|
||||||
if (dialogResult == -1) return;
|
if (dialogResult == -1) return;
|
||||||
usbInstStuff::installTitleUsb(this->selectedTitles, dialogResult);
|
usbInstStuff::installTitleUsb(this->selectedTitles, dialogResult);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void usbInstPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
if (Down & HidNpadButton_B) {
|
if (Down & HidNpadButton_B) {
|
||||||
tin::util::USBCmdManager::SendExitCmd();
|
tin::util::USBCmdManager::SendExitCmd();
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_A)) {
|
if ((Down & HidNpadButton_A)) {
|
||||||
this->selectTitle(this->menu->GetSelectedIndex());
|
this->selectTitle(this->menu->GetSelectedIndex());
|
||||||
if (this->menu->GetItems().size() == 1 && this->selectedTitles.size() == 1) {
|
if (this->menu->GetItems().size() == 1 && this->selectedTitles.size() == 1) {
|
||||||
this->startInstall();
|
this->startInstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((Down & HidNpadButton_Y)) {
|
if ((Down & HidNpadButton_Y)) {
|
||||||
if (this->selectedTitles.size() == this->menu->GetItems().size()) this->drawMenuItems(true);
|
if (this->selectedTitles.size() == this->menu->GetItems().size()) this->drawMenuItems(true);
|
||||||
else {
|
else {
|
||||||
for (long unsigned int i = 0; i < this->menu->GetItems().size(); i++) {
|
for (long unsigned int i = 0; i < this->menu->GetItems().size(); i++) {
|
||||||
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
if (this->menu->GetItems()[i]->GetIcon() == "romfs:/images/icons/check-box-outline.png") continue;
|
||||||
else this->selectTitle(i);
|
else this->selectTitle(i);
|
||||||
}
|
}
|
||||||
this->drawMenuItems(false);
|
this->drawMenuItems(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Down & HidNpadButton_Plus) {
|
if (Down & HidNpadButton_Plus) {
|
||||||
if (this->selectedTitles.size() == 0) {
|
if (this->selectedTitles.size() == 0) {
|
||||||
this->selectTitle(this->menu->GetSelectedIndex());
|
this->selectTitle(this->menu->GetSelectedIndex());
|
||||||
this->startInstall();
|
this->startInstall();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->startInstall();
|
this->startInstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -38,143 +38,144 @@ SOFTWARE.
|
|||||||
#include "ui/instPage.hpp"
|
#include "ui/instPage.hpp"
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
extern MainApplication *mainApp;
|
extern MainApplication* mainApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace usbInstStuff {
|
namespace usbInstStuff {
|
||||||
struct TUSHeader
|
struct TUSHeader
|
||||||
{
|
{
|
||||||
u32 magic; // TUL0 (Tinfoil Usb List 0)
|
u32 magic; // TUL0 (Tinfoil Usb List 0)
|
||||||
u32 titleListSize;
|
u32 titleListSize;
|
||||||
u64 padding;
|
u64 padding;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
int bufferData(void* buf, size_t size, u64 timeout = 5000000000)
|
int bufferData(void* buf, size_t size, u64 timeout = 5000000000)
|
||||||
{
|
{
|
||||||
u8* tempBuffer = (u8*)memalign(0x1000, size);
|
u8* tempBuffer = (u8*)memalign(0x1000, size);
|
||||||
if (tin::util::USBRead(tempBuffer, size, timeout) == 0) return 0;
|
if (tin::util::USBRead(tempBuffer, size, timeout) == 0) return 0;
|
||||||
memcpy(buf, tempBuffer, size);
|
memcpy(buf, tempBuffer, size);
|
||||||
free(tempBuffer);
|
free(tempBuffer);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> OnSelected() {
|
std::vector<std::string> OnSelected() {
|
||||||
TUSHeader header;
|
TUSHeader header;
|
||||||
u64 freq = armGetSystemTickFreq();
|
u64 freq = armGetSystemTickFreq();
|
||||||
u64 startTime = armGetSystemTick();
|
u64 startTime = armGetSystemTick();
|
||||||
while(true) {
|
while (true) {
|
||||||
// If we don't update the UI occasionally the Switch basically crashes on this screen if you press the home button
|
// If we don't update the UI occasionally the Switch basically crashes on this screen if you press the home button
|
||||||
u64 newTime = armGetSystemTick();
|
u64 newTime = armGetSystemTick();
|
||||||
if (newTime - startTime >= freq * 0.25) {
|
if (newTime - startTime >= freq * 0.25) {
|
||||||
startTime = newTime;
|
startTime = newTime;
|
||||||
inst::ui::mainApp->CallForRender();
|
inst::ui::mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferData(&header, sizeof(TUSHeader), 500000000) != 0) break;
|
if (bufferData(&header, sizeof(TUSHeader), 500000000) != 0) break;
|
||||||
u64 kDown = inst::ui::mainApp->GetButtonsDown();
|
u64 kDown = inst::ui::mainApp->GetButtonsDown();
|
||||||
if (kDown & HidNpadButton_B) return {};
|
if (kDown & HidNpadButton_B) return {};
|
||||||
if (kDown & HidNpadButton_X) inst::ui::mainApp->CreateShowDialog("inst.usb.help.title"_lang, "inst.usb.help.desc"_lang, {"common.ok"_lang}, true);
|
if (kDown & HidNpadButton_X) inst::ui::mainApp->CreateShowDialog("inst.usb.help.title"_lang, "inst.usb.help.desc"_lang, { "common.ok"_lang }, true);
|
||||||
if (!inst::util::usbIsConnected()) return {};
|
if (!inst::util::usbIsConnected()) return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.magic != 0x304C5554) return {};
|
if (header.magic != 0x304C5554) return {};
|
||||||
|
|
||||||
std::vector<std::string> titleNames;
|
std::vector<std::string> titleNames;
|
||||||
char* titleNameBuffer = (char*)memalign(0x1000, header.titleListSize + 1);
|
char* titleNameBuffer = (char*)memalign(0x1000, header.titleListSize + 1);
|
||||||
memset(titleNameBuffer, 0, header.titleListSize + 1);
|
memset(titleNameBuffer, 0, header.titleListSize + 1);
|
||||||
|
|
||||||
tin::util::USBRead(titleNameBuffer, header.titleListSize, 10000000000);
|
tin::util::USBRead(titleNameBuffer, header.titleListSize, 10000000000);
|
||||||
|
|
||||||
// Split the string up into individual title names
|
// Split the string up into individual title names
|
||||||
std::stringstream titleNamesStream(titleNameBuffer);
|
std::stringstream titleNamesStream(titleNameBuffer);
|
||||||
std::string segment;
|
std::string segment;
|
||||||
while (std::getline(titleNamesStream, segment, '\n')) titleNames.push_back(segment);
|
while (std::getline(titleNamesStream, segment, '\n')) titleNames.push_back(segment);
|
||||||
free(titleNameBuffer);
|
free(titleNameBuffer);
|
||||||
std::sort(titleNames.begin(), titleNames.end(), inst::util::ignoreCaseCompare);
|
std::sort(titleNames.begin(), titleNames.end(), inst::util::ignoreCaseCompare);
|
||||||
|
|
||||||
return titleNames;
|
return titleNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void installTitleUsb(std::vector<std::string> ourTitleList, int ourStorage)
|
void installTitleUsb(std::vector<std::string> ourTitleList, int ourStorage)
|
||||||
{
|
{
|
||||||
inst::util::initInstallServices();
|
inst::util::initInstallServices();
|
||||||
inst::ui::instPage::loadInstallScreen();
|
inst::ui::instPage::loadInstallScreen();
|
||||||
bool nspInstalled = true;
|
bool nspInstalled = true;
|
||||||
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
NcmStorageId m_destStorageId = NcmStorageId_SdCard;
|
||||||
|
|
||||||
if (ourStorage) m_destStorageId = NcmStorageId_BuiltInUser;
|
if (ourStorage) m_destStorageId = NcmStorageId_BuiltInUser;
|
||||||
unsigned int fileItr;
|
unsigned int fileItr;
|
||||||
|
|
||||||
std::vector<std::string> fileNames;
|
std::vector<std::string> fileNames;
|
||||||
for (long unsigned int i = 0; i < ourTitleList.size(); i++) {
|
for (long unsigned int i = 0; i < ourTitleList.size(); i++) {
|
||||||
fileNames.push_back(inst::util::shortenString(inst::util::formatUrlString(ourTitleList[i]), 40, true));
|
fileNames.push_back(inst::util::shortenString(inst::util::formatUrlString(ourTitleList[i]), 40, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> previousClockValues;
|
std::vector<int> previousClockValues;
|
||||||
if (inst::config::overClock) {
|
if (inst::config::overClock) {
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(0, 1785000000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(1, 76800000)[0]);
|
||||||
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
previousClockValues.push_back(inst::util::setClockSpeed(2, 1600000000)[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (fileItr = 0; fileItr < ourTitleList.size(); fileItr++) {
|
for (fileItr = 0; fileItr < ourTitleList.size(); fileItr++) {
|
||||||
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + fileNames[fileItr] + "inst.usb.source_string"_lang);
|
inst::ui::instPage::setTopInstInfoText("inst.info_page.top_info0"_lang + fileNames[fileItr] + "inst.usb.source_string"_lang);
|
||||||
std::unique_ptr<tin::install::Install> installTask;
|
std::unique_ptr<tin::install::Install> installTask;
|
||||||
|
|
||||||
if (ourTitleList[fileItr].compare(ourTitleList[fileItr].size() - 3, 2, "xc") == 0) {
|
if (ourTitleList[fileItr].compare(ourTitleList[fileItr].size() - 3, 2, "xc") == 0) {
|
||||||
auto usbXCI = std::make_shared<tin::install::xci::USBXCI>(ourTitleList[fileItr]);
|
auto usbXCI = std::make_shared<tin::install::xci::USBXCI>(ourTitleList[fileItr]);
|
||||||
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, usbXCI);
|
installTask = std::make_unique<tin::install::xci::XCIInstallTask>(m_destStorageId, inst::config::ignoreReqVers, usbXCI);
|
||||||
} else {
|
}
|
||||||
auto usbNSP = std::make_shared<tin::install::nsp::USBNSP>(ourTitleList[fileItr]);
|
else {
|
||||||
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, usbNSP);
|
auto usbNSP = std::make_shared<tin::install::nsp::USBNSP>(ourTitleList[fileItr]);
|
||||||
}
|
installTask = std::make_unique<tin::install::nsp::NSPInstall>(m_destStorageId, inst::config::ignoreReqVers, usbNSP);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("%s\n", "Preparing installation");
|
LOG_DEBUG("%s\n", "Preparing installation");
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.preparing"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
installTask->Prepare();
|
installTask->Prepare();
|
||||||
|
|
||||||
installTask->Begin();
|
installTask->Begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e) {
|
catch (std::exception& e) {
|
||||||
LOG_DEBUG("Failed to install");
|
LOG_DEBUG("Failed to install");
|
||||||
LOG_DEBUG("%s", e.what());
|
LOG_DEBUG("%s", e.what());
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + fileNames[fileItr]);
|
inst::ui::instPage::setInstInfoText("inst.info_page.failed"_lang + fileNames[fileItr]);
|
||||||
inst::ui::instPage::setInstBarPerc(0);
|
inst::ui::instPage::setInstBarPerc(0);
|
||||||
std::string audioPath = "romfs:/audio/bark.wav";
|
std::string audioPath = "romfs:/audio/bark.wav";
|
||||||
if (inst::config::gayMode) audioPath = "";
|
if (inst::config::gayMode) audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
if (std::filesystem::exists(inst::config::appDir + "/bark.wav")) audioPath = inst::config::appDir + "/bark.wav";
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + fileNames[fileItr] + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), {"common.ok"_lang}, true);
|
inst::ui::mainApp->CreateShowDialog("inst.info_page.failed"_lang + fileNames[fileItr] + "!", "inst.info_page.failed_desc"_lang + "\n\n" + (std::string)e.what(), { "common.ok"_lang }, true);
|
||||||
audioThread.join();
|
audioThread.join();
|
||||||
nspInstalled = false;
|
nspInstalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousClockValues.size() > 0) {
|
if (previousClockValues.size() > 0) {
|
||||||
inst::util::setClockSpeed(0, previousClockValues[0]);
|
inst::util::setClockSpeed(0, previousClockValues[0]);
|
||||||
inst::util::setClockSpeed(1, previousClockValues[1]);
|
inst::util::setClockSpeed(1, previousClockValues[1]);
|
||||||
inst::util::setClockSpeed(2, previousClockValues[2]);
|
inst::util::setClockSpeed(2, previousClockValues[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nspInstalled) {
|
if (nspInstalled) {
|
||||||
tin::util::USBCmdManager::SendExitCmd();
|
tin::util::USBCmdManager::SendExitCmd();
|
||||||
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
inst::ui::instPage::setInstInfoText("inst.info_page.complete"_lang);
|
||||||
inst::ui::instPage::setInstBarPerc(100);
|
inst::ui::instPage::setInstBarPerc(100);
|
||||||
std::string audioPath = "romfs:/audio/awoo.wav";
|
std::string audioPath = "romfs:/audio/awoo.wav";
|
||||||
if (inst::config::gayMode) audioPath = "";
|
if (inst::config::gayMode) audioPath = "";
|
||||||
if (std::filesystem::exists(inst::config::appDir + "/awoo.wav")) audioPath = inst::config::appDir + "/awoo.wav";
|
if (std::filesystem::exists(inst::config::appDir + "/awoo.wav")) audioPath = inst::config::appDir + "/awoo.wav";
|
||||||
std::thread audioThread(inst::util::playAudio,audioPath);
|
std::thread audioThread(inst::util::playAudio, audioPath);
|
||||||
if (ourTitleList.size() > 1) inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
if (ourTitleList.size() > 1) inst::ui::mainApp->CreateShowDialog(std::to_string(ourTitleList.size()) + "inst.info_page.desc0"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
else inst::ui::mainApp->CreateShowDialog(fileNames[0] + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), {"common.ok"_lang}, true);
|
else inst::ui::mainApp->CreateShowDialog(fileNames[0] + "inst.info_page.desc1"_lang, Language::GetRandomMsg(), { "common.ok"_lang }, true);
|
||||||
audioThread.join();
|
audioThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Done");
|
LOG_DEBUG("Done");
|
||||||
inst::ui::instPage::loadMainMenu();
|
inst::ui::instPage::loadMainMenu();
|
||||||
inst::util::deinitInstallServices();
|
inst::util::deinitInstallServices();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,68 +4,68 @@
|
|||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
|
|
||||||
namespace inst::config {
|
namespace inst::config {
|
||||||
std::string gAuthKey;
|
std::string gAuthKey;
|
||||||
std::string sigPatchesUrl;
|
std::string sigPatchesUrl;
|
||||||
std::string lastNetUrl;
|
std::string lastNetUrl;
|
||||||
std::vector<std::string> updateInfo;
|
std::vector<std::string> updateInfo;
|
||||||
int languageSetting;
|
int languageSetting;
|
||||||
bool autoUpdate;
|
bool autoUpdate;
|
||||||
bool deletePrompt;
|
bool deletePrompt;
|
||||||
bool gayMode;
|
bool gayMode;
|
||||||
bool ignoreReqVers;
|
bool ignoreReqVers;
|
||||||
bool overClock;
|
bool overClock;
|
||||||
bool usbAck;
|
bool usbAck;
|
||||||
bool validateNCAs;
|
bool validateNCAs;
|
||||||
|
|
||||||
void setConfig() {
|
void setConfig() {
|
||||||
nlohmann::json j = {
|
nlohmann::json j = {
|
||||||
{"autoUpdate", autoUpdate},
|
{"autoUpdate", autoUpdate},
|
||||||
{"deletePrompt", deletePrompt},
|
{"deletePrompt", deletePrompt},
|
||||||
{"gAuthKey", gAuthKey},
|
{"gAuthKey", gAuthKey},
|
||||||
{"gayMode", gayMode},
|
{"gayMode", gayMode},
|
||||||
{"ignoreReqVers", ignoreReqVers},
|
{"ignoreReqVers", ignoreReqVers},
|
||||||
{"languageSetting", languageSetting},
|
{"languageSetting", languageSetting},
|
||||||
{"overClock", overClock},
|
{"overClock", overClock},
|
||||||
{"sigPatchesUrl", sigPatchesUrl},
|
{"sigPatchesUrl", sigPatchesUrl},
|
||||||
{"usbAck", usbAck},
|
{"usbAck", usbAck},
|
||||||
{"validateNCAs", validateNCAs},
|
{"validateNCAs", validateNCAs},
|
||||||
{"lastNetUrl", lastNetUrl}
|
{"lastNetUrl", lastNetUrl}
|
||||||
};
|
};
|
||||||
std::ofstream file(inst::config::configPath);
|
std::ofstream file(inst::config::configPath);
|
||||||
file << std::setw(4) << j << std::endl;
|
file << std::setw(4) << j << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseConfig() {
|
void parseConfig() {
|
||||||
try {
|
try {
|
||||||
std::ifstream file(inst::config::configPath);
|
std::ifstream file(inst::config::configPath);
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
file >> j;
|
file >> j;
|
||||||
autoUpdate = j["autoUpdate"].get<bool>();
|
autoUpdate = j["autoUpdate"].get<bool>();
|
||||||
deletePrompt = j["deletePrompt"].get<bool>();
|
deletePrompt = j["deletePrompt"].get<bool>();
|
||||||
gAuthKey = j["gAuthKey"].get<std::string>();
|
gAuthKey = j["gAuthKey"].get<std::string>();
|
||||||
gayMode = j["gayMode"].get<bool>();
|
gayMode = j["gayMode"].get<bool>();
|
||||||
ignoreReqVers = j["ignoreReqVers"].get<bool>();
|
ignoreReqVers = j["ignoreReqVers"].get<bool>();
|
||||||
languageSetting = j["languageSetting"].get<int>();
|
languageSetting = j["languageSetting"].get<int>();
|
||||||
overClock = j["overClock"].get<bool>();
|
overClock = j["overClock"].get<bool>();
|
||||||
sigPatchesUrl = j["sigPatchesUrl"].get<std::string>();
|
sigPatchesUrl = j["sigPatchesUrl"].get<std::string>();
|
||||||
usbAck = j["usbAck"].get<bool>();
|
usbAck = j["usbAck"].get<bool>();
|
||||||
validateNCAs = j["validateNCAs"].get<bool>();
|
validateNCAs = j["validateNCAs"].get<bool>();
|
||||||
lastNetUrl = j["lastNetUrl"].get<std::string>();
|
lastNetUrl = j["lastNetUrl"].get<std::string>();
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// If loading values from the config fails, we just load the defaults and overwrite the old config
|
// If loading values from the config fails, we just load the defaults and overwrite the old config
|
||||||
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};
|
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 };
|
||||||
sigPatchesUrl = "https://github.com/Huntereb/Awoo-Installer/releases/download/SignaturePatches/patches.zip";
|
sigPatchesUrl = "https://github.com/Huntereb/Awoo-Installer/releases/download/SignaturePatches/patches.zip";
|
||||||
languageSetting = 99;
|
languageSetting = 99;
|
||||||
autoUpdate = true;
|
autoUpdate = true;
|
||||||
deletePrompt = true;
|
deletePrompt = true;
|
||||||
gayMode = false;
|
gayMode = false;
|
||||||
ignoreReqVers = true;
|
ignoreReqVers = true;
|
||||||
overClock = false;
|
overClock = false;
|
||||||
usbAck = false;
|
usbAck = false;
|
||||||
validateNCAs = true;
|
validateNCAs = true;
|
||||||
lastNetUrl = "https://";
|
lastNetUrl = "https://";
|
||||||
setConfig();
|
setConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,86 +5,86 @@
|
|||||||
#include <mbedtls/bignum.h>
|
#include <mbedtls/bignum.h>
|
||||||
|
|
||||||
void Crypto::calculateMGF1andXOR(unsigned char* data, size_t data_size, const void* source, size_t source_size) {
|
void Crypto::calculateMGF1andXOR(unsigned char* data, size_t data_size, const void* source, size_t source_size) {
|
||||||
unsigned char h_buf[RSA_2048_BYTES] = {0};
|
unsigned char h_buf[RSA_2048_BYTES] = { 0 };
|
||||||
memcpy(h_buf, source, source_size);
|
memcpy(h_buf, source, source_size);
|
||||||
|
|
||||||
unsigned char mgf1_buf[0x20];
|
unsigned char mgf1_buf[0x20];
|
||||||
size_t ofs = 0;
|
size_t ofs = 0;
|
||||||
unsigned int seed = 0;
|
unsigned int seed = 0;
|
||||||
while (ofs < data_size) {
|
while (ofs < data_size) {
|
||||||
for (unsigned int i = 0; i < sizeof(seed); i++) {
|
for (unsigned int i = 0; i < sizeof(seed); i++) {
|
||||||
h_buf[source_size + 3 - i] = (seed >> (8 * i)) & 0xFF;
|
h_buf[source_size + 3 - i] = (seed >> (8 * i)) & 0xFF;
|
||||||
}
|
}
|
||||||
sha256CalculateHash(mgf1_buf, h_buf, source_size + 4);
|
sha256CalculateHash(mgf1_buf, h_buf, source_size + 4);
|
||||||
for (unsigned int i = ofs; i < data_size && i < ofs + 0x20; i++) {
|
for (unsigned int i = ofs; i < data_size && i < ofs + 0x20; i++) {
|
||||||
data[i] ^= mgf1_buf[i - ofs];
|
data[i] ^= mgf1_buf[i - ofs];
|
||||||
}
|
}
|
||||||
seed++;
|
seed++;
|
||||||
ofs += 0x20;
|
ofs += 0x20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Crypto::rsa2048PssVerify(const void *data, size_t len, const unsigned char *signature, const unsigned char *modulus) {
|
bool Crypto::rsa2048PssVerify(const void* data, size_t len, const unsigned char* signature, const unsigned char* modulus) {
|
||||||
mbedtls_mpi signature_mpi;
|
mbedtls_mpi signature_mpi;
|
||||||
mbedtls_mpi modulus_mpi;
|
mbedtls_mpi modulus_mpi;
|
||||||
mbedtls_mpi e_mpi;
|
mbedtls_mpi e_mpi;
|
||||||
mbedtls_mpi message_mpi;
|
mbedtls_mpi message_mpi;
|
||||||
|
|
||||||
mbedtls_mpi_init(&signature_mpi);
|
mbedtls_mpi_init(&signature_mpi);
|
||||||
mbedtls_mpi_init(&modulus_mpi);
|
mbedtls_mpi_init(&modulus_mpi);
|
||||||
mbedtls_mpi_init(&e_mpi);
|
mbedtls_mpi_init(&e_mpi);
|
||||||
mbedtls_mpi_init(&message_mpi);
|
mbedtls_mpi_init(&message_mpi);
|
||||||
mbedtls_mpi_lset(&message_mpi, RSA_2048_BITS);
|
mbedtls_mpi_lset(&message_mpi, RSA_2048_BITS);
|
||||||
|
|
||||||
unsigned char m_buf[RSA_2048_BYTES];
|
unsigned char m_buf[RSA_2048_BYTES];
|
||||||
unsigned char h_buf[0x24];
|
unsigned char h_buf[0x24];
|
||||||
const unsigned char E[3] = {1, 0, 1};
|
const unsigned char E[3] = { 1, 0, 1 };
|
||||||
|
|
||||||
mbedtls_mpi_read_binary(&e_mpi, E, 3);
|
mbedtls_mpi_read_binary(&e_mpi, E, 3);
|
||||||
mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES);
|
mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES);
|
||||||
mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES);
|
mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES);
|
||||||
mbedtls_mpi_exp_mod(&message_mpi, &signature_mpi, &e_mpi, &modulus_mpi, NULL);
|
mbedtls_mpi_exp_mod(&message_mpi, &signature_mpi, &e_mpi, &modulus_mpi, NULL);
|
||||||
|
|
||||||
if (mbedtls_mpi_write_binary(&message_mpi, m_buf, RSA_2048_BYTES) != 0) {
|
if (mbedtls_mpi_write_binary(&message_mpi, m_buf, RSA_2048_BYTES) != 0) {
|
||||||
throw std::runtime_error("Failed to export exponentiated RSA message!");
|
throw std::runtime_error("Failed to export exponentiated RSA message!");
|
||||||
}
|
}
|
||||||
|
|
||||||
mbedtls_mpi_free(&signature_mpi);
|
mbedtls_mpi_free(&signature_mpi);
|
||||||
mbedtls_mpi_free(&modulus_mpi);
|
mbedtls_mpi_free(&modulus_mpi);
|
||||||
mbedtls_mpi_free(&e_mpi);
|
mbedtls_mpi_free(&e_mpi);
|
||||||
mbedtls_mpi_free(&message_mpi);
|
mbedtls_mpi_free(&message_mpi);
|
||||||
|
|
||||||
/* There's no automated PSS verification as far as I can tell. */
|
/* There's no automated PSS verification as far as I can tell. */
|
||||||
if (m_buf[RSA_2048_BYTES-1] != 0xBC) {
|
if (m_buf[RSA_2048_BYTES - 1] != 0xBC) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(h_buf, 0, 0x24);
|
memset(h_buf, 0, 0x24);
|
||||||
memcpy(h_buf, m_buf + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
|
memcpy(h_buf, m_buf + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
|
||||||
|
|
||||||
/* Decrypt maskedDB. */
|
/* Decrypt maskedDB. */
|
||||||
calculateMGF1andXOR(m_buf, RSA_2048_BYTES - 0x20 - 1, h_buf, 0x20);
|
calculateMGF1andXOR(m_buf, RSA_2048_BYTES - 0x20 - 1, h_buf, 0x20);
|
||||||
|
|
||||||
m_buf[0] &= 0x7F; /* Constant lmask for rsa-2048-pss. */
|
m_buf[0] &= 0x7F; /* Constant lmask for rsa-2048-pss. */
|
||||||
|
|
||||||
/* Validate DB. */
|
/* Validate DB. */
|
||||||
for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) {
|
for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) {
|
||||||
if (m_buf[i] != 0) {
|
if (m_buf[i] != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) {
|
if (m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check hash correctness. */
|
/* Check hash correctness. */
|
||||||
unsigned char validate_buf[8 + 0x20 + 0x20];
|
unsigned char validate_buf[8 + 0x20 + 0x20];
|
||||||
unsigned char validate_hash[0x20];
|
unsigned char validate_hash[0x20];
|
||||||
memset(validate_buf, 0, 0x48);
|
memset(validate_buf, 0, 0x48);
|
||||||
|
|
||||||
sha256CalculateHash(&validate_buf[8], data, len);
|
sha256CalculateHash(&validate_buf[8], data, len);
|
||||||
memcpy(&validate_buf[0x28], &m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20);
|
memcpy(&validate_buf[0x28], &m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20);
|
||||||
sha256CalculateHash(validate_hash, validate_buf, 0x48);
|
sha256CalculateHash(validate_hash, validate_buf, 0x48);
|
||||||
|
|
||||||
return memcmp(h_buf, validate_hash, 0x20) == 0;
|
return memcmp(h_buf, validate_hash, 0x20) == 0;
|
||||||
}
|
}
|
@ -7,96 +7,97 @@
|
|||||||
#include "util/error.hpp"
|
#include "util/error.hpp"
|
||||||
#include "ui/instPage.hpp"
|
#include "ui/instPage.hpp"
|
||||||
|
|
||||||
static size_t writeDataFile(void *ptr, size_t size, size_t nmemb, void *stream) {
|
static size_t writeDataFile(void* ptr, size_t size, size_t nmemb, void* stream) {
|
||||||
size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
|
size_t written = fwrite(ptr, size, nmemb, (FILE*)stream);
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t writeDataBuffer(char *ptr, size_t size, size_t nmemb, void *userdata) {
|
size_t writeDataBuffer(char* ptr, size_t size, size_t nmemb, void* userdata) {
|
||||||
std::ostringstream *stream = (std::ostringstream*)userdata;
|
std::ostringstream* stream = (std::ostringstream*)userdata;
|
||||||
size_t count = size * nmemb;
|
size_t count = size * nmemb;
|
||||||
stream->write(ptr, count);
|
stream->write(ptr, count);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
|
int progress_callback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
|
||||||
if (ultotal) {
|
if (ultotal) {
|
||||||
int uploadProgress = (int)(((double)ulnow / (double)ultotal) * 100.0);
|
int uploadProgress = (int)(((double)ulnow / (double)ultotal) * 100.0);
|
||||||
inst::ui::instPage::setInstBarPerc(uploadProgress);
|
inst::ui::instPage::setInstBarPerc(uploadProgress);
|
||||||
} else if (dltotal) {
|
}
|
||||||
int downloadProgress = (int)(((double)dlnow / (double)dltotal) * 100.0);
|
else if (dltotal) {
|
||||||
inst::ui::instPage::setInstBarPerc(downloadProgress);
|
int downloadProgress = (int)(((double)dlnow / (double)dltotal) * 100.0);
|
||||||
}
|
inst::ui::instPage::setInstBarPerc(downloadProgress);
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace inst::curl {
|
namespace inst::curl {
|
||||||
bool downloadFile (const std::string ourUrl, const char *pagefilename, long timeout, bool writeProgress) {
|
bool downloadFile(const std::string ourUrl, const char* pagefilename, long timeout, bool writeProgress) {
|
||||||
CURL *curl_handle;
|
CURL* curl_handle;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
FILE *pagefile;
|
FILE* pagefile;
|
||||||
|
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
|
||||||
curl_handle = curl_easy_init();
|
|
||||||
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_URL, ourUrl.c_str());
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Awoo-Installer");
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, timeout);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeDataFile);
|
|
||||||
if (writeProgress) curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, progress_callback);
|
|
||||||
|
|
||||||
pagefile = fopen(pagefilename, "wb");
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);
|
|
||||||
result = curl_easy_perform(curl_handle);
|
|
||||||
|
|
||||||
curl_easy_cleanup(curl_handle);
|
|
||||||
curl_global_cleanup();
|
|
||||||
fclose(pagefile);
|
|
||||||
|
|
||||||
if (result == CURLE_OK) return true;
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
else {
|
curl_handle = curl_easy_init();
|
||||||
LOG_DEBUG(curl_easy_strerror(result));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string downloadToBuffer (const std::string ourUrl, int firstRange, int secondRange, long timeout) {
|
curl_easy_setopt(curl_handle, CURLOPT_URL, ourUrl.c_str());
|
||||||
CURL *curl_handle;
|
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
CURLcode result;
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
std::ostringstream stream;
|
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Awoo-Installer");
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L);
|
||||||
curl_handle = curl_easy_init();
|
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, timeout);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_URL, ourUrl.c_str());
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeDataFile);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
if (writeProgress) curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, progress_callback);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Awoo-Installer");
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, timeout);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeDataBuffer);
|
|
||||||
if (firstRange && secondRange) {
|
|
||||||
const char * ourRange = (std::to_string(firstRange) + "-" + std::to_string(secondRange)).c_str();
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_RANGE, ourRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &stream);
|
|
||||||
result = curl_easy_perform(curl_handle);
|
|
||||||
|
|
||||||
curl_easy_cleanup(curl_handle);
|
|
||||||
curl_global_cleanup();
|
|
||||||
|
|
||||||
if (result == CURLE_OK) return stream.str();
|
pagefile = fopen(pagefilename, "wb");
|
||||||
else {
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);
|
||||||
LOG_DEBUG(curl_easy_strerror(result));
|
result = curl_easy_perform(curl_handle);
|
||||||
return "";
|
|
||||||
}
|
curl_easy_cleanup(curl_handle);
|
||||||
}
|
curl_global_cleanup();
|
||||||
|
fclose(pagefile);
|
||||||
|
|
||||||
|
if (result == CURLE_OK) return true;
|
||||||
|
else {
|
||||||
|
LOG_DEBUG(curl_easy_strerror(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string downloadToBuffer(const std::string ourUrl, int firstRange, int secondRange, long timeout) {
|
||||||
|
CURL* curl_handle;
|
||||||
|
CURLcode result;
|
||||||
|
std::ostringstream stream;
|
||||||
|
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
curl_handle = curl_easy_init();
|
||||||
|
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_URL, ourUrl.c_str());
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Awoo-Installer");
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, timeout);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeDataBuffer);
|
||||||
|
if (firstRange && secondRange) {
|
||||||
|
const char* ourRange = (std::to_string(firstRange) + "-" + std::to_string(secondRange)).c_str();
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_RANGE, ourRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &stream);
|
||||||
|
result = curl_easy_perform(curl_handle);
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl_handle);
|
||||||
|
curl_global_cleanup();
|
||||||
|
|
||||||
|
if (result == CURLE_OK) return stream.str();
|
||||||
|
else {
|
||||||
|
LOG_DEBUG(curl_easy_strerror(result));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -29,25 +29,25 @@ SOFTWARE.
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
void printBytes(u8 *bytes, size_t size, bool includeHeader)
|
void printBytes(u8* bytes, size_t size, bool includeHeader)
|
||||||
{
|
{
|
||||||
#ifdef NXLINK_DEBUG
|
#ifdef NXLINK_DEBUG
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (includeHeader)
|
if (includeHeader)
|
||||||
{
|
{
|
||||||
printf("\n\n00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
|
printf("\n\n00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
|
||||||
printf("-----------------------------------------------\n");
|
printf("-----------------------------------------------\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
printf("%02x ", bytes[i]);
|
printf("%02x ", bytes[i]);
|
||||||
count++;
|
count++;
|
||||||
if ((count % 16) == 0)
|
if ((count % 16) == 0)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
@ -31,23 +31,23 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::util
|
namespace tin::util
|
||||||
{
|
{
|
||||||
// TODO: do this manually so we don't have to "install" the cnmt's
|
// TODO: do this manually so we don't have to "install" the cnmt's
|
||||||
nx::ncm::ContentMeta GetContentMetaFromNCA(const std::string& ncaPath)
|
nx::ncm::ContentMeta GetContentMetaFromNCA(const std::string& ncaPath)
|
||||||
{
|
{
|
||||||
// Create the cnmt filesystem
|
// Create the cnmt filesystem
|
||||||
nx::fs::IFileSystem cnmtNCAFileSystem;
|
nx::fs::IFileSystem cnmtNCAFileSystem;
|
||||||
cnmtNCAFileSystem.OpenFileSystemWithId(ncaPath, FsFileSystemType_ContentMeta, 0);
|
cnmtNCAFileSystem.OpenFileSystemWithId(ncaPath, FsFileSystemType_ContentMeta, 0);
|
||||||
tin::install::nsp::SimpleFileSystem cnmtNCASimpleFileSystem(cnmtNCAFileSystem, "/", ncaPath + "/");
|
tin::install::nsp::SimpleFileSystem cnmtNCASimpleFileSystem(cnmtNCAFileSystem, "/", ncaPath + "/");
|
||||||
|
|
||||||
// Find and read the cnmt file
|
// Find and read the cnmt file
|
||||||
auto cnmtName = cnmtNCASimpleFileSystem.GetFileNameFromExtension("", "cnmt");
|
auto cnmtName = cnmtNCASimpleFileSystem.GetFileNameFromExtension("", "cnmt");
|
||||||
auto cnmtFile = cnmtNCASimpleFileSystem.OpenFile(cnmtName);
|
auto cnmtFile = cnmtNCASimpleFileSystem.OpenFile(cnmtName);
|
||||||
u64 cnmtSize = cnmtFile.GetSize();
|
u64 cnmtSize = cnmtFile.GetSize();
|
||||||
|
|
||||||
tin::data::ByteBuffer cnmtBuf;
|
tin::data::ByteBuffer cnmtBuf;
|
||||||
cnmtBuf.Resize(cnmtSize);
|
cnmtBuf.Resize(cnmtSize);
|
||||||
cnmtFile.Read(0x0, cnmtBuf.GetData(), cnmtSize);
|
cnmtFile.Read(0x0, cnmtBuf.GetData(), cnmtSize);
|
||||||
|
|
||||||
return nx::ncm::ContentMeta(cnmtBuf.GetData(), cnmtBuf.GetSize());
|
return nx::ncm::ContentMeta(cnmtBuf.GetData(), cnmtBuf.GetSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,86 +6,86 @@
|
|||||||
#include "util/config.hpp"
|
#include "util/config.hpp"
|
||||||
|
|
||||||
namespace Language {
|
namespace Language {
|
||||||
json lang;
|
json lang;
|
||||||
|
|
||||||
void Load() {
|
void Load() {
|
||||||
std::ifstream ifs;
|
std::ifstream ifs;
|
||||||
std::string languagePath;
|
std::string languagePath;
|
||||||
int langInt = inst::config::languageSetting;
|
int langInt = inst::config::languageSetting;
|
||||||
if (langInt == 99) {
|
if (langInt == 99) {
|
||||||
SetLanguage ourLang;
|
SetLanguage ourLang;
|
||||||
u64 lcode = 0;
|
u64 lcode = 0;
|
||||||
setInitialize();
|
setInitialize();
|
||||||
setGetSystemLanguage(&lcode);
|
setGetSystemLanguage(&lcode);
|
||||||
setMakeLanguage(lcode, &ourLang);
|
setMakeLanguage(lcode, &ourLang);
|
||||||
setExit();
|
setExit();
|
||||||
langInt = (int)ourLang;
|
langInt = (int)ourLang;
|
||||||
}
|
}
|
||||||
switch (langInt) {
|
switch (langInt) {
|
||||||
case 0:
|
case 0:
|
||||||
languagePath = "romfs:/lang/jp.json";
|
languagePath = "romfs:/lang/jp.json";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
case 13:
|
case 13:
|
||||||
languagePath = "romfs:/lang/fr.json";
|
languagePath = "romfs:/lang/fr.json";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
languagePath = "romfs:/lang/de.json";
|
languagePath = "romfs:/lang/de.json";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
languagePath = "romfs:/lang/it.json";
|
languagePath = "romfs:/lang/it.json";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
case 14:
|
case 14:
|
||||||
languagePath = "romfs:/lang/es-419.json";
|
languagePath = "romfs:/lang/es-419.json";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
case 15:
|
case 15:
|
||||||
languagePath = "romfs:/lang/zh-CN.json";
|
languagePath = "romfs:/lang/zh-CN.json";
|
||||||
// the default font will miss some chinese character, so use a chinese font (simplified)
|
// the default font will miss some chinese character, so use a chinese font (simplified)
|
||||||
//pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::ChineseSimplified);
|
//pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::ChineseSimplified);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
languagePath = "romfs:/lang/ko.json";
|
languagePath = "romfs:/lang/ko.json";
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
languagePath = "romfs:/lang/nl.json";
|
languagePath = "romfs:/lang/nl.json";
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
languagePath = "romfs:/lang/pt.json";
|
languagePath = "romfs:/lang/pt.json";
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
languagePath = "romfs:/lang/ru.json";
|
languagePath = "romfs:/lang/ru.json";
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
languagePath = "romfs:/lang/zh-TW.json";
|
languagePath = "romfs:/lang/zh-TW.json";
|
||||||
// the default font will miss some chinese character, so use a chinese font (traditional)
|
// the default font will miss some chinese character, so use a chinese font (traditional)
|
||||||
//pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::ChineseTraditional);
|
//pu::ui::render::SetDefaultFontFromShared(pu::ui::render::SharedFont::ChineseTraditional);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
languagePath = "romfs:/lang/en.json";
|
languagePath = "romfs:/lang/en.json";
|
||||||
}
|
}
|
||||||
if (std::filesystem::exists(languagePath)) ifs = std::ifstream(languagePath);
|
if (std::filesystem::exists(languagePath)) ifs = std::ifstream(languagePath);
|
||||||
else ifs = std::ifstream("romfs:/lang/en.json");
|
else ifs = std::ifstream("romfs:/lang/en.json");
|
||||||
if (!ifs.good()) {
|
if (!ifs.good()) {
|
||||||
std::cout << "[FAILED TO LOAD LANGUAGE FILE]" << std::endl;
|
std::cout << "[FAILED TO LOAD LANGUAGE FILE]" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lang = json::parse(ifs);
|
lang = json::parse(ifs);
|
||||||
ifs.close();
|
ifs.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LanguageEntry(std::string key) {
|
std::string LanguageEntry(std::string key) {
|
||||||
json j = GetRelativeJson(lang, key);
|
json j = GetRelativeJson(lang, key);
|
||||||
if (j == nullptr) {
|
if (j == nullptr) {
|
||||||
return "didn't find: " + key;
|
return "didn't find: " + key;
|
||||||
}
|
}
|
||||||
return j.get<std::string>();
|
return j.get<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetRandomMsg() {
|
std::string GetRandomMsg() {
|
||||||
json j = Language::GetRelativeJson(lang, "inst.finished");
|
json j = Language::GetRelativeJson(lang, "inst.finished");
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
return(j[rand() % j.size()]);
|
return(j[rand() % j.size()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,262 +31,262 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::network
|
namespace tin::network
|
||||||
{
|
{
|
||||||
// HTTPHeader
|
// HTTPHeader
|
||||||
|
|
||||||
HTTPHeader::HTTPHeader(std::string url) :
|
HTTPHeader::HTTPHeader(std::string url) :
|
||||||
m_url(url)
|
m_url(url)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HTTPHeader::ParseHTMLHeader(char* bytes, size_t size, size_t numItems, void* userData)
|
size_t HTTPHeader::ParseHTMLHeader(char* bytes, size_t size, size_t numItems, void* userData)
|
||||||
{
|
{
|
||||||
HTTPHeader* header = reinterpret_cast<HTTPHeader*>(userData);
|
HTTPHeader* header = reinterpret_cast<HTTPHeader*>(userData);
|
||||||
size_t numBytes = size * numItems;
|
size_t numBytes = size * numItems;
|
||||||
std::string line(bytes, numBytes);
|
std::string line(bytes, numBytes);
|
||||||
|
|
||||||
// Remove any newlines or carriage returns
|
// Remove any newlines or carriage returns
|
||||||
line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
|
line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
|
||||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||||
|
|
||||||
// Split into key and value
|
// Split into key and value
|
||||||
if (!line.empty())
|
if (!line.empty())
|
||||||
{
|
{
|
||||||
auto keyEnd = line.find(": ");
|
auto keyEnd = line.find(": ");
|
||||||
|
|
||||||
if (keyEnd != 0)
|
if (keyEnd != 0)
|
||||||
{
|
{
|
||||||
std::string key = line.substr(0, keyEnd);
|
std::string key = line.substr(0, keyEnd);
|
||||||
std::string value = line.substr(keyEnd + 2);
|
std::string value = line.substr(keyEnd + 2);
|
||||||
|
|
||||||
// Make key lowercase
|
// Make key lowercase
|
||||||
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
header->m_values[key] = value;
|
header->m_values[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return numBytes;
|
return numBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPHeader::PerformRequest()
|
void HTTPHeader::PerformRequest()
|
||||||
{
|
{
|
||||||
// We don't want any existing values to get mixed up with this request
|
// We don't want any existing values to get mixed up with this request
|
||||||
m_values.clear();
|
m_values.clear();
|
||||||
|
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
CURLcode rc = (CURLcode)0;
|
CURLcode rc = (CURLcode)0;
|
||||||
|
|
||||||
if (!curl)
|
if (!curl)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to initialize curl\n");
|
THROW_FORMAT("Failed to initialize curl\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_NOBODY, true);
|
curl_easy_setopt(curl, CURLOPT_NOBODY, true);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);
|
curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &tin::network::HTTPHeader::ParseHTMLHeader);
|
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &tin::network::HTTPHeader::ParseHTMLHeader);
|
||||||
|
|
||||||
rc = curl_easy_perform(curl);
|
rc = curl_easy_perform(curl);
|
||||||
if (rc != CURLE_OK)
|
if (rc != CURLE_OK)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to retrieve HTTP Header: %s\n", curl_easy_strerror(rc));
|
THROW_FORMAT("Failed to retrieve HTTP Header: %s\n", curl_easy_strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 httpCode = 0;
|
u64 httpCode = 0;
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if (httpCode != 200 && httpCode != 204)
|
if (httpCode != 200 && httpCode != 204)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Unexpected HTTP response code when retrieving header: %lu\n", httpCode);
|
THROW_FORMAT("Unexpected HTTP response code when retrieving header: %lu\n", httpCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPHeader::HasValue(std::string key)
|
bool HTTPHeader::HasValue(std::string key)
|
||||||
{
|
{
|
||||||
return m_values.count(key);
|
return m_values.count(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string HTTPHeader::GetValue(std::string key)
|
std::string HTTPHeader::GetValue(std::string key)
|
||||||
{
|
{
|
||||||
return m_values[key];
|
return m_values[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
// End HTTPHeader
|
// End HTTPHeader
|
||||||
// HTTPDownload
|
// HTTPDownload
|
||||||
|
|
||||||
HTTPDownload::HTTPDownload(std::string url) :
|
HTTPDownload::HTTPDownload(std::string url) :
|
||||||
m_url(url), m_header(url)
|
m_url(url), m_header(url)
|
||||||
{
|
{
|
||||||
// The header won't be populated until we do this
|
// The header won't be populated until we do this
|
||||||
m_header.PerformRequest();
|
m_header.PerformRequest();
|
||||||
|
|
||||||
if (m_header.HasValue("accept-ranges"))
|
if (m_header.HasValue("accept-ranges"))
|
||||||
{
|
{
|
||||||
m_rangesSupported = m_header.GetValue("accept-ranges") == "bytes";
|
m_rangesSupported = m_header.GetValue("accept-ranges") == "bytes";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
CURLcode rc = (CURLcode)0;
|
CURLcode rc = (CURLcode)0;
|
||||||
|
|
||||||
if (!curl)
|
if (!curl)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to initialize curl\n");
|
THROW_FORMAT("Failed to initialize curl\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_NOBODY, true);
|
curl_easy_setopt(curl, CURLOPT_NOBODY, true);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
||||||
curl_easy_setopt(curl, CURLOPT_RANGE, "0-0");
|
curl_easy_setopt(curl, CURLOPT_RANGE, "0-0");
|
||||||
|
|
||||||
rc = curl_easy_perform(curl);
|
rc = curl_easy_perform(curl);
|
||||||
if (rc != CURLE_OK)
|
if (rc != CURLE_OK)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to retrieve HTTP Header: %s\n", curl_easy_strerror(rc));
|
THROW_FORMAT("Failed to retrieve HTTP Header: %s\n", curl_easy_strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 httpCode = 0;
|
u64 httpCode = 0;
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
m_rangesSupported = httpCode == 206;
|
m_rangesSupported = httpCode == 206;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HTTPDownload::ParseHTMLData(char* bytes, size_t size, size_t numItems, void* userData)
|
size_t HTTPDownload::ParseHTMLData(char* bytes, size_t size, size_t numItems, void* userData)
|
||||||
{
|
{
|
||||||
auto streamFunc = *reinterpret_cast<std::function<size_t (u8* bytes, size_t size)>*>(userData);
|
auto streamFunc = *reinterpret_cast<std::function<size_t(u8* bytes, size_t size)>*>(userData);
|
||||||
size_t numBytes = size * numItems;
|
size_t numBytes = size * numItems;
|
||||||
|
|
||||||
if (streamFunc != nullptr)
|
if (streamFunc != nullptr)
|
||||||
return streamFunc((u8*)bytes, numBytes);
|
return streamFunc((u8*)bytes, numBytes);
|
||||||
|
|
||||||
return numBytes;
|
return numBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPDownload::BufferDataRange(void* buffer, size_t offset, size_t size, std::function<void (size_t sizeRead)> progressFunc)
|
void HTTPDownload::BufferDataRange(void* buffer, size_t offset, size_t size, std::function<void(size_t sizeRead)> progressFunc)
|
||||||
{
|
{
|
||||||
size_t sizeRead = 0;
|
size_t sizeRead = 0;
|
||||||
|
|
||||||
auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t
|
auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t
|
||||||
{
|
{
|
||||||
if (sizeRead + streamBufSize > size)
|
if (sizeRead + streamBufSize > size)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("New read size 0x%lx would exceed total expected size 0x%lx\n", sizeRead + streamBufSize, size);
|
LOG_DEBUG("New read size 0x%lx would exceed total expected size 0x%lx\n", sizeRead + streamBufSize, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progressFunc != nullptr)
|
if (progressFunc != nullptr)
|
||||||
progressFunc(sizeRead);
|
progressFunc(sizeRead);
|
||||||
|
|
||||||
memcpy(reinterpret_cast<u8*>(buffer) + sizeRead, streamBuf, streamBufSize);
|
memcpy(reinterpret_cast<u8*>(buffer) + sizeRead, streamBuf, streamBufSize);
|
||||||
sizeRead += streamBufSize;
|
sizeRead += streamBufSize;
|
||||||
return streamBufSize;
|
return streamBufSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
this->StreamDataRange(offset, size, streamFunc);
|
this->StreamDataRange(offset, size, streamFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int HTTPDownload::StreamDataRange(size_t offset, size_t size, std::function<size_t (u8* bytes, size_t size)> streamFunc)
|
int HTTPDownload::StreamDataRange(size_t offset, size_t size, std::function<size_t(u8* bytes, size_t size)> streamFunc)
|
||||||
{
|
{
|
||||||
if (!m_rangesSupported)
|
if (!m_rangesSupported)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Attempted range request when ranges aren't supported!\n");
|
THROW_FORMAT("Attempted range request when ranges aren't supported!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writeDataFunc = streamFunc;
|
auto writeDataFunc = streamFunc;
|
||||||
|
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
CURLcode rc = (CURLcode)0;
|
CURLcode rc = (CURLcode)0;
|
||||||
|
|
||||||
if (!curl)
|
if (!curl)
|
||||||
{
|
{
|
||||||
THROW_FORMAT("Failed to initialize curl\n");
|
THROW_FORMAT("Failed to initialize curl\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << offset << "-" << (offset + size - 1);
|
ss << offset << "-" << (offset + size - 1);
|
||||||
auto range = ss.str();
|
auto range = ss.str();
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
||||||
curl_easy_setopt(curl, CURLOPT_RANGE, range.c_str());
|
curl_easy_setopt(curl, CURLOPT_RANGE, range.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeDataFunc);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeDataFunc);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &tin::network::HTTPDownload::ParseHTMLData);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &tin::network::HTTPDownload::ParseHTMLData);
|
||||||
|
|
||||||
rc = curl_easy_perform(curl);
|
rc = curl_easy_perform(curl);
|
||||||
|
|
||||||
u64 httpCode = 0;
|
u64 httpCode = 0;
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if (httpCode != 206 || rc != CURLE_OK) return 1;
|
if (httpCode != 206 || rc != CURLE_OK) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// End HTTPDownload
|
// End HTTPDownload
|
||||||
|
|
||||||
size_t WaitReceiveNetworkData(int sockfd, void* buf, size_t len)
|
size_t WaitReceiveNetworkData(int sockfd, void* buf, size_t len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
size_t read = 0;
|
size_t read = 0;
|
||||||
|
|
||||||
while ((((ret = recv(sockfd, (u8*)buf + read, len - read, 0)) > 0 && (read += ret) < len) || errno == EAGAIN))
|
while ((((ret = recv(sockfd, (u8*)buf + read, len - read, 0)) > 0 && (read += ret) < len) || errno == EAGAIN))
|
||||||
{
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WaitSendNetworkData(int sockfd, void* buf, size_t len)
|
size_t WaitSendNetworkData(int sockfd, void* buf, size_t len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
|
|
||||||
while (written < len)
|
while (written < len)
|
||||||
{
|
{
|
||||||
/*if (padGetButtonsDown(m_pad) & HidNpadButton_B) // Break if user clicks 'B'
|
/*if (padGetButtonsDown(m_pad) & HidNpadButton_B) // Break if user clicks 'B'
|
||||||
break;*/
|
break;*/
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ret = send(sockfd, (u8*)buf + written, len - written, 0);
|
ret = send(sockfd, (u8*)buf + written, len - written, 0);
|
||||||
|
|
||||||
if (ret < 0){ // If error
|
|
||||||
if (errno == EWOULDBLOCK || errno == EAGAIN){ // Is it because other side is busy?
|
|
||||||
sleep(5);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break; // No? Die.
|
|
||||||
}
|
|
||||||
|
|
||||||
written += ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NSULDrop(std::string url)
|
if (ret < 0) { // If error
|
||||||
{
|
if (errno == EWOULDBLOCK || errno == EAGAIN) { // Is it because other side is busy?
|
||||||
CURL* curl = curl_easy_init();
|
sleep(5);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break; // No? Die.
|
||||||
|
}
|
||||||
|
|
||||||
if (!curl)
|
written += ret;
|
||||||
{
|
}
|
||||||
THROW_FORMAT("Failed to initialize curl\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
return written;
|
||||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DROP");
|
}
|
||||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 50);
|
|
||||||
|
|
||||||
curl_easy_perform(curl); // ignore returning value
|
void NSULDrop(std::string url)
|
||||||
|
{
|
||||||
|
CURL* curl = curl_easy_init();
|
||||||
|
|
||||||
curl_easy_cleanup(curl);
|
if (!curl)
|
||||||
}
|
{
|
||||||
|
THROW_FORMAT("Failed to initialize curl\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DROP");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "tinfoil");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 50);
|
||||||
|
|
||||||
|
curl_easy_perform(curl); // ignore returning value
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
}
|
}
|
@ -27,108 +27,108 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::util
|
namespace tin::util
|
||||||
{
|
{
|
||||||
u64 GetRightsIdTid(FsRightsId rightsId)
|
u64 GetRightsIdTid(FsRightsId rightsId)
|
||||||
{
|
{
|
||||||
return __bswap64(*(u64 *)rightsId.c);
|
return __bswap64(*(u64*)rightsId.c);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetRightsIdKeyGen(FsRightsId rightsId)
|
u64 GetRightsIdKeyGen(FsRightsId rightsId)
|
||||||
{
|
{
|
||||||
return __bswap64(*(u64 *)(rightsId.c + 8));
|
return __bswap64(*(u64*)(rightsId.c + 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetNcaIdString(const NcmContentId& ncaId)
|
std::string GetNcaIdString(const NcmContentId& ncaId)
|
||||||
{
|
{
|
||||||
char ncaIdStr[FS_MAX_PATH] = {0};
|
char ncaIdStr[FS_MAX_PATH] = { 0 };
|
||||||
u64 ncaIdLower = __bswap64(*(u64 *)ncaId.c);
|
u64 ncaIdLower = __bswap64(*(u64*)ncaId.c);
|
||||||
u64 ncaIdUpper = __bswap64(*(u64 *)(ncaId.c + 0x8));
|
u64 ncaIdUpper = __bswap64(*(u64*)(ncaId.c + 0x8));
|
||||||
snprintf(ncaIdStr, FS_MAX_PATH, "%016lx%016lx", ncaIdLower, ncaIdUpper);
|
snprintf(ncaIdStr, FS_MAX_PATH, "%016lx%016lx", ncaIdLower, ncaIdUpper);
|
||||||
return std::string(ncaIdStr);
|
return std::string(ncaIdStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
NcmContentId GetNcaIdFromString(std::string ncaIdStr)
|
NcmContentId GetNcaIdFromString(std::string ncaIdStr)
|
||||||
{
|
{
|
||||||
NcmContentId ncaId = {0};
|
NcmContentId ncaId = { 0 };
|
||||||
char lowerU64[17] = {0};
|
char lowerU64[17] = { 0 };
|
||||||
char upperU64[17] = {0};
|
char upperU64[17] = { 0 };
|
||||||
memcpy(lowerU64, ncaIdStr.c_str(), 16);
|
memcpy(lowerU64, ncaIdStr.c_str(), 16);
|
||||||
memcpy(upperU64, ncaIdStr.c_str() + 16, 16);
|
memcpy(upperU64, ncaIdStr.c_str() + 16, 16);
|
||||||
|
|
||||||
*(u64 *)ncaId.c = __bswap64(strtoul(lowerU64, NULL, 16));
|
*(u64*)ncaId.c = __bswap64(strtoul(lowerU64, NULL, 16));
|
||||||
*(u64 *)(ncaId.c + 8) = __bswap64(strtoul(upperU64, NULL, 16));
|
*(u64*)(ncaId.c + 8) = __bswap64(strtoul(upperU64, NULL, 16));
|
||||||
|
|
||||||
return ncaId;
|
return ncaId;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType)
|
u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType)
|
||||||
{
|
{
|
||||||
switch (contentMetaType)
|
switch (contentMetaType)
|
||||||
{
|
{
|
||||||
case NcmContentMetaType_Patch:
|
case NcmContentMetaType_Patch:
|
||||||
return titleId ^ 0x800;
|
return titleId ^ 0x800;
|
||||||
|
|
||||||
case NcmContentMetaType_AddOnContent:
|
case NcmContentMetaType_AddOnContent:
|
||||||
return (titleId ^ 0x1000) & ~0xFFF;
|
return (titleId ^ 0x1000) & ~0xFFF;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return titleId;
|
return titleId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetBaseTitleName(u64 baseTitleId)
|
std::string GetBaseTitleName(u64 baseTitleId)
|
||||||
{
|
{
|
||||||
Result rc = 0;
|
Result rc = 0;
|
||||||
NsApplicationControlData appControlData;
|
NsApplicationControlData appControlData;
|
||||||
size_t sizeRead;
|
size_t sizeRead;
|
||||||
|
|
||||||
if (R_FAILED(rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, baseTitleId, &appControlData, sizeof(NsApplicationControlData), &sizeRead)))
|
if (R_FAILED(rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, baseTitleId, &appControlData, sizeof(NsApplicationControlData), &sizeRead)))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Failed to get application control data. Error code: 0x%08x\n", rc);
|
LOG_DEBUG("Failed to get application control data. Error code: 0x%08x\n", rc);
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sizeRead < sizeof(appControlData.nacp))
|
if (sizeRead < sizeof(appControlData.nacp))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Incorrect size for nacp\n");
|
LOG_DEBUG("Incorrect size for nacp\n");
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
NacpLanguageEntry *languageEntry;
|
NacpLanguageEntry* languageEntry;
|
||||||
|
|
||||||
if (R_FAILED(rc = nacpGetLanguageEntry(&appControlData.nacp, &languageEntry)))
|
if (R_FAILED(rc = nacpGetLanguageEntry(&appControlData.nacp, &languageEntry)))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Failed to get language entry. Error code: 0x%08x\n", rc);
|
LOG_DEBUG("Failed to get language entry. Error code: 0x%08x\n", rc);
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (languageEntry == NULL)
|
if (languageEntry == NULL)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Language entry is null! Error code: 0x%08x\n", rc);
|
LOG_DEBUG("Language entry is null! Error code: 0x%08x\n", rc);
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return languageEntry->name;
|
return languageEntry->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetTitleName(u64 titleId, NcmContentMetaType contentMetaType)
|
std::string GetTitleName(u64 titleId, NcmContentMetaType contentMetaType)
|
||||||
{
|
{
|
||||||
u64 baseTitleId = GetBaseTitleId(titleId, contentMetaType);
|
u64 baseTitleId = GetBaseTitleId(titleId, contentMetaType);
|
||||||
std::string titleName = GetBaseTitleName(baseTitleId);
|
std::string titleName = GetBaseTitleName(baseTitleId);
|
||||||
|
|
||||||
switch (contentMetaType)
|
switch (contentMetaType)
|
||||||
{
|
{
|
||||||
case NcmContentMetaType_Patch:
|
case NcmContentMetaType_Patch:
|
||||||
titleName += " (Update)";
|
titleName += " (Update)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NcmContentMetaType_AddOnContent:
|
case NcmContentMetaType_AddOnContent:
|
||||||
titleName += " (DLC)";
|
titleName += " (DLC)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return titleName;
|
return titleName;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,151 +9,153 @@
|
|||||||
|
|
||||||
// https://github.com/AtlasNX/Kosmos-Updater/blob/master/source/FileManager.cpp
|
// https://github.com/AtlasNX/Kosmos-Updater/blob/master/source/FileManager.cpp
|
||||||
|
|
||||||
unz_file_info_s * _getFileInfo(unzFile unz) {
|
unz_file_info_s* _getFileInfo(unzFile unz) {
|
||||||
unz_file_info_s * fileInfo = (unz_file_info_s*) malloc(sizeof(unz_file_info_s));
|
unz_file_info_s* fileInfo = (unz_file_info_s*)malloc(sizeof(unz_file_info_s));
|
||||||
unzGetCurrentFileInfo(unz, fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
unzGetCurrentFileInfo(unz, fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string _getFullFileName(unzFile unz, unz_file_info_s * fileInfo) {
|
std::string _getFullFileName(unzFile unz, unz_file_info_s* fileInfo) {
|
||||||
char filePath[fileInfo->size_filename + 1];
|
char filePath[fileInfo->size_filename + 1];
|
||||||
|
|
||||||
unzGetCurrentFileInfo(unz, fileInfo, filePath, fileInfo->size_filename, NULL, 0, NULL, 0);
|
|
||||||
filePath[fileInfo->size_filename] = '\0';
|
|
||||||
|
|
||||||
std::string path(filePath);
|
|
||||||
path.resize(fileInfo->size_filename);
|
|
||||||
|
|
||||||
return path;
|
unzGetCurrentFileInfo(unz, fileInfo, filePath, fileInfo->size_filename, NULL, 0, NULL, 0);
|
||||||
|
filePath[fileInfo->size_filename] = '\0';
|
||||||
|
|
||||||
|
std::string path(filePath);
|
||||||
|
path.resize(fileInfo->size_filename);
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _makeDirectoryParents(std::string path)
|
bool _makeDirectoryParents(std::string path)
|
||||||
{
|
{
|
||||||
bool bSuccess = false;
|
bool bSuccess = false;
|
||||||
int nRC = ::mkdir(path.c_str(), 0775);
|
int nRC = ::mkdir(path.c_str(), 0775);
|
||||||
if(nRC == -1)
|
if (nRC == -1)
|
||||||
{
|
{
|
||||||
switch(errno)
|
switch (errno)
|
||||||
{
|
{
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
//parent didn't exist, try to create it
|
//parent didn't exist, try to create it
|
||||||
if( _makeDirectoryParents(path.substr(0, path.find_last_of('/'))))
|
if (_makeDirectoryParents(path.substr(0, path.find_last_of('/'))))
|
||||||
//Now, try to create again.
|
//Now, try to create again.
|
||||||
bSuccess = 0 == ::mkdir(path.c_str(), 0775);
|
bSuccess = 0 == ::mkdir(path.c_str(), 0775);
|
||||||
else
|
else
|
||||||
bSuccess = false;
|
bSuccess = false;
|
||||||
break;
|
break;
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
//Done!
|
//Done!
|
||||||
bSuccess = true;
|
bSuccess = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bSuccess = false;
|
bSuccess = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
bSuccess = true;
|
bSuccess = true;
|
||||||
|
|
||||||
return bSuccess;
|
return bSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _extractFile(const char * path, unzFile unz, unz_file_info_s * fileInfo) {
|
int _extractFile(const char* path, unzFile unz, unz_file_info_s* fileInfo) {
|
||||||
//check to make sure filepath or fileInfo isnt null
|
//check to make sure filepath or fileInfo isnt null
|
||||||
if (path == NULL || fileInfo == NULL)
|
if (path == NULL || fileInfo == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (unzOpenCurrentFile(unz) != UNZ_OK)
|
if (unzOpenCurrentFile(unz) != UNZ_OK)
|
||||||
return -2;
|
return -2;
|
||||||
|
|
||||||
char folderPath[strlen(path) + 1];
|
char folderPath[strlen(path) + 1];
|
||||||
strcpy(folderPath, path);
|
strcpy(folderPath, path);
|
||||||
char * pos = strrchr(folderPath, '/');
|
char* pos = strrchr(folderPath, '/');
|
||||||
if (pos != NULL) {
|
if (pos != NULL) {
|
||||||
*pos = '\0';
|
*pos = '\0';
|
||||||
_makeDirectoryParents(std::string(folderPath));
|
_makeDirectoryParents(std::string(folderPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 blocksize = 0x8000;
|
u32 blocksize = 0x8000;
|
||||||
u8 * buffer = (u8*) malloc(blocksize);
|
u8* buffer = (u8*)malloc(blocksize);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return -3;
|
return -3;
|
||||||
u32 done = 0;
|
u32 done = 0;
|
||||||
int writeBytes = 0;
|
int writeBytes = 0;
|
||||||
FILE * fp = fopen(path, "w");
|
FILE* fp = fopen(path, "w");
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (done < fileInfo->uncompressed_size) {
|
while (done < fileInfo->uncompressed_size) {
|
||||||
if (done + blocksize > fileInfo->uncompressed_size) {
|
if (done + blocksize > fileInfo->uncompressed_size) {
|
||||||
blocksize = fileInfo->uncompressed_size - done;
|
blocksize = fileInfo->uncompressed_size - done;
|
||||||
}
|
}
|
||||||
unzReadCurrentFile(unz, buffer, blocksize);
|
unzReadCurrentFile(unz, buffer, blocksize);
|
||||||
writeBytes = write(fileno(fp), buffer, blocksize);
|
writeBytes = write(fileno(fp), buffer, blocksize);
|
||||||
if (writeBytes <= 0) {
|
if (writeBytes <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
done += writeBytes;
|
done += writeBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
fflush(fp);
|
fflush(fp);
|
||||||
fsync(fileno(fp));
|
fsync(fileno(fp));
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
if (done != fileInfo->uncompressed_size)
|
if (done != fileInfo->uncompressed_size)
|
||||||
return -4;
|
return -4;
|
||||||
|
|
||||||
unzCloseCurrentFile(unz);
|
unzCloseCurrentFile(unz);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace inst::zip {
|
namespace inst::zip {
|
||||||
bool extractFile(const std::string filename, const std::string destination) {
|
bool extractFile(const std::string filename, const std::string destination) {
|
||||||
unzFile unz = unzOpen(filename.c_str());
|
unzFile unz = unzOpen(filename.c_str());
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int code;
|
int code;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
code = unzGoToFirstFile(unz);
|
code = unzGoToFirstFile(unz);
|
||||||
} else {
|
}
|
||||||
code = unzGoToNextFile(unz);
|
else {
|
||||||
}
|
code = unzGoToNextFile(unz);
|
||||||
i++;
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
if (code == UNZ_END_OF_LIST_OF_FILE) {
|
if (code == UNZ_END_OF_LIST_OF_FILE) {
|
||||||
break;
|
break;
|
||||||
} else {
|
}
|
||||||
unz_file_pos pos;
|
else {
|
||||||
unzGetFilePos(unz, &pos);
|
unz_file_pos pos;
|
||||||
}
|
unzGetFilePos(unz, &pos);
|
||||||
|
}
|
||||||
|
|
||||||
unz_file_info_s * fileInfo = _getFileInfo(unz);
|
unz_file_info_s* fileInfo = _getFileInfo(unz);
|
||||||
|
|
||||||
std::string fileName = destination;
|
std::string fileName = destination;
|
||||||
fileName += _getFullFileName(unz, fileInfo);
|
fileName += _getFullFileName(unz, fileInfo);
|
||||||
|
|
||||||
if (fileName.back() != '/') {
|
if (fileName.back() != '/') {
|
||||||
int result = _extractFile(fileName.c_str(), unz, fileInfo);
|
int result = _extractFile(fileName.c_str(), unz, fileInfo);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
free(fileInfo);
|
free(fileInfo);
|
||||||
unzClose(unz);
|
unzClose(unz);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(fileInfo);
|
free(fileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i <= 0) {
|
if (i <= 0) {
|
||||||
unzClose(unz);
|
unzClose(unz);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unzClose(unz);
|
unzClose(unz);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -29,77 +29,77 @@ SOFTWARE.
|
|||||||
|
|
||||||
namespace tin::util
|
namespace tin::util
|
||||||
{
|
{
|
||||||
void USBCmdManager::SendCmdHeader(u32 cmdId, size_t dataSize)
|
void USBCmdManager::SendCmdHeader(u32 cmdId, size_t dataSize)
|
||||||
{
|
{
|
||||||
USBCmdHeader header;
|
USBCmdHeader header;
|
||||||
header.magic = 0x30435554; // TUC0 (Tinfoil USB Command 0)
|
header.magic = 0x30435554; // TUC0 (Tinfoil USB Command 0)
|
||||||
header.type = USBCmdType::REQUEST;
|
header.type = USBCmdType::REQUEST;
|
||||||
header.cmdId = cmdId;
|
header.cmdId = cmdId;
|
||||||
header.dataSize = dataSize;
|
header.dataSize = dataSize;
|
||||||
|
|
||||||
USBWrite(&header, sizeof(USBCmdHeader));
|
USBWrite(&header, sizeof(USBCmdHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBCmdManager::SendExitCmd()
|
void USBCmdManager::SendExitCmd()
|
||||||
{
|
{
|
||||||
USBCmdManager::SendCmdHeader(0, 0);
|
USBCmdManager::SendCmdHeader(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
USBCmdHeader USBCmdManager::SendFileRangeCmd(std::string nspName, u64 offset, u64 size)
|
USBCmdHeader USBCmdManager::SendFileRangeCmd(std::string nspName, u64 offset, u64 size)
|
||||||
{
|
{
|
||||||
struct FileRangeCmdHeader
|
struct FileRangeCmdHeader
|
||||||
{
|
{
|
||||||
u64 size;
|
u64 size;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 nspNameLen;
|
u64 nspNameLen;
|
||||||
u64 padding;
|
u64 padding;
|
||||||
} fRangeHeader;
|
} fRangeHeader;
|
||||||
|
|
||||||
fRangeHeader.size = size;
|
fRangeHeader.size = size;
|
||||||
fRangeHeader.offset = offset;
|
fRangeHeader.offset = offset;
|
||||||
fRangeHeader.nspNameLen = nspName.size();
|
fRangeHeader.nspNameLen = nspName.size();
|
||||||
fRangeHeader.padding = 0;
|
fRangeHeader.padding = 0;
|
||||||
|
|
||||||
USBCmdManager::SendCmdHeader(1, sizeof(FileRangeCmdHeader) + fRangeHeader.nspNameLen);
|
USBCmdManager::SendCmdHeader(1, sizeof(FileRangeCmdHeader) + fRangeHeader.nspNameLen);
|
||||||
USBWrite(&fRangeHeader, sizeof(FileRangeCmdHeader));
|
USBWrite(&fRangeHeader, sizeof(FileRangeCmdHeader));
|
||||||
USBWrite(nspName.c_str(), fRangeHeader.nspNameLen);
|
USBWrite(nspName.c_str(), fRangeHeader.nspNameLen);
|
||||||
|
|
||||||
USBCmdHeader responseHeader;
|
USBCmdHeader responseHeader;
|
||||||
USBRead(&responseHeader, sizeof(USBCmdHeader));
|
USBRead(&responseHeader, sizeof(USBCmdHeader));
|
||||||
return responseHeader;
|
return responseHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t USBRead(void* out, size_t len, u64 timeout)
|
size_t USBRead(void* out, size_t len, u64 timeout)
|
||||||
{
|
{
|
||||||
u8* tmpBuf = (u8*)out;
|
u8* tmpBuf = (u8*)out;
|
||||||
size_t sizeRemaining = len;
|
size_t sizeRemaining = len;
|
||||||
size_t tmpSizeRead = 0;
|
size_t tmpSizeRead = 0;
|
||||||
|
|
||||||
while (sizeRemaining)
|
while (sizeRemaining)
|
||||||
{
|
{
|
||||||
tmpSizeRead = awoo_usbCommsRead(tmpBuf, sizeRemaining, timeout);
|
tmpSizeRead = awoo_usbCommsRead(tmpBuf, sizeRemaining, timeout);
|
||||||
if (tmpSizeRead == 0) return 0;
|
if (tmpSizeRead == 0) return 0;
|
||||||
tmpBuf += tmpSizeRead;
|
tmpBuf += tmpSizeRead;
|
||||||
sizeRemaining -= tmpSizeRead;
|
sizeRemaining -= tmpSizeRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t USBWrite(const void* in, size_t len, u64 timeout)
|
size_t USBWrite(const void* in, size_t len, u64 timeout)
|
||||||
{
|
{
|
||||||
const u8 *bufptr = (const u8 *)in;
|
const u8* bufptr = (const u8*)in;
|
||||||
size_t cursize = len;
|
size_t cursize = len;
|
||||||
size_t tmpsize = 0;
|
size_t tmpsize = 0;
|
||||||
|
|
||||||
while (cursize)
|
while (cursize)
|
||||||
{
|
{
|
||||||
tmpsize = awoo_usbCommsWrite(bufptr, cursize, timeout);
|
tmpsize = awoo_usbCommsWrite(bufptr, cursize, timeout);
|
||||||
if (tmpsize == 0) return 0;
|
if (tmpsize == 0) return 0;
|
||||||
bufptr += tmpsize;
|
bufptr += tmpsize;
|
||||||
cursize -= tmpsize;
|
cursize -= tmpsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,341 +18,344 @@
|
|||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
|
|
||||||
namespace inst::util {
|
namespace inst::util {
|
||||||
void initApp () {
|
void initApp() {
|
||||||
// Seethe
|
// Seethe
|
||||||
if (!std::filesystem::exists("sdmc:/switch")) std::filesystem::create_directory("sdmc:/switch");
|
if (!std::filesystem::exists("sdmc:/switch")) std::filesystem::create_directory("sdmc:/switch");
|
||||||
if (!std::filesystem::exists(inst::config::appDir)) std::filesystem::create_directory(inst::config::appDir);
|
if (!std::filesystem::exists(inst::config::appDir)) std::filesystem::create_directory(inst::config::appDir);
|
||||||
inst::config::parseConfig();
|
inst::config::parseConfig();
|
||||||
|
|
||||||
socketInitializeDefault();
|
socketInitializeDefault();
|
||||||
#ifdef __DEBUG__
|
#ifdef __DEBUG__
|
||||||
nxlinkStdio();
|
nxlinkStdio();
|
||||||
#endif
|
#endif
|
||||||
awoo_usbCommsInitialize();
|
awoo_usbCommsInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinitApp () {
|
void deinitApp() {
|
||||||
socketExit();
|
socketExit();
|
||||||
awoo_usbCommsExit();
|
awoo_usbCommsExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initInstallServices() {
|
void initInstallServices() {
|
||||||
ncmInitialize();
|
ncmInitialize();
|
||||||
nsextInitialize();
|
nsextInitialize();
|
||||||
esInitialize();
|
esInitialize();
|
||||||
splCryptoInitialize();
|
splCryptoInitialize();
|
||||||
splInitialize();
|
splInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinitInstallServices() {
|
void deinitInstallServices() {
|
||||||
ncmExit();
|
ncmExit();
|
||||||
nsextExit();
|
nsextExit();
|
||||||
esExit();
|
esExit();
|
||||||
splCryptoExit();
|
splCryptoExit();
|
||||||
splExit();
|
splExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct caseInsensitiveLess : public std::binary_function< char,char,bool > {
|
struct caseInsensitiveLess : public std::binary_function< char, char, bool > {
|
||||||
bool operator () (char x, char y) const {
|
bool operator () (char x, char y) const {
|
||||||
return toupper(static_cast< unsigned char >(x)) < toupper(static_cast< unsigned char >(y));
|
return toupper(static_cast<unsigned char>(x)) < toupper(static_cast<unsigned char>(y));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ignoreCaseCompare(const std::string &a, const std::string &b) {
|
bool ignoreCaseCompare(const std::string& a, const std::string& b) {
|
||||||
return std::lexicographical_compare(a.begin(), a.end() , b.begin() ,b.end() , caseInsensitiveLess());
|
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), caseInsensitiveLess());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::filesystem::path> getDirectoryFiles(const std::string & dir, const std::vector<std::string> & extensions) {
|
std::vector<std::filesystem::path> getDirectoryFiles(const std::string& dir, const std::vector<std::string>& extensions) {
|
||||||
std::vector<std::filesystem::path> files;
|
std::vector<std::filesystem::path> files;
|
||||||
for(auto & p: std::filesystem::directory_iterator(dir))
|
for (auto& p : std::filesystem::directory_iterator(dir))
|
||||||
{
|
{
|
||||||
if (std::filesystem::is_regular_file(p))
|
if (std::filesystem::is_regular_file(p))
|
||||||
{
|
{
|
||||||
std::string ourExtension = p.path().extension().string();
|
std::string ourExtension = p.path().extension().string();
|
||||||
std::transform(ourExtension.begin(), ourExtension.end(), ourExtension.begin(), ::tolower);
|
std::transform(ourExtension.begin(), ourExtension.end(), ourExtension.begin(), ::tolower);
|
||||||
if (extensions.empty() || std::find(extensions.begin(), extensions.end(), ourExtension) != extensions.end())
|
if (extensions.empty() || std::find(extensions.begin(), extensions.end(), ourExtension) != extensions.end())
|
||||||
{
|
{
|
||||||
files.push_back(p.path());
|
files.push_back(p.path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(files.begin(), files.end(), ignoreCaseCompare);
|
std::sort(files.begin(), files.end(), ignoreCaseCompare);
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::filesystem::path> getDirsAtPath(const std::string & dir) {
|
std::vector<std::filesystem::path> getDirsAtPath(const std::string& dir) {
|
||||||
std::vector<std::filesystem::path> files;
|
std::vector<std::filesystem::path> files;
|
||||||
for(auto & p: std::filesystem::directory_iterator(dir))
|
for (auto& p : std::filesystem::directory_iterator(dir))
|
||||||
{
|
{
|
||||||
if (std::filesystem::is_directory(p))
|
if (std::filesystem::is_directory(p))
|
||||||
{
|
{
|
||||||
files.push_back(p.path());
|
files.push_back(p.path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(files.begin(), files.end(), ignoreCaseCompare);
|
std::sort(files.begin(), files.end(), ignoreCaseCompare);
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool removeDirectory(std::string dir) {
|
bool removeDirectory(std::string dir) {
|
||||||
try {
|
try {
|
||||||
for(auto & p: std::filesystem::recursive_directory_iterator(dir))
|
for (auto& p : std::filesystem::recursive_directory_iterator(dir))
|
||||||
{
|
{
|
||||||
if (std::filesystem::is_regular_file(p))
|
if (std::filesystem::is_regular_file(p))
|
||||||
{
|
{
|
||||||
std::filesystem::remove(p);
|
std::filesystem::remove(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rmdir(dir.c_str());
|
rmdir(dir.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (std::filesystem::filesystem_error & e) {
|
catch (std::filesystem::filesystem_error& e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool copyFile(std::string inFile, std::string outFile) {
|
bool copyFile(std::string inFile, std::string outFile) {
|
||||||
char ch;
|
char ch;
|
||||||
std::ifstream f1(inFile);
|
std::ifstream f1(inFile);
|
||||||
std::ofstream f2(outFile);
|
std::ofstream f2(outFile);
|
||||||
|
|
||||||
if(!f1 || !f2) return false;
|
if (!f1 || !f2) return false;
|
||||||
|
|
||||||
while(f1 && f1.get(ch)) f2.put(ch);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string formatUrlString(std::string ourString) {
|
while (f1 && f1.get(ch)) f2.put(ch);
|
||||||
std::stringstream ourStream(ourString);
|
return true;
|
||||||
std::string segment;
|
}
|
||||||
std::vector<std::string> seglist;
|
|
||||||
|
|
||||||
while(std::getline(ourStream, segment, '/')) {
|
std::string formatUrlString(std::string ourString) {
|
||||||
seglist.push_back(segment);
|
std::stringstream ourStream(ourString);
|
||||||
}
|
std::string segment;
|
||||||
|
std::vector<std::string> seglist;
|
||||||
|
|
||||||
CURL *curl = curl_easy_init();
|
while (std::getline(ourStream, segment, '/')) {
|
||||||
int outlength;
|
seglist.push_back(segment);
|
||||||
std::string finalString = curl_easy_unescape(curl, seglist[seglist.size() - 1].c_str(), seglist[seglist.size() - 1].length(), &outlength);
|
}
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
|
|
||||||
return finalString;
|
CURL* curl = curl_easy_init();
|
||||||
}
|
int outlength;
|
||||||
|
std::string finalString = curl_easy_unescape(curl, seglist[seglist.size() - 1].c_str(), seglist[seglist.size() - 1].length(), &outlength);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
std::string formatUrlLink(std::string ourString){
|
return finalString;
|
||||||
std::string::size_type pos = ourString.find('/');
|
}
|
||||||
if (pos != std::string::npos)
|
|
||||||
return ourString.substr(0, pos);
|
|
||||||
else
|
|
||||||
return ourString;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string shortenString(std::string ourString, int ourLength, bool isFile) {
|
std::string formatUrlLink(std::string ourString) {
|
||||||
std::filesystem::path ourStringAsAPath = ourString;
|
std::string::size_type pos = ourString.find('/');
|
||||||
std::string ourExtension = ourStringAsAPath.extension().string();
|
if (pos != std::string::npos)
|
||||||
if (ourString.size() - ourExtension.size() > (unsigned long)ourLength) {
|
return ourString.substr(0, pos);
|
||||||
if(isFile) return (std::string)ourString.substr(0,ourLength) + "(...)" + ourExtension;
|
else
|
||||||
else return (std::string)ourString.substr(0,ourLength) + "...";
|
return ourString;
|
||||||
} else return ourString;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::string readTextFromFile(std::string ourFile) {
|
std::string shortenString(std::string ourString, int ourLength, bool isFile) {
|
||||||
if (std::filesystem::exists(ourFile)) {
|
std::filesystem::path ourStringAsAPath = ourString;
|
||||||
FILE * file = fopen(ourFile.c_str(), "r");
|
std::string ourExtension = ourStringAsAPath.extension().string();
|
||||||
char line[1024];
|
if (ourString.size() - ourExtension.size() > (unsigned long)ourLength) {
|
||||||
fgets(line, 1024, file);
|
if (isFile) return (std::string)ourString.substr(0, ourLength) + "(...)" + ourExtension;
|
||||||
std::string url = line;
|
else return (std::string)ourString.substr(0, ourLength) + "...";
|
||||||
fflush(file);
|
}
|
||||||
fclose(file);
|
else return ourString;
|
||||||
return url;
|
}
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string softwareKeyboard(std::string guideText, std::string initialText, int LenMax) {
|
std::string readTextFromFile(std::string ourFile) {
|
||||||
Result rc=0;
|
if (std::filesystem::exists(ourFile)) {
|
||||||
SwkbdConfig kbd;
|
FILE* file = fopen(ourFile.c_str(), "r");
|
||||||
char tmpoutstr[LenMax + 1] = {0};
|
char line[1024];
|
||||||
rc = swkbdCreate(&kbd, 0);
|
fgets(line, 1024, file);
|
||||||
if (R_SUCCEEDED(rc)) {
|
std::string url = line;
|
||||||
swkbdConfigMakePresetDefault(&kbd);
|
fflush(file);
|
||||||
swkbdConfigSetGuideText(&kbd, guideText.c_str());
|
fclose(file);
|
||||||
swkbdConfigSetInitialText(&kbd, initialText.c_str());
|
return url;
|
||||||
swkbdConfigSetStringLenMax(&kbd, LenMax);
|
}
|
||||||
rc = swkbdShow(&kbd, tmpoutstr, sizeof(tmpoutstr));
|
return "";
|
||||||
swkbdClose(&kbd);
|
}
|
||||||
if (R_SUCCEEDED(rc) && tmpoutstr[0] != 0) return(((std::string)(tmpoutstr)));
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getDriveFileName(std::string fileId) {
|
std::string softwareKeyboard(std::string guideText, std::string initialText, int LenMax) {
|
||||||
std::string htmlData = inst::curl::downloadToBuffer("https://drive.google.com/file/d/" + fileId + "/view");
|
Result rc = 0;
|
||||||
if (htmlData.size() > 0) {
|
SwkbdConfig kbd;
|
||||||
std::smatch ourMatches;
|
char tmpoutstr[LenMax + 1] = { 0 };
|
||||||
std::regex ourRegex("<title>\\s*(.+?)\\s*</title>");
|
rc = swkbdCreate(&kbd, 0);
|
||||||
std::regex_search(htmlData, ourMatches, ourRegex);
|
if (R_SUCCEEDED(rc)) {
|
||||||
if (ourMatches.size() > 1) {
|
swkbdConfigMakePresetDefault(&kbd);
|
||||||
if (ourMatches[1].str() == "Google Drive -- Page Not Found") return "";
|
swkbdConfigSetGuideText(&kbd, guideText.c_str());
|
||||||
return ourMatches[1].str().substr(0, ourMatches[1].str().size() - 15);
|
swkbdConfigSetInitialText(&kbd, initialText.c_str());
|
||||||
}
|
swkbdConfigSetStringLenMax(&kbd, LenMax);
|
||||||
}
|
rc = swkbdShow(&kbd, tmpoutstr, sizeof(tmpoutstr));
|
||||||
return "";
|
swkbdClose(&kbd);
|
||||||
}
|
if (R_SUCCEEDED(rc) && tmpoutstr[0] != 0) return(((std::string)(tmpoutstr)));
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint32_t> setClockSpeed(int deviceToClock, uint32_t clockSpeed) {
|
std::string getDriveFileName(std::string fileId) {
|
||||||
uint32_t hz = 0;
|
std::string htmlData = inst::curl::downloadToBuffer("https://drive.google.com/file/d/" + fileId + "/view");
|
||||||
uint32_t previousHz = 0;
|
if (htmlData.size() > 0) {
|
||||||
|
std::smatch ourMatches;
|
||||||
|
std::regex ourRegex("<title>\\s*(.+?)\\s*</title>");
|
||||||
|
std::regex_search(htmlData, ourMatches, ourRegex);
|
||||||
|
if (ourMatches.size() > 1) {
|
||||||
|
if (ourMatches[1].str() == "Google Drive -- Page Not Found") return "";
|
||||||
|
return ourMatches[1].str().substr(0, ourMatches[1].str().size() - 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
if (deviceToClock > 2 || deviceToClock < 0) return {0,0};
|
std::vector<uint32_t> setClockSpeed(int deviceToClock, uint32_t clockSpeed) {
|
||||||
|
uint32_t hz = 0;
|
||||||
|
uint32_t previousHz = 0;
|
||||||
|
|
||||||
if(hosversionAtLeast(8,0,0)) {
|
if (deviceToClock > 2 || deviceToClock < 0) return { 0,0 };
|
||||||
ClkrstSession session = {0};
|
|
||||||
PcvModuleId pcvModuleId;
|
|
||||||
pcvInitialize();
|
|
||||||
clkrstInitialize();
|
|
||||||
|
|
||||||
switch (deviceToClock) {
|
if (hosversionAtLeast(8, 0, 0)) {
|
||||||
case 0:
|
ClkrstSession session = { 0 };
|
||||||
pcvGetModuleId(&pcvModuleId, PcvModule_CpuBus);
|
PcvModuleId pcvModuleId;
|
||||||
break;
|
pcvInitialize();
|
||||||
case 1:
|
clkrstInitialize();
|
||||||
pcvGetModuleId(&pcvModuleId, PcvModule_GPU);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
pcvGetModuleId(&pcvModuleId, PcvModule_EMC);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
clkrstOpenSession(&session, pcvModuleId, 3);
|
switch (deviceToClock) {
|
||||||
clkrstGetClockRate(&session, &previousHz);
|
case 0:
|
||||||
clkrstSetClockRate(&session, clockSpeed);
|
pcvGetModuleId(&pcvModuleId, PcvModule_CpuBus);
|
||||||
clkrstGetClockRate(&session, &hz);
|
break;
|
||||||
|
case 1:
|
||||||
|
pcvGetModuleId(&pcvModuleId, PcvModule_GPU);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pcvGetModuleId(&pcvModuleId, PcvModule_EMC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
pcvExit();
|
clkrstOpenSession(&session, pcvModuleId, 3);
|
||||||
clkrstCloseSession(&session);
|
clkrstGetClockRate(&session, &previousHz);
|
||||||
clkrstExit();
|
clkrstSetClockRate(&session, clockSpeed);
|
||||||
|
clkrstGetClockRate(&session, &hz);
|
||||||
|
|
||||||
return {previousHz, hz};
|
pcvExit();
|
||||||
} else {
|
clkrstCloseSession(&session);
|
||||||
PcvModule pcvModule;
|
clkrstExit();
|
||||||
pcvInitialize();
|
|
||||||
|
|
||||||
switch (deviceToClock) {
|
return { previousHz, hz };
|
||||||
case 0:
|
}
|
||||||
pcvModule = PcvModule_CpuBus;
|
else {
|
||||||
break;
|
PcvModule pcvModule;
|
||||||
case 1:
|
pcvInitialize();
|
||||||
pcvModule = PcvModule_GPU;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
pcvModule = PcvModule_EMC;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcvGetClockRate(pcvModule, &previousHz);
|
switch (deviceToClock) {
|
||||||
pcvSetClockRate(pcvModule, clockSpeed);
|
case 0:
|
||||||
pcvGetClockRate(pcvModule, &hz);
|
pcvModule = PcvModule_CpuBus;
|
||||||
|
break;
|
||||||
pcvExit();
|
case 1:
|
||||||
|
pcvModule = PcvModule_GPU;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pcvModule = PcvModule_EMC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return {previousHz, hz};
|
pcvGetClockRate(pcvModule, &previousHz);
|
||||||
}
|
pcvSetClockRate(pcvModule, clockSpeed);
|
||||||
}
|
pcvGetClockRate(pcvModule, &hz);
|
||||||
|
|
||||||
std::string getIPAddress() {
|
pcvExit();
|
||||||
struct in_addr addr = {(in_addr_t) gethostid()};
|
|
||||||
return inet_ntoa(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool usbIsConnected() {
|
|
||||||
UsbState state = UsbState_Detached;
|
|
||||||
usbDsGetState(&state);
|
|
||||||
return state == UsbState_Configured;
|
|
||||||
}
|
|
||||||
|
|
||||||
void playAudio(std::string audioPath) {
|
return { previousHz, hz };
|
||||||
int audio_rate = 22050;
|
}
|
||||||
Uint16 audio_format = AUDIO_S16SYS;
|
}
|
||||||
int audio_channels = 2;
|
|
||||||
int audio_buffers = 4096;
|
|
||||||
|
|
||||||
if(Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) return;
|
std::string getIPAddress() {
|
||||||
|
struct in_addr addr = { (in_addr_t)gethostid() };
|
||||||
|
return inet_ntoa(addr);
|
||||||
|
}
|
||||||
|
|
||||||
Mix_Chunk *sound = NULL;
|
bool usbIsConnected() {
|
||||||
sound = Mix_LoadWAV(audioPath.c_str());
|
UsbState state = UsbState_Detached;
|
||||||
if(sound == NULL) {
|
usbDsGetState(&state);
|
||||||
Mix_FreeChunk(sound);
|
return state == UsbState_Configured;
|
||||||
Mix_CloseAudio();
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int channel = Mix_PlayChannel(-1, sound, 0);
|
void playAudio(std::string audioPath) {
|
||||||
if(channel == -1) {
|
int audio_rate = 22050;
|
||||||
Mix_FreeChunk(sound);
|
Uint16 audio_format = AUDIO_S16SYS;
|
||||||
Mix_CloseAudio();
|
int audio_channels = 2;
|
||||||
return;
|
int audio_buffers = 4096;
|
||||||
}
|
|
||||||
|
|
||||||
while(Mix_Playing(channel) != 0);
|
if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) return;
|
||||||
|
|
||||||
Mix_FreeChunk(sound);
|
Mix_Chunk* sound = NULL;
|
||||||
Mix_CloseAudio();
|
sound = Mix_LoadWAV(audioPath.c_str());
|
||||||
|
if (sound == NULL) {
|
||||||
|
Mix_FreeChunk(sound);
|
||||||
|
Mix_CloseAudio();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
int channel = Mix_PlayChannel(-1, sound, 0);
|
||||||
}
|
if (channel == -1) {
|
||||||
|
Mix_FreeChunk(sound);
|
||||||
std::vector<std::string> checkForAppUpdate () {
|
Mix_CloseAudio();
|
||||||
try {
|
return;
|
||||||
std::string jsonData = inst::curl::downloadToBuffer("https://api.github.com/repos/Huntereb/Awoo-Installer/releases/latest", 0, 0, 1000L);
|
}
|
||||||
if (jsonData.size() == 0) return {};
|
|
||||||
nlohmann::json ourJson = nlohmann::json::parse(jsonData);
|
|
||||||
if (ourJson["tag_name"].get<std::string>() != inst::config::appVersion) {
|
|
||||||
std::vector<std::string> ourUpdateInfo = {ourJson["tag_name"].get<std::string>(), ourJson["assets"][0]["browser_download_url"].get<std::string>()};
|
|
||||||
inst::config::updateInfo = ourUpdateInfo;
|
|
||||||
return ourUpdateInfo;
|
|
||||||
}
|
|
||||||
} catch (...) {}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
double GetAvailableSpace(const char* path)
|
while (Mix_Playing(channel) != 0);
|
||||||
{
|
|
||||||
struct statvfs stat = { 0 };
|
|
||||||
|
|
||||||
if (statvfs(path, &stat) != 0) {
|
Mix_FreeChunk(sound);
|
||||||
// error happens, just quits here
|
Mix_CloseAudio();
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the available size is f_bsize * f_bavail
|
return;
|
||||||
return stat.f_bsize * stat.f_bavail;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
double amountOfDiskSpaceUsed(const char* path)
|
std::vector<std::string> checkForAppUpdate() {
|
||||||
{
|
try {
|
||||||
struct statvfs stat = { 0 };
|
std::string jsonData = inst::curl::downloadToBuffer("https://api.github.com/repos/Huntereb/Awoo-Installer/releases/latest", 0, 0, 1000L);
|
||||||
|
if (jsonData.size() == 0) return {};
|
||||||
|
nlohmann::json ourJson = nlohmann::json::parse(jsonData);
|
||||||
|
if (ourJson["tag_name"].get<std::string>() != inst::config::appVersion) {
|
||||||
|
std::vector<std::string> ourUpdateInfo = { ourJson["tag_name"].get<std::string>(), ourJson["assets"][0]["browser_download_url"].get<std::string>() };
|
||||||
|
inst::config::updateInfo = ourUpdateInfo;
|
||||||
|
return ourUpdateInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) {}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
if (statvfs(path, &stat) != 0) {
|
double GetAvailableSpace(const char* path)
|
||||||
// error happens, just quits here
|
{
|
||||||
return -1;
|
struct statvfs stat = { 0 };
|
||||||
}
|
|
||||||
const auto total = static_cast<unsigned long>(stat.f_blocks);
|
|
||||||
const auto available = static_cast<unsigned long>(stat.f_bavail);
|
|
||||||
const auto availableToRoot = static_cast<unsigned long>(stat.f_bfree);
|
|
||||||
const auto used = total - availableToRoot;
|
|
||||||
const auto nonRootTotal = used + available;
|
|
||||||
return 100.0 * static_cast<double>(used) / static_cast<double>(nonRootTotal);
|
|
||||||
}
|
|
||||||
|
|
||||||
double totalsize(const char* path)
|
if (statvfs(path, &stat) != 0) {
|
||||||
{
|
// error happens, just quits here
|
||||||
struct statvfs stat;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (statvfs(path, &stat) != 0) {
|
// the available size is f_bsize * f_bavail
|
||||||
// error happens, just quits here
|
return stat.f_bsize * stat.f_bavail;
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
return stat.f_blocks * stat.f_frsize;
|
double amountOfDiskSpaceUsed(const char* path)
|
||||||
}
|
{
|
||||||
|
struct statvfs stat = { 0 };
|
||||||
|
|
||||||
|
if (statvfs(path, &stat) != 0) {
|
||||||
|
// error happens, just quits here
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const auto total = static_cast<unsigned long>(stat.f_blocks);
|
||||||
|
const auto available = static_cast<unsigned long>(stat.f_bavail);
|
||||||
|
const auto availableToRoot = static_cast<unsigned long>(stat.f_bfree);
|
||||||
|
const auto used = total - availableToRoot;
|
||||||
|
const auto nonRootTotal = used + available;
|
||||||
|
return 100.0 * static_cast<double>(used) / static_cast<double>(nonRootTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
double totalsize(const char* path)
|
||||||
|
{
|
||||||
|
struct statvfs stat;
|
||||||
|
|
||||||
|
if (statvfs(path, &stat) != 0) {
|
||||||
|
// error happens, just quits here
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return stat.f_blocks * stat.f_frsize;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user