Compare commits

3 Commits
Author SHA1 Message Date
tobid7 0ab0929746 started some work on cia/ncch 2025-11-28 17:49:05 +01:00
tobid7 8c1a48a527 updated to newer palladium 2025-11-28 17:48:54 +01:00
tobid7 6242a7565e fixes 2025-11-28 17:48:27 +01:00
28 changed files with 454 additions and 698 deletions
+1 -1
View File
@@ -3,4 +3,4 @@
url = https://dev.npid7.de/tobid7/cli-fancy url = https://dev.npid7.de/tobid7/cli-fancy
[submodule "vendor/palladium"] [submodule "vendor/palladium"]
path = vendor/palladium path = vendor/palladium
url = https://github.com/tobid7/palladium url = https://dev.npid7.de/tobid7/palladium.git
+7 -7
View File
@@ -19,25 +19,25 @@ if(${CTRFF_3DS})
endif() endif()
endif() endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-psabi -O3") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-psabi -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -fno-rtti")
endif() endif()
add_library(ctrff STATIC add_library(ctrff STATIC
source/3dsx.cpp
source/bclim.cpp
source/bcstm.cpp
source/bcwav.cpp
source/binutil.cpp
source/helper.cpp source/helper.cpp
source/lz11.cpp source/lz11.cpp
source/smdh.cpp source/smdh.cpp
source/binutil.cpp
source/bcstm.cpp
source/bcwav.cpp
source/3dsx.cpp
) )
target_include_directories(ctrff PUBLIC include) target_include_directories(ctrff PUBLIC include)
target_include_directories(ctrff PRIVATE vendor/palladium/include)
if(${CTRFF_DESKTOP}) if(${CTRFF_DESKTOP})
add_subdirectory(vendor/palladium)
add_executable(ctrff-cli tool/main.cpp) add_executable(ctrff-cli tool/main.cpp)
target_include_directories(ctrff-cli PUBLIC include vendor/stb vendor/cli-fancy/include) target_include_directories(ctrff-cli PUBLIC include vendor/stb vendor/cli-fancy/include)
target_link_libraries(ctrff-cli PUBLIC ctrff palladium) target_link_libraries(ctrff-cli PUBLIC ctrff)
add_executable(test tool/test.cpp) add_executable(test tool/test.cpp)
target_include_directories(test PUBLIC include vendor/stb vendor/cli-fancy/include) target_include_directories(test PUBLIC include vendor/stb vendor/cli-fancy/include)
target_link_libraries(test PUBLIC ctrff) target_link_libraries(test PUBLIC ctrff)
+3 -3
View File
@@ -35,10 +35,10 @@ Not all Planned formates are listed here yet
| Format | State | Notes | | Format | State | Notes |
| ------ | ----- | ----- | | ------ | ----- | ----- |
| 3dsx | Basic Loading and Viewing of Meta Data Smdh | | | 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 | | bcwav | Basic Loading (not tested yet) | Not finished yet |
| bclim | Creating A8,RGBA32,RGB565 done | WIP | | bclim | Nothing done yet (Started creating header) | |
| lz11 | Encoder done, Decoder missing | WIP | | lz11 | Encoder done, Decoder missing | Files are bit diffrent to the ones bannertool generates (don't know why) |
| romfs | Nothing Done yet (Started creating header) | | | romfs | Nothing Done yet (Started creating header) | |
| smdh | Almost done | missing safetey checks | | smdh | Almost done | missing safetey checks |
| cbmd | Nothing done yet | | | cbmd | Nothing done yet | |
+2 -3
View File
@@ -162,13 +162,12 @@ using u16 = unsigned short; // or uint16_t
using u8 = unsigned char; // or uint8_t using u8 = unsigned char; // or uint8_t
``` ```
## Tools / Devices / File Sources used for research ## Tools / Devices / File SOurces used for research
| Name | Description | | Name | Description |
|---|---| |---|---|
| Visual Studio Code | Used for creating ctrff c++ code for bcstm | | Visual Studio Code | Used for creating ctrff c++ code for bcstm |
| ImHex | Used to Analyze the Hex Code of the bcstm Files | | 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 | | 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 | | 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) | | 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 | | CTGP 7 | Used to get Test files |
| Super Mario Maker 3ds (Cartridge) | 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 | | 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 |
+25 -4
View File
@@ -13,7 +13,8 @@
- 2.3 [Reference Types](#reference-types) - 2.3 [Reference Types](#reference-types)
- 3 [Block Header](#block-header) - 3 [Block Header](#block-header)
- 4 [Info Block](#info-block) - 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 [DSP ADPCM Info](#dsp-adpcm-info)
- 5.1 [DSP ADPCM Param](#dsp-adpcm-param) - 5.1 [DSP ADPCM Param](#dsp-adpcm-param)
- 5.2 [DSP ADPCM Context](#dsp-adpcm-context) - 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 | 4 | [u32](#u32) | Reserved |
| 0x18 | 8 | [Reference Table](#reference-table) | Channel Info Reference Table | | 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 ### Channel Info
| Offset | Size | Datatype | Description | | Offset | Size | Datatype | Description |
@@ -140,18 +162,17 @@ using u16 = unsigned short; // or uint16_t
using u8 = unsigned char; // or uint8_t using u8 = unsigned char; // or uint8_t
``` ```
## Tools / Devices / File Sources used for research ## Tools / Devices / File SOurces used for research
| Name | Description | | Name | Description |
|---|---| |---|---|
| Visual Studio Code | Used for creating ctrff c++ code for bcstm | | Visual Studio Code | Used for creating ctrff c++ code for bcstm |
| ImHex | Used to Analyze the Hex Code of the bcstm Files | | ImHex | Used to Analyze the Hex Code of the bcstm Files |
| Citra | Fast way to generate Log files when developing ctrff | | 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 | | 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) | | New 3ds XL | Testing on Real Hardware (BCSTM-Player) |
| Mario Kart 7 (Cartridge) | Used to get Test files | | Mario Kart 7 (Cartridge) | Used to get Test files |
| CTGP 7 | Used to get Test files | | CTGP 7 | Used to get Test files |
| Super Mario Maker 3ds (Cartridge) | 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 | | 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 |
-1
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <ctrff/3dsx.hpp> #include <ctrff/3dsx.hpp>
#include <ctrff/bclim.hpp>
#include <ctrff/bcstm.hpp> #include <ctrff/bcstm.hpp>
#include <ctrff/bcwav.hpp> #include <ctrff/bcwav.hpp>
#include <ctrff/binutil.hpp> #include <ctrff/binutil.hpp>
+14 -13
View File
@@ -1,8 +1,9 @@
#pragma once #pragma once
#include <ctrff/helper.hpp> #include <ctrff/helper.hpp>
#include <ctrff/pd_p_api.hpp>
#include <ctrff/smdh.hpp> #include <ctrff/smdh.hpp>
#include <ctrff/types.hpp> #include <pd.hpp>
namespace ctrff { namespace ctrff {
class CTRFF_API _3dsx : public BinFile { class CTRFF_API _3dsx : public BinFile {
@@ -22,24 +23,24 @@ class CTRFF_API _3dsx : public BinFile {
void Write(std::fstream& f) const override; void Write(std::fstream& f) const override;
void Read(std::fstream& f) override; void Read(std::fstream& f) override;
ctrff::u32 Magic; PD::u32 Magic;
ctrff::u16 HeaderSize; PD::u16 HeaderSize;
ctrff::u16 RelocHeaderSize; PD::u16 RelocHeaderSize;
ctrff::u32 FormatVersion; PD::u32 FormatVersion;
ctrff::u32 Flags; PD::u32 Flags;
// Sizes of the code, rodata and data segments + // Sizes of the code, rodata and data segments +
// size of the BSS section (uninitialized latter half of the data segment) // size of the BSS section (uninitialized latter half of the data segment)
ctrff::u32 CodeSegSize; PD::u32 CodeSegSize;
ctrff::u32 RodataSegSize; PD::u32 RodataSegSize;
ctrff::u32 DataSegSize; PD::u32 DataSegSize;
ctrff::u32 BssSize; PD::u32 BssSize;
/// Extended Header /// /// Extended Header ///
// smdh offset // smdh offset
ctrff::u32 SMDHOff; PD::u32 SMDHOff;
// smdh size // smdh size
ctrff::u32 SMDHSize; PD::u32 SMDHSize;
// fs offset // fs offset
ctrff::u32 FsOff; PD::u32 FsOff;
SMDH Meta; SMDH Meta;
}; };
/** Probably only germen people will understand */ /** Probably only germen people will understand */
-94
View File
@@ -1,94 +0,0 @@
#pragma once
#include <cstring>
#include <ctrff/binutil.hpp>
#include <ctrff/helper.hpp>
#include <ctrff/types.hpp>
#include <filesystem>
namespace ctrff {
class CTRFF_API BCLIM : public BinFile {
public:
BCLIM() {}
~BCLIM() {}
enum Format : u32 {
L8,
A8, // tested
LA4,
LA8,
HILO8,
RGB565, // tested
RGB888,
RGBA5551,
RGBA4444,
RGBA8888, // tested
ETC1,
ETC1A4,
L4,
A4,
};
struct Header {
static Header Default() {
Header h;
h.Magic = 0x4d494c43;
h.Endianness = 0xfeff;
h.HeaderSize = 0x14;
h.Version = 0x2020000;
h.FileSize = 0;
h.NumSections = 0;
return h;
}
u32 Magic; // 0x4d494c43 "CLIM"
u16 Endianness;
u16 HeaderSize;
u32 Version;
u32 FileSize;
u32 NumSections;
};
struct ImagHeader {
static ImagHeader Default() {
ImagHeader h;
h.Magic = 0x67616d69;
h.HeaderSize = 0x14;
h.Width = 0;
h.Height = 0;
h.Format = A8;
h.ImageSize = 0;
return h;
}
u32 Magic; // 0x67616d69 "imag"
u32 HeaderSize;
u16 Width;
u16 Height;
u32 Format; // A bit waste of data lol
u32 ImageSize;
};
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 CreateByImage(const std::vector<u8>& data, int w, int h, Format fmt);
/** Write not supported btw */
void Write(std::fstream& f) const override;
void Read(std::fstream& f) override;
private:
std::vector<u8> pBuffer;
Header pCurrent;
ImagHeader pImag;
bool CreateMode = false;
};
} // namespace ctrff
+63 -97
View File
@@ -1,7 +1,8 @@
#pragma once #pragma once
#include <ctrff/binutil.hpp> #include <ctrff/binutil.hpp>
#include <ctrff/types.hpp> #include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff { namespace ctrff {
class CTRFF_API BCSTM { class CTRFF_API BCSTM {
@@ -12,44 +13,39 @@ class CTRFF_API BCSTM {
void LoadFile(const std::string& path); void LoadFile(const std::string& path);
void CleanUp(); void CleanUp();
void ReadGotoBeginning(bool use_loop_beg = false); 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 */ /** Some useful Getters */
ctrff::u8 GetNumChannels() const { PD::u8 GetNumChannels() const { return pInfoBlock.StreamInfo.ChannelCount; }
return pInfoBlock.StreamInfo.ChannelCount; PD::u32 GetSampleRate() const { return pInfoBlock.StreamInfo.SampleRate; }
} PD::u32 GetBlockSize() const { return pInfoBlock.StreamInfo.SampleBlockSize; }
ctrff::u32 GetSampleRate() const { return pInfoBlock.StreamInfo.SampleRate; } PD::u32 GetNumBlocks() const { return pInfoBlock.StreamInfo.SampleBlockNum; }
ctrff::u32 GetBlockSize() const { PD::u32 GetBlockSamples() const {
return pInfoBlock.StreamInfo.SampleBlockSize;
}
ctrff::u32 GetNumBlocks() const {
return pInfoBlock.StreamInfo.SampleBlockNum;
}
ctrff::u32 GetBlockSamples() const {
return pInfoBlock.StreamInfo.SampleBlockSampleNum; return pInfoBlock.StreamInfo.SampleBlockSampleNum;
} }
ctrff::u32 GetLastBlockSamples() const { PD::u32 GetLastBlockSamples() const {
return pInfoBlock.StreamInfo.LastSampleBlockSampleNum; return pInfoBlock.StreamInfo.LastSampleBlockSampleNum;
} }
bool IsLooping() const { return pInfoBlock.StreamInfo.Loop; } bool IsLooping() const { return pInfoBlock.StreamInfo.Loop; }
ctrff::u32 GetLoopStart() const { PD::u32 GetLoopStart() const {
return pInfoBlock.StreamInfo.LoopStartFrame / GetBlockSamples(); return pInfoBlock.StreamInfo.LoopStartFrame / GetNumBlocks();
} }
ctrff::u32 GetLoopEnd() const { PD::u32 GetLoopEnd() const {
/** Get temp references for better readability */ /** Get temp references for better readability */
const ctrff::u32& loop_end = pInfoBlock.StreamInfo.LoopEndFrame; const PD::u32& loop_end = pInfoBlock.StreamInfo.LoopEndFrame;
const ctrff::u32& block_samples = GetBlockSamples(); const PD::u32& block_samples = GetNumBlocks();
return (loop_end % block_samples ? GetNumBlocks() return (loop_end % block_samples ? block_samples
: loop_end / block_samples); : loop_end / block_samples);
} }
/** Internal Data (can be made private with private: but public by default) */ /** Internal Data (can be made private with private: but public by default) */
enum Endianness : ctrff::u16 { enum Endianness : PD::u16 {
Big = 0xfffe, ///< Big Endian Big = 0xfffe, ///< Big Endian
Little = 0xfeff, ///< Little Endian Little = 0xfeff, ///< Little Endian
}; };
enum ReferenceTypes : ctrff::u16 { enum ReferenceTypes : PD::u16 {
Ref_ByteTable = 0x0100, Ref_ByteTable = 0x0100,
Ref_ReferenceTable = 0x0101, Ref_ReferenceTable = 0x0101,
Ref_DSP_ADPCM_Info = 0x0300, Ref_DSP_ADPCM_Info = 0x0300,
@@ -63,7 +59,7 @@ class CTRFF_API BCSTM {
Ref_ChannelInfo = 0x4102, Ref_ChannelInfo = 0x4102,
}; };
enum Encoding : ctrff::u8 { enum Encoding : PD::u8 {
PCM8 = 0, PCM8 = 0,
PCM16 = 1, PCM16 = 1,
/** Only supported encoding in BCSTM-Player */ /** Only supported encoding in BCSTM-Player */
@@ -72,55 +68,46 @@ class CTRFF_API BCSTM {
}; };
struct Reference { struct Reference {
Reference() : TypeID(0), Padding(0), Offset(0) {} PD::u16 TypeID;
Reference(ctrff::u16 t, ctrff::u16 p, ctrff::u32 o) PD::u16 Padding;
: TypeID(t), Padding(p), Offset(o) {} PD::u32 Offset; /** null -> uint32_max */
ctrff::u16 TypeID;
ctrff::u16 Padding;
ctrff::u32 Offset; /** null -> uint32_max */
}; };
struct ReferenceTable { struct ReferenceTable {
ReferenceTable() : Count(0) {} PD::u32 Count;
ctrff::u32 Count; PD::Vec<Reference> Refs;
std::vector<Reference> Refs;
}; };
struct SizedReference { struct SizedReference {
SizedReference() : Size(0) {}
Reference Ref; Reference Ref;
ctrff::u32 Size; PD::u32 Size;
}; };
struct StreamInfo { struct StreamInfo {
StreamInfo(); PD::u8 Encoding;
ctrff::u8 Encoding; PD::u8 Loop;
ctrff::u8 Loop; PD::u8 ChannelCount;
ctrff::u8 ChannelCount; PD::u8 Padding;
ctrff::u8 Padding; PD::u32 SampleRate;
ctrff::u32 SampleRate; PD::u32 LoopStartFrame;
ctrff::u32 LoopStartFrame; PD::u32 LoopEndFrame;
ctrff::u32 LoopEndFrame; PD::u32 SampleBlockNum;
ctrff::u32 SampleBlockNum; PD::u32 SampleBlockSize;
ctrff::u32 SampleBlockSize; PD::u32 SampleBlockSampleNum;
ctrff::u32 SampleBlockSampleNum; PD::u32 LastSampleBlockSize;
ctrff::u32 LastSampleBlockSize; PD::u32 LastSampleBlockSampleNum;
ctrff::u32 LastSampleBlockSampleNum; PD::u32 LastSampleBlockPaddedSize;
ctrff::u32 LastSampleBlockPaddedSize; PD::u32 SeekDataSize;
ctrff::u32 SeekDataSize; PD::u32 SeekIntervalSampleNum;
ctrff::u32 SeekIntervalSampleNum;
Reference SampleDataRef; Reference SampleDataRef;
}; };
struct BlockHeader { struct BlockHeader {
BlockHeader() : Magic(0), Size(0) {} PD::u32 Magic;
BlockHeader(ctrff::u32 m, ctrff::u32 s) : Magic(m), Size(s) {} PD::u32 Size;
ctrff::u32 Magic;
ctrff::u32 Size;
}; };
struct InfoBlock { struct InfoBlock {
InfoBlock() = default;
BlockHeader Header; BlockHeader Header;
Reference StreamInfoRef; Reference StreamInfoRef;
Reference TrackInfoTabRef; Reference TrackInfoTabRef;
@@ -128,74 +115,53 @@ class CTRFF_API BCSTM {
BCSTM::StreamInfo StreamInfo; BCSTM::StreamInfo StreamInfo;
ReferenceTable TrackInfoTab; ReferenceTable TrackInfoTab;
ReferenceTable ChannelInfoTab; 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 */ /** SeekDataBlock cause they are the same struct */
struct SD_Block { struct SD_Block {
SD_Block() {}
BlockHeader Header; BlockHeader Header;
std::vector<ctrff::u8> Data; PD::Vec<PD::u8> Data;
}; };
struct DSP_ADPCM_Param { struct DSP_ADPCM_Param {
// Lets keep this not clean here :/ PD::u16 Coefficients[0x10];
DSP_ADPCM_Param() {}
ctrff::u16 Coefficients[0x10];
}; };
struct DSP_ADPCM_Context { struct DSP_ADPCM_Context {
DSP_ADPCM_Context() PD::u8 PredictorScale;
: PredictorScale(0), PD::u8 Reserved;
Reserved(0), PD::u16 PreviousSample;
PreviousSample(0), PD::u16 SecondPreviousSample;
SecondPreviousSample(0) {}
ctrff::u8 PredictorScale;
ctrff::u8 Reserved;
ctrff::u16 PreviousSample;
ctrff::u16 SecondPreviousSample;
}; };
struct DSP_ADPCM_Info { struct DSP_ADPCM_Info {
DSP_ADPCM_Info() : Padding(0) {}
DSP_ADPCM_Param Param; DSP_ADPCM_Param Param;
DSP_ADPCM_Context Context; DSP_ADPCM_Context Context;
DSP_ADPCM_Context LoopContext; DSP_ADPCM_Context LoopContext;
ctrff::u16 Padding; PD::u16 Padding;
}; };
struct ByteTable { struct ByteTable {
ByteTable(ctrff::u32 size = 0) : Size(size) {} PD::u32 Size;
ctrff::u32 Size; PD::Vec<PD::u8> Table;
std::vector<ctrff::u8> Table;
}; };
struct TrackInfo { struct TrackInfo {
TrackInfo() : Volume(0), Pan(0), Padding(0) {} PD::u8 Volume;
ctrff::u8 Volume; PD::u8 Pan;
ctrff::u8 Pan; PD::u16 Padding;
ctrff::u16 Padding;
Reference ChennelIndexTabRef; Reference ChennelIndexTabRef;
ByteTable ChannelIndexTab; ByteTable ChannelIndexTab;
}; };
struct Header { struct Header {
// Warum sieht dass so ~~nicht~~ gut aus... PD::u32 Magic; /** CSTM */
Header() PD::u16 Endianness = Little; /** Default */
: Magic(0), PD::u16 HeaderSize; /** Header Size probably */
Endianness(Little), PD::u32 Version; /** Format Version? */
HeaderSize(0), PD::u32 FileSize; /** File Size */
Version(0), PD::u16 NumBlocks; /** Number of blocks */
FileSize(0), PD::u16 Reserved; /** Reserved */
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 */
}; };
Header pHeader; Header pHeader;
@@ -205,7 +171,7 @@ class CTRFF_API BCSTM {
InfoBlock pInfoBlock; InfoBlock pInfoBlock;
SD_Block pSeekBlock; SD_Block pSeekBlock;
SD_Block pDataBlock; SD_Block pDataBlock;
std::vector<DSP_ADPCM_Info> pDSP_ADPCM_Info; PD::Vec<DSP_ADPCM_Info> pDSP_ADPCM_Info;
/** File Stream */ /** File Stream */
std::fstream pFile; std::fstream pFile;
/** Endianness based reader */ /** Endianness based reader */
+57 -68
View File
@@ -1,7 +1,8 @@
#pragma once #pragma once
#include <ctrff/binutil.hpp> #include <ctrff/binutil.hpp>
#include <ctrff/types.hpp> #include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff { namespace ctrff {
class CTRFF_API BCWAV { class CTRFF_API BCWAV {
@@ -12,15 +13,15 @@ class CTRFF_API BCWAV {
void LoadFile(const std::string& path); void LoadFile(const std::string& path);
void CleanUp(); void CleanUp();
void ReadGotoBeginning(bool use_loop_beg = false); 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) */ /** Internal Data (can be made private with private: but public by default) */
enum Endianness : ctrff::u16 { enum Endianness : PD::u16 {
Big = 0xfffe, ///< Big Endian Big = 0xfffe, ///< Big Endian
Little = 0xfeff, ///< Little Endian Little = 0xfeff, ///< Little Endian
}; };
enum ReferenceTypes : ctrff::u16 { enum ReferenceTypes : PD::u16 {
Ref_DSP_ADPCM_Info = 0x0300, Ref_DSP_ADPCM_Info = 0x0300,
Ref_IMA_ADPCM_Info = 0x0301, Ref_IMA_ADPCM_Info = 0x0301,
Ref_SampleData = 0x1f00, Ref_SampleData = 0x1f00,
@@ -29,7 +30,7 @@ class CTRFF_API BCWAV {
Ref_ChannelInfo = 0x7100, Ref_ChannelInfo = 0x7100,
}; };
enum Encoding : ctrff::u8 { enum Encoding : PD::u8 {
PCM8 = 0, PCM8 = 0,
PCM16 = 1, PCM16 = 1,
/** Only supported encoding in BCSTM-Player */ /** Only supported encoding in BCSTM-Player */
@@ -38,101 +39,89 @@ class CTRFF_API BCWAV {
}; };
struct Reference { struct Reference {
Reference() : TypeID(0), Padding(0), Offset(0) {} PD::u16 TypeID;
ctrff::u16 TypeID; PD::u16 Padding;
ctrff::u16 Padding; PD::u32 Offset; /** null -> uint32_max */
ctrff::u32 Offset; /** null -> uint32_max */
}; };
struct ReferenceTable { struct ReferenceTable {
ReferenceTable() : Count(0) {} PD::u32 Count;
ctrff::u32 Count; PD::Vec<Reference> Refs;
std::vector<Reference> Refs;
}; };
struct SizedReference { struct SizedReference {
SizedReference() : Size(0) {}
Reference Ref; 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 { struct BlockHeader {
BlockHeader() : Magic(0), Size(0) {} PD::u32 Magic;
ctrff::u32 Magic; PD::u32 Size;
ctrff::u32 Size;
}; };
struct InfoBlock { struct InfoBlock {
InfoBlock()
: Encoding(0),
Loop(0),
Padding(0),
SampleRate(0),
LoopStartFrame(0),
LoopEndFrame(0),
Reserved(0) {}
BlockHeader Header; BlockHeader Header;
ctrff::u8 Encoding; PD::u8 Encoding;
ctrff::u8 Loop; PD::u8 Loop;
ctrff::u16 Padding; PD::u16 Padding;
ctrff::u32 SampleRate; PD::u32 SampleRate;
ctrff::u32 LoopStartFrame; PD::u32 LoopStartFrame;
ctrff::u32 LoopEndFrame; PD::u32 LoopEndFrame;
ctrff::u32 Reserved; PD::u32 Reserved;
ReferenceTable ChannelInfoTab; ReferenceTable ChannelInfoTab;
std::vector<Reference> ChannelInfoRefs; /** The refs of the refs ?? */ PD::Vec<Reference> ChannelInfoRefs; /** The refs of the refs ?? */
}; };
struct DataBlock { struct DataBlock {
DataBlock() {
for (int i = 0; i < 3; i++) {
Padding[i] = 0;
}
}
BlockHeader Header; BlockHeader Header;
ctrff::u32 Padding[3]; PD::u32 Padding[3];
std::vector<ctrff::u8> Data; PD::Vec<PD::u8> Data;
}; };
struct DSP_ADPCM_Param { struct DSP_ADPCM_Param {
ctrff::u16 Coefficients[0x10]; PD::u16 Coefficients[0x10];
}; };
struct DSP_ADPCM_Context { struct DSP_ADPCM_Context {
DSP_ADPCM_Context() PD::u8 PredictorScale;
: PredictorScale(0), PD::u8 Reserved;
Reserved(0), PD::u16 PreviousSample;
PreviousSample(0), PD::u16 SecondPreviousSample;
SecondPreviousSample(0) {}
ctrff::u8 PredictorScale;
ctrff::u8 Reserved;
ctrff::u16 PreviousSample;
ctrff::u16 SecondPreviousSample;
}; };
struct DSP_ADPCM_Info { struct DSP_ADPCM_Info {
DSP_ADPCM_Info() : Padding(0) {}
DSP_ADPCM_Param Param; DSP_ADPCM_Param Param;
DSP_ADPCM_Context Context; DSP_ADPCM_Context Context;
DSP_ADPCM_Context LoopContext; DSP_ADPCM_Context LoopContext;
ctrff::u16 Padding; PD::u16 Padding;
}; };
struct Header { struct Header {
Header() PD::u32 Magic; /** CWAV */
: Magic(0), PD::u16 Endianness = Little; /** Default */
Endianness(Little), PD::u16 HeaderSize; /** Header Size probably */
HeaderSize(0), PD::u32 Version; /** Format Version? */
Version(0), PD::u32 FileSize; /** File Size */
FileSize(0), PD::u16 NumBlocks; /** Number of blocks */
NumBlocks(0), PD::u16 Reserved; /** Reserved */
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 */
}; };
Header pHeader; Header pHeader;
@@ -140,7 +129,7 @@ class CTRFF_API BCWAV {
SizedReference pDataBlockRef; SizedReference pDataBlockRef;
InfoBlock pInfoBlock; InfoBlock pInfoBlock;
DataBlock pDataBlock; DataBlock pDataBlock;
std::vector<DSP_ADPCM_Info> pDSP_ADPCM_Info; PD::Vec<DSP_ADPCM_Info> pDSP_ADPCM_Info;
/** File Stream */ /** File Stream */
std::fstream pFile; std::fstream pFile;
/** Endianness based reader */ /** Endianness based reader */
+2 -1
View File
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <ctrff/types.hpp> #include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff { namespace ctrff {
class BinFile { class BinFile {
+24
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
+8 -8
View File
@@ -1,16 +1,16 @@
#pragma once #pragma once
#include <ctrff/types.hpp> #include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff { namespace ctrff {
CTRFF_API void String2U16(ctrff::u16 *res, const std::string &src, size_t max); CTRFF_API void String2U16(PD::u16 *res, const std::string &src, size_t max);
CTRFF_API std::string U16toU8(ctrff::u16 *in, size_t max); CTRFF_API std::string U16toU8(PD::u16 *in, size_t max);
CTRFF_API void RGB565toRGBA(std::vector<ctrff::u8> &img, ctrff::u16 *icon, CTRFF_API void RGB565toRGBA(std::vector<PD::u8> &img, PD::u16 *icon,
const int &w, const int &h); const int &w, const int &h);
// Image can only be rgba8888 // 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); const int &w, const int &h);
CTRFF_API std::vector<ctrff::u8> DownscaleImage( CTRFF_API std::vector<PD::u8> DownscaleImage(const std::vector<PD::u8> &img,
const std::vector<ctrff::u8> &img, int w, int h, int scale); int w, int h, int scale);
CTRFF_API ctrff::u32 TileIndex(const int &x, const int &y, const int &w);
} // namespace ctrff } // namespace ctrff
+3 -2
View File
@@ -1,9 +1,10 @@
#pragma once #pragma once
#include <ctrff/types.hpp> #include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
namespace ctrff { namespace ctrff {
namespace LZ11 { 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 } // namespace ctrff
+44
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
@@ -23,7 +23,7 @@ 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
/*
#ifdef _WIN32 // Windows (MSVC Tested) #ifdef _WIN32 // Windows (MSVC Tested)
#ifdef CTRFF_BUILD_SHARED #ifdef CTRFF_BUILD_SHARED
#define CTRFF_API __declspec(dllexport) #define CTRFF_API __declspec(dllexport)
@@ -45,37 +45,6 @@ SOFTWARE.
#elif defined(__3DS__) // 3ds Specific #elif defined(__3DS__) // 3ds Specific
// Only Static supported // Only Static supported
#define CTRFF_API #define CTRFF_API
#else*/ #else
#define CTRFF_API #define CTRFF_API
//#endif #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
+30 -28
View File
@@ -2,7 +2,8 @@
#include <ctrff/binutil.hpp> #include <ctrff/binutil.hpp>
#include <ctrff/helper.hpp> #include <ctrff/helper.hpp>
#include <ctrff/types.hpp> #include <ctrff/pd_p_api.hpp>
#include <pd.hpp>
// Basic Info // Basic Info
// language_slots: 16 // language_slots: 16
@@ -15,15 +16,16 @@ namespace ctrff {
// SMDH Size (Note that this needs to be declared here as // SMDH Size (Note that this needs to be declared here as
// a sizeof(SMDH) will not return the expected size due to // a sizeof(SMDH) will not return the expected size due to
// use of Serializable) // use of Serializable)
constexpr ctrff::u32 SMDH_Size = 0x36C0; constexpr PD::u32 SMDH_Size = 0x36C0;
struct CTRFF_API SMDH { struct CTRFF_API SMDH {
SMDH() { SMDH() {
std::fill_n(Magic, ctrff::ArraySize(Magic), 0); std::fill_n(Magic, PD::ArraySize(Magic), 0);
std::fill_n(IconSmall, ctrff::ArraySize(IconSmall), 0); std::fill_n(IconSmall, PD::ArraySize(IconSmall), 0);
std::fill_n(IconLarge, ctrff::ArraySize(IconLarge), 0); std::fill_n(IconLarge, PD::ArraySize(IconLarge), 0);
} }
~SMDH() = default; ~SMDH() = default;
static SMDH Default(); static SMDH Default();
PD_SMART_CTOR(SMDH);
enum Language { enum Language {
Language_Japanese, Language_Japanese,
@@ -95,8 +97,8 @@ struct CTRFF_API SMDH {
void Write(std::fstream &f) const; void Write(std::fstream &f) const;
void Read(std::fstream &f); void Read(std::fstream &f);
void SetIcon(const std::vector<ctrff::u8> &buf); void SetIcon(const std::vector<PD::u8> &buf);
std::vector<ctrff::u8> GetIcon(); std::vector<PD::u8> GetIcon();
void SetShortTitle(const std::string &t, Language l = Language_All); void SetShortTitle(const std::string &t, Language l = Language_All);
void SetLongTitle(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); void SetAuthor(const std::string &t, Language l = Language_All);
@@ -106,36 +108,36 @@ struct CTRFF_API SMDH {
struct CTRFF_API Title { struct CTRFF_API Title {
Title() { Title() {
std::fill_n(ShortTitle, ctrff::ArraySize(ShortTitle), 0); std::fill_n(ShortTitle, PD::ArraySize(ShortTitle), 0);
std::fill_n(LongTitle, ctrff::ArraySize(LongTitle), 0); std::fill_n(LongTitle, PD::ArraySize(LongTitle), 0);
std::fill_n(Author, ctrff::ArraySize(Author), 0); std::fill_n(Author, PD::ArraySize(Author), 0);
}; };
ctrff::u16 ShortTitle[0x40]; PD::u16 ShortTitle[0x40];
ctrff::u16 LongTitle[0x80]; PD::u16 LongTitle[0x80];
ctrff::u16 Author[0x40]; PD::u16 Author[0x40];
}; };
struct CTRFF_API Settings { struct CTRFF_API Settings {
Settings() { std::fill_n(Ratings, ctrff::ArraySize(Ratings), 0); }; Settings() { std::fill_n(Ratings, PD::ArraySize(Ratings), 0); };
ctrff::u8 Ratings[16]; PD::u8 Ratings[16];
ctrff::u32 RegionLock = 0; PD::u32 RegionLock = 0;
ctrff::u32 MatchmakerID = 0; PD::u32 MatchmakerID = 0;
ctrff::u64 MatchmakerBitID = 0; PD::u64 MatchmakerBitID = 0;
ctrff::u32 Flags = 0; PD::u32 Flags = 0;
ctrff::u16 EulaVersion = 0; PD::u16 EulaVersion = 0;
ctrff::u16 Reserved = 0; PD::u16 Reserved = 0;
ctrff::u32 OptimalBannerFrame = 0; PD::u32 OptimalBannerFrame = 0;
ctrff::u32 StreetpassID = 0; PD::u32 StreetpassID = 0;
}; };
char Magic[4]; char Magic[4];
ctrff::u16 Version = 0; PD::u16 Version = 0;
ctrff::u16 Reserved = 0; PD::u16 Reserved = 0;
Title Titles[16]; Title Titles[16];
Settings Settings; Settings Settings;
ctrff::u64 Reserved1 = 0; PD::u64 Reserved1 = 0;
ctrff::u16 IconSmall[0x240]; // 24x24 PD::u16 IconSmall[0x240]; // 24x24
ctrff::u16 IconLarge[0x900]; // 48x48 PD::u16 IconLarge[0x900]; // 48x48
}; };
} // namespace ctrff } // namespace ctrff
-55
View File
@@ -1,55 +0,0 @@
#include <ctrff/bclim.hpp>
namespace ctrff {
CTRFF_API void BCLIM::Write(std::fstream& f) const {
f.write(reinterpret_cast<const char*>(pBuffer.data()), pBuffer.size());
f.write((const char*)&pCurrent.Magic, sizeof(pCurrent.Magic));
f.write((const char*)&pCurrent.Endianness, sizeof(pCurrent.Endianness));
f.write((const char*)&pCurrent.HeaderSize, sizeof(pCurrent.HeaderSize));
f.write((const char*)&pCurrent.Version, sizeof(pCurrent.Version));
f.write((const char*)&pCurrent.FileSize, sizeof(pCurrent.FileSize));
f.write((const char*)&pCurrent.NumSections, sizeof(pCurrent.NumSections));
f.write((const char*)&pImag.Magic, sizeof(pImag.Magic));
f.write((const char*)&pImag.HeaderSize, sizeof(pImag.HeaderSize));
f.write((const char*)&pImag.Width, sizeof(pImag.Width));
f.write((const char*)&pImag.Height, sizeof(pImag.Height));
f.write((const char*)&pImag.Format, sizeof(pImag.Format));
f.write((const char*)&pImag.ImageSize, sizeof(pImag.ImageSize));
}
CTRFF_API void BCLIM::Read(std::fstream& f) {
f.seekg(std::ios::end);
size_t size = f.tellg();
if (size < (sizeof(Header) + sizeof(ImagHeader))) {
throw std::runtime_error("Invalid File!");
}
f.seekg(size - sizeof(Header) - sizeof(ImagHeader));
Header h;
ImagHeader imag;
f.read(reinterpret_cast<char*>(&h), sizeof(h));
f.read(reinterpret_cast<char*>(&imag), sizeof(imag));
if (h.Magic != 0x4d494c43) {
throw std::runtime_error("[ctrff] BCLIM: Not a bclim file!");
}
if (imag.Magic != 0x67616d69) {
throw std::runtime_error("[ctrff] BCLIM: Invalid Data");
}
}
CTRFF_API void BCLIM::CreateByImage(const std::vector<u8>& data, int w, int h,
Format fmt) {
CreateMode = true;
pImag = ImagHeader::Default();
pCurrent = Header::Default();
pImag.Format = fmt;
pImag.Width = w;
pImag.Height = h;
pImag.ImageSize = data.size();
pBuffer.resize(data.size());
for (int i = 0; i < data.size(); i++) {
pBuffer[i] = data[i];
}
pCurrent.FileSize = pBuffer.size() + pCurrent.HeaderSize + pImag.HeaderSize;
pCurrent.NumSections = 1;
}
} // namespace ctrff
+33 -51
View File
@@ -1,7 +1,7 @@
#include <ctrff/bcstm.hpp> #include <ctrff/bcstm.hpp>
/** Using this a single time so inline it */ /** 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) | return (in >> 24) | ((in >> 8) & 0x0000FF00) | ((in << 8) & 0x00FF0000) |
(in << 24); (in << 24);
} }
@@ -28,7 +28,7 @@ CTRFF_API void BCSTM::LoadFile(const std::string& path) {
pReader.Read(pHeader.FileSize); pReader.Read(pHeader.FileSize);
pReader.Read(pHeader.NumBlocks); pReader.Read(pHeader.NumBlocks);
pReader.Read(pHeader.Reserved); pReader.Read(pHeader.Reserved);
for (ctrff::u16 i = 0; i < pHeader.NumBlocks; i++) { for (PD::u16 i = 0; i < pHeader.NumBlocks; i++) {
SizedReference ref; SizedReference ref;
ReadSizedReference(ref); ReadSizedReference(ref);
if (ref.Ref.TypeID == Ref_InfoBlock) { if (ref.Ref.TypeID == Ref_InfoBlock) {
@@ -61,6 +61,9 @@ CTRFF_API void BCSTM::ReadInfoBlock(InfoBlock& block) {
ReadReference(block.TrackInfoTabRef); ReadReference(block.TrackInfoTabRef);
ReadReference(block.ChannelInfoTabRef); ReadReference(block.ChannelInfoTabRef);
pReader.Read(block.StreamInfo.Encoding); 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.Loop);
pReader.Read(block.StreamInfo.ChannelCount); pReader.Read(block.StreamInfo.ChannelCount);
pReader.Read(block.StreamInfo.Padding); pReader.Read(block.StreamInfo.Padding);
@@ -94,10 +97,9 @@ CTRFF_API void BCSTM::ReadInfoBlock(InfoBlock& block) {
std::ios::beg); std::ios::beg);
Reference r; Reference r;
ReadReference(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++) {
for (size_t i = 0; i < block.ChannelInfoRefs.size(); i++) {
size_t off = pInfoBlockRef.Ref.Offset; size_t off = pInfoBlockRef.Ref.Offset;
off += sizeof(BlockHeader); off += sizeof(BlockHeader);
off += block.ChannelInfoTabRef.Offset; off += block.ChannelInfoTabRef.Offset;
@@ -106,8 +108,7 @@ CTRFF_API void BCSTM::ReadInfoBlock(InfoBlock& block) {
pFile.seekg(off, std::ios::beg); pFile.seekg(off, std::ios::beg);
DSP_ADPCM_Info t; /** temp */ DSP_ADPCM_Info t; /** temp */
pReader.ReadEx(t); /** This Section gets read normally */ pReader.ReadEx(t); /** This Section gets read normally */
pDSP_ADPCM_Info.push_back(t); 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!"); throw std::runtime_error("BCSTM: SeekBlock Size is not 0x20 aligned!");
} }
pSeekBlock.Data.reserve(pSeekBlock.Header.Size + 1); pSeekBlock.Data.Reserve(pSeekBlock.Header.Size + 1);
for (ctrff::u32 i = 0; i < pSeekBlock.Header.Size; i++) { for (PD::u32 i = 0; i < pSeekBlock.Header.Size; i++) {
ctrff::u8 v; PD::u8 v;
pReader.Read(v); pReader.Read(v);
pSeekBlock.Data.push_back(v); pSeekBlock.Data.Add(v);
} }
} }
CTRFF_API void BCSTM::ReadReferenceTab(ReferenceTable& tab) { CTRFF_API void BCSTM::ReadReferenceTab(ReferenceTable& tab) {
pReader.Read(tab.Count); pReader.Read(tab.Count);
tab.Refs.reserve(tab.Count + 1); tab.Refs.Reserve(tab.Count + 1);
for (ctrff::u32 i = 0; i < tab.Count; i++) { for (PD::u32 i = 0; i < tab.Count; i++) {
Reference r; Reference r;
pReader.Read(r.TypeID); pReader.Read(r.TypeID);
pReader.Read(r.Padding); pReader.Read(r.Padding);
pReader.Read(r.Offset); pReader.Read(r.Offset);
tab.Refs.push_back(r); tab.Refs.Add(r);
} }
} }
@@ -146,26 +147,28 @@ CTRFF_API void BCSTM::ReadGotoBeginning(bool use_loop_beg) {
size_t off = pDataBlockRef.Ref.Offset + 0x20; size_t off = pDataBlockRef.Ref.Offset + 0x20;
/** Shift to loop start if enabled */ /** Shift to loop start if enabled */
if (use_loop_beg) { 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); pFile.seekg(off, std::ios::beg);
} catch (const std::exception& e) {
throw std::runtime_error(e.what());
}
if (pFile.tellg() > pHeader.FileSize) { if (pFile.tellg() > pHeader.FileSize) {
throw std::runtime_error("BCSTM: Seeked Out of range!"); throw std::runtime_error("BCSTM: Seeked Out of range!");
} }
} }
CTRFF_API void BCSTM::ReadBlock(ctrff::u32 block, ctrff::u8* ref) { CTRFF_API void BCSTM::ReadBlock(PD::u32 block, PD::u8* ref) {
if (!ref) {
throw std::runtime_error("BCSTM: pointer ref is nullptr!");
}
if (pFile.tellg() > pHeader.FileSize || block >= GetNumBlocks()) { if (pFile.tellg() > pHeader.FileSize || block >= GetNumBlocks()) {
throw std::runtime_error(std::format( 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), pFile.read(
(block == (GetNumBlocks() - 1) reinterpret_cast<char*>(ref),
? pInfoBlock.StreamInfo.LastSampleBlockPaddedSize (block == (GetNumBlocks() - 1) ? pInfoBlock.StreamInfo.LastSampleBlockSize
: GetBlockSize())); : GetBlockSize()));
} }
@@ -177,32 +180,11 @@ CTRFF_API void BCSTM::CleanUp() {
throw std::runtime_error(e.what()); throw std::runtime_error(e.what());
} }
} }
pInfoBlock = InfoBlock(); pInfoBlock.ChannelInfoRefs.Clear();
pHeader = Header(); pInfoBlock.ChannelInfoTab.Refs.Clear();
pInfoBlockRef = SizedReference(); pInfoBlock.ChannelInfoTab.Count = 0;
pSeekBlockRef = SizedReference(); pInfoBlock.TrackInfoTab.Refs.Clear();
pDataBlockRef = SizedReference(); pInfoBlock.TrackInfoTab.Count = 0;
pInfoBlock = InfoBlock(); pDSP_ADPCM_Info.Clear();
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;
} }
} // namespace ctrff } // namespace ctrff
+19 -19
View File
@@ -1,7 +1,7 @@
#include <ctrff/bcwav.hpp> #include <ctrff/bcwav.hpp>
/** Using this a single time so inline it */ /** 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) | return (in >> 24) | ((in >> 8) & 0x0000FF00) | ((in << 8) & 0x00FF0000) |
(in << 24); (in << 24);
} }
@@ -28,7 +28,7 @@ CTRFF_API void BCWAV::LoadFile(const std::string& path) {
pReader.Read(pHeader.FileSize); pReader.Read(pHeader.FileSize);
pReader.Read(pHeader.NumBlocks); pReader.Read(pHeader.NumBlocks);
pReader.Read(pHeader.Reserved); pReader.Read(pHeader.Reserved);
for (ctrff::u16 i = 0; i < pHeader.NumBlocks; i++) { for (PD::u16 i = 0; i < pHeader.NumBlocks; i++) {
SizedReference ref; SizedReference ref;
ReadSizedReference(ref); ReadSizedReference(ref);
if (ref.Ref.TypeID == Ref_InfoBlock) { if (ref.Ref.TypeID == Ref_InfoBlock) {
@@ -67,10 +67,9 @@ CTRFF_API void BCWAV::ReadInfoBlock(InfoBlock& block) {
std::ios::beg); std::ios::beg);
Reference r; Reference r;
ReadReference(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++) {
for (size_t i = 0; i < block.ChannelInfoRefs.size(); i++) {
size_t off = pInfoBlockRef.Ref.Offset; size_t off = pInfoBlockRef.Ref.Offset;
off += sizeof(BlockHeader); off += sizeof(BlockHeader);
off += block.ChannelInfoTab.Refs[i].Offset; off += block.ChannelInfoTab.Refs[i].Offset;
@@ -78,20 +77,19 @@ CTRFF_API void BCWAV::ReadInfoBlock(InfoBlock& block) {
pFile.seekg(off, std::ios::beg); pFile.seekg(off, std::ios::beg);
DSP_ADPCM_Info t; /** temp */ DSP_ADPCM_Info t; /** temp */
pReader.ReadEx(t); /** This Section gets read normally */ pReader.ReadEx(t); /** This Section gets read normally */
pDSP_ADPCM_Info.push_back(t); pDSP_ADPCM_Info.Add(t);
}
} }
} }
CTRFF_API void BCWAV::ReadReferenceTab(ReferenceTable& tab) { CTRFF_API void BCWAV::ReadReferenceTab(ReferenceTable& tab) {
pReader.Read(tab.Count); pReader.Read(tab.Count);
tab.Refs.reserve(tab.Count + 1); tab.Refs.Reserve(tab.Count + 1);
for (ctrff::u32 i = 0; i < tab.Count; i++) { for (PD::u32 i = 0; i < tab.Count; i++) {
Reference r; Reference r;
pReader.Read(r.TypeID); pReader.Read(r.TypeID);
pReader.Read(r.Padding); pReader.Read(r.Padding);
pReader.Read(r.Offset); 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 */ /** Shift to loop start if enabled */
if (use_loop_beg) { if (use_loop_beg) {
// off += GetNumBlocks() * GetNumChannels() * GetLoopStart(); // off += GetNumBlocks() * GetNumChannels() * GetLoopStart();
// off += GetNumChannels() * pInfoBlock.StreamInfo.LoopStartFrame;
} }
// block_size * channel_count * loop_start
try {
pFile.seekg(off, std::ios::beg); pFile.seekg(off, std::ios::beg);
} catch (const std::exception& e) {
throw std::runtime_error(e.what());
}
if (pFile.tellg() > pHeader.FileSize) { if (pFile.tellg() > pHeader.FileSize) {
throw std::runtime_error("BCWAV: Seeked Out of range!"); 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()) { // if (pFile.tellg() > pHeader.FileSize || block >= GetNumBlocks()) {
// throw std::runtime_error("BCWAV: Decode block Out of range!"); // 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()); throw std::runtime_error(e.what());
} }
} }
pInfoBlock = InfoBlock(); pInfoBlock.ChannelInfoRefs.Clear();
pHeader = Header(); pInfoBlock.ChannelInfoTab.Refs.Clear();
pInfoBlockRef = SizedReference(); pInfoBlock.ChannelInfoTab.Count = 0;
pDataBlockRef = SizedReference(); pDSP_ADPCM_Info.Clear();
// Does not get read idk why i added it
// cause it needs to be streamed
pDataBlock = DataBlock();
pDSP_ADPCM_Info.clear();
} }
} // namespace ctrff } // namespace ctrff
+11 -11
View File
@@ -2,22 +2,22 @@
namespace ctrff { namespace ctrff {
/** Supported reads */ /** Supported reads */
template CTRFF_API void BinUtil::Read<ctrff::u8>(ctrff::u8&); template CTRFF_API void BinUtil::Read<PD::u8>(PD::u8&);
template CTRFF_API void BinUtil::Read<ctrff::u16>(ctrff::u16&); template CTRFF_API void BinUtil::Read<PD::u16>(PD::u16&);
template CTRFF_API void BinUtil::Read<ctrff::u32>(ctrff::u32&); template CTRFF_API void BinUtil::Read<PD::u32>(PD::u32&);
template CTRFF_API void BinUtil::Read<ctrff::u64>(ctrff::u64&); template CTRFF_API void BinUtil::Read<PD::u64>(PD::u64&);
/** Supported writes */ /** Supported writes */
template CTRFF_API void BinUtil::Write<ctrff::u8>(const ctrff::u8&); template CTRFF_API void BinUtil::Write<PD::u8>(const PD::u8&);
template CTRFF_API void BinUtil::Write<ctrff::u16>(const ctrff::u16&); template CTRFF_API void BinUtil::Write<PD::u16>(const PD::u16&);
template CTRFF_API void BinUtil::Write<ctrff::u32>(const ctrff::u32&); template CTRFF_API void BinUtil::Write<PD::u32>(const PD::u32&);
template CTRFF_API void BinUtil::Write<ctrff::u64>(const ctrff::u64&); template CTRFF_API void BinUtil::Write<PD::u64>(const PD::u64&);
template <typename T> template <typename T>
void BinUtil::Read(T& v) { void BinUtil::Read(T& v) {
// Check if Value could be Read // Check if Value could be Read
static_assert(std::is_integral<T>::value, "Cannot Read type T"); static_assert(std::is_integral<T>::value, "Cannot Read type T");
v = 0; // Set value to 0 (most cases a windows problem) 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 // Read data into buffer
m_file.read(reinterpret_cast<char*>(buf.data()), sizeof(T)); m_file.read(reinterpret_cast<char*>(buf.data()), sizeof(T));
// Loop or in be reverse loop and chift the values // Loop or in be reverse loop and chift the values
@@ -29,11 +29,11 @@ template <typename T>
void BinUtil::Write(const T& v) { void BinUtil::Write(const T& v) {
// Check if Value could Write // Check if Value could Write
static_assert(std::is_integral<T>::value, "Cannot Write type T"); 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 // Loop or in be reverse loop and write the values
for (size_t i = 0; i < sizeof(T); i++) { 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] = 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 // Write buffer into file
m_file.write(reinterpret_cast<const char*>(buf.data()), sizeof(T)); m_file.write(reinterpret_cast<const char*>(buf.data()), sizeof(T));
+26 -30
View File
@@ -2,34 +2,31 @@
#include <cwchar> #include <cwchar>
#include <iostream> #include <iostream>
void MakePixelRGBA(ctrff::u8 &r, ctrff::u8 &g, ctrff::u8 &b, ctrff::u8 &a, void MakePixelRGBA(PD::u8 &r, PD::u8 &g, PD::u8 &b, PD::u8 &a, PD::u16 px) {
ctrff::u16 px) {
b = (px & 0x1f) << 3; b = (px & 0x1f) << 3;
g = ((px >> 0x5) & 0x3f) << 2; g = ((px >> 0x5) & 0x3f) << 2;
r = ((px >> 0xb) & 0x1f) << 3; r = ((px >> 0xb) & 0x1f) << 3;
a = 0xff; a = 0xff;
} }
CTRFF_API ctrff::u16 MakePixel565(const ctrff::u8 &r, const ctrff::u8 &g, CTRFF_API PD::u16 MakePixel565(const PD::u8 &r, const PD::u8 &g,
const ctrff::u8 &b) { const PD::u8 &b) {
ctrff::u16 res = 0; PD::u16 res = 0;
res |= (r & ~0x7) << 8; res |= (r & ~0x7) << 8;
res |= (g & ~0x3) << 3; res |= (g & ~0x3) << 3;
res |= (b) >> 3; res |= (b) >> 3;
return res; return res;
} }
CTRFF_API ctrff::u32 ctrff::TileIndex(const int &x, const int &y, CTRFF_API PD::u32 TileIndex(const int &x, const int &y, const int &w) {
const int &w) {
return (((y >> 3) * (w >> 3) + (x >> 3)) << 6) + return (((y >> 3) * (w >> 3) + (x >> 3)) << 6) +
((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) |
((x & 4) << 2) | ((y & 4) << 3)); ((x & 4) << 2) | ((y & 4) << 3));
} }
// TODO: Fix colors // TODO: Fix colors
CTRFF_API void ctrff::RGB565toRGBA(std::vector<ctrff::u8> &img, CTRFF_API void ctrff::RGB565toRGBA(std::vector<PD::u8> &img, PD::u16 *icon,
ctrff::u16 *icon, const int &w, const int &w, const int &h) {
const int &h) {
if (img.size() != (48 * 48 * 4)) { if (img.size() != (48 * 48 * 4)) {
img.resize(48 * 48 * 4); img.resize(48 * 48 * 4);
img.clear(); img.clear();
@@ -37,37 +34,36 @@ CTRFF_API void ctrff::RGB565toRGBA(std::vector<ctrff::u8> &img,
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) { for (int x = 0; x < w; x++) {
auto idx = TileIndex(x, y, w); 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], MakePixelRGBA(img[pos + 0], img[pos + 1], img[pos + 2], img[pos + 3],
icon[idx]); icon[idx]);
} }
} }
} }
CTRFF_API void ctrff::RGBA2RGB565(ctrff::u16 *out, CTRFF_API void ctrff::RGBA2RGB565(PD::u16 *out, const std::vector<PD::u8> &img,
const std::vector<ctrff::u8> &img,
const int &w, const int &h) { const int &w, const int &h) {
if (img.size() != size_t(w * h * 4)) return; 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 y = 0; y < h; y++) {
for (int x = 0; x < w; x++) { for (int x = 0; x < w; x++) {
auto idx = TileIndex(x, y, w); 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]); out[idx] = MakePixel565(img[pos], img[pos + 1], img[pos + 2]);
} }
} }
} }
CTRFF_API std::vector<ctrff::u8> ctrff::DownscaleImage( CTRFF_API std::vector<PD::u8> ctrff::DownscaleImage(
const std::vector<ctrff::u8> &img, int w, int h, int scale) { const std::vector<PD::u8> &img, int w, int h, int scale) {
std::vector<ctrff::u8> res(((w / scale) * (h / scale)) * 4); std::vector<PD::u8> res(((w / scale) * (h / scale)) * 4);
int samples = scale * scale; int samples = scale * scale;
for (int y = 0; y < h; y += scale) { for (int y = 0; y < h; y += scale) {
for (int x = 0; x < w; x += scale) { for (int x = 0; x < w; x += scale) {
ctrff::u32 r = 0; PD::u32 r = 0;
ctrff::u32 g = 0; PD::u32 g = 0;
ctrff::u32 b = 0; PD::u32 b = 0;
ctrff::u32 a = 0; PD::u32 a = 0;
for (int oy = 0; oy < scale; oy++) { for (int oy = 0; oy < scale; oy++) {
for (int ox = 0; ox < scale; ox++) { for (int ox = 0; ox < scale; ox++) {
int pos = ((y + oy) * w + (x + ox)) * 4; int pos = ((y + oy) * w + (x + ox)) * 4;
@@ -78,16 +74,16 @@ CTRFF_API std::vector<ctrff::u8> ctrff::DownscaleImage(
} }
} }
int pos = ((y / scale) * (w / scale) + (x / scale)) * 4; int pos = ((y / scale) * (w / scale) + (x / scale)) * 4;
res[pos++] = (ctrff::u8)(r / samples); res[pos++] = (PD::u8)(r / samples);
res[pos++] = (ctrff::u8)(g / samples); res[pos++] = (PD::u8)(g / samples);
res[pos++] = (ctrff::u8)(b / samples); res[pos++] = (PD::u8)(b / samples);
res[pos++] = (ctrff::u8)(a / samples); res[pos++] = (PD::u8)(a / samples);
} }
} }
return res; 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) { size_t max) {
/// GOT FORCED TO REPLACE std::wstring_convert by some /// GOT FORCED TO REPLACE std::wstring_convert by some
/// manual work as it got removed in cxx20 /// manual work as it got removed in cxx20
@@ -97,7 +93,7 @@ CTRFF_API void ctrff::String2U16(ctrff::u16 *res, const std::string &src,
size_t len = 0; size_t len = 0;
size_t i = 0; size_t i = 0;
while (i < src.size() && len < max) { while (i < src.size() && len < max) {
ctrff::u8 c = src[i]; PD::u8 c = src[i];
if (c < 0x80) { if (c < 0x80) {
// 1byte // 1byte
@@ -120,7 +116,7 @@ CTRFF_API void ctrff::String2U16(ctrff::u16 *res, const std::string &src,
// 4byte // 4byte
if (i + 3 >= src.size()) if (i + 3 >= src.size())
throw std::invalid_argument("Invalid UTF-8 sequence"); throw std::invalid_argument("Invalid UTF-8 sequence");
ctrff::u32 codepoint = ((c & 0x07) << 18) | ((src[i + 1] & 0x3F) << 12) | PD::u32 codepoint = ((c & 0x07) << 18) | ((src[i + 1] & 0x3F) << 12) |
((src[i + 2] & 0x3F) << 6) | (src[i + 3] & 0x3F); ((src[i + 2] & 0x3F) << 6) | (src[i + 3] & 0x3F);
codepoint -= 0x10000; codepoint -= 0x10000;
res[len++] = 0xD800 | ((codepoint >> 10) & 0x3FF); res[len++] = 0xD800 | ((codepoint >> 10) & 0x3FF);
@@ -132,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 /// GOT FORCED TO REPLACE std::wstring_convert by some
/// manual work as it got removed in cxx20 /// manual work as it got removed in cxx20
if (!in || max == 0) { if (!in || max == 0) {
+41 -54
View File
@@ -5,20 +5,20 @@
namespace ctrff { namespace ctrff {
namespace LZ11 { namespace LZ11 {
ctrff::u32 GetOccurenceLength(const ctrff::u8* new_ptr, u32 new_len, PD::u32 GetOccurenceLength(const PD::u8* new_ptr, size_t new_len,
const ctrff::u8* old_ptr, u32 old_len, const PD::u8* old_ptr, size_t old_len,
ctrff::u32& disp) { PD::u32& disp) {
disp = 0; disp = 0;
if (new_len == 0) { if (new_len == 0) {
return 0; return 0;
} }
ctrff::u32 res = 0; PD::u32 res = 0;
if (old_len > 0) { if (old_len > 0) {
for (u32 i = 0; i < old_len - 1; i++) { for (size_t i = 0; i < old_len - 1; i++) {
auto ref = old_ptr + i; auto ref = old_ptr + i;
u32 len = 0; size_t len = 0;
for (u32 j = 0; j < new_len; j++) { for (size_t j = 0; j < new_len; j++) {
if (*(ref + j) != *(new_ptr + j)) { if (*(ref + j) != (*new_ptr + j)) {
break; break;
} }
len++; len++;
@@ -35,73 +35,59 @@ ctrff::u32 GetOccurenceLength(const ctrff::u8* new_ptr, u32 new_len,
return res; 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) { if (in.size() > 0xFFFFFF) {
std::cout << "ERROR: LZ11 input is too large!" << std::endl; std::cout << "ERROR: LZ11 input is too large!" << std::endl;
return std::vector<ctrff::u8>(); return std::vector<PD::u8>();
} }
std::stringstream s; std::stringstream s;
struct header {
u8 Magic;
u8 Size1;
u8 Size2;
u8 Size3;
};
header hdr;
hdr.Magic = 0x11;
hdr.Size1 = in.size() & 0xFF;
hdr.Size2 = (in.size() >> 8) & 0xFF;
hdr.Size3 = (in.size() >> 16) & 0xFF;
// SETUP HEADER // // SETUP HEADER //
s.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr)); 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);
u32 res_len = 4; // 4-byte header size_t res_len = 4; // 4-byte header
ctrff::u8 out_buf[0x21]; // 33 bytes PD::u8 out_buf[0x21]; // 33 bytes
memset(out_buf, 0x0, sizeof(out_buf)); out_buf[0] = 0;
u32 obl = 1; // out_buf_len size_t obl = 1; // out_buf_len
u32 buf_blocks = 0; size_t buf_blocks = 0;
u32 rb = 0; size_t rb = 0;
while (rb < in.size()) { while (rb < in.size()) {
if (buf_blocks == 8) { if (buf_blocks == 8 || obl >= sizeof(out_buf) - 3) {
s.write(reinterpret_cast<const char*>(out_buf), obl); s.write(reinterpret_cast<const char*>(out_buf), obl);
res_len += obl; res_len += obl;
memset(out_buf, 0x0, sizeof(out_buf)); out_buf[0] = 0;
obl = 1; obl = 1;
buf_blocks = 0; buf_blocks = 0;
} }
ctrff::u32 disp = 0; PD::u32 disp = 0;
u32 old_len = std::min(rb, static_cast<u32>(0x1000)); size_t old_len = std::min(rb, static_cast<size_t>(0x1000));
u32 len = LZ11::GetOccurenceLength( size_t len = LZ11::GetOccurenceLength(
in.data() + rb, in.data() + rb, std::min(in.size() - rb, static_cast<size_t>(0x10110)),
std::min((u32)in.size() - rb, static_cast<u32>(0x10110)),
in.data() + rb - old_len, old_len, disp); in.data() + rb - old_len, old_len, disp);
if (len < 3) { if (len < 3) {
out_buf[obl++] = in[rb++]; out_buf[obl++] = in[rb++];
} else { } else {
rb += len; 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) { if (len > 0x110) {
out_buf[obl] = 0x10; out_buf[obl++] =
out_buf[obl] |= static_cast<ctrff::u8>(((len - 0x111) >> 12) & 0x0F); 0x10 | static_cast<PD::u8>(((len - 0x111) >> 12) & 0x0F);
obl++; out_buf[obl++] = static_cast<PD::u8>(((len - 0x111) >> 4) & 0xFF);
out_buf[obl] = static_cast<ctrff::u8>(((len - 0x111) >> 4) & 0xFF); out_buf[obl] = static_cast<PD::u8>(((len - 0x111) << 4) & 0xF0);
obl++;
out_buf[obl] = static_cast<ctrff::u8>(((len - 0x111) << 4) & 0xF0);
} else if (len > 0x10) { } else if (len > 0x10) {
out_buf[obl] = 0x00; out_buf[obl++] = 0x00 | static_cast<PD::u8>(((len - 0x11) >> 4) & 0x0F);
out_buf[obl] |= static_cast<ctrff::u8>(((len - 0x111) >> 4) & 0x0F); out_buf[obl] = static_cast<PD::u8>(((len - 0x11) << 4) & 0xF0);
obl++;
out_buf[obl] = static_cast<ctrff::u8>(((len - 0x111) << 4) & 0xF0);
} else { } else {
out_buf[obl] = static_cast<ctrff::u8>(((len - 1) << 4) & 0xF0); out_buf[obl] |= static_cast<PD::u8>(((len - 1) << 4) & 0xF0);
} }
out_buf[obl] |= static_cast<ctrff::u8>(((disp - 1) >> 8) & 0x0F);
obl++;
out_buf[obl] = static_cast<ctrff::u8>((disp - 1) & 0xFF);
obl++; obl++;
out_buf[obl++] = static_cast<PD::u8>(((disp - 1) >> 8) & 0x0F);
out_buf[obl++] = static_cast<PD::u8>((disp - 1) & 0xFF);
} }
buf_blocks++; buf_blocks++;
} }
@@ -112,14 +98,15 @@ CTRFF_API std::vector<ctrff::u8> Compress(const std::vector<ctrff::u8>& in) {
} }
if (res_len % 4 != 0) { if (res_len % 4 != 0) {
ctrff::u32 pad_len = 4 - (res_len % 4); PD::u32 pad_len = 4 - (res_len % 4);
ctrff::u8 pad[4] = {0}; PD::u8 pad[4] = {0};
s.write(reinterpret_cast<const char*>(pad), pad_len); s.write(reinterpret_cast<const char*>(pad), pad_len);
res_len += pad_len; res_len += pad_len;
} }
std::string tmp = s.str(); std::vector<PD::u8> res(res_len);
return std::vector<u8>(tmp.begin(), tmp.end()); s.read(reinterpret_cast<char*>(res.data()), res.size());
return res;
} }
} // namespace LZ11 } // namespace LZ11
} // namespace ctrff } // namespace ctrff
+3 -3
View File
@@ -39,14 +39,14 @@ CTRFF_API void ctrff::SMDH::Read(std::fstream &f) {
f.read(reinterpret_cast<char *>(&IconLarge), sizeof(IconLarge)); 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); RGBA2RGB565(IconLarge, buf, 48, 48);
auto small_icon = DownscaleImage(buf, 48, 48, 2); auto small_icon = DownscaleImage(buf, 48, 48, 2);
RGBA2RGB565(IconSmall, small_icon, 24, 24); RGBA2RGB565(IconSmall, small_icon, 24, 24);
} }
CTRFF_API std::vector<ctrff::u8> ctrff::SMDH::GetIcon() { CTRFF_API std::vector<PD::u8> ctrff::SMDH::GetIcon() {
std::vector<ctrff::u8> res(48 * 48 * 4); std::vector<PD::u8> res(48 * 48 * 4);
ctrff::RGB565toRGBA(res, IconLarge, 48, 48); ctrff::RGB565toRGBA(res, IconLarge, 48, 48);
return res; return res;
} }
+3 -79
View File
@@ -5,7 +5,6 @@
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <map> #include <map>
#include <palladium>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -122,7 +121,7 @@ void MakeSMDH(const cf7::command::ArgumentList &data) {
smdh.SetAuthor(a); smdh.SetAuthor(a);
std::vector<unsigned char> img; std::vector<unsigned char> img;
int w, h, c; 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) { if (buf == nullptr) {
cf7::PrintFancy({ cf7::PrintFancy({
std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Error", cf7::col(190, 0, 0)),
@@ -443,76 +442,9 @@ void LZ11Compress(const cf7::command::ArgumentList &data) {
out.close(); out.close();
} }
void BCLIMMaker(const cf7::command::ArgumentList &data) {
std::string i = cf7::command::GetArg(data, "input");
std::string o = cf7::command::GetArg(data, "output");
std::string f = cf7::command::GetArg(data, "format");
if (i.empty() || o.empty()) {
std::cout << "[ctrff] BCLIM: Error, no input or output" << std::endl;
return;
}
if (f.empty() || (f.compare("rgba32") != 0 && f.compare("a8") != 0 &&
f.compare("rgb565") != 0)) {
f = "a8";
}
int w = 0, h = 0, c = 0;
auto ret = stbi_load(i.c_str(), &w, &h, &c, 4);
if (!ret) {
std::cout << "[ctrff] BCLIM: Failed to load image " + i << std::endl;
return;
}
if (!PD::BitUtil::IsSingleBit(w) || !PD::BitUtil::IsSingleBit(h)) {
std::cout << "[ctrff] BCLIM: Image with and height must be a power of 8!";
return;
}
size_t size = w * h;
if (f == "rgba32") {
size *= 4;
} else if (f == "rgb565") {
size *= 2;
}
std::vector<ctrff::u8> res(size);
if (f == "rgba32" || f == "a8") {
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4;
int dst = ctrff::TileIndex(x, y, w);
if (f == "rgba32") {
dst *= 4;
res[dst + 3] = ret[src + 0];
res[dst + 2] = ret[src + 1];
res[dst + 1] = ret[src + 2];
res[dst + 0] = ret[src + 3];
} else {
res[dst] = ret[src + 3];
}
}
}
} else if (f == "rgb565") {
std::vector<ctrff::u16> res16(w * h);
ctrff::RGBA2RGB565(res16.data(),
std::vector<ctrff::u8>(ret, ret + (w * h * 4)), w, h);
for (int i = 0; i < res16.size(); i++) {
int pos = i * 2;
res[pos] = (ctrff::u8)(res16[i] & 0xff);
res[pos + 1] = (ctrff::u8)((res16[i] >> 8) & 0xff);
}
}
ctrff::BCLIM file;
ctrff::BCLIM::Format fmt = ctrff::BCLIM::A8;
if (f == "rgba32") {
fmt = ctrff::BCLIM::RGBA8888;
} else if (f == "rgb565") {
fmt = ctrff::BCLIM::RGB565;
}
file.CreateByImage(res, w, h, fmt);
file.Save(o);
std::cout << "File " + o + " created" << std::endl;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
cf7::fancy_print = false; cf7::fancy_print = true;
cf7::colors_supported = false; cf7::colors_supported = true;
cf7::arg_mgr mgr(argc, argv); cf7::arg_mgr mgr(argc, argv);
mgr.SetAppInfo("ctrff", "1.0.0"); mgr.SetAppInfo("ctrff", "1.0.0");
auto makesmdh_cmd = cf7::command("makesmdh", "Create a SMDH File"); auto makesmdh_cmd = cf7::command("makesmdh", "Create a SMDH File");
@@ -565,14 +497,6 @@ int main(int argc, char *argv[]) {
cf7::command("hex", "Show Hex view of a File") cf7::command("hex", "Show Hex view of a File")
.AddSubEntry(cf7::command::sub("i", "input", "Input File path", true)) .AddSubEntry(cf7::command::sub("i", "input", "Input File path", true))
.SetFunction(Hex)); .SetFunction(Hex));
mgr.AddCommand(
cf7::command("makebclim", "Create CTR Layout Image")
.AddSubEntry(cf7::command::sub("i", "input", "Input png|bmp", true))
.AddSubEntry(cf7::command::sub("o", "output",
"Output path of .bclim file", true))
.AddSubEntry(cf7::command::sub("f", "format",
"Image format rgba32|rgb565|a8", true))
.SetFunction(BCLIMMaker));
mgr.Execute(); mgr.Execute();
return 0; return 0;
} }
+8 -8
View File
@@ -16,20 +16,20 @@ void Result(const std::string& name, T a, T b) {
void BinTest(bool be) { void BinTest(bool be) {
std::fstream s("test.bin", std::ios::out | std::ios::binary); std::fstream s("test.bin", std::ios::out | std::ios::binary);
ctrff::u8 t8 = 0xdf; PD::u8 t8 = 0xdf;
ctrff::u16 t16 = 0x4564; PD::u16 t16 = 0x4564;
ctrff::u32 t32 = 0x58464743; PD::u32 t32 = 0x58464743;
ctrff::u64 t64 = 1234567890123456789ULL; PD::u64 t64 = 1234567890123456789ULL;
ctrff::BinUtil u(s, be); ctrff::BinUtil u(s, be);
u.Write(t8); u.Write(t8);
u.Write(t16); u.Write(t16);
u.Write(t32); u.Write(t32);
u.Write(t64); u.Write(t64);
s.close(); s.close();
ctrff::u8 r8 = 0; PD::u8 r8 = 0;
ctrff::u16 r16 = 0; PD::u16 r16 = 0;
ctrff::u32 r32 = 0; PD::u32 r32 = 0;
ctrff::u64 r64 = 0; PD::u64 r64 = 0;
s.open("test.bin", std::ios::in | std::ios::binary); s.open("test.bin", std::ios::in | std::ios::binary);
u.Read(r8); u.Read(r8);
u.Read(r16); u.Read(r16);