3 Commits
main ... indev

Author SHA1 Message Date
0ab0929746 started some work on cia/ncch 2025-11-28 17:49:05 +01:00
8c1a48a527 updated to newer palladium 2025-11-28 17:48:54 +01:00
6242a7565e fixes 2025-11-28 17:48:27 +01:00
24 changed files with 427 additions and 425 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "vendor/cli-fancy"]
path = vendor/cli-fancy
url = https://dev.npid7.de/tobid7/cli-fancy
[submodule "vendor/palladium"]
path = vendor/palladium
url = https://dev.npid7.de/tobid7/palladium.git

View File

@@ -19,6 +19,7 @@ if(${CTRFF_3DS})
endif()
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-psabi -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -fno-rtti")
endif()
add_library(ctrff STATIC
@@ -31,6 +32,7 @@ add_library(ctrff STATIC
source/3dsx.cpp
)
target_include_directories(ctrff PUBLIC include)
target_include_directories(ctrff PRIVATE vendor/palladium/include)
if(${CTRFF_DESKTOP})
add_executable(ctrff-cli tool/main.cpp)

View File

@@ -35,7 +35,7 @@ Not all Planned formates are listed here yet
| Format | State | Notes |
| ------ | ----- | ----- |
| 3dsx | Basic Loading and Viewing of Meta Data Smdh | |
| bcstm | Loading of almost every Data | Fully done and playable by BCSTM-Player |
| bcstm | Loading of almost every Data | Not capable of playing them yet (prefetch kernel panic) |
| bcwav | Basic Loading (not tested yet) | Not finished yet |
| bclim | Nothing done yet (Started creating header) | |
| lz11 | Encoder done, Decoder missing | Files are bit diffrent to the ones bannertool generates (don't know why) |

View File

@@ -162,13 +162,12 @@ using u16 = unsigned short; // or uint16_t
using u8 = unsigned char; // or uint8_t
```
## Tools / Devices / File Sources used for research
## Tools / Devices / File SOurces used for research
| Name | Description |
|---|---|
| Visual Studio Code | Used for creating ctrff c++ code for bcstm |
| ImHex | Used to Analyze the Hex Code of the bcstm Files |
| LoopingAudioConverter | Used to create some files for testing |
| Citra | Fast way to generate Log files when developing ctrff |
| ctrff-cli | Tool to generate Debug Output on Desktop OS like seen in BCSTM-Player File inspector |
| New 3ds XL | Testing on Real Hardware (BCSTM-Player) |
@@ -176,4 +175,4 @@ using u8 = unsigned char; // or uint8_t
| CTGP 7 | Used to get Test files |
| Super Mario Maker 3ds (Cartridge) | Used to get Test files |
| Mario and Luigi Bowsers inside story (Cartridge) | Used to get Test files |
| Donkey Kong Country Returns 3D (Cardridge) | Used to get Test files |
| Donkey Kong Country Returns 3D | Used to get Test files |

View File

@@ -13,7 +13,8 @@
- 2.3 [Reference Types](#reference-types)
- 3 [Block Header](#block-header)
- 4 [Info Block](#info-block)
- 4.1 [Channel Info](#channel-info)
- 4.1 [Stream Info](#stream-info)
- 4.2 [Channel Info](#channel-info)
- 5 [DSP ADPCM Info](#dsp-adpcm-info)
- 5.1 [DSP ADPCM Param](#dsp-adpcm-param)
- 5.2 [DSP ADPCM Context](#dsp-adpcm-context)
@@ -90,6 +91,27 @@ All Reference Offsets at the beginning of Info Block are Relative to the **Infob
| 0x18 | 4 | [u32](#u32) | Reserved |
| 0x18 | 8 | [Reference Table](#reference-table) | Channel Info Reference Table |
### Stream Info
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 1 | [u8](#u8) | Encoding |
| 0x01 | 1 | [u8](#u8) | Loop `1 == true -- 0 == false` |
| 0x02 | 1 | [u8](#u8) | Num Channels |
| 0x03 | 1 | [u8](#u8) | Padding |
| 0x04 | 4 | [u32](#u32) | Sample Rate |
| 0x04 | 4 | [u32](#u32) | Loop Start |
| 0x04 | 4 | [u32](#u32) | Loop End |
| 0x04 | 4 | [u32](#u32) | Sample Blocks |
| 0x04 | 4 | [u32](#u32) | Sample Block Size |
| 0x04 | 4 | [u32](#u32) | Sample Block Samples |
| 0x04 | 4 | [u32](#u32) | Last Sample Block Size |
| 0x04 | 4 | [u32](#u32) | Last Sample Block Samples |
| 0x04 | 4 | [u32](#u32) | Last Sample Block Padded Size |
| 0x04 | 4 | [u32](#u32) | Seek Data Size |
| 0x04 | 4 | [u32](#u32) | Seek Interval Samples |
| 0x04 | 4 | [Reference](#reference) | Sample Data Reference |
### Channel Info
| Offset | Size | Datatype | Description |
@@ -140,18 +162,17 @@ using u16 = unsigned short; // or uint16_t
using u8 = unsigned char; // or uint8_t
```
## Tools / Devices / File Sources used for research
## Tools / Devices / File SOurces used for research
| Name | Description |
|---|---|
| Visual Studio Code | Used for creating ctrff c++ code for bcstm |
| ImHex | Used to Analyze the Hex Code of the bcstm Files |
| Citra | Fast way to generate Log files when developing ctrff |
| LoopingAudioConverter | Used to create some files for testing |
| ctrff-cli | Tool to generate Debug Output on Desktop OS like seen in BCSTM-Player File inspector |
| New 3ds XL | Testing on Real Hardware (BCSTM-Player) |
| Mario Kart 7 (Cartridge) | Used to get Test files |
| CTGP 7 | Used to get Test files |
| Super Mario Maker 3ds (Cartridge) | Used to get Test files |
| Mario and Luigi Bowsers inside story (Cartridge) | Used to get Test files |
| Donkey Kong Country Returns 3D (Cardridge) | Used to get Test files |
| Donkey Kong Country Returns 3D | Used to get Test files |

View File

@@ -1,8 +1,9 @@
#pragma once
#include <ctrff/helper.hpp>
#include <ctrff/pd_p_api.hpp>
#include <ctrff/smdh.hpp>
#include <ctrff/types.hpp>
#include <pd.hpp>
namespace ctrff {
class CTRFF_API _3dsx : public BinFile {
@@ -22,24 +23,24 @@ class CTRFF_API _3dsx : public BinFile {
void Write(std::fstream& f) const override;
void Read(std::fstream& f) override;
ctrff::u32 Magic;
ctrff::u16 HeaderSize;
ctrff::u16 RelocHeaderSize;
ctrff::u32 FormatVersion;
ctrff::u32 Flags;
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)
ctrff::u32 CodeSegSize;
ctrff::u32 RodataSegSize;
ctrff::u32 DataSegSize;
ctrff::u32 BssSize;
PD::u32 CodeSegSize;
PD::u32 RodataSegSize;
PD::u32 DataSegSize;
PD::u32 BssSize;
/// Extended Header ///
// smdh offset
ctrff::u32 SMDHOff;
PD::u32 SMDHOff;
// smdh size
ctrff::u32 SMDHSize;
PD::u32 SMDHSize;
// fs offset
ctrff::u32 FsOff;
PD::u32 FsOff;
SMDH Meta;
};
/** Probably only germen people will understand */

View File

@@ -1,7 +1,8 @@
#pragma once
#include <ctrff/binutil.hpp>
#include <ctrff/types.hpp>
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
class CTRFF_API BCSTM {
@@ -12,44 +13,39 @@ class CTRFF_API BCSTM {
void LoadFile(const std::string& path);
void CleanUp();
void ReadGotoBeginning(bool use_loop_beg = false);
void ReadBlock(ctrff::u32 block, ctrff::u8* ref);
void ReadBlock(PD::u32 block, PD::u8* ref);
PD::u32 LeseZeiger() { return pFile.tellg(); }
/** Some useful Getters */
ctrff::u8 GetNumChannels() const {
return pInfoBlock.StreamInfo.ChannelCount;
}
ctrff::u32 GetSampleRate() const { return pInfoBlock.StreamInfo.SampleRate; }
ctrff::u32 GetBlockSize() const {
return pInfoBlock.StreamInfo.SampleBlockSize;
}
ctrff::u32 GetNumBlocks() const {
return pInfoBlock.StreamInfo.SampleBlockNum;
}
ctrff::u32 GetBlockSamples() const {
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;
}
ctrff::u32 GetLastBlockSamples() const {
PD::u32 GetLastBlockSamples() const {
return pInfoBlock.StreamInfo.LastSampleBlockSampleNum;
}
bool IsLooping() const { return pInfoBlock.StreamInfo.Loop; }
ctrff::u32 GetLoopStart() const {
return pInfoBlock.StreamInfo.LoopStartFrame / GetBlockSamples();
PD::u32 GetLoopStart() const {
return pInfoBlock.StreamInfo.LoopStartFrame / GetNumBlocks();
}
ctrff::u32 GetLoopEnd() const {
PD::u32 GetLoopEnd() const {
/** Get temp references for better readability */
const ctrff::u32& loop_end = pInfoBlock.StreamInfo.LoopEndFrame;
const ctrff::u32& block_samples = GetBlockSamples();
return (loop_end % block_samples ? GetNumBlocks()
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 : ctrff::u16 {
enum Endianness : PD::u16 {
Big = 0xfffe, ///< Big Endian
Little = 0xfeff, ///< Little Endian
};
enum ReferenceTypes : ctrff::u16 {
enum ReferenceTypes : PD::u16 {
Ref_ByteTable = 0x0100,
Ref_ReferenceTable = 0x0101,
Ref_DSP_ADPCM_Info = 0x0300,
@@ -63,7 +59,7 @@ class CTRFF_API BCSTM {
Ref_ChannelInfo = 0x4102,
};
enum Encoding : ctrff::u8 {
enum Encoding : PD::u8 {
PCM8 = 0,
PCM16 = 1,
/** Only supported encoding in BCSTM-Player */
@@ -72,55 +68,46 @@ class CTRFF_API BCSTM {
};
struct Reference {
Reference() : TypeID(0), Padding(0), Offset(0) {}
Reference(ctrff::u16 t, ctrff::u16 p, ctrff::u32 o)
: TypeID(t), Padding(p), Offset(o) {}
ctrff::u16 TypeID;
ctrff::u16 Padding;
ctrff::u32 Offset; /** null -> uint32_max */
PD::u16 TypeID;
PD::u16 Padding;
PD::u32 Offset; /** null -> uint32_max */
};
struct ReferenceTable {
ReferenceTable() : Count(0) {}
ctrff::u32 Count;
std::vector<Reference> Refs;
PD::u32 Count;
PD::Vec<Reference> Refs;
};
struct SizedReference {
SizedReference() : Size(0) {}
Reference Ref;
ctrff::u32 Size;
PD::u32 Size;
};
struct StreamInfo {
StreamInfo();
ctrff::u8 Encoding;
ctrff::u8 Loop;
ctrff::u8 ChannelCount;
ctrff::u8 Padding;
ctrff::u32 SampleRate;
ctrff::u32 LoopStartFrame;
ctrff::u32 LoopEndFrame;
ctrff::u32 SampleBlockNum;
ctrff::u32 SampleBlockSize;
ctrff::u32 SampleBlockSampleNum;
ctrff::u32 LastSampleBlockSize;
ctrff::u32 LastSampleBlockSampleNum;
ctrff::u32 LastSampleBlockPaddedSize;
ctrff::u32 SeekDataSize;
ctrff::u32 SeekIntervalSampleNum;
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 {
BlockHeader() : Magic(0), Size(0) {}
BlockHeader(ctrff::u32 m, ctrff::u32 s) : Magic(m), Size(s) {}
ctrff::u32 Magic;
ctrff::u32 Size;
PD::u32 Magic;
PD::u32 Size;
};
struct InfoBlock {
InfoBlock() = default;
BlockHeader Header;
Reference StreamInfoRef;
Reference TrackInfoTabRef;
@@ -128,74 +115,53 @@ class CTRFF_API BCSTM {
BCSTM::StreamInfo StreamInfo;
ReferenceTable TrackInfoTab;
ReferenceTable ChannelInfoTab;
std::vector<Reference> ChannelInfoRefs; /** The refs of the refs ?? */
PD::Vec<Reference> ChannelInfoRefs; /** The refs of the refs ?? */
};
/** SeekDataBlock cause they are the same struct */
struct SD_Block {
SD_Block() {}
BlockHeader Header;
std::vector<ctrff::u8> Data;
PD::Vec<PD::u8> Data;
};
struct DSP_ADPCM_Param {
// Lets keep this not clean here :/
DSP_ADPCM_Param() {}
ctrff::u16 Coefficients[0x10];
PD::u16 Coefficients[0x10];
};
struct DSP_ADPCM_Context {
DSP_ADPCM_Context()
: PredictorScale(0),
Reserved(0),
PreviousSample(0),
SecondPreviousSample(0) {}
ctrff::u8 PredictorScale;
ctrff::u8 Reserved;
ctrff::u16 PreviousSample;
ctrff::u16 SecondPreviousSample;
PD::u8 PredictorScale;
PD::u8 Reserved;
PD::u16 PreviousSample;
PD::u16 SecondPreviousSample;
};
struct DSP_ADPCM_Info {
DSP_ADPCM_Info() : Padding(0) {}
DSP_ADPCM_Param Param;
DSP_ADPCM_Context Context;
DSP_ADPCM_Context LoopContext;
ctrff::u16 Padding;
PD::u16 Padding;
};
struct ByteTable {
ByteTable(ctrff::u32 size = 0) : Size(size) {}
ctrff::u32 Size;
std::vector<ctrff::u8> Table;
PD::u32 Size;
PD::Vec<PD::u8> Table;
};
struct TrackInfo {
TrackInfo() : Volume(0), Pan(0), Padding(0) {}
ctrff::u8 Volume;
ctrff::u8 Pan;
ctrff::u16 Padding;
PD::u8 Volume;
PD::u8 Pan;
PD::u16 Padding;
Reference ChennelIndexTabRef;
ByteTable ChannelIndexTab;
};
struct Header {
// Warum sieht dass so ~~nicht~~ gut aus...
Header()
: Magic(0),
Endianness(Little),
HeaderSize(0),
Version(0),
FileSize(0),
NumBlocks(0),
Reserved(0) {}
ctrff::u32 Magic; /** CSTM */
ctrff::u16 Endianness = Little; /** Default */
ctrff::u16 HeaderSize; /** Header Size probably */
ctrff::u32 Version; /** Format Version? */
ctrff::u32 FileSize; /** File Size */
ctrff::u16 NumBlocks; /** Number of blocks */
ctrff::u16 Reserved; /** Reserved */
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;
@@ -205,7 +171,7 @@ class CTRFF_API BCSTM {
InfoBlock pInfoBlock;
SD_Block pSeekBlock;
SD_Block pDataBlock;
std::vector<DSP_ADPCM_Info> pDSP_ADPCM_Info;
PD::Vec<DSP_ADPCM_Info> pDSP_ADPCM_Info;
/** File Stream */
std::fstream pFile;
/** Endianness based reader */

View File

@@ -1,7 +1,8 @@
#pragma once
#include <ctrff/binutil.hpp>
#include <ctrff/types.hpp>
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
class CTRFF_API BCWAV {
@@ -12,15 +13,15 @@ class CTRFF_API BCWAV {
void LoadFile(const std::string& path);
void CleanUp();
void ReadGotoBeginning(bool use_loop_beg = false);
void ReadBlock(ctrff::u32 block, ctrff::u8* ref);
void ReadBlock(PD::u32 block, PD::u8* ref);
/** Internal Data (can be made private with private: but public by default) */
enum Endianness : ctrff::u16 {
enum Endianness : PD::u16 {
Big = 0xfffe, ///< Big Endian
Little = 0xfeff, ///< Little Endian
};
enum ReferenceTypes : ctrff::u16 {
enum ReferenceTypes : PD::u16 {
Ref_DSP_ADPCM_Info = 0x0300,
Ref_IMA_ADPCM_Info = 0x0301,
Ref_SampleData = 0x1f00,
@@ -29,7 +30,7 @@ class CTRFF_API BCWAV {
Ref_ChannelInfo = 0x7100,
};
enum Encoding : ctrff::u8 {
enum Encoding : PD::u8 {
PCM8 = 0,
PCM16 = 1,
/** Only supported encoding in BCSTM-Player */
@@ -38,101 +39,89 @@ class CTRFF_API BCWAV {
};
struct Reference {
Reference() : TypeID(0), Padding(0), Offset(0) {}
ctrff::u16 TypeID;
ctrff::u16 Padding;
ctrff::u32 Offset; /** null -> uint32_max */
PD::u16 TypeID;
PD::u16 Padding;
PD::u32 Offset; /** null -> uint32_max */
};
struct ReferenceTable {
ReferenceTable() : Count(0) {}
ctrff::u32 Count;
std::vector<Reference> Refs;
PD::u32 Count;
PD::Vec<Reference> Refs;
};
struct SizedReference {
SizedReference() : Size(0) {}
Reference Ref;
ctrff::u32 Size;
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 {
BlockHeader() : Magic(0), Size(0) {}
ctrff::u32 Magic;
ctrff::u32 Size;
PD::u32 Magic;
PD::u32 Size;
};
struct InfoBlock {
InfoBlock()
: Encoding(0),
Loop(0),
Padding(0),
SampleRate(0),
LoopStartFrame(0),
LoopEndFrame(0),
Reserved(0) {}
BlockHeader Header;
ctrff::u8 Encoding;
ctrff::u8 Loop;
ctrff::u16 Padding;
ctrff::u32 SampleRate;
ctrff::u32 LoopStartFrame;
ctrff::u32 LoopEndFrame;
ctrff::u32 Reserved;
PD::u8 Encoding;
PD::u8 Loop;
PD::u16 Padding;
PD::u32 SampleRate;
PD::u32 LoopStartFrame;
PD::u32 LoopEndFrame;
PD::u32 Reserved;
ReferenceTable ChannelInfoTab;
std::vector<Reference> ChannelInfoRefs; /** The refs of the refs ?? */
PD::Vec<Reference> ChannelInfoRefs; /** The refs of the refs ?? */
};
struct DataBlock {
DataBlock() {
for (int i = 0; i < 3; i++) {
Padding[i] = 0;
}
}
BlockHeader Header;
ctrff::u32 Padding[3];
std::vector<ctrff::u8> Data;
PD::u32 Padding[3];
PD::Vec<PD::u8> Data;
};
struct DSP_ADPCM_Param {
ctrff::u16 Coefficients[0x10];
PD::u16 Coefficients[0x10];
};
struct DSP_ADPCM_Context {
DSP_ADPCM_Context()
: PredictorScale(0),
Reserved(0),
PreviousSample(0),
SecondPreviousSample(0) {}
ctrff::u8 PredictorScale;
ctrff::u8 Reserved;
ctrff::u16 PreviousSample;
ctrff::u16 SecondPreviousSample;
PD::u8 PredictorScale;
PD::u8 Reserved;
PD::u16 PreviousSample;
PD::u16 SecondPreviousSample;
};
struct DSP_ADPCM_Info {
DSP_ADPCM_Info() : Padding(0) {}
DSP_ADPCM_Param Param;
DSP_ADPCM_Context Context;
DSP_ADPCM_Context LoopContext;
ctrff::u16 Padding;
PD::u16 Padding;
};
struct Header {
Header()
: Magic(0),
Endianness(Little),
HeaderSize(0),
Version(0),
FileSize(0),
NumBlocks(0),
Reserved(0) {}
ctrff::u32 Magic; /** CWAV */
ctrff::u16 Endianness = Little; /** Default */
ctrff::u16 HeaderSize; /** Header Size probably */
ctrff::u32 Version; /** Format Version? */
ctrff::u32 FileSize; /** File Size */
ctrff::u16 NumBlocks; /** Number of blocks */
ctrff::u16 Reserved; /** Reserved */
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;
@@ -140,7 +129,7 @@ class CTRFF_API BCWAV {
SizedReference pDataBlockRef;
InfoBlock pInfoBlock;
DataBlock pDataBlock;
std::vector<DSP_ADPCM_Info> pDSP_ADPCM_Info;
PD::Vec<DSP_ADPCM_Info> pDSP_ADPCM_Info;
/** File Stream */
std::fstream pFile;
/** Endianness based reader */

View File

@@ -1,6 +1,7 @@
#pragma once
#include <ctrff/types.hpp>
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff {
class BinFile {

24
include/ctrff/cia.hpp Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include <ctrff/helper.hpp>
#include <ctrff/pd_p_api.hpp>
#include <ctrff/smdh.hpp>
#include <pd.hpp>
namespace ctrff {
class Cia : public BinFile {
public:
Cia() {}
~Cia() {}
PD::u32 HeaderSize;
PD::u16 Type;
PD::u16 Version;
PD::u32 CertChainSize;
PD::u32 TikSize;
PD::u32 TmdFileSize;
PD::u32 MetaSize;
PD::u64 ContentSize;
PD::u8 ContentIndex[0x2000];
};
} // namespace ctrff

View File

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

View File

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

44
include/ctrff/ncch.hpp Normal file
View File

@@ -0,0 +1,44 @@
#pragma once
#include <ctrff/helper.hpp>
#include <ctrff/pd_p_api.hpp>
#include <ctrff/smdh.hpp>
#include <pd.hpp>
namespace ctrff {
class NCCH : public BinFile {
public:
NCCH() {}
~NCCH() {}
PD::u8 Sig[0x100];
PD::u32 Magic;
PD::u32 ContentLen; // 1 (Media Unit) = 0x200 bytes
PD::u64 PartitionID;
PD::u16 MarkerCode;
PD::u16 Version;
PD::u32 Wtf;
PD::u64 ProgramID;
PD::u8 Reserved[0x10];
PD::u8 LogoHash[0x20]; // Firm 5.0.0-11+
PD::u8 ProdCode[0x10];
PD::u8 ExHeaderHash[0x20];
PD::u32 ExHeaderLen;
PD::u32 Reserved1;
PD::u64 Flags;
PD::u32 PlainRegionOff; // In Media Units
PD::u32 PlainRegionSize;
PD::u32 LogoRegionOff;
PD::u32 LogoRegionSize;
PD::u32 ExeFsOff;
PD::u32 ExeFsSize;
PD::u32 ExeFsHashRegionSize;
PD::u32 Reserved2;
PD::u32 RomFsOff;
PD::u32 RomFsSize;
PD::u32 RomFsHashRegionSize;
PD::u32 Reserved;
PD::u8 ExeFsSuperBlockHash[0x20];
PD::u8 RomFsSuperBlockHash[0x20];
};
} // namespace ctrff

View File

@@ -48,34 +48,3 @@ SOFTWARE.
#else
#define CTRFF_API
#endif
#include <cstddef>
#include <format>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
namespace ctrff {
using u8 = unsigned char;
using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;
/**
* Function to get Arraysize for any type using modern c++ to
* get the size at compiletime instead of runtime
* @note this function only works for Arrays declared as
* type arr[size] and not for pointer references.
* This function will precalculate the size at compile time
* while keeping the code clean to not hardcode arraysizes
* into functions like std::fill_n
*/
template <typename T, size_t N>
constexpr size_t ArraySize(T (&)[N]) noexcept {
return N;
}
} // namespace ctrff

View File

@@ -2,7 +2,8 @@
#include <ctrff/binutil.hpp>
#include <ctrff/helper.hpp>
#include <ctrff/types.hpp>
#include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
// Basic Info
// language_slots: 16
@@ -15,15 +16,16 @@ 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 ctrff::u32 SMDH_Size = 0x36C0;
constexpr PD::u32 SMDH_Size = 0x36C0;
struct CTRFF_API SMDH {
SMDH() {
std::fill_n(Magic, ctrff::ArraySize(Magic), 0);
std::fill_n(IconSmall, ctrff::ArraySize(IconSmall), 0);
std::fill_n(IconLarge, ctrff::ArraySize(IconLarge), 0);
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,
@@ -95,8 +97,8 @@ struct CTRFF_API SMDH {
void Write(std::fstream &f) const;
void Read(std::fstream &f);
void SetIcon(const std::vector<ctrff::u8> &buf);
std::vector<ctrff::u8> GetIcon();
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);
@@ -106,36 +108,36 @@ struct CTRFF_API SMDH {
struct CTRFF_API Title {
Title() {
std::fill_n(ShortTitle, ctrff::ArraySize(ShortTitle), 0);
std::fill_n(LongTitle, ctrff::ArraySize(LongTitle), 0);
std::fill_n(Author, ctrff::ArraySize(Author), 0);
std::fill_n(ShortTitle, PD::ArraySize(ShortTitle), 0);
std::fill_n(LongTitle, PD::ArraySize(LongTitle), 0);
std::fill_n(Author, PD::ArraySize(Author), 0);
};
ctrff::u16 ShortTitle[0x40];
ctrff::u16 LongTitle[0x80];
ctrff::u16 Author[0x40];
PD::u16 ShortTitle[0x40];
PD::u16 LongTitle[0x80];
PD::u16 Author[0x40];
};
struct CTRFF_API Settings {
Settings() { std::fill_n(Ratings, ctrff::ArraySize(Ratings), 0); };
ctrff::u8 Ratings[16];
ctrff::u32 RegionLock = 0;
ctrff::u32 MatchmakerID = 0;
ctrff::u64 MatchmakerBitID = 0;
ctrff::u32 Flags = 0;
ctrff::u16 EulaVersion = 0;
ctrff::u16 Reserved = 0;
ctrff::u32 OptimalBannerFrame = 0;
ctrff::u32 StreetpassID = 0;
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];
ctrff::u16 Version = 0;
ctrff::u16 Reserved = 0;
PD::u16 Version = 0;
PD::u16 Reserved = 0;
Title Titles[16];
Settings Settings;
ctrff::u64 Reserved1 = 0;
ctrff::u16 IconSmall[0x240]; // 24x24
ctrff::u16 IconLarge[0x900]; // 48x48
PD::u64 Reserved1 = 0;
PD::u16 IconSmall[0x240]; // 24x24
PD::u16 IconLarge[0x900]; // 48x48
};
} // namespace ctrff

View File

@@ -1,7 +1,7 @@
#include <ctrff/bcstm.hpp>
/** Using this a single time so inline it */
inline ctrff::u32 Swap32(ctrff::u32 in) {
inline PD::u32 Swap32(PD::u32 in) {
return (in >> 24) | ((in >> 8) & 0x0000FF00) | ((in << 8) & 0x00FF0000) |
(in << 24);
}
@@ -28,7 +28,7 @@ CTRFF_API void BCSTM::LoadFile(const std::string& path) {
pReader.Read(pHeader.FileSize);
pReader.Read(pHeader.NumBlocks);
pReader.Read(pHeader.Reserved);
for (ctrff::u16 i = 0; i < pHeader.NumBlocks; i++) {
for (PD::u16 i = 0; i < pHeader.NumBlocks; i++) {
SizedReference ref;
ReadSizedReference(ref);
if (ref.Ref.TypeID == Ref_InfoBlock) {
@@ -61,6 +61,9 @@ CTRFF_API void BCSTM::ReadInfoBlock(InfoBlock& block) {
ReadReference(block.TrackInfoTabRef);
ReadReference(block.ChannelInfoTabRef);
pReader.Read(block.StreamInfo.Encoding);
if (block.StreamInfo.Encoding != DSP_ADPCM) {
throw std::runtime_error("Only DSP ADPCM is supported yet!");
}
pReader.Read(block.StreamInfo.Loop);
pReader.Read(block.StreamInfo.ChannelCount);
pReader.Read(block.StreamInfo.Padding);
@@ -94,20 +97,18 @@ CTRFF_API void BCSTM::ReadInfoBlock(InfoBlock& block) {
std::ios::beg);
Reference r;
ReadReference(r);
block.ChannelInfoRefs.push_back(r);
block.ChannelInfoRefs.Add(r);
}
if (block.StreamInfo.Encoding == DSP_ADPCM) {
for (size_t i = 0; i < block.ChannelInfoRefs.size(); i++) {
size_t off = pInfoBlockRef.Ref.Offset;
off += sizeof(BlockHeader);
off += block.ChannelInfoTabRef.Offset;
off += block.ChannelInfoTab.Refs[i].Offset;
off += block.ChannelInfoRefs[i].Offset;
pFile.seekg(off, std::ios::beg);
DSP_ADPCM_Info t; /** temp */
pReader.ReadEx(t); /** This Section gets read normally */
pDSP_ADPCM_Info.push_back(t);
}
for (size_t i = 0; i < block.ChannelInfoRefs.Size(); i++) {
size_t off = pInfoBlockRef.Ref.Offset;
off += sizeof(BlockHeader);
off += block.ChannelInfoTabRef.Offset;
off += block.ChannelInfoTab.Refs[i].Offset;
off += block.ChannelInfoRefs[i].Offset;
pFile.seekg(off, std::ios::beg);
DSP_ADPCM_Info t; /** temp */
pReader.ReadEx(t); /** This Section gets read normally */
pDSP_ADPCM_Info.Add(t);
}
}
@@ -118,23 +119,23 @@ CTRFF_API void BCSTM::ReadSeekBlock(SD_Block& block) {
throw std::runtime_error("BCSTM: SeekBlock Size is not 0x20 aligned!");
}
pSeekBlock.Data.reserve(pSeekBlock.Header.Size + 1);
for (ctrff::u32 i = 0; i < pSeekBlock.Header.Size; i++) {
ctrff::u8 v;
pSeekBlock.Data.Reserve(pSeekBlock.Header.Size + 1);
for (PD::u32 i = 0; i < pSeekBlock.Header.Size; i++) {
PD::u8 v;
pReader.Read(v);
pSeekBlock.Data.push_back(v);
pSeekBlock.Data.Add(v);
}
}
CTRFF_API void BCSTM::ReadReferenceTab(ReferenceTable& tab) {
pReader.Read(tab.Count);
tab.Refs.reserve(tab.Count + 1);
for (ctrff::u32 i = 0; i < tab.Count; i++) {
tab.Refs.Reserve(tab.Count + 1);
for (PD::u32 i = 0; i < tab.Count; i++) {
Reference r;
pReader.Read(r.TypeID);
pReader.Read(r.Padding);
pReader.Read(r.Offset);
tab.Refs.push_back(r);
tab.Refs.Add(r);
}
}
@@ -146,27 +147,29 @@ CTRFF_API void BCSTM::ReadGotoBeginning(bool use_loop_beg) {
size_t off = pDataBlockRef.Ref.Offset + 0x20;
/** Shift to loop start if enabled */
if (use_loop_beg) {
off += GetLoopStart() * GetBlockSize() * GetNumChannels();
off += GetNumBlocks() * GetNumChannels() * GetLoopStart();
// off += GetNumChannels() * pInfoBlock.StreamInfo.LoopStartFrame;
}
// block_size * channel_count * loop_start
try {
pFile.seekg(off, std::ios::beg);
} catch (const std::exception& e) {
throw std::runtime_error(e.what());
}
pFile.seekg(off, std::ios::beg);
if (pFile.tellg() > pHeader.FileSize) {
throw std::runtime_error("BCSTM: Seeked Out of range!");
}
}
CTRFF_API void BCSTM::ReadBlock(ctrff::u32 block, ctrff::u8* ref) {
if (!ref) {
throw std::runtime_error("BCSTM: pointer ref is nullptr!");
}
CTRFF_API void BCSTM::ReadBlock(PD::u32 block, PD::u8* ref) {
if (pFile.tellg() > pHeader.FileSize || block >= GetNumBlocks()) {
throw std::runtime_error(std::format(
"BCSTM: Decode block out of range! ({}/{})", block, GetNumBlocks()));
"BCSTM: Decode block Out of range! ({} > {})", block, GetNumBlocks()));
}
pFile.read(reinterpret_cast<char*>(ref),
(block == (GetNumBlocks() - 1)
? pInfoBlock.StreamInfo.LastSampleBlockPaddedSize
: GetBlockSize()));
pFile.read(
reinterpret_cast<char*>(ref),
(block == (GetNumBlocks() - 1) ? pInfoBlock.StreamInfo.LastSampleBlockSize
: GetBlockSize()));
}
CTRFF_API void BCSTM::CleanUp() {
@@ -177,32 +180,11 @@ CTRFF_API void BCSTM::CleanUp() {
throw std::runtime_error(e.what());
}
}
pInfoBlock = InfoBlock();
pHeader = Header();
pInfoBlockRef = SizedReference();
pSeekBlockRef = SizedReference();
pDataBlockRef = SizedReference();
pInfoBlock = InfoBlock();
pSeekBlock = SD_Block();
pDataBlock = SD_Block();
pDSP_ADPCM_Info.clear();
}
CTRFF_API BCSTM::StreamInfo::StreamInfo() {
ChannelCount = 0;
Encoding = 0;
LastSampleBlockPaddedSize = 0;
LastSampleBlockSampleNum = 0;
LastSampleBlockSize = 0;
Loop = 0;
LoopEndFrame = 0;
LoopStartFrame = 0;
Padding = 0;
SampleBlockNum = 0;
SampleBlockSampleNum = 0;
SampleBlockSize = 0;
SampleRate = 0;
SeekDataSize = 0;
SeekIntervalSampleNum = 0;
pInfoBlock.ChannelInfoRefs.Clear();
pInfoBlock.ChannelInfoTab.Refs.Clear();
pInfoBlock.ChannelInfoTab.Count = 0;
pInfoBlock.TrackInfoTab.Refs.Clear();
pInfoBlock.TrackInfoTab.Count = 0;
pDSP_ADPCM_Info.Clear();
}
} // namespace ctrff

View File

@@ -1,7 +1,7 @@
#include <ctrff/bcwav.hpp>
/** Using this a single time so inline it */
inline ctrff::u32 Swap32(ctrff::u32 in) {
inline PD::u32 Swap32(PD::u32 in) {
return (in >> 24) | ((in >> 8) & 0x0000FF00) | ((in << 8) & 0x00FF0000) |
(in << 24);
}
@@ -28,7 +28,7 @@ CTRFF_API void BCWAV::LoadFile(const std::string& path) {
pReader.Read(pHeader.FileSize);
pReader.Read(pHeader.NumBlocks);
pReader.Read(pHeader.Reserved);
for (ctrff::u16 i = 0; i < pHeader.NumBlocks; i++) {
for (PD::u16 i = 0; i < pHeader.NumBlocks; i++) {
SizedReference ref;
ReadSizedReference(ref);
if (ref.Ref.TypeID == Ref_InfoBlock) {
@@ -67,31 +67,29 @@ CTRFF_API void BCWAV::ReadInfoBlock(InfoBlock& block) {
std::ios::beg);
Reference r;
ReadReference(r);
block.ChannelInfoRefs.push_back(r);
block.ChannelInfoRefs.Add(r);
}
if (block.Encoding == DSP_ADPCM) {
for (size_t i = 0; i < block.ChannelInfoRefs.size(); i++) {
size_t off = pInfoBlockRef.Ref.Offset;
off += sizeof(BlockHeader);
off += block.ChannelInfoTab.Refs[i].Offset;
off += block.ChannelInfoRefs[i].Offset;
pFile.seekg(off, std::ios::beg);
DSP_ADPCM_Info t; /** temp */
pReader.ReadEx(t); /** This Section gets read normally */
pDSP_ADPCM_Info.push_back(t);
}
for (size_t i = 0; i < block.ChannelInfoRefs.Size(); i++) {
size_t off = pInfoBlockRef.Ref.Offset;
off += sizeof(BlockHeader);
off += block.ChannelInfoTab.Refs[i].Offset;
off += block.ChannelInfoRefs[i].Offset;
pFile.seekg(off, std::ios::beg);
DSP_ADPCM_Info t; /** temp */
pReader.ReadEx(t); /** This Section gets read normally */
pDSP_ADPCM_Info.Add(t);
}
}
CTRFF_API void BCWAV::ReadReferenceTab(ReferenceTable& tab) {
pReader.Read(tab.Count);
tab.Refs.reserve(tab.Count + 1);
for (ctrff::u32 i = 0; i < tab.Count; i++) {
tab.Refs.Reserve(tab.Count + 1);
for (PD::u32 i = 0; i < tab.Count; i++) {
Reference r;
pReader.Read(r.TypeID);
pReader.Read(r.Padding);
pReader.Read(r.Offset);
tab.Refs.push_back(r);
tab.Refs.Add(r);
}
}
@@ -104,14 +102,20 @@ CTRFF_API void BCWAV::ReadGotoBeginning(bool use_loop_beg) {
/** Shift to loop start if enabled */
if (use_loop_beg) {
// off += GetNumBlocks() * GetNumChannels() * GetLoopStart();
// off += GetNumChannels() * pInfoBlock.StreamInfo.LoopStartFrame;
}
// block_size * channel_count * loop_start
try {
pFile.seekg(off, std::ios::beg);
} catch (const std::exception& e) {
throw std::runtime_error(e.what());
}
pFile.seekg(off, std::ios::beg);
if (pFile.tellg() > pHeader.FileSize) {
throw std::runtime_error("BCWAV: Seeked Out of range!");
}
}
CTRFF_API void BCWAV::ReadBlock(ctrff::u32 block, ctrff::u8* ref) {
CTRFF_API void BCWAV::ReadBlock(PD::u32 block, PD::u8* ref) {
// if (pFile.tellg() > pHeader.FileSize || block >= GetNumBlocks()) {
// throw std::runtime_error("BCWAV: Decode block Out of range!");
// }
@@ -130,13 +134,9 @@ CTRFF_API void BCWAV::CleanUp() {
throw std::runtime_error(e.what());
}
}
pInfoBlock = InfoBlock();
pHeader = Header();
pInfoBlockRef = SizedReference();
pDataBlockRef = SizedReference();
// Does not get read idk why i added it
// cause it needs to be streamed
pDataBlock = DataBlock();
pDSP_ADPCM_Info.clear();
pInfoBlock.ChannelInfoRefs.Clear();
pInfoBlock.ChannelInfoTab.Refs.Clear();
pInfoBlock.ChannelInfoTab.Count = 0;
pDSP_ADPCM_Info.Clear();
}
} // namespace ctrff

View File

@@ -2,22 +2,22 @@
namespace ctrff {
/** Supported reads */
template CTRFF_API void BinUtil::Read<ctrff::u8>(ctrff::u8&);
template CTRFF_API void BinUtil::Read<ctrff::u16>(ctrff::u16&);
template CTRFF_API void BinUtil::Read<ctrff::u32>(ctrff::u32&);
template CTRFF_API void BinUtil::Read<ctrff::u64>(ctrff::u64&);
template CTRFF_API void BinUtil::Read<PD::u8>(PD::u8&);
template CTRFF_API void BinUtil::Read<PD::u16>(PD::u16&);
template CTRFF_API void BinUtil::Read<PD::u32>(PD::u32&);
template CTRFF_API void BinUtil::Read<PD::u64>(PD::u64&);
/** Supported writes */
template CTRFF_API void BinUtil::Write<ctrff::u8>(const ctrff::u8&);
template CTRFF_API void BinUtil::Write<ctrff::u16>(const ctrff::u16&);
template CTRFF_API void BinUtil::Write<ctrff::u32>(const ctrff::u32&);
template CTRFF_API void BinUtil::Write<ctrff::u64>(const ctrff::u64&);
template CTRFF_API void BinUtil::Write<PD::u8>(const PD::u8&);
template CTRFF_API void BinUtil::Write<PD::u16>(const PD::u16&);
template CTRFF_API void BinUtil::Write<PD::u32>(const PD::u32&);
template CTRFF_API void BinUtil::Write<PD::u64>(const PD::u64&);
template <typename T>
void BinUtil::Read(T& v) {
// Check if Value could be Read
static_assert(std::is_integral<T>::value, "Cannot Read type T");
v = 0; // Set value to 0 (most cases a windows problem)
std::vector<ctrff::u8> buf(sizeof(T), 0); // declare buffer
std::vector<PD::u8> buf(sizeof(T), 0); // declare buffer
// Read data into buffer
m_file.read(reinterpret_cast<char*>(buf.data()), sizeof(T));
// Loop or in be reverse loop and chift the values
@@ -29,11 +29,11 @@ template <typename T>
void BinUtil::Write(const T& v) {
// Check if Value could Write
static_assert(std::is_integral<T>::value, "Cannot Write type T");
std::vector<ctrff::u8> buf(sizeof(T), 0); // declare buffer
std::vector<PD::u8> buf(sizeof(T), 0); // declare buffer
// Loop or in be reverse loop and write the values
for (size_t i = 0; i < sizeof(T); i++) {
buf[(m_big ? sizeof(T) - 1 - i : i)] = buf[m_big ? sizeof(T) - 1 - i : i] =
static_cast<ctrff::u8>((v >> (8 * i)) & 0xFF);
static_cast<PD::u8>((v >> (8 * i)) & 0xFF);
}
// Write buffer into file
m_file.write(reinterpret_cast<const char*>(buf.data()), sizeof(T));

View File

@@ -2,33 +2,31 @@
#include <cwchar>
#include <iostream>
void MakePixelRGBA(ctrff::u8 &r, ctrff::u8 &g, ctrff::u8 &b, ctrff::u8 &a,
ctrff::u16 px) {
void MakePixelRGBA(PD::u8 &r, PD::u8 &g, PD::u8 &b, PD::u8 &a, PD::u16 px) {
b = (px & 0x1f) << 3;
g = ((px >> 0x5) & 0x3f) << 2;
r = ((px >> 0xb) & 0x1f) << 3;
a = 0xff;
}
CTRFF_API ctrff::u16 MakePixel565(const ctrff::u8 &r, const ctrff::u8 &g,
const ctrff::u8 &b) {
ctrff::u16 res = 0;
CTRFF_API PD::u16 MakePixel565(const PD::u8 &r, const PD::u8 &g,
const PD::u8 &b) {
PD::u16 res = 0;
res |= (r & ~0x7) << 8;
res |= (g & ~0x3) << 3;
res |= (b) >> 3;
return res;
}
CTRFF_API ctrff::u32 TileIndex(const int &x, const int &y, const int &w) {
CTRFF_API PD::u32 TileIndex(const int &x, const int &y, const int &w) {
return (((y >> 3) * (w >> 3) + (x >> 3)) << 6) +
((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) |
((x & 4) << 2) | ((y & 4) << 3));
}
// TODO: Fix colors
CTRFF_API void ctrff::RGB565toRGBA(std::vector<ctrff::u8> &img,
ctrff::u16 *icon, const int &w,
const int &h) {
CTRFF_API void ctrff::RGB565toRGBA(std::vector<PD::u8> &img, PD::u16 *icon,
const int &w, const int &h) {
if (img.size() != (48 * 48 * 4)) {
img.resize(48 * 48 * 4);
img.clear();
@@ -36,37 +34,36 @@ CTRFF_API void ctrff::RGB565toRGBA(std::vector<ctrff::u8> &img,
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
auto idx = TileIndex(x, y, w);
ctrff::u32 pos = (y * w + x) * 4;
PD::u32 pos = (y * w + x) * 4;
MakePixelRGBA(img[pos + 0], img[pos + 1], img[pos + 2], img[pos + 3],
icon[idx]);
}
}
}
CTRFF_API void ctrff::RGBA2RGB565(ctrff::u16 *out,
const std::vector<ctrff::u8> &img,
CTRFF_API void ctrff::RGBA2RGB565(PD::u16 *out, const std::vector<PD::u8> &img,
const int &w, const int &h) {
if (img.size() != size_t(w * h * 4)) return;
std::vector<ctrff::u8> px8 = img;
std::vector<PD::u8> px8 = img;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
auto idx = TileIndex(x, y, w);
ctrff::u32 pos = (y * w + x) * 4;
PD::u32 pos = (y * w + x) * 4;
out[idx] = MakePixel565(img[pos], img[pos + 1], img[pos + 2]);
}
}
}
CTRFF_API std::vector<ctrff::u8> ctrff::DownscaleImage(
const std::vector<ctrff::u8> &img, int w, int h, int scale) {
std::vector<ctrff::u8> res(((w / scale) * (h / scale)) * 4);
CTRFF_API std::vector<PD::u8> ctrff::DownscaleImage(
const std::vector<PD::u8> &img, int w, int h, int scale) {
std::vector<PD::u8> res(((w / scale) * (h / scale)) * 4);
int samples = scale * scale;
for (int y = 0; y < h; y += scale) {
for (int x = 0; x < w; x += scale) {
ctrff::u32 r = 0;
ctrff::u32 g = 0;
ctrff::u32 b = 0;
ctrff::u32 a = 0;
PD::u32 r = 0;
PD::u32 g = 0;
PD::u32 b = 0;
PD::u32 a = 0;
for (int oy = 0; oy < scale; oy++) {
for (int ox = 0; ox < scale; ox++) {
int pos = ((y + oy) * w + (x + ox)) * 4;
@@ -77,16 +74,16 @@ CTRFF_API std::vector<ctrff::u8> ctrff::DownscaleImage(
}
}
int pos = ((y / scale) * (w / scale) + (x / scale)) * 4;
res[pos++] = (ctrff::u8)(r / samples);
res[pos++] = (ctrff::u8)(g / samples);
res[pos++] = (ctrff::u8)(b / samples);
res[pos++] = (ctrff::u8)(a / samples);
res[pos++] = (PD::u8)(r / samples);
res[pos++] = (PD::u8)(g / samples);
res[pos++] = (PD::u8)(b / samples);
res[pos++] = (PD::u8)(a / samples);
}
}
return res;
}
CTRFF_API void ctrff::String2U16(ctrff::u16 *res, const std::string &src,
CTRFF_API void ctrff::String2U16(PD::u16 *res, const std::string &src,
size_t max) {
/// GOT FORCED TO REPLACE std::wstring_convert by some
/// manual work as it got removed in cxx20
@@ -96,7 +93,7 @@ CTRFF_API void ctrff::String2U16(ctrff::u16 *res, const std::string &src,
size_t len = 0;
size_t i = 0;
while (i < src.size() && len < max) {
ctrff::u8 c = src[i];
PD::u8 c = src[i];
if (c < 0x80) {
// 1byte
@@ -119,8 +116,8 @@ CTRFF_API void ctrff::String2U16(ctrff::u16 *res, const std::string &src,
// 4byte
if (i + 3 >= src.size())
throw std::invalid_argument("Invalid UTF-8 sequence");
ctrff::u32 codepoint = ((c & 0x07) << 18) | ((src[i + 1] & 0x3F) << 12) |
((src[i + 2] & 0x3F) << 6) | (src[i + 3] & 0x3F);
PD::u32 codepoint = ((c & 0x07) << 18) | ((src[i + 1] & 0x3F) << 12) |
((src[i + 2] & 0x3F) << 6) | (src[i + 3] & 0x3F);
codepoint -= 0x10000;
res[len++] = 0xD800 | ((codepoint >> 10) & 0x3FF);
res[len++] = 0xDC00 | (codepoint & 0x3FF);
@@ -131,7 +128,7 @@ CTRFF_API void ctrff::String2U16(ctrff::u16 *res, const std::string &src,
}
}
CTRFF_API std::string ctrff::U16toU8(ctrff::u16 *in, size_t max) {
CTRFF_API std::string ctrff::U16toU8(PD::u16 *in, size_t max) {
/// GOT FORCED TO REPLACE std::wstring_convert by some
/// manual work as it got removed in cxx20
if (!in || max == 0) {

View File

@@ -5,14 +5,14 @@
namespace ctrff {
namespace LZ11 {
ctrff::u32 GetOccurenceLength(const ctrff::u8* new_ptr, size_t new_len,
const ctrff::u8* old_ptr, size_t old_len,
ctrff::u32& disp) {
PD::u32 GetOccurenceLength(const PD::u8* new_ptr, size_t new_len,
const PD::u8* old_ptr, size_t old_len,
PD::u32& disp) {
disp = 0;
if (new_len == 0) {
return 0;
}
ctrff::u32 res = 0;
PD::u32 res = 0;
if (old_len > 0) {
for (size_t i = 0; i < old_len - 1; i++) {
auto ref = old_ptr + i;
@@ -35,20 +35,20 @@ ctrff::u32 GetOccurenceLength(const ctrff::u8* new_ptr, size_t new_len,
return res;
}
CTRFF_API std::vector<ctrff::u8> Compress(const std::vector<ctrff::u8>& in) {
CTRFF_API std::vector<PD::u8> Compress(const std::vector<PD::u8>& in) {
if (in.size() > 0xFFFFFF) {
std::cout << "ERROR: LZ11 input is too large!" << std::endl;
return std::vector<ctrff::u8>();
return std::vector<PD::u8>();
}
std::stringstream s;
// SETUP HEADER //
s << static_cast<ctrff::u8>(0x11);
s << static_cast<ctrff::u8>(in.size() & 0xFF);
s << static_cast<ctrff::u8>((in.size() >> 8) & 0xFF);
s << static_cast<ctrff::u8>((in.size() >> 16) & 0xFF);
s << static_cast<PD::u8>(0x11);
s << static_cast<PD::u8>(in.size() & 0xFF);
s << static_cast<PD::u8>((in.size() >> 8) & 0xFF);
s << static_cast<PD::u8>((in.size() >> 16) & 0xFF);
size_t res_len = 4; // 4-byte header
ctrff::u8 out_buf[0x21]; // 33 bytes
size_t res_len = 4; // 4-byte header
PD::u8 out_buf[0x21]; // 33 bytes
out_buf[0] = 0;
size_t obl = 1; // out_buf_len
size_t buf_blocks = 0;
@@ -63,7 +63,7 @@ CTRFF_API std::vector<ctrff::u8> Compress(const std::vector<ctrff::u8>& in) {
buf_blocks = 0;
}
ctrff::u32 disp = 0;
PD::u32 disp = 0;
size_t old_len = std::min(rb, static_cast<size_t>(0x1000));
size_t len = LZ11::GetOccurenceLength(
in.data() + rb, std::min(in.size() - rb, static_cast<size_t>(0x10110)),
@@ -73,22 +73,21 @@ CTRFF_API std::vector<ctrff::u8> Compress(const std::vector<ctrff::u8>& in) {
out_buf[obl++] = in[rb++];
} else {
rb += len;
out_buf[0] |= static_cast<ctrff::u8>(1 << (7 - buf_blocks));
out_buf[0] |= static_cast<PD::u8>(1 << (7 - buf_blocks));
if (len > 0x110) {
out_buf[obl++] =
0x10 | static_cast<ctrff::u8>(((len - 0x111) >> 12) & 0x0F);
out_buf[obl++] = static_cast<ctrff::u8>(((len - 0x111) >> 4) & 0xFF);
out_buf[obl] = static_cast<ctrff::u8>(((len - 0x111) << 4) & 0xF0);
0x10 | static_cast<PD::u8>(((len - 0x111) >> 12) & 0x0F);
out_buf[obl++] = static_cast<PD::u8>(((len - 0x111) >> 4) & 0xFF);
out_buf[obl] = static_cast<PD::u8>(((len - 0x111) << 4) & 0xF0);
} else if (len > 0x10) {
out_buf[obl++] =
0x00 | static_cast<ctrff::u8>(((len - 0x11) >> 4) & 0x0F);
out_buf[obl] = static_cast<ctrff::u8>(((len - 0x11) << 4) & 0xF0);
out_buf[obl++] = 0x00 | static_cast<PD::u8>(((len - 0x11) >> 4) & 0x0F);
out_buf[obl] = static_cast<PD::u8>(((len - 0x11) << 4) & 0xF0);
} else {
out_buf[obl] |= static_cast<ctrff::u8>(((len - 1) << 4) & 0xF0);
out_buf[obl] |= static_cast<PD::u8>(((len - 1) << 4) & 0xF0);
}
obl++;
out_buf[obl++] = static_cast<ctrff::u8>(((disp - 1) >> 8) & 0x0F);
out_buf[obl++] = static_cast<ctrff::u8>((disp - 1) & 0xFF);
out_buf[obl++] = static_cast<PD::u8>(((disp - 1) >> 8) & 0x0F);
out_buf[obl++] = static_cast<PD::u8>((disp - 1) & 0xFF);
}
buf_blocks++;
}
@@ -99,13 +98,13 @@ CTRFF_API std::vector<ctrff::u8> Compress(const std::vector<ctrff::u8>& in) {
}
if (res_len % 4 != 0) {
ctrff::u32 pad_len = 4 - (res_len % 4);
ctrff::u8 pad[4] = {0};
PD::u32 pad_len = 4 - (res_len % 4);
PD::u8 pad[4] = {0};
s.write(reinterpret_cast<const char*>(pad), pad_len);
res_len += pad_len;
}
std::vector<ctrff::u8> res(res_len);
std::vector<PD::u8> res(res_len);
s.read(reinterpret_cast<char*>(res.data()), res.size());
return res;
}

View File

@@ -39,14 +39,14 @@ CTRFF_API void ctrff::SMDH::Read(std::fstream &f) {
f.read(reinterpret_cast<char *>(&IconLarge), sizeof(IconLarge));
}
CTRFF_API void ctrff::SMDH::SetIcon(const std::vector<ctrff::u8> &buf) {
CTRFF_API void ctrff::SMDH::SetIcon(const std::vector<PD::u8> &buf) {
RGBA2RGB565(IconLarge, buf, 48, 48);
auto small_icon = DownscaleImage(buf, 48, 48, 2);
RGBA2RGB565(IconSmall, small_icon, 24, 24);
}
CTRFF_API std::vector<ctrff::u8> ctrff::SMDH::GetIcon() {
std::vector<ctrff::u8> res(48 * 48 * 4);
CTRFF_API std::vector<PD::u8> ctrff::SMDH::GetIcon() {
std::vector<PD::u8> res(48 * 48 * 4);
ctrff::RGB565toRGBA(res, IconLarge, 48, 48);
return res;
}

View File

@@ -121,7 +121,7 @@ void MakeSMDH(const cf7::command::ArgumentList &data) {
smdh.SetAuthor(a);
std::vector<unsigned char> img;
int w, h, c;
ctrff::u8 *buf = stbi_load(i.c_str(), &w, &h, &c, 4);
PD::u8 *buf = stbi_load(i.c_str(), &w, &h, &c, 4);
if (buf == nullptr) {
cf7::PrintFancy({
std::make_pair("Error", cf7::col(190, 0, 0)),

View File

@@ -16,20 +16,20 @@ void Result(const std::string& name, T a, T b) {
void BinTest(bool be) {
std::fstream s("test.bin", std::ios::out | std::ios::binary);
ctrff::u8 t8 = 0xdf;
ctrff::u16 t16 = 0x4564;
ctrff::u32 t32 = 0x58464743;
ctrff::u64 t64 = 1234567890123456789ULL;
PD::u8 t8 = 0xdf;
PD::u16 t16 = 0x4564;
PD::u32 t32 = 0x58464743;
PD::u64 t64 = 1234567890123456789ULL;
ctrff::BinUtil u(s, be);
u.Write(t8);
u.Write(t16);
u.Write(t32);
u.Write(t64);
s.close();
ctrff::u8 r8 = 0;
ctrff::u16 r16 = 0;
ctrff::u32 r32 = 0;
ctrff::u64 r64 = 0;
PD::u8 r8 = 0;
PD::u16 r16 = 0;
PD::u32 r32 = 0;
PD::u64 r64 = 0;
s.open("test.bin", std::ios::in | std::ios::binary);
u.Read(r8);
u.Read(r16);

1
vendor/palladium vendored Submodule

Submodule vendor/palladium added at a0960bd717