Public V0.0.1

This commit is contained in:
2025-05-04 13:32:07 +02:00
commit 996998785c
30 changed files with 4397 additions and 0 deletions

48
include/ctrff/3dsx.hpp Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <ctrff/helper.hpp>
#include <ctrff/pd_p_api.hpp>
#include <ctrff/smdh.hpp>
#include <pd.hpp>
namespace ctrff {
class CTRFF_API _3dsx : public BinFile {
public:
_3dsx() {}
~_3dsx() {}
void Load(const std::string& path) {
std::fstream f(path, std::ios::in | std::ios::binary);
Read(f);
f.close();
}
bool HasMeta() { return SMDHSize == SMDH_Size; }
/** Write not supported btw */
void Write(std::fstream& f) const override;
void Read(std::fstream& f) override;
PD::u32 Magic;
PD::u16 HeaderSize;
PD::u16 RelocHeaderSize;
PD::u32 FormatVersion;
PD::u32 Flags;
// Sizes of the code, rodata and data segments +
// size of the BSS section (uninitialized latter half of the data segment)
PD::u32 CodeSegSize;
PD::u32 RodataSegSize;
PD::u32 DataSegSize;
PD::u32 BssSize;
/// Extended Header ///
// smdh offset
PD::u32 SMDHOff;
// smdh size
PD::u32 SMDHSize;
// fs offset
PD::u32 FsOff;
SMDH Meta;
};
/** Probably only germen people will understand */
using DreiDSX = _3dsx;
} // namespace ctrff

241
include/ctrff/bcstm.hpp Normal file
View File

