[nx] Added SacBinary, FacHeader, FacBinary.

This commit is contained in:
jakcron 2017-07-06 20:57:33 +10:00
parent 844a46c83a
commit 724fc26349
8 changed files with 693 additions and 0 deletions

167
lib/nx/FacBinary.cpp Normal file
View file

@ -0,0 +1,167 @@
#include "FacBinary.h"
FacBinary::FacBinary() :
mHeader()
{
clearVariables();
}
FacBinary::FacBinary(const FacBinary & other)
{
importBinary(other.getBytes(), other.getSize());
}
FacBinary::FacBinary(const u8 * bytes, size_t len)
{
importBinary(bytes, len);
}
bool FacBinary::operator==(const FacBinary & other) const
{
return isEqual(other);
}
bool FacBinary::operator!=(const FacBinary & other) const
{
return !isEqual(other);
}
void FacBinary::operator=(const FacBinary & other)
{
copyFrom(other);
}
const u8 * FacBinary::getBytes() const
{
return mBinaryBlob.getBytes();
}
size_t FacBinary::getSize() const
{
return mBinaryBlob.getSize();
}
void FacBinary::exportBinary()
{
mHeader.setFsaRights(mFsaRights);
mHeader.setContentOwnerIdSize(mContentOwnerIds.getSize() * sizeof(u32));
mHeader.setSaveDataOwnerIdSize(mSaveDataOwnerIds.getSize() * sizeof(u32));
mHeader.exportBinary();
mBinaryBlob.alloc(mHeader.getFacSize());
memcpy(mBinaryBlob.getBytes(), mHeader.getBytes(), mHeader.getSize());
u32* rawContentOwnerIds = (u32*)(mBinaryBlob.getBytes() + mHeader.getContentOwnerIdOffset());
for (size_t i = 0; i < mContentOwnerIds.getSize(); i++)
{
rawContentOwnerIds[i] = le_word(mContentOwnerIds[i]);
}
u32* rawSaveDataOwnerIds = (u32*)(mBinaryBlob.getBytes() + mHeader.getSaveDataOwnerIdOffset());
for (size_t i = 0; i < mSaveDataOwnerIds.getSize(); i++)
{
rawSaveDataOwnerIds[i] = le_word(mSaveDataOwnerIds[i]);
}
}
void FacBinary::importBinary(const u8 * bytes)
{
throw fnd::Exception(kModuleName, "Unsupported operation. importBinary(const u8* bytes) is not supported for variable size structures.");
}
void FacBinary::importBinary(const u8 * bytes, size_t len)
{
clearVariables();
mHeader.importBinary(bytes, len);
if (mHeader.getFacSize() > len)
{
throw fnd::Exception(kModuleName, "FAC binary too small");
}
mBinaryBlob.alloc(mHeader.getFacSize());
memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize());
mFsaRights = mHeader.getFsaRights();
u32* rawContentOwnerIds = (u32*)(mBinaryBlob.getBytes() + mHeader.getContentOwnerIdOffset());
size_t rawContentOwnerIdNum = mHeader.getContentOwnerIdSize() / sizeof(u32);
for (size_t i = 0; i < rawContentOwnerIdNum; i++)
{
addContentOwnerId(le_word(rawContentOwnerIds[i]));
}
u32* rawSaveDataOwnerIds = (u32*)(mBinaryBlob.getBytes() + mHeader.getSaveDataOwnerIdOffset());
size_t rawSaveDataOwnerIdNum = mHeader.getSaveDataOwnerIdSize() / sizeof(u32);
for (size_t i = 0; i < rawSaveDataOwnerIdNum; i++)
{
addSaveDataOwnerId(le_word(rawSaveDataOwnerIds[i]));
}
}
bool FacBinary::isPermissionSet(FsAccessFlag flag) const
{
return (mFsaRights & flag) == flag;
}
void FacBinary::addPermission(FsAccessFlag flag)
{
mFsaRights |= flag;
}
void FacBinary::removePermission(FsAccessFlag flag)
{
mFsaRights &= ~(u64)flag;
}
const fnd::List<u32>& FacBinary::getContentOwnerIds() const
{
return mContentOwnerIds;
}
void FacBinary::addContentOwnerId(u32 id)
{
mContentOwnerIds.addElement(id);
}
const fnd::List<u32>& FacBinary::getSaveDataOwnerIds() const
{
return mSaveDataOwnerIds;
}
void FacBinary::addSaveDataOwnerId(u32 id)
{
mSaveDataOwnerIds.addElement(id);
}
void FacBinary::clearVariables()
{
mHeader = FacHeader();
mFsaRights = 0;
mContentOwnerIds.clear();
mSaveDataOwnerIds.clear();
}
bool FacBinary::isEqual(const FacBinary & other) const
{
return (mHeader == other.mHeader) \
&& (mFsaRights == other.mFsaRights) \
&& (mContentOwnerIds == other.mContentOwnerIds) \
&& (mSaveDataOwnerIds == other.mSaveDataOwnerIds);
}
void FacBinary::copyFrom(const FacBinary & other)
{
if (other.getSize())
{
importBinary(other.getBytes(), other.getSize());
}
else
{
mBinaryBlob.clear();
mHeader = other.mHeader;
mFsaRights = other.mFsaRights;
mContentOwnerIds = other.mContentOwnerIds;
mSaveDataOwnerIds = other.mSaveDataOwnerIds;
}
}

