diff --git a/README.md b/README.md index 37c26fb..7051033 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ Tools & Libraries for NX (Nintendo Switch). * __libcrypto__ - Cryptographic functions (AES,SHA,RSA). Wrapper for [mbedTLS](https://github.com/ARMmbed/mbedtls) * __libcompress__ - Compression algorithms (LZ4). Wrapper for [lz4](https://github.com/lz4/lz4) * __libes__ - Handling of (NX relevant) eShop file type processing. (eTickets, etc) -* __libnx__ - Handling of NX file types +* __libnx__ - Handling of NX file types. +* __libnx-hb__ - Handling of NX (homebrew extensions) file types. # Building diff --git a/lib/libnx-hb/include/nx/NroAssetHeader.h b/lib/libnx-hb/include/nx/NroAssetHeader.h new file mode 100644 index 0000000..96e8e22 --- /dev/null +++ b/lib/libnx-hb/include/nx/NroAssetHeader.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include +#include + +namespace nx +{ + class NroAssetHeader : + public fnd::ISerialiseableBinary + { + public: + struct sSection + { + uint64_t offset; + uint64_t size; + + void operator=(const sSection& other) + { + offset = other.offset; + size = other.size; + } + + bool operator==(const sSection& other) const + { + return (offset == other.offset) \ + && (size == other.size); + } + + bool operator!=(const sSection& other) const + { + return !(*this == other); + } + }; + + NroAssetHeader(); + NroAssetHeader(const NroAssetHeader& other); + NroAssetHeader(const byte_t* bytes, size_t len); + + bool operator==(const NroAssetHeader& other) const; + bool operator!=(const NroAssetHeader& other) const; + void operator=(const NroAssetHeader& other); + + // to be used after export + const byte_t* getBytes() const; + size_t getSize() const; + + // export/import binary + void exportBinary(); + void importBinary(const byte_t* bytes, size_t len); + + // variables + void clear(); + + const sSection& getIconInfo() const; + void setIconInfo(const sSection& info); + + const sSection& getNacpInfo() const; + void setNacpInfo(const sSection& info); + + const sSection& getRomfsInfo() const; + void setRomfsInfo(const sSection& info); + private: + const std::string kModuleName = "NRO_ASSET_HEADER"; + + // binary + fnd::MemoryBlob mBinaryBlob; + + // data + sSection mIconInfo; + sSection mNacpInfo; + sSection mRomfsInfo; + + // helpers + bool isEqual(const NroAssetHeader& other) const; + void copyFrom(const NroAssetHeader& other); + }; + +} \ No newline at end of file diff --git a/lib/libnx-hb/include/nx/nro-hb.h b/lib/libnx-hb/include/nx/nro-hb.h new file mode 100644 index 0000000..32f0e0f --- /dev/null +++ b/lib/libnx-hb/include/nx/nro-hb.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +namespace nx +{ + namespace nro + { + static const uint64_t kNroHomebrewSig = _MAKE_STRUCT_SIGNATURE_U64("HOMEBREW"); + static const uint32_t kAssetSig = _MAKE_STRUCT_SIGNATURE("ASET"); + + static const uint32_t kDefaultAssetFormatVersion = 0; + } + +#pragma pack(push,1) + struct sNroAssetSection + { + le_uint64_t offset; + le_uint64_t size; + }; + + struct sNroAssetHeader + { + le_uint32_t signature; + le_uint32_t format_version; + sNroAssetSection icon; + sNroAssetSection nacp; + sNroAssetSection romfs; + }; +#pragma pack(pop) +} \ No newline at end of file diff --git a/lib/libnx-hb/makefile b/lib/libnx-hb/makefile new file mode 100644 index 0000000..f069c2b --- /dev/null +++ b/lib/libnx-hb/makefile @@ -0,0 +1,47 @@ +# Sources +SRC_DIR = source +OBJS = $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c))) + +# External dependencies +DEPENDS = fnd crypto nx +LIB_DIR = .. +INCS = -I"include" $(foreach dep,$(DEPENDS), -I"$(LIB_DIR)/lib$(dep)/include") + + +# Compiler Settings +CXXFLAGS = -std=c++11 $(INCS) -D__STDC_FORMAT_MACROS -Wall -Wno-unused-value +CFLAGS = -std=c11 $(INCS) -Wall -Wno-unused-value +ARFLAGS = cr -o +ifeq ($(OS),Windows_NT) + # Windows Only Flags/Libs + CC = x86_64-w64-mingw32-gcc + CXX = x86_64-w64-mingw32-g++ + CFLAGS += -Wno-unused-but-set-variable + CXXFLAGS += -Wno-unused-but-set-variable +else + UNAME = $(shell uname -s) + ifeq ($(UNAME), Darwin) + # MacOS Only Flags/Libs + CFLAGS += -Wno-unused-private-field + CXXFLAGS += -Wno-unused-private-field + ARFLAGS = rc + else + # *nix Only Flags/Libs + CFLAGS += -Wno-unused-but-set-variable + CXXFLAGS += -Wno-unused-but-set-variable + endif + +endif + +# Output +OUTPUT = $(shell basename $(CURDIR)).a + +main: build + +rebuild: clean build + +build: $(OBJS) + ar $(ARFLAGS) $(OUTPUT) $(OBJS) + +clean: + rm -rf $(OUTPUT) $(OBJS) \ No newline at end of file diff --git a/lib/libnx-hb/source/NroAssetHeader.cpp b/lib/libnx-hb/source/NroAssetHeader.cpp new file mode 100644 index 0000000..60c82e9 --- /dev/null +++ b/lib/libnx-hb/source/NroAssetHeader.cpp @@ -0,0 +1,153 @@ +#include + +nx::NroAssetHeader::NroAssetHeader() +{ + clear(); +} + +nx::NroAssetHeader::NroAssetHeader(const NroAssetHeader& other) +{ + copyFrom(other); +} + +nx::NroAssetHeader::NroAssetHeader(const byte_t* bytes, size_t len) +{ + importBinary(bytes, len); +} + +bool nx::NroAssetHeader::operator==(const NroAssetHeader& other) const +{ + return isEqual(other); +} + +bool nx::NroAssetHeader::operator!=(const NroAssetHeader& other) const +{ + return !(*this == other); +} + +void nx::NroAssetHeader::operator=(const NroAssetHeader& other) +{ + copyFrom(other); +} + +const byte_t* nx::NroAssetHeader::getBytes() const +{ + return mBinaryBlob.getBytes(); +} + +size_t nx::NroAssetHeader::getSize() const +{ + return mBinaryBlob.getSize(); +} + +void nx::NroAssetHeader::exportBinary() +{ + mBinaryBlob.alloc(sizeof(sNroAssetHeader)); + nx::sNroAssetHeader* hdr = (nx::sNroAssetHeader*)mBinaryBlob.getBytes(); + + // set header identifers + hdr->signature = nro::kAssetSig; + hdr->format_version = nro::kDefaultAssetFormatVersion; + + // set icon section + hdr->icon.offset = mIconInfo.offset; + hdr->icon.size = mIconInfo.size; + + // set nacp section + hdr->nacp.offset = mNacpInfo.offset; + hdr->nacp.size = mNacpInfo.size; + + // set romfs section + hdr->romfs.offset = mRomfsInfo.offset; + hdr->romfs.size = mRomfsInfo.size; +} + +void nx::NroAssetHeader::importBinary(const byte_t* bytes, size_t len) +{ + // check input data size + if (len < sizeof(sNroAssetHeader)) + { + throw fnd::Exception(kModuleName, "NRO Asset header size is too small"); + } + + // clear internal members + clear(); + + // allocate internal local binary copy + mBinaryBlob.alloc(sizeof(sNroAssetHeader)); + memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize()); + + // get sNroAssetHeader ptr + const nx::sNroAssetHeader* hdr = (const nx::sNroAssetHeader*)mBinaryBlob.getBytes(); + + // check NRO signature + if (hdr->signature.get() != nro::kAssetSig) + { + throw fnd::Exception(kModuleName, "NRO Asset header corrupt (unrecognised header signature)"); + } + + // check NRO format version + if (hdr->format_version.get() != nro::kDefaultAssetFormatVersion) + { + throw fnd::Exception(kModuleName, "NRO Asset header corrupt (unsupported format version)"); + } + + mIconInfo.offset = hdr->icon.offset.get(); + mIconInfo.size = hdr->icon.size.get(); + mNacpInfo.offset = hdr->nacp.offset.get(); + mNacpInfo.size = hdr->nacp.size.get(); + mRomfsInfo.offset = hdr->romfs.offset.get(); + mRomfsInfo.size = hdr->romfs.size.get(); +} + +void nx::NroAssetHeader::clear() +{ + mBinaryBlob.clear(); + memset(&mIconInfo, 0, sizeof(mIconInfo)); + memset(&mNacpInfo, 0, sizeof(mNacpInfo)); + memset(&mRomfsInfo, 0, sizeof(mRomfsInfo)); +} + +const nx::NroAssetHeader::sSection& nx::NroAssetHeader::getIconInfo() const +{ + return mIconInfo; +} + +void nx::NroAssetHeader::setIconInfo(const nx::NroAssetHeader::sSection& info) +{ + mIconInfo = info; +} + +const nx::NroAssetHeader::sSection& nx::NroAssetHeader::getNacpInfo() const +{ + return mNacpInfo; +} + +void nx::NroAssetHeader::setNacpInfo(const sSection& info) +{ + mNacpInfo = info; +} + +const nx::NroAssetHeader::sSection& nx::NroAssetHeader::getRomfsInfo() const +{ + return mRomfsInfo; +} + +void nx::NroAssetHeader::setRomfsInfo(const sSection& info) +{ + mRomfsInfo = info; +} + +bool nx::NroAssetHeader::isEqual(const NroAssetHeader& other) const +{ + return (mIconInfo == other.mIconInfo) \ + && (mNacpInfo == other.mNacpInfo) \ + && (mRomfsInfo == other.mRomfsInfo); +} + +void nx::NroAssetHeader::copyFrom(const NroAssetHeader& other) +{ + mIconInfo = other.mIconInfo; + mNacpInfo = other.mNacpInfo; + mRomfsInfo = other.mRomfsInfo; +} \ No newline at end of file diff --git a/lib/makefile b/lib/makefile index db1fbe0..89636d0 100644 --- a/lib/makefile +++ b/lib/makefile @@ -1,4 +1,4 @@ -LIBS = libfnd libcrypto libcompress libes libnx +LIBS = libfnd libcrypto libcompress libes libnx libnx-hb main: build rebuild: clean build