@ -0,0 +1,241 @@
#pragma once
#include <ctrff/binutil.hpp>
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
class CTRFF_API BCSTM {
public:
BCSTM() : pReader(pFile) {}
~BCSTM() { CleanUp(); }
void LoadFile(const std::string& path);
void CleanUp();
void ReadGotoBeginning(bool use_loop_beg = false);
void ReadBlock(PD::u32 block, PD::u8* ref);
PD::u32 LeseZeiger() { return pFile.tellg(); }
/** Some useful Getters */
PD::u8 GetNumChannels() const { return pInfoBlock.StreamInfo.ChannelCount; }
PD::u32 GetSampleRate() const { return pInfoBlock.StreamInfo.SampleRate; }
PD::u32 GetBlockSize() const { return pInfoBlock.StreamInfo.SampleBlockSize; }
PD::u32 GetNumBlocks() const { return pInfoBlock.StreamInfo.SampleBlockNum; }
PD::u32 GetBlockSamples() const {
return pInfoBlock.StreamInfo.SampleBlockSampleNum;
}
PD::u32 GetLastBlockSamples() const {
return pInfoBlock.StreamInfo.LastSampleBlockSampleNum;
}
bool IsLooping() const { return pInfoBlock.StreamInfo.Loop; }
PD::u32 GetLoopStart() const {
return pInfoBlock.StreamInfo.LoopStartFrame / GetNumBlocks();
}
PD::u32 GetLoopEnd() const {
/** Get temp references for better readability */
const PD::u32& loop_end = pInfoBlock.StreamInfo.LoopEndFrame;
const PD::u32& block_samples = GetNumBlocks();
return (loop_end % block_samples ? block_samples
: loop_end / block_samples);
}
/** Internal Data (can be made private with private: but public by default) */
enum Endianness : PD::u16 {
Big = 0xfffe, ///< Big Endian
Little = 0xfeff, ///< Little Endian
};
enum ReferenceTypes : PD::u16 {
Ref_ByteTable = 0x0100,
Ref_ReferenceTable = 0x0101,
Ref_DSP_ADPCM_Info = 0x0300,
Ref_IMA_ADPCM_Info = 0x0301,
Ref_SampleData = 0x1f00,
Ref_InfoBlock = 0x4000,
Ref_SeekBlock = 0x4001,
Ref_DataBlock = 0x4002,
Ref_StreamInfo = 0x4100,
Ref_TrackInfo = 0x4101,
Ref_ChannelInfo = 0x4102,
};
enum Encoding : PD::u8 {
PCM8 = 0,
PCM16 = 1,
/** Only supported encoding in BCSTM-Player */
DSP_ADPCM = 2,
IMA_ADPCM = 3,
};
struct Reference {
PD::u16 TypeID;
PD::u16 Padding;
PD::u32 Offset; /** null -> uint32_max */
};
struct ReferenceTable {
PD::u32 Count;
PD::Vec<Reference> Refs;
};
struct SizedReference {
Reference Ref;
PD::u32 Size;
};
struct StreamInfo {
PD::u8 Encoding;
PD::u8 Loop;
PD::u8 ChannelCount;
PD::u8 Padding;
PD::u32 SampleRate;
PD::u32 LoopStartFrame;
PD::u32 LoopEndFrame;
PD::u32 SampleBlockNum;
PD::u32 SampleBlockSize;
PD::u32 SampleBlockSampleNum;
PD::u32 LastSampleBlockSize;
PD::u32 LastSampleBlockSampleNum;
PD::u32 LastSampleBlockPaddedSize;
PD::u32 SeekDataSize;
PD::u32 SeekIntervalSampleNum;
Reference SampleDataRef;
};
struct BlockHeader {
PD::u32 Magic;
PD::u32 Size;
};
struct InfoBlock {
BlockHeader Header;
Reference StreamInfoRef;
Reference TrackInfoTabRef;
Reference ChannelInfoTabRef;
BCSTM::StreamInfo StreamInfo;
ReferenceTable TrackInfoTab;
ReferenceTable ChannelInfoTab;
PD::Vec<Reference> ChannelInfoRefs; /** The refs of the refs ?? */
};
/** SeekDataBlock cause they are the same struct */
struct SD_Block {
BlockHeader Header;
PD::Vec<PD::u8> Data;
};
struct DSP_ADPCM_Param {
PD::u16 Coefficients[0x10];
};
struct DSP_ADPCM_Context {
PD::u8 PredictorScale;
PD::u8 Reserved;
PD::u16 PreviousSample;
PD::u16 SecondPreviousSample;
};
struct DSP_ADPCM_Info {
DSP_ADPCM_Param Param;
DSP_ADPCM_Context Context;
DSP_ADPCM_Context LoopContext;
PD::u16 Padding;
};
struct ByteTable {
PD::u32 Size;
PD::Vec<PD::u8> Table;
};
struct TrackInfo {
PD::u8 Volume;
PD::u8 Pan;
PD::u16 Padding;
Reference ChennelIndexTabRef;
ByteTable ChannelIndexTab;
};
struct Header {
PD::u32 Magic; /** CSTM */
PD::u16 Endianness = Little; /** Default */
PD::u16 HeaderSize; /** Header Size probably */
PD::u32 Version; /** Format Version? */
PD::u32 FileSize; /** File Size */
PD::u16 NumBlocks; /** Number of blocks */
PD::u16 Reserved; /** Reserved */
};
Header pHeader;
SizedReference pInfoBlockRef;
SizedReference pSeekBlockRef;
SizedReference pDataBlockRef;
InfoBlock pInfoBlock;
SD_Block pSeekBlock;
SD_Block pDataBlock;
PD::Vec<DSP_ADPCM_Info> pDSP_ADPCM_Info;
/** File Stream */
std::fstream pFile;
/** Endianness based reader */
BinUtil pReader;
void ReadReference(Reference& ref);
void ReadSizedReference(SizedReference& ref);
void ReadInfoBlock(InfoBlock& block);
void ReadSeekBlock(SD_Block& block);
void ReadReferenceTab(ReferenceTable& tab);
static std::string Endianness2String(const Endianness& e) {
switch (e) {
case Little:
return "Little";
case Big:
return "Big";
default:
return "Unknown";
}
}
static std::string ReferenceType2String(const ReferenceTypes& e) {
switch (e) {
case Ref_ByteTable:
return "ByteTable";
case Ref_ReferenceTable:
return "ReferenceTable";
case Ref_DSP_ADPCM_Info:
return "DSP_ADPCM_Info";
case Ref_IMA_ADPCM_Info:
return "IMA_ADPCM_Info";
case Ref_SampleData:
return "SampleData";
case Ref_InfoBlock:
return "InfoBlock";
case Ref_SeekBlock:
return "SeekBlock";
case Ref_DataBlock:
return "DataBlock";
case Ref_StreamInfo:
return "StreamInfo";
case Ref_TrackInfo:
return "TrackInfo";
case Ref_ChannelInfo:
return "ChannelInfo";
default:
return "Unknown";
}
}
static std::string Encoding2String(const Encoding& e) {
switch (e) {
case PCM8:
return "PCM8";
case PCM16:
return "PCM16";
case DSP_ADPCM:
return "DSP ADPCM";
case IMA_ADPCM:
return "IMA ADPCM";
default:
return "Unknown";
}
}
};
} // namespace ctrff