81
lib/nx/FacBinary.h Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#include <string>
#include <fnd/memory_blob.h>
#include <fnd/List.h>
#include <nx/ISerialiseableBinary.h>
#include <nx/FacHeader.h>
class FacBinary :
public ISerialiseableBinary
{
public:
enum FsAccessFlag
{
FSA_APPLICATION_INFO = BIT(0),
FSA_BOOT_MODE_CONTROL = BIT(1),
FSA_CALIBRATION = BIT(2),
FSA_SYSTEM_SAVE_DATA = BIT(3),
FSA_GAME_CARD = BIT(4),
FSA_SAVE_DATA_BACKUP = BIT(5),
FSA_SAVE_DATA_MANAGEMENT = BIT(6),
FSA_BIS_ALL_RAW = BIT(7),
FSA_GAME_CARD_RAW = BIT(8),
FSA_GAME_CARD_PRIVATE = BIT(9),
FSA_SET_TIME = BIT(10),
FSA_CONTENT_MANAGER = BIT(11),
FSA_IMAGE_MANAGER = BIT(12),
FSA_CREATE_SAVE_DATA = BIT(13),
FSA_SYSTEM_SAVE_DATA_MANAGEMENT = BIT(14),
FSA_BIS_FILE_SYSTEM = BIT(15),
FSA_SYSTEM_UPDATE = BIT(16),
FSA_SAVE_DATA_META = BIT(17),
FSA_DEVICE_SAVE_CONTROL = BIT(19),
FSA_SETTINGS_CONTROL = BIT(20),
FSA_DEBUG = BIT(62),
FSA_FULL_PERMISSION = BIT(63),
};
FacBinary();
FacBinary(const FacBinary& other);
FacBinary(const u8* bytes, size_t len);
bool operator==(const FacBinary& other) const;
bool operator!=(const FacBinary& other) const;
void operator=(const FacBinary& other);
// 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 isPermissionSet(FsAccessFlag flag) const;
void addPermission(FsAccessFlag flag);
void removePermission(FsAccessFlag flag);
const fnd::List<u32>& getContentOwnerIds() const;
void addContentOwnerId(u32 id);
const fnd::List<u32>& getSaveDataOwnerIds() const;
void addSaveDataOwnerId(u32 id);
private:
const std::string kModuleName = "FAC_BINARY";
// raw binary
fnd::MemoryBlob mBinaryBlob;
// variables
FacHeader mHeader;
u64 mFsaRights;
fnd::List<u32> mContentOwnerIds;
fnd::List<u32> mSaveDataOwnerIds;
void clearVariables();
bool isEqual(const FacBinary& other) const;
void copyFrom(const FacBinary& other);
};

171
lib/nx/FacHeader.cpp Normal file
View file

