[nx] Add ISerialiseableInterface, which AciHeader and NcaHeader inherit from. Also added SacEntry.

This commit is contained in:
jakcron 2017-07-06 13:30:27 +10:00
parent bd8a232160
commit 337a5eff25
9 changed files with 260 additions and 19 deletions

View file

@ -19,20 +19,45 @@ void AciHeader::calculateSectionOffsets()
mKc.offset = mSac.offset + align(mSac.size, kAciAlignSize); mKc.offset = mSac.offset + align(mSac.size, kAciAlignSize);
} }
AciHeader::AciHeader()
{
clearVariables();
}
AciHeader::AciHeader(const AciHeader & other)
{
importBinary(other.getBytes(), other.getSize());
}
AciHeader::AciHeader(const u8 * bytes)
{
importBinary(bytes);
}
bool AciHeader::operator==(const AciHeader & other)
{
return memcmp(this->getBytes(), other.getBytes(), this->getSize());
}
void AciHeader::operator=(const AciHeader & other)
{
this->importBinary(other.getBytes(), other.getSize());
}
const u8 * AciHeader::getBytes() const const u8 * AciHeader::getBytes() const
{ {
return mBinaryBlob.data(); return mBinaryBlob.getBytes();
} }
size_t AciHeader::getSize() const size_t AciHeader::getSize() const
{ {
return mBinaryBlob.size(); return mBinaryBlob.getSize();
} }
void AciHeader::exportBinary() void AciHeader::exportBinary()
{ {
mBinaryBlob.alloc(sizeof(sAciHeader)); mBinaryBlob.alloc(sizeof(sAciHeader));
sAciHeader* hdr = (sAciHeader*)mBinaryBlob.data(); sAciHeader* hdr = (sAciHeader*)mBinaryBlob.getBytes();
// set type // set type
switch (mType) switch (mType)
@ -65,9 +90,9 @@ void AciHeader::importBinary(const u8 * bytes)
clearVariables(); clearVariables();
mBinaryBlob.alloc(sizeof(sAciHeader)); mBinaryBlob.alloc(sizeof(sAciHeader));
memcpy(mBinaryBlob.data(), bytes, sizeof(sAciHeader)); memcpy(mBinaryBlob.getBytes(), bytes, sizeof(sAciHeader));
sAciHeader* hdr = (sAciHeader*)mBinaryBlob.data(); sAciHeader* hdr = (sAciHeader*)mBinaryBlob.getBytes();
if (memcmp(hdr->signature(), kAciStructSig.c_str(), 4) == 0) if (memcmp(hdr->signature(), kAciStructSig.c_str(), 4) == 0)
{ {
@ -91,6 +116,15 @@ void AciHeader::importBinary(const u8 * bytes)
mKc.size = hdr->kc().size(); mKc.size = hdr->kc().size();
} }
void AciHeader::importBinary(const u8 * bytes, size_t len)
{
if (len < sizeof(sAciHeader))
{
throw fnd::Exception(kModuleName, "ACI header too small");
}
importBinary(bytes);
}
AciHeader::AciType AciHeader::getAciType() const AciHeader::AciType AciHeader::getAciType() const
{ {
return mType; return mType;

View file

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <string>
#include <fnd/types.h> #include <fnd/types.h>
#include <fnd/memory_blob.h> #include <fnd/memory_blob.h>
#include <string> #include <nx/ISerialiseableBinary.h>
class AciHeader class AciHeader : public ISerialiseableBinary
{ {
public: public:
enum AciType enum AciType
@ -18,6 +19,13 @@ public:
size_t size; size_t size;
}; };
AciHeader();
AciHeader(const AciHeader& other);
AciHeader(const u8* bytes);
bool operator==(const AciHeader& other);
void operator=(const AciHeader& other);
// to be used after export // to be used after export
const u8* getBytes() const; const u8* getBytes() const;
size_t getSize() const; size_t getSize() const;
@ -25,6 +33,7 @@ public:
// export/import binary // export/import binary
void exportBinary(); void exportBinary();
void importBinary(const u8* bytes); void importBinary(const u8* bytes);
void importBinary(const u8* bytes, size_t len);
// variables // variables
AciType getAciType() const; AciType getAciType() const;
@ -56,13 +65,13 @@ private:
{ {
private: private:
u32 offset_; // aligned by 0x10 from the last one u32 offset_; // aligned by 0x10 from the last one
u32 size_; u32 mSize;
public: public:
u32 offset() const { return le_word(offset_); } u32 offset() const { return le_word(offset_); }
void set_offset(u32 offset) { offset_ = le_word(offset); } void set_offset(u32 offset) { offset_ = le_word(offset); }
u32 size() const { return le_word(size_); } u32 size() const { return le_word(mSize); }
void set_size(u32 size) { size_ = le_word(size); } void set_size(u32 size) { mSize = le_word(size); }
} fac_, sac_, kc_; } fac_, sac_, kc_;
u8 reserved_3[8]; u8 reserved_3[8];
public: public:

View file

@ -0,0 +1,17 @@
#pragma once
#include <fnd/types.h>
class ISerialiseableBinary
{
public:
virtual bool operator==(const ISerialiseableBinary& other) = 0;
virtual void operator=(const ISerialiseableBinary& other) = 0;
virtual const u8* getBytes() const = 0;
virtual size_t getSize() const = 0;
virtual void exportBinary() = 0;
virtual void importBinary(const u8* bytes) = 0;
virtual void importBinary(const u8* bytes, size_t len) = 0;
};

View file

@ -4,7 +4,7 @@
void NcaHeader::exportBinary() void NcaHeader::exportBinary()
{ {
mBinaryBlob.alloc(sizeof(sNcaHeader)); mBinaryBlob.alloc(sizeof(sNcaHeader));
sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.data(); sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.getBytes();
hdr->set_signature(kNcaSig.c_str()); hdr->set_signature(kNcaSig.c_str());
hdr->set_block_size(kDefaultBlockSize); hdr->set_block_size(kDefaultBlockSize);
@ -36,9 +36,9 @@ void NcaHeader::importBinary(const u8 * bytes)
clearVariables(); clearVariables();
mBinaryBlob.alloc(sizeof(sNcaHeader)); mBinaryBlob.alloc(sizeof(sNcaHeader));
memcpy(mBinaryBlob.data(), bytes, sizeof(sNcaHeader)); memcpy(mBinaryBlob.getBytes(), bytes, sizeof(sNcaHeader));
sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.data(); sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.getBytes();
if (memcmp(hdr->signature(), kNcaSig.c_str(), 4) != 0) if (memcmp(hdr->signature(), kNcaSig.c_str(), 4) != 0)
{ {
@ -68,6 +68,15 @@ void NcaHeader::importBinary(const u8 * bytes)
} }
} }
void NcaHeader::importBinary(const u8 * bytes, size_t len)
{
if (len < sizeof(sNcaHeader))
{
throw fnd::Exception(kModuleName, "NCA header size is too small");
}
importBinary(bytes);
}
u64 NcaHeader::getNcaSize() const u64 NcaHeader::getNcaSize() const
{ {
return mNcaSize; return mNcaSize;
@ -157,12 +166,22 @@ NcaHeader::NcaHeader(const u8 * bytes)
importBinary(bytes); importBinary(bytes);
} }
bool NcaHeader::operator==(const NcaHeader & other)
{
return memcmp(this->getBytes(), other.getBytes(), this->getSize()) == 0;
}
void NcaHeader::operator=(const NcaHeader & other)
{
this->importBinary(other.getBytes(), other.getSize());
}
const u8 * NcaHeader::getBytes() const const u8 * NcaHeader::getBytes() const
{ {
return mBinaryBlob.data(); return mBinaryBlob.getBytes();
} }
size_t NcaHeader::getSize() const size_t NcaHeader::getSize() const
{ {
return mBinaryBlob.size(); return mBinaryBlob.getSize();
} }

View file

@ -1,12 +1,13 @@
#pragma once #pragma once
#include <vector>
#include <string>
#include <fnd/types.h> #include <fnd/types.h>
#include <fnd/memory_blob.h> #include <fnd/memory_blob.h>
#include <crypto/aes.h> #include <crypto/aes.h>
#include <crypto/sha.h> #include <crypto/sha.h>
#include <vector> #include <nx/ISerialiseableBinary.h>
#include <string>
class NcaHeader class NcaHeader : public ISerialiseableBinary
{ {
public: public:
struct sSection struct sSection
@ -19,10 +20,15 @@ public:
crypto::sha::sSha256Hash hash; crypto::sha::sSha256Hash hash;
}; };
static const size_t kDefaultBlockSize = 0x200;
NcaHeader(); NcaHeader();
NcaHeader(const NcaHeader& other); NcaHeader(const NcaHeader& other);
NcaHeader(const u8* bytes); NcaHeader(const u8* bytes);
bool operator==(const NcaHeader& other);
void operator=(const NcaHeader& other);
// to be used after export // to be used after export
const u8* getBytes() const; const u8* getBytes() const;
size_t getSize() const; size_t getSize() const;
@ -30,6 +36,7 @@ public:
// export/import binary // export/import binary
void exportBinary(); void exportBinary();
void importBinary(const u8* bytes); void importBinary(const u8* bytes);
void importBinary(const u8* bytes, size_t len);
// variables // variables
u64 getNcaSize() const; u64 getNcaSize() const;
@ -45,7 +52,6 @@ public:
private: private:
const std::string kModuleName = "NCA_HEADER"; const std::string kModuleName = "NCA_HEADER";
const std::string kNcaSig = "NCA2"; const std::string kNcaSig = "NCA2";
static const size_t kDefaultBlockSize = 0x200;
static const size_t kSectionNum = 4; static const size_t kSectionNum = 4;
static const size_t kAesKeyNum = 4; static const size_t kAesKeyNum = 4;

101
lib/nx/SacEntry.cpp Normal file
View file

@ -0,0 +1,101 @@
#include "SacEntry.h"
SacEntry::SacEntry() :
mIsServer(false),
mName("")
{
}
SacEntry::SacEntry(const SacEntry & other)
{
importBinary(other.getBytes(), other.getSize());
}
SacEntry::SacEntry(const u8 * bytes)
{
importBinary(bytes);
}
const u8 * SacEntry::getBytes() const
{
return mBinaryBlob.getBytes();
}
size_t SacEntry::getSize() const
{
return mBinaryBlob.getSize();
}
void SacEntry::exportBinary()
{
try {
mBinaryBlob.alloc(mName.size() + 1);
}
catch (const fnd::Exception& e)
{
throw fnd::Exception(kModuleName, "Failed to allocate memory for SacEntry: " + std::string(e.what()));
}
if (mName.length() > kMaxServiceNameLen)
{
throw fnd::Exception(kModuleName, "Service name string too long (max 8 chars)");
}
// copy data into binary blob
mBinaryBlob[0] = (mIsServer ? SAC_IS_SERVER : 0) | (mName.length() & SAC_NAME_LEN_MASK);
memcpy(mBinaryBlob.getBytes() + 1, mName.c_str(), mName.length());
}
void SacEntry::importBinary(const u8 * bytes)
{
bool isServer = (bytes[0] & SAC_IS_SERVER) == SAC_IS_SERVER;
size_t nameLen = (bytes[0] & SAC_NAME_LEN_MASK);
if (nameLen == 0)
{
throw fnd::Exception(kModuleName, "SAC entry has no service name");
}
else if (nameLen > kMaxServiceNameLen)
{
throw fnd::Exception(kModuleName, "Service name string too long (max 8 chars)");
}
mBinaryBlob.alloc(nameLen + 1);
memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize());
mIsServer = isServer;
mName = std::string((const char*)(mBinaryBlob.getBytes() + 1), nameLen);
}
void SacEntry::importBinary(const u8 * bytes, size_t len)
{
importBinary(bytes);
if (getSize() != len)
{
throw fnd::Exception(kModuleName, "SAC Entry has unexpected size");
}
}
bool SacEntry::isServer() const
{
return mIsServer;
}
void SacEntry::setIsServer(bool isServer)
{
mIsServer = isServer;
}
const std::string & SacEntry::getName() const
{
return mName;
}
void SacEntry::setName(const std::string & name)
{
if (name.length() > kMaxServiceNameLen)
{
throw fnd::Exception(kModuleName, "Service name string too long (max 8 chars)");
}
mName = name;
}

43
lib/nx/SacEntry.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#include <string>
#include <fnd/types.h>
#include <fnd/memory_blob.h>
#include <nx/ISerialiseableBinary.h>
class SacEntry : public ISerialiseableBinary
{
SacEntry();
SacEntry(const SacEntry& other);
SacEntry(const u8* bytes);
// to be used after export
const u8* getBytes() const;
size_t getSize() const;
// export/import binary
void exportBinary();
void importBinary(const u8* bytes);
void importBinary(const u8* bytes, size_t len);
// variables
bool isServer() const;
void setIsServer(bool isServer);
const std::string& getName() const;
void setName(const std::string& name);
private:
const std::string kModuleName = "SAC_ENTRY";
static const size_t kMaxServiceNameLen = 8;
enum SacEntryFlag
{
SAC_IS_SERVER = BIT(7),
SAC_NAME_LEN_MASK = BIT(7)-1
};
// raw binary
fnd::MemoryBlob mBinaryBlob;
// variables
bool mIsServer;
std::string mName;
};

View file

@ -20,12 +20,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="AciHeader.h" /> <ClInclude Include="AciHeader.h" />
<ClInclude Include="ISerialiseableBinary.h" />
<ClInclude Include="NcaHeader.h" /> <ClInclude Include="NcaHeader.h" />
<ClInclude Include="NXCrypto.h" /> <ClInclude Include="NXCrypto.h" />
<ClInclude Include="SacEntry.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="AciHeader.cpp" /> <ClCompile Include="AciHeader.cpp" />
<ClCompile Include="NcaHeader.cpp" /> <ClCompile Include="NcaHeader.cpp" />
<ClCompile Include="SacEntry.cpp" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion> <VCProjectVersion>15.0</VCProjectVersion>

View file

@ -24,6 +24,12 @@
<ClInclude Include="AciHeader.h"> <ClInclude Include="AciHeader.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="SacEntry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ISerialiseableBinary.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="NcaHeader.cpp"> <ClCompile Include="NcaHeader.cpp">
@ -32,5 +38,8 @@
<ClCompile Include="AciHeader.cpp"> <ClCompile Include="AciHeader.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="SacEntry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>