188
include/ctrff/bcwav.hpp Normal file
View File

@ -0,0 +1,188 @@
#pragma once
#include <ctrff/binutil.hpp>
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
class CTRFF_API BCWAV {
public:
BCWAV() : pReader(pFile) {}
~BCWAV() { CleanUp(); }
void LoadFile(const std::string& path);
void CleanUp();
void ReadGotoBeginning(bool use_loop_beg = false);
void ReadBlock(PD::u32 block, PD::u8* ref);
/** Internal Data (can be made private with private: but public by default) */
enum Endianness : PD::u16 {
Big = 0xfffe, ///< Big Endian
Little = 0xfeff, ///< Little Endian
};
enum ReferenceTypes : PD::u16 {
Ref_DSP_ADPCM_Info = 0x0300,
Ref_IMA_ADPCM_Info = 0x0301,
Ref_SampleData = 0x1f00,
Ref_InfoBlock = 0x7000,
Ref_DataBlock = 0x7001,
Ref_ChannelInfo = 0x7100,
};
enum Encoding : PD::u8 {
PCM8 = 0,
PCM16 = 1,
/** Only supported encoding in BCSTM-Player */
DSP_ADPCM = 2,
IMA_ADPCM = 3,
};
struct Reference {
PD::u16 TypeID;
PD::u16 Padding;
PD::u32 Offset; /** null -> uint32_max */
};
struct ReferenceTable {
PD::u32 Count;
PD::Vec<Reference> Refs;
};
struct SizedReference {
Reference Ref;
PD::u32 Size;
};
struct StreamInfo {
PD::u8 Encoding;
PD::u8 Loop;
PD::u8 ChannelCount;
PD::u8 Padding;
PD::u32 SampleRate;
PD::u32 LoopStartFrame;
PD::u32 LoopEndFrame;
PD::u32 SampleBlockNum;
PD::u32 SampleBlockSize;
PD::u32 SampleBlockSampleNum;
PD::u32 LastSampleBlockSize;
PD::u32 LastSampleBlockSampleNum;
PD::u32 LastSampleBlockPaddedSize;
PD::u32 SeekDataSize;
PD::u32 SeekIntervalSampleNum;
Reference SampleDataRef;
};
struct BlockHeader {
PD::u32 Magic;
PD::u32 Size;
};
struct InfoBlock {
BlockHeader Header;
PD::u8 Encoding;
PD::u8 Loop;
PD::u16 Padding;
PD::u32 SampleRate;
PD::u32 LoopStartFrame;
PD::u32 LoopEndFrame;
PD::u32 Reserved;
ReferenceTable ChannelInfoTab;
PD::Vec<Reference> ChannelInfoRefs; /** The refs of the refs ?? */
};
struct DataBlock {
BlockHeader Header;
PD::u32 Padding[3];
PD::Vec<PD::u8> Data;
};
struct DSP_ADPCM_Param {
PD::u16 Coefficients[0x10];
};
struct DSP_ADPCM_Context {
PD::u8 PredictorScale;
PD::u8 Reserved;
PD::u16 PreviousSample;
PD::u16 SecondPreviousSample;
};
struct DSP_ADPCM_Info {
DSP_ADPCM_Param Param;
DSP_ADPCM_Context Context;
DSP_ADPCM_Context LoopContext;
PD::u16 Padding;
};
struct Header {
PD::u32 Magic; /** CWAV */
PD::u16 Endianness = Little; /** Default */
PD::u16 HeaderSize; /** Header Size probably */
PD::u32 Version; /** Format Version? */
PD::u32 FileSize; /** File Size */
PD::u16 NumBlocks; /** Number of blocks */
PD::u16 Reserved; /** Reserved */
};
Header pHeader;
SizedReference pInfoBlockRef;
SizedReference pDataBlockRef;
InfoBlock pInfoBlock;
DataBlock pDataBlock;
PD::Vec<DSP_ADPCM_Info> pDSP_ADPCM_Info;
/** File Stream */
std::fstream pFile;
/** Endianness based reader */
BinUtil pReader;
void ReadReference(Reference& ref);
void ReadSizedReference(SizedReference& ref);
void ReadInfoBlock(InfoBlock& block);
void ReadReferenceTab(ReferenceTable& tab);
static std::string Endianness2String(const Endianness& e) {
switch (e) {
case Little:
return "Little";
case Big:
return "Big";
default:
return "Unknown";
}
}
static std::string ReferenceType2String(const ReferenceTypes& e) {
switch (e) {
case Ref_DSP_ADPCM_Info:
return "DSP_ADPCM_Info";
case Ref_IMA_ADPCM_Info:
return "IMA_ADPCM_Info";
case Ref_SampleData:
return "SampleData";
case Ref_InfoBlock:
return "InfoBlock";
case Ref_DataBlock:
return "DataBlock";
case Ref_ChannelInfo:
return "ChannelInfo";
default:
return "Unknown";
}
}
static std::string Encoding2String(const Encoding& e) {
switch (e) {
case PCM8:
return "PCM8";
case PCM16:
return "PCM16";
case DSP_ADPCM:
return "DSP ADPCM";
case IMA_ADPCM:
return "IMA ADPCM";
default:
return "Unknown";
}
}
};
} // namespace ctrff