@ -0,0 +1,171 @@
#include "FacHeader.h"
FacHeader::FacHeader()
{
clearVariables();
}
FacHeader::FacHeader(const FacHeader & other)
{
copyFrom(other);
}
FacHeader::FacHeader(const u8 * bytes)
{
importBinary(bytes);
}
bool FacHeader::operator==(const FacHeader & other) const
{
return isEqual(other);
}
bool FacHeader::operator!=(const FacHeader & other) const
{
return !isEqual(other);
}
void FacHeader::operator=(const FacHeader & other)
{
copyFrom(other);
}
const u8 * FacHeader::getBytes() const
{
return mBinaryBlob.getBytes();
}
size_t FacHeader::getSize() const
{
return mBinaryBlob.getSize();
}
void FacHeader::exportBinary()
{
mBinaryBlob.alloc(sizeof(sFacHeader));
sFacHeader* hdr = (sFacHeader*)mBinaryBlob.getBytes();
hdr->set_version(kFacFormatVersion);
hdr->set_fac_flags(mFsaRights);
calculateOffsets();
hdr->content_owner_ids().set_start(mContentOwnerIdPos.offset);
hdr->content_owner_ids().set_end(mContentOwnerIdPos.offset + mContentOwnerIdPos.size);
hdr->save_data_owner_ids().set_start(mSaveDataOwnerIdPos.offset);
hdr->save_data_owner_ids().set_end(mSaveDataOwnerIdPos.offset + mSaveDataOwnerIdPos.size);
}
void FacHeader::importBinary(const u8 * bytes)
{
mBinaryBlob.alloc(sizeof(sFacHeader));
memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize());
sFacHeader* hdr = (sFacHeader*)mBinaryBlob.getBytes();
if (hdr->version() != kFacFormatVersion)
{
throw fnd::Exception(kModuleName, "Unsupported FAC format version");
}
mFsaRights = hdr->fac_flags();
mContentOwnerIdPos.offset = hdr->content_owner_ids().start();
mContentOwnerIdPos.size = hdr->content_owner_ids().end() - hdr->content_owner_ids().start();
mSaveDataOwnerIdPos.offset = hdr->save_data_owner_ids().start();
mSaveDataOwnerIdPos.size = hdr->save_data_owner_ids().end() - hdr->save_data_owner_ids().start();
}
void FacHeader::importBinary(const u8 * bytes, size_t len)
{
if (len < sizeof(sFacHeader))
{
throw fnd::Exception(kModuleName, "FAC header too small");
}
importBinary(bytes);
}
u64 FacHeader::getFacSize() const
{
return getSaveDataOwnerIdOffset() + getSaveDataOwnerIdSize();
}
u64 FacHeader::getFsaRights() const
{
return mFsaRights;
}
void FacHeader::setFsaRights(u64 flag)
{
mFsaRights = flag;
}
size_t FacHeader::getContentOwnerIdOffset() const
{
return mContentOwnerIdPos.offset;
}
size_t FacHeader::getContentOwnerIdSize() const
{
return mContentOwnerIdPos.size;
}
void FacHeader::setContentOwnerIdSize(size_t size)
{
mContentOwnerIdPos.size = size;
}
size_t FacHeader::getSaveDataOwnerIdOffset() const
{
return mSaveDataOwnerIdPos.offset;
}
size_t FacHeader::getSaveDataOwnerIdSize() const
{
return mSaveDataOwnerIdPos.size;
}
void FacHeader::setSaveDataOwnerIdSize(size_t size)
{
mSaveDataOwnerIdPos.size = size;
}
void FacHeader::clearVariables()
{
mFsaRights = 0;
mContentOwnerIdPos.offset = 0;
mContentOwnerIdPos.size = 0;
mSaveDataOwnerIdPos.offset = 0;
mSaveDataOwnerIdPos.size = 0;
}
void FacHeader::calculateOffsets()
{
mContentOwnerIdPos.offset = align(sizeof(sFacHeader), 4);
mSaveDataOwnerIdPos.offset = mContentOwnerIdPos.offset + align(mContentOwnerIdPos.size, 4);
}
bool FacHeader::isEqual(const FacHeader & other) const
{
return (mFsaRights == other.mFsaRights) \
&& (mContentOwnerIdPos.offset == other.mContentOwnerIdPos.offset) \
&& (mContentOwnerIdPos.size == other.mContentOwnerIdPos.size) \
&& (mSaveDataOwnerIdPos.offset == other.mSaveDataOwnerIdPos.offset) \
&& (mSaveDataOwnerIdPos.size == other.mSaveDataOwnerIdPos.size);
}
void FacHeader::copyFrom(const FacHeader & other)
{
if (other.getSize())
{
importBinary(other.getBytes(), other.getSize());
}
else
{
mBinaryBlob.clear();
mFsaRights = other.mFsaRights;
mContentOwnerIdPos.offset = other.mContentOwnerIdPos.offset;
mContentOwnerIdPos.size = other.mContentOwnerIdPos.size;
mSaveDataOwnerIdPos.offset = other.mSaveDataOwnerIdPos.offset;
mSaveDataOwnerIdPos.size = other.mSaveDataOwnerIdPos.size;
}
}

93
lib/nx/FacHeader.h Normal file
View file

@ -0,0 +1,93 @@
#pragma once
#include <string>
#include <fnd/memory_blob.h>
#include <nx/ISerialiseableBinary.h>
class FacHeader :
public ISerialiseableBinary
{
public:
FacHeader();
FacHeader(const FacHeader& other);
FacHeader(const u8* bytes);
bool operator==(const FacHeader& other) const;
bool operator!=(const FacHeader& other) const;
void operator=(const FacHeader& other);
// 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
u64 getFacSize() const;
u64 getFsaRights() const;
void setFsaRights(u64 flag);
size_t getContentOwnerIdOffset() const;
size_t getContentOwnerIdSize() const;
void setContentOwnerIdSize(size_t size);
size_t getSaveDataOwnerIdOffset() const;
size_t getSaveDataOwnerIdSize() const;
void setSaveDataOwnerIdSize(size_t size);
private:
const std::string kModuleName = "FAC_HEADER";
static const u32 kFacFormatVersion = 1;
#pragma pack (push, 1)
struct sFacHeader
{
private:
u32 version_; // default 1
u64 fac_flags_;
struct sFacSection
{
private:
u32 start_;
u32 end_;
public:
u32 start() const { return le_word(start_); }
void set_start(u32 start) { start_ = le_word(start); }
u32 end() const { return le_word(end_); }
void set_end(u32 end) { end_ = le_word(end); }
} content_owner_ids_, save_data_owner_ids_; // the data for these follow later in binary. start/end relative to base of FacData instance
public:
u32 version() const { return le_word(version_); }
void set_version(u32 version) { version_ = le_word(version); }
u64 fac_flags() const { return le_dword(fac_flags_); }
void set_fac_flags(u64 fac_flags) { fac_flags_ = le_dword(fac_flags); }
const sFacSection& content_owner_ids() const { return content_owner_ids_; }
sFacSection& content_owner_ids() { return content_owner_ids_; }
const sFacSection& save_data_owner_ids() const { return save_data_owner_ids_; }
sFacSection& save_data_owner_ids() { return save_data_owner_ids_; }
};
#pragma pack (pop)
// raw binary
fnd::MemoryBlob mBinaryBlob;
// variables
u64 mFsaRights;
struct sSection {
size_t offset;
size_t size;
} mContentOwnerIdPos, mSaveDataOwnerIdPos;
void clearVariables();
void calculateOffsets();
bool isEqual(const FacHeader& other) const;
void copyFrom(const FacHeader& other);
};

111
lib/nx/SacBinary.cpp Normal file
View file