43
include/ctrff/binutil.hpp Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
class BinFile {
public:
BinFile() = default;
~BinFile() = default;
virtual void Write(std::fstream& s) const = 0;
virtual void Read(std::fstream& s) = 0;
};
class CTRFF_API BinUtil {
public:
BinUtil(std::fstream& f, bool big = false) : m_file(f), m_big(big) {}
~BinUtil() = default;
void SetEndianess(bool big) { m_big = big; }
template <typename T>
void Read(T& v);
template <typename T>
void Write(const T& v);
/** Note that this func ignores Endianness */
template <typename T>
void ReadEx(T& v) {
static_assert(std::is_trivially_copyable_v<T>, "Cannot Read type T");
m_file.read(reinterpret_cast<char*>(&v), sizeof(T));
}
/** Note that this func ignores Endianness */
template <typename T>
void WriteEx(T& v) {
m_file.write(reinterpret_cast<const char*>(&v), sizeof(T));
}
private:
std::fstream& m_file;
bool m_big;
};
} // namespace ctrff

16
include/ctrff/helper.hpp Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
CTRFF_API void String2U16(PD::u16 *res, const std::string &src, size_t max);
CTRFF_API std::string U16toU8(PD::u16 *in, size_t max);
CTRFF_API void RGB565toRGBA(std::vector<PD::u8> &img, PD::u16 *icon,
const int &w, const int &h);
// Image can only be rgba8888
CTRFF_API void RGBA2RGB565(PD::u16 *out, const std::vector<PD::u8> &img,
const int &w, const int &h);
CTRFF_API std::vector<PD::u8> DownscaleImage(const std::vector<PD::u8> &img,
int w, int h, int scale);
} // namespace ctrff

10
include/ctrff/lz11.hpp Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
namespace LZ11 {
CTRFF_API std::vector<PD::u8> Compress(const std::vector<PD::u8>& in);
}
} // namespace ctrff

View File

@ -0,0 +1,50 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2025 tobid7
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifdef _WIN32 // Windows (MSVC Tested)
#ifdef CTRFF_BUILD_SHARED
#define CTRFF_API __declspec(dllexport)
#else
#define CTRFF_API __declspec(dllimport)
#endif
#elif defined(__APPLE__) // macOS (untested yet)
#ifdef CTRFF_BUILD_SHARED
#define CTRFF_API __attribute__((visibility("default")))
#else
#define CTRFF_API
#endif
#elif defined(__linux__) // Linux (untested yet)
#ifdef CTRFF_BUILD_SHARED
#define CTRFF_API __attribute__((visibility("default")))
#else
#define CTRFF_API
#endif
#elif defined(__3DS__) // 3ds Specific
// Only Static supported
#define CTRFF_API
#else
#define CTRFF_API
#endif

143
include/ctrff/smdh.hpp Normal file
View File

@ -0,0 +1,143 @@
#pragma once
#include <ctrff/binutil.hpp>
#include <ctrff/helper.hpp>
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
// Basic Info
// language_slots: 16
// valid_language_slots: 12
// rating_slots: 16
// small_icon: 24
// large_icon = 48
namespace ctrff {
// SMDH Size (Note that this needs to be declared here as
// a sizeof(SMDH) will not return the expected size due to
// use of Serializable)
constexpr PD::u32 SMDH_Size = 0x36C0;
struct CTRFF_API SMDH {
SMDH() {
std::fill_n(Magic, PD::ArraySize(Magic), 0);
std::fill_n(IconSmall, PD::ArraySize(IconSmall), 0);
std::fill_n(IconLarge, PD::ArraySize(IconLarge), 0);
}
~SMDH() = default;
static SMDH Default();
PD_SMART_CTOR(SMDH);
enum Language {
Language_Japanese,
Language_English,
Language_French,
Language_German,
Language_Italian,
Language_Spanish,
Language_Chinese_Simplified,
Language_Korean,
Language_Dutch,
Language_Portuguese,
Language_Russian,
Language_Chinese_Traditional,
// To Overrite Aall Languages
// returns japanese on get funcs
Language_All = 0x47,
};
enum Rating {
Rating_CERO = 0,
Rating_ESRB = 1,
Rating_USK = 3,
Rating_PEGI_GEN = 4,
Rating_PEGI_PTR = 6,
Rating_PEGI_BBFC = 7,
Rating_COB = 8,
Rating_GRB = 9,
Rating_CGSRR = 10,
};
enum Region {
Region_JAPAN = 1 << 0,
Region_NORTH_AMERICA = 1 << 1,
Region_EUROPE = 1 << 2,
Region_AUSTRALIA = 1 << 3,
Region_CHINA = 1 << 4,
Region_KOREA = 1 << 5,
Region_TAIWAN = 1 << 6,
// Not a bitmask, but a value.
Region_FREE = 0x7FFFFFFF,
};
enum Flag {
Flag_VISIBLE = 1 << 0,
Flag_AUTO_BOOT = 1 << 1,
Flag_ALLOW_3D = 1 << 2,
Flag_REQUIRE_EULA = 1 << 3,
Flag_AUTO_SAVE_ON_EXIT = 1 << 4,
Flag_USE_EXTENDED_BANNER = 1 << 5,
Flag_RATING_REQUIED = 1 << 6,
Flag_USE_SAVE_DATA = 1 << 7,
Flag_RECORD_USAGE = 1 << 8,
Flag_DISABLE_SAVE_BACKUPS = 1 << 10,
Flag_NEW_3DS = 1 << 12,
Flag_DEFAULT = Flag_VISIBLE | Flag_ALLOW_3D | Flag_RECORD_USAGE,
};
void Load(const std::string &path) {
std::fstream f(path, std::ios::in | std::ios::binary);
Read(f);
f.close();
}
void Save(const std::string &path) {
std::fstream f(path, std::ios::out | std::ios::binary);
Write(f);
f.close();
}
void Write(std::fstream &f) const;
void Read(std::fstream &f);
void SetIcon(const std::vector<PD::u8> &buf);
std::vector<PD::u8> GetIcon();
void SetShortTitle(const std::string &t, Language l = Language_All);
void SetLongTitle(const std::string &t, Language l = Language_All);
void SetAuthor(const std::string &t, Language l = Language_All);
std::string GetShortTitle(Language l = Language_All);
std::string GetLongTitle(Language l = Language_All);
std::string GetAuthor(Language l = Language_All);
struct CTRFF_API Title {
Title() {
std::fill_n(ShortTitle, PD::ArraySize(ShortTitle), 0);
std::fill_n(LongTitle, PD::ArraySize(LongTitle), 0);
std::fill_n(Author, PD::ArraySize(Author), 0);
};
PD::u16 ShortTitle[0x40];
PD::u16 LongTitle[0x80];
PD::u16 Author[0x40];
};
struct CTRFF_API Settings {
Settings() { std::fill_n(Ratings, PD::ArraySize(Ratings), 0); };
PD::u8 Ratings[16];
PD::u32 RegionLock = 0;
PD::u32 MatchmakerID = 0;
PD::u64 MatchmakerBitID = 0;
PD::u32 Flags = 0;
PD::u16 EulaVersion = 0;
PD::u16 Reserved = 0;
PD::u32 OptimalBannerFrame = 0;
PD::u32 StreetpassID = 0;
};
char Magic[4];
PD::u16 Version = 0;
PD::u16 Reserved = 0;
Title Titles[16];
Settings Settings;
PD::u64 Reserved1 = 0;
PD::u16 IconSmall[0x240]; // 24x24
PD::u16 IconLarge[0x900]; // 48x48
};
} // namespace ctrff