@ -0,0 +1,111 @@
#include "SacBinary.h"
SacBinary::SacBinary()
{
}
SacBinary::SacBinary(const SacBinary & other)
{
copyFrom(other);
}
SacBinary::SacBinary(const u8 * bytes, size_t len)
{
importBinary(bytes, len);
}
bool SacBinary::operator==(const SacBinary & other) const
{
return isEqual(other);
}
bool SacBinary::operator!=(const SacBinary & other) const
{
return !isEqual(other);
}
void SacBinary::operator=(const SacBinary & other)
{
copyFrom(other);
}
const u8 * SacBinary::getBytes() const
{
return mBinaryBlob.getBytes();
}
size_t SacBinary::getSize() const
{
return mBinaryBlob.getSize();
}
void SacBinary::exportBinary()
{
size_t totalSize = 0;
for (size_t i = 0; i < mServices.getSize(); i++)
{
mServices[i].exportBinary();
totalSize += mServices[i].getSize();
}
mBinaryBlob.alloc(totalSize);
for (size_t i = 0, pos = 0; i < mServices.getSize(); pos += mServices[i].getSize(), i++)
{
memcpy((mBinaryBlob.getBytes() + pos), mServices[i].getBytes(), mServices[i].getSize());
}
}
void SacBinary::importBinary(const u8 * bytes)
{
throw fnd::Exception(kModuleName, "Unsupported operation. importBinary(const u8* bytes) is not supported for variable size structures.");
}
void SacBinary::importBinary(const u8 * bytes, size_t len)
{
clearVariables();
mBinaryBlob.alloc(len);
memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize());
SacEntry svc;
for (size_t pos = 0; pos < len; pos += mServices.atBack().getSize())
{
svc.importBinary((const u8*)(mBinaryBlob.getBytes() + pos), len - pos);
mServices.addElement(svc);
}
}
const fnd::List<SacEntry>& SacBinary::getServiceList() const
{
return mServices;
}
void SacBinary::addService(const SacEntry& service)
{
mServices.addElement(service);
}
void SacBinary::clearVariables()
{
mBinaryBlob.clear();
mServices.clear();
}
bool SacBinary::isEqual(const SacBinary & other) const
{
return mServices == other.mServices;
}
void SacBinary::copyFrom(const SacBinary & other)
{
if (other.getSize())
{
importBinary(other.getBytes(), other.getSize());
}
else
{
this->mBinaryBlob.clear();
this->mServices = other.mServices;
}
}

46
lib/nx/SacBinary.h Normal file
View file

@ -0,0 +1,46 @@
#pragma once
#include <string>
#include <vector>
#include <fnd/memory_blob.h>
#include <fnd/List.h>
#include <nx/ISerialiseableBinary.h>
#include <nx/SacEntry.h>
class SacBinary :
public ISerialiseableBinary
{
public:
SacBinary();
SacBinary(const SacBinary& other);
SacBinary(const u8* bytes, size_t len);
bool operator==(const SacBinary& other) const;
bool operator!=(const SacBinary& other) const;
void operator=(const SacBinary& other);
// 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
const fnd::List<SacEntry>& getServiceList() const;
void addService(const SacEntry& service);
private:
const std::string kModuleName = "SAC_BINARY";
// raw binary
fnd::MemoryBlob mBinaryBlob;
// variables
fnd::List<SacEntry> mServices;
void clearVariables();
bool isEqual(const SacBinary& other) const;
void copyFrom(const SacBinary& other);
};

View file

@ -20,14 +20,20 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="AciHeader.h" /> <ClInclude Include="AciHeader.h" />
<ClInclude Include="FacBinary.h" />
<ClInclude Include="FacHeader.h" />
<ClInclude Include="ISerialiseableBinary.h" /> <ClInclude Include="ISerialiseableBinary.h" />
<ClInclude Include="NcaHeader.h" /> <ClInclude Include="NcaHeader.h" />
<ClInclude Include="NXCrypto.h" /> <ClInclude Include="NXCrypto.h" />
<ClInclude Include="SacBinary.h" />
<ClInclude Include="SacEntry.h" /> <ClInclude Include="SacEntry.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="AciHeader.cpp" /> <ClCompile Include="AciHeader.cpp" />
<ClCompile Include="FacBinary.cpp" />
<ClCompile Include="FacHeader.cpp" />
<ClCompile Include="NcaHeader.cpp" /> <ClCompile Include="NcaHeader.cpp" />
<ClCompile Include="SacBinary.cpp" />
<ClCompile Include="SacEntry.cpp" /> <ClCompile Include="SacEntry.cpp" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">

View file

@ -30,6 +30,15 @@
<ClInclude Include="ISerialiseableBinary.h"> <ClInclude Include="ISerialiseableBinary.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FacHeader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FacBinary.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SacBinary.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="NcaHeader.cpp"> <ClCompile Include="NcaHeader.cpp">
@ -41,5 +50,14 @@
<ClCompile Include="SacEntry.cpp"> <ClCompile Include="SacEntry.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FacHeader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FacBinary.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SacBinary.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>