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
33 changed files with 799 additions and 1478 deletions
-321
View File
@@ -1,321 +0,0 @@
---
Language: Cpp
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: BinPack
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: Yes
ColumnLimit: 80
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: "^<.*"
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: ".*"
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: "([-_](test|unittest))?$"
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: true
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ""
MacroBlockEnd: ""
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
PPIndentWidth: -1
QualifierAlignment: Leave
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- "c++"
- "C++"
CanonicalDelimiter: ""
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: pb
BasedOnStyle: google
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Auto
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...
+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
+13 -18
View File
@@ -7,12 +7,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED true)
option(CTRFF_DESKTOP OFF "Buid for Desktop Platform") option(CTRFF_DESKTOP OFF "Buid for Desktop Platform")
option(CTRFF_3DS OFF "Build lib for 3ds") option(CTRFF_3DS OFF "Build lib for 3ds")
option(CTRFF_SHARED OFF)
if(${CTRFF_3DS}) if(${CTRFF_3DS})
set(CTRFF_DESKTOP OFF CACHE BOOL) set(CTRFF_DESKTOP OFF CACHE BOOL)
set(CTRFF_BUILD_GUI OFF CACHE BOOL) set(CTRFF_BUILD_GUI OFF CACHE BOOL)
set(CTRFF_SHARED OFF CACHE BOOL)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
if(DEFINED ENV{DEVKITPRO}) if(DEFINED ENV{DEVKITPRO})
set(CMAKE_TOOLCHAIN_FILE "$ENV{DEVKITPRO}/cmake/3DS.cmake" CACHE PATH "toolchain file") set(CMAKE_TOOLCHAIN_FILE "$ENV{DEVKITPRO}/cmake/3DS.cmake" CACHE PATH "toolchain file")
@@ -21,31 +19,28 @@ 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()
set(CTRFF_SOURCE 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/pica.cpp
source/smdh.cpp source/smdh.cpp
source/binutil.cpp
source/bcstm.cpp
source/bcwav.cpp
source/3dsx.cpp
) )
if(${CTRFF_SHARED})
add_library(ctrff SHARED ${CTRFF_SOURCE})
target_compile_definitions(ctrff PUBLIC CTRFF_SHARED)
target_compile_definitions(ctrff PRIVATE CTRFF_BUILD_SHARED)
else()
add_library(ctrff STATIC ${CTRFF_SOURCE})
endif()
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(tools) add_executable(ctrff-cli tool/main.cpp)
target_include_directories(ctrff-cli PUBLIC include vendor/stb vendor/cli-fancy/include)
target_link_libraries(ctrff-cli PUBLIC ctrff)
add_executable(test tool/test.cpp)
target_include_directories(test PUBLIC include vendor/stb vendor/cli-fancy/include)
target_link_libraries(test PUBLIC ctrff)
endif() endif()
install(TARGETS ctrff) install(TARGETS ctrff)
+4 -4
View File
@@ -4,7 +4,7 @@ Tool/Library to work with Nintendo 3ds File formats
## Note ## Note
The Docs can be found in the [Wiki](https://github.com/tobid7/ctrff/wiki) now. **CTRFF Requires Palladium Headers from branch devel040 (as this is the branch the lib was latest tested with)**
## Building ## Building
@@ -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 A4,A8,LA4,LA8,L4,L8,RGB24,RGBA32,RGBA4444,RGB565 done | WIP | | bclim | Nothing done yet (Started creating header) | |
| lz11 | Encoder done, Decoder done | | | 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 | |
+178
View File
@@ -0,0 +1,178 @@
# BCSTM File Format
**Note that this Docs are based on Current State of development and are very unfinished**
## Contents
- 1 [Header](#header)
- 2 [Reference](#reference)
- 2.1 [Sized Reference](#sized-reference)
- 2.2 [Reference Table](#reference-table)
- 2.3 [Reference Types](#reference-types)
- 3 [Block Header](#block-header)
- 4 [Info Block](#info-block)
- 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)
- 6 [Basic Data Types](#basic-datatypes)
- 7 [Tools Devices used for Research](#tools--devices--file-sources-used-for-research)
## Header
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 4 | [u32](#u32) | Magic **'CSTM'** `0x4D545343` |
| 0x04 | 2 | [u16](#u16) | Endianness `Big == 0xfffe` `Little == 0xfeff` |
| 0x06 | 2 | [u16](#u16) | Header Size `0x40` |
| 0x08 | 4 | [u32](#u32) | Version |
| 0x0c | 4 | [u32](#u32) | File Size |
| 0x10 | 2 | [u16](#u16) | Num Blocks (Should be 3) |
| 0x12 | 2 | [u16](#u16) | Reserved |
| 0x14 | 12 | [Sized Reference](#sized-reference) | Info Block Sized Reference |
| 0x20 | 12 | [Sized Reference](#sized-reference) | Seek Block Sized Reference |
| 0x2c | 12| [Sized Reference](#sized-reference) | Data Block Sized Reference |
## Reference
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 2 | [Reference Type](#reference-types) | TypeID |
| 0x02 | 2 | [u16](u16) | Padding |
| 0x04 | 4 | [u32](u32) | Offset **(0xffffffff represents null)** |
### Sized Reference
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 8 | [Reference](#reference) | Reference |
| 0x08 | 4 | [u32](u32) | Size |
### Reference Table
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 4 | [u32](#u32) | Count |
| 0x04 | Count*8 | [Reference](#reference) | References |
### Reference Types
| ID | Type |
|---|---|
| 0x0100 | Byte Table |
| 0x0101 | [Reference Table](#reference-table) |
| 0x0300 | [DSP ADPCM Info](#dsp-adpcm-info) |
| 0x0301 | IMA ADPCM Info |
| 0x1f00 | Sample Data |
| 0x4000 | [Info Block](#info-block) |
| 0x4001 | Seek Block |
| 0x4002 | Data Block |
| 0x4100 | [Stream Info](#stream-info) |
| 0x4101 | Track Info |
| 0x4102 | [Channel Info](#channel-info) |
## Block Header
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 4 | [u32](#u32) | Magic |
| 0x04 | 4 | [u32](#u32) | Size |
## Info Block
All Reference Offsets at the beginning of Info Block are Relative to the **Infoblock + 0x08 (size of Block Header) Position**
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 8 | [Block Header](#block-header) | Block Header |
| 0x08 | 8 | [Reference](#reference) | Stream Info Reference |
| 0x10 | 8 | [Reference](#reference) | Track Info Reference Table Reference |
| 0x18 | 8 | [Reference](#reference) | Channel Info Reference Table Table Reference |
| 0x20 | 56 | [Stream Info](#stream-info) | Stream Info |
### 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 |
|---|---|---|---|
| 0x00 | 8 | [Reference](#reference) | Reference to [DSP ADPCM Info](#dsp-adpcm-info) **!!! The Offsets are Relative to the start Pos of the Channel Info Object !!!** |
## DSP ADPCM Info
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 32 | [Param](#dsp-adpcm-param) | Coefficients |
| 0x20 | 6 | [DSP Context](#dsp-adpcm-context) | Context |
| 0x26 | 6 | [DSP Context](#dsp-adpcm-context) | Loop Context |
| 0x2c | 2 | [u16](#u16) | Padding |
### DSP ADPCM Param
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 32 | [u16](#u16) | 16 Bit Coefficients |
### DSP ADPCM Context
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 1 | [u8](#u8) | 4Bit Predictor and 4Bit Scale |
| 0x01 | 1 | [u8](#u8) | Reserved |
| 0x02 | 2 | [16](#u16) | Previous Sample |
| 0x02 | 2 | [16](#u16) | Second Previous Sample |
## Basic Datatypes
### u32
```cpp
using u32 = unsigned int; // or uint32_t
```
### u16
```cpp
using u16 = unsigned short; // or uint16_t
```
### u8
```cpp
using u8 = unsigned char; // or uint8_t
```
## 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 |
| 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 | Used to get Test files |
+178
View File
@@ -0,0 +1,178 @@
# BCWAV File Format
**Note that this Docs are based on Current State of development and are very unfinished**
**This file can be very incorect due to copying from bcstm_doku.md**
## Contents
- 1 [Header](#header)
- 2 [Reference](#reference)
- 2.1 [Sized Reference](#sized-reference)
- 2.2 [Reference Table](#reference-table)
- 2.3 [Reference Types](#reference-types)
- 3 [Block Header](#block-header)
- 4 [Info Block](#info-block)
- 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)
- 6 [Basic Data Types](#basic-datatypes)
- 7 [Tools Devices used for Research](#tools--devices--file-sources-used-for-research)
## Header
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 4 | [u32](#u32) | Magic **'CWAV'** `0x56415743` |
| 0x04 | 2 | [u16](#u16) | Endianness `Big == 0xfffe` `Little == 0xfeff` |
| 0x06 | 2 | [u16](#u16) | Header Size `0x40` |
| 0x08 | 4 | [u32](#u32) | Version |
| 0x0c | 4 | [u32](#u32) | File Size |
| 0x10 | 2 | [u16](#u16) | Num Blocks (Should be 2) |
| 0x12 | 2 | [u16](#u16) | Reserved |
| 0x14 | 12 | [Sized Reference](#sized-reference) | Info Block Sized Reference |
| 0x20 | 12| [Sized Reference](#sized-reference) | Data Block Sized Reference |
## Reference
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 2 | [Reference Type](#reference-types) | TypeID |
| 0x02 | 2 | [u16](u16) | Padding |
| 0x04 | 4 | [u32](u32) | Offset **(0xffffffff represents null)** |
### Sized Reference
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 8 | [Reference](#reference) | Reference |
| 0x08 | 4 | [u32](u32) | Size |
### Reference Table
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 4 | [u32](#u32) | Count |
| 0x04 | Count*8 | [Reference](#reference) | References |
### Reference Types
| ID | Type |
|---|---|
| 0x0300 | [DSP ADPCM Info](#dsp-adpcm-info) |
| 0x0301 | IMA ADPCM Info |
| 0x1f00 | Sample Data |
| 0x7000 | [Info Block](#info-block) |
| 0x7001 | Data Block |
| 0x7100 | [Channel Info](#channel-info) |
## Block Header
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 4 | [u32](#u32) | Magic |
| 0x04 | 4 | [u32](#u32) | Size |
## Info Block
All Reference Offsets at the beginning of Info Block are Relative to the **Infoblock + 0x08 (size of Block Header) Position**
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 8 | [Block Header](#block-header) | Block Header |
| 0x08 | 1 | [u8](#u8) | Encoding |
| 0x09 | 1 | [u8](#u8) | Loop `1 == true -- 0 == false` |
| 0x0a | 1 | [u16](#u16) | Padding |
| 0x0c | 4 | [u32](#u32) | Sample Rate |
| 0x10 | 4 | [u32](#u32) | Loop Start |
| 0x14 | 4 | [u32](#u32) | Loop End |
| 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 |
|---|---|---|---|
| 0x00 | 8 | [Reference](#reference) | Reference to [DSP ADPCM Info](#dsp-adpcm-info) **!!! The Offsets are Relative to the start Pos of the Channel Info Object !!!** |
## DSP ADPCM Info
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 32 | [Param](#dsp-adpcm-param) | Coefficients |
| 0x20 | 6 | [DSP Context](#dsp-adpcm-context) | Context |
| 0x26 | 6 | [DSP Context](#dsp-adpcm-context) | Loop Context |
| 0x2c | 2 | [u16](#u16) | Padding |
### DSP ADPCM Param
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 32 | [u16](#u16) | 16 Bit Coefficients |
### DSP ADPCM Context
| Offset | Size | Datatype | Description |
|---|---|---|---|
| 0x00 | 1 | [u8](#u8) | 4Bit Predictor and 4Bit Scale |
| 0x01 | 1 | [u8](#u8) | Reserved |
| 0x02 | 2 | [16](#u16) | Previous Sample |
| 0x02 | 2 | [16](#u16) | Second Previous Sample |
## Basic Datatypes
### u32
```cpp
using u32 = unsigned int; // or uint32_t
```
### u16
```cpp
using u16 = unsigned short; // or uint16_t
```
### u8
```cpp
using u8 = unsigned char; // or uint8_t
```
## 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 |
| 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 | Used to get Test files |
+1 -3
View File
@@ -1,10 +1,8 @@
#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>
#include <ctrff/lz11.hpp> #include <ctrff/lz11.hpp>
#include <ctrff/pica.hpp> #include <ctrff/smdh.hpp>
#include <ctrff/smdh.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; // 0x58534433 "3DSX" 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 */
-99
View File
@@ -1,99 +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() : pCurrent(Header::Default()), pImag(ImagHeader::Default()) {}
~BCLIM() {}
enum Format : u32 {
L8, // tested
A8, // tested
LA4, // tested
LA8, // tested
HILO8,
RGB565, // tested
RGB888, // tested
RGBA5551,
RGBA4444, // tested
RGBA8888, // tested
ETC1,
ETC1A4,
L4, // tested
A4, // tested
};
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);
Format GetFmt() const { return (Format)pImag.Format; }
std::vector<u8> GetImage() { return pBuffer; }
int GetWidth() const { return pImag.Width; }
int GetHeight() const { return pImag.Height; }
/** 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
+64 -98
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 CTRFF_API 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 -9
View File
@@ -1,17 +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, const 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 void Flip(std::vector<u8> &buf, int w, int h);
CTRFF_API ctrff::u32 TileIndex(const int &x, const int &y, const int &w);
} // namespace ctrff } // namespace ctrff
+4 -4
View File
@@ -1,10 +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);
CTRFF_API std::vector<ctrff::u8> Decompress(const std::vector<ctrff::u8>& in); }
} // namespace LZ11
} // 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
@@ -24,7 +24,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#ifdef CTRFF_SHARED
#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)
@@ -48,39 +47,4 @@ SOFTWARE.
#define CTRFF_API #define CTRFF_API
#else #else
#define CTRFF_API #define CTRFF_API
#endif #endif
#else
#define CTRFF_API
#endif
#include <cstddef>
#include <format>
#include <fstream>
#include <iostream>
#include <memory>
#include <numeric>
#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
-34
View File
@@ -1,34 +0,0 @@
#pragma once
#include <ctrff/types.hpp>
/**
* 3ds GPU Stuff
*/
namespace ctrff {
namespace Pica {
enum Color : u32 {
L8, // tested
A8, // tested
LA4, // tested
LA8, // tested
HILO8,
RGB565, // tested
RGB888, // tested
RGBA5551,
RGBA4444, // tested
RGBA8888, // tested
ETC1,
ETC1A4,
L4, // tested
A4, // tested
};
CTRFF_API void EncodeImage(std::vector<ctrff::u8>& ret,
const std::vector<ctrff::u8>& rgba, int w, int h,
Color dst);
CTRFF_API void DecodeImage(std::vector<ctrff::u8>& ret,
const std::vector<ctrff::u8>& pixels, int w, int h,
Color src);
} // namespace Pica
} // 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
-56
View File
@@ -1,56 +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(0, 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));
f.read(reinterpret_cast<char*>(&pCurrent), sizeof(pCurrent));
f.read(reinterpret_cast<char*>(&pImag), sizeof(pImag));
if (pCurrent.Magic != 0x4d494c43) {
throw std::runtime_error("[ctrff] BCLIM: Not a bclim file!");
}
if (pImag.Magic != 0x67616d69) {
throw std::runtime_error("[ctrff] BCLIM: Invalid Data");
}
f.seekg(0, std::ios::beg);
pBuffer.resize(pImag.ImageSize);
f.read(reinterpret_cast<char*>(pBuffer.data()), pBuffer.size());
}
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 (size_t i = 0; i < data.size(); i++) {
pBuffer[i] = data[i];
}
pCurrent.FileSize = pBuffer.size() + pCurrent.HeaderSize + pImag.HeaderSize;
pCurrent.NumSections = 1;
}
} // namespace ctrff
+43 -61
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,20 +97,18 @@ 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; off += block.ChannelInfoTab.Refs[i].Offset;
off += block.ChannelInfoTab.Refs[i].Offset; off += block.ChannelInfoRefs[i].Offset;
off += block.ChannelInfoRefs[i].Offset; 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.Add(t);
pDSP_ADPCM_Info.push_back(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,27 +147,29 @@ 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);
} catch (const std::exception& e) {
throw std::runtime_error(e.what());
} }
pFile.seekg(off, std::ios::beg);
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()));
} }
CTRFF_API void BCSTM::CleanUp() { CTRFF_API void BCSTM::CleanUp() {
@@ -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
+27 -27
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,31 +67,29 @@ 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; off += block.ChannelInfoRefs[i].Offset;
off += block.ChannelInfoRefs[i].Offset; 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.Add(t);
pDSP_ADPCM_Info.push_back(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);
} catch (const std::exception& e) {
throw std::runtime_error(e.what());
} }
pFile.seekg(off, std::ios::beg);
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
+12 -12
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,13 +29,13 @@ 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));
} }
} // namespace ctrff } // namespace ctrff
+31 -49
View File
@@ -2,72 +2,68 @@
#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,
const ctrff::u16 *icon, const int &w, const int &w, const int &h) {
const int &h) { if (img.size() != (48 * 48 * 4)) {
if (img.size() != size_t(w * h * 4)) { img.resize(48 * 48 * 4);
img.clear(); img.clear();
img.resize(w * h * 4);
} }
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,30 +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::Flip(std::vector<ctrff::u8> &buf, int w, int h) { CTRFF_API void ctrff::String2U16(PD::u16 *res, const std::string &src,
std::vector<ctrff::u8> tmp = buf;
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4;
int dst = ((h - 1 - y) * w + x) * 4;
buf[dst + 0] = tmp[src + 0];
buf[dst + 1] = tmp[src + 1];
buf[dst + 2] = tmp[src + 2];
buf[dst + 3] = tmp[src + 3];
}
}
}
CTRFF_API void ctrff::String2U16(ctrff::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
@@ -111,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
@@ -134,8 +116,8 @@ 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);
res[len++] = 0xDC00 | (codepoint & 0x3FF); res[len++] = 0xDC00 | (codepoint & 0x3FF);
@@ -146,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) {
@@ -164,7 +146,7 @@ CTRFF_API std::string ctrff::U16toU8(ctrff::u16 *in, size_t max) {
} else if (c < 0x800) { } else if (c < 0x800) {
result.push_back(static_cast<char>(0xC0 | (c >> 6))); result.push_back(static_cast<char>(0xC0 | (c >> 6)));
result.push_back(static_cast<char>(0x80 | (c & 0x3F))); result.push_back(static_cast<char>(0x80 | (c & 0x3F)));
} else if (c <= 0xffff) { } else if (c < 0x10000) {
result.push_back(static_cast<char>(0xE0 | (c >> 12))); result.push_back(static_cast<char>(0xE0 | (c >> 12)));
result.push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3F))); result.push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3F)));
result.push_back(static_cast<char>(0x80 | (c & 0x3F))); result.push_back(static_cast<char>(0x80 | (c & 0x3F)));
@@ -174,4 +156,4 @@ CTRFF_API std::string ctrff::U16toU8(ctrff::u16 *in, size_t max) {
} }
return result; return result;
} }
+42 -105
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) {
throw std::runtime_error("[ctrff] LZ11: Input is tool large to compress"); 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,64 +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;
// Baed on
// https://github.com/Gericom/EveryFileExplorer/blob/master/CommonCompressors/LZ11.cs
// Needs some fixes cause this code looks very unsafe to me tbh
CTRFF_API std::vector<ctrff::u8> Decompress(const std::vector<ctrff::u8>& in) {
if (!in.size()) {
throw std::runtime_error("[ctrff] LZ11: Cannot decompress empty buffer!");
}
if (in[0] != 0x11) {
throw std::runtime_error("[ctrff] LZ11: Not a lz11 file!");
}
u32 len = in[1] | (in[2] << 8) | (in[3] << 16);
std::vector<u8> ret(len, 0x0);
int off = 4;
int dst_off = 0;
while (true) {
u8 header = in[off++];
for (int i = 0; i < 8; i++) {
if ((header & 0x80) == 0) {
ret[dst_off++] = in[off++];
} else {
u8 a = in[off++];
int off2;
int length;
if ((a >> 4) == 0) {
u8 b = in[off++];
u8 c = in[off++];
length = (((a & 0xF) << 4) | (b >> 4)) + 0x11;
off2 = (((b & 0xF) << 8) | c) + 1;
} else if ((a >> 4) == 1) {
u8 b = in[off++];
u8 c = in[off++];
u8 d = in[off++];
length = (((a & 0xF) << 12) | (b << 4) | (c >> 4)) + 0x111;
off2 = (((c & 0xF) << 8) | d) + 1;
} else {
u8 b = in[off++];
off2 = (((a & 0xF) << 8) | b) + 1;
length = (a >> 4) + 1;
}
for (int j = 0; j < length; j++) {
ret[dst_off] = ret[dst_off - off2];
dst_off++;
}
}
if ((u32)dst_off >= len) return ret;
header <<= 1;
}
}
} }
} // namespace LZ11 } // namespace LZ11
} // namespace ctrff } // namespace ctrff
-311
View File
@@ -1,311 +0,0 @@
#include <ctrff/helper.hpp>
#include <ctrff/pica.hpp>
namespace ctrff {
namespace Pica {
CTRFF_API void EncodeImage(std::vector<ctrff::u8>& ret,
const std::vector<ctrff::u8>& rgba, int w, int h,
Color dst_color) {
// Only used in rgb/rgba
int bpp = dst_color == RGBA8888 ? 4 : 3;
switch (dst_color) {
case RGB565:
ret.resize(w * h * 2);
ctrff::RGBA2RGB565(reinterpret_cast<ctrff::u16*>(ret.data()), rgba, w, h);
break;
case RGB888:
case RGBA8888:
ret.resize(w * h * bpp);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w) * bpp;
for (int i = 0; i < bpp; i++) {
ret[dst + bpp - 1 - i] = rgba[src + i];
}
}
}
break;
case A8:
ret.resize(w * h);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w);
ret[dst] = rgba[src + 3]; // extract alpha only
}
}
break;
case A4:
ret.resize((w * h) >> 1);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w);
ctrff::u8 tmp = rgba[src + 3] >> 4;
int a4pos = dst >> 1;
if ((dst & 1) == 0) {
ret[a4pos] = (tmp << 4) | (ret[a4pos] & 0x0f);
} else {
ret[a4pos] = (ret[a4pos] & 0xf0) | tmp;
}
}
}
break;
case L8:
ret.resize(w * h);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w);
// Basic luminance calculation (already used in renderd7)
ret[dst] =
(rgba[src + 0] * 77 + rgba[src + 1] * 150 + rgba[src + 2] * 29) >>
8;
}
}
break;
case L4:
ret.resize((w * h) >> 1);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w);
// Basically same as a4 just with the luminance calculation func
ctrff::u8 tmp = ((rgba[src + 0] * 77 + rgba[src + 1] * 150 +
rgba[src + 2] * 29) >>
8) >>
4;
int a4pos = dst >> 1;
if ((dst & 1) == 0) {
ret[a4pos] = (tmp << 4) | (ret[a4pos] & 0x0f);
} else {
ret[a4pos] = (ret[a4pos] & 0xf0) | tmp;
}
}
}
break;
case RGBA4444:
ret.resize(w * h * 2);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w) * 2;
ret[dst + 0] = rgba[src + 3] >> 4;
ret[dst + 0] |= (rgba[src + 2] >> 4) << 4;
ret[dst + 1] = rgba[src + 1] >> 4;
ret[dst + 1] |= (rgba[src + 0] >> 4) << 4;
}
}
break;
case RGBA5551: // not working ???
ret.resize(w * h * 2);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w) * 2;
ctrff::u16 px = 0;
px |= (rgba[src + 3] < 128 ? 0 : 1) << 15; // A
px |= ((rgba[src + 2] >> 3) & 0x1f) << 10; // BBBBB
px |= ((rgba[src + 1] >> 3) & 0x1f) << 5; // GGGGG
px |= ((rgba[src + 0] >> 3) & 0x1f); // RRRRR
ret[dst] = px & 0xff;
ret[dst + 1] = (px << 8) & 0xff;
}
}
break;
case LA8:
ret.resize(w * h * 2);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w) * 2;
ret[dst] =
(rgba[src + 0] * 77 + rgba[src + 1] * 150 + rgba[src + 2] * 29) >>
8;
ret[dst + 1] = rgba[src + 3];
}
}
break;
case LA4:
ret.resize(w * h);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = (y * w + x) * 4; // basic rgba indexing btw
int dst = ctrff::TileIndex(x, y, w);
ret[dst] = 0;
ret[dst] |= (((rgba[src + 0] * 77 + rgba[src + 1] * 150 +
rgba[src + 2] * 29) >>
8) >>
4) &
0xf;
ret[dst] |= (((rgba[src + 3] >> 4) & 0xf) << 4) | ret[dst];
}
}
break;
default:
throw std::runtime_error("[ctrff] Pica: Unsupported Color format: " +
std::to_string((int)dst_color));
break;
}
}
CTRFF_API void DecodeImage(std::vector<ctrff::u8>& ret,
const std::vector<ctrff::u8>& pixels, int w, int h,
Color src_color) {
switch (src_color) {
case RGB565:
ret.resize(w * h * 4);
ctrff::RGB565toRGBA(
ret, reinterpret_cast<const ctrff::u16*>(pixels.data()), w, h);
break;
case RGB888:
case RGBA8888:
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int bpp = src_color == RGBA8888 ? 4 : 3;
int src = ctrff::TileIndex(x, y, w) * bpp;
int dst = (y * w + x) * 4; // basic rgba indexing btw
for (int i = 0; i < bpp; i++) {
ret[dst + i] = pixels[src + bpp - 1 - i];
}
if (src_color == RGB888) {
ret[dst + 3] = 255;
}
}
}
break;
case A8:
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w);
int dst = (y * w + x) * 4;
ret[dst + 0] = 255;
ret[dst + 1] = 255;
ret[dst + 2] = 255;
ret[dst + 3] = pixels[src];
}
}
break;
case A4: // most hated by me (tobid7)
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w);
int dst = (y * w + x) * 4;
/**
* Basically checking by %2 aka &1 if we have a high or low nibble
* by this we either extract the high or low one and multiply
* by 17 aka 0x11 to get the resulting A8 Value
*/
ctrff::u8 a4 = src & 1 ? ((pixels[src >> 1] >> 4) & 0xf) * 0x11
: (pixels[src >> 1] & 0xf) * 0x11;
ret[dst + 0] = 255;
ret[dst + 1] = 255;
ret[dst + 2] = 255;
ret[dst + 3] = a4;
}
}
break;
case L4: // most hated by me (tobid7)
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w);
int dst = (y * w + x) * 4;
/**
* Same as A4
* Basically checking by %2 aka &1 if we have a high or low nibble
* by this we either extract the high or low one and multiply
* by 17 aka 0x11 to get the resulting A8 Value
*/
ctrff::u8 a4 = src & 1 ? ((pixels[src >> 1] >> 4) & 0xf) * 0x11
: (pixels[src >> 1] & 0xf) * 0x11;
ret[dst + 0] = a4;
ret[dst + 1] = a4;
ret[dst + 2] = a4;
ret[dst + 3] = 255;
}
}
break;
case L8:
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w);
int dst = (y * w + x) * 4;
ret[dst + 0] = pixels[src];
ret[dst + 1] = pixels[src];
ret[dst + 2] = pixels[src];
ret[dst + 3] = 255;
}
}
break;
case RGBA4444:
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w) * 2;
int dst = (y * w + x) * 4; // basic rgba indexing btw
ret[dst + 0] = ((pixels[src + 1] >> 4) & 0xf) << 4;
ret[dst + 1] = (pixels[src + 1] & 0xf) << 4;
ret[dst + 2] = ((pixels[src + 0] >> 4) & 0xf) << 4;
ret[dst + 3] = (pixels[src + 0] & 0xf) << 4;
}
}
break;
case RGBA5551: // not working
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w) * 2;
int dst = (y * w + x) * 4; // basic rgba indexing btw
ctrff::u16 px = ret[src] | (ret[src + 1] << 8);
ret[dst + 0] = (px & 0x1f) * 0x1f;
ret[dst + 1] = ((px >> 5) & 0x1f) * 0x1f;
ret[dst + 2] = ((px >> 10) & 0x1f) * 0x1f;
ret[dst + 3] = 255; // ((*px >> 15) & 0x1) ? 255 : 0;
}
}
break;
case LA8:
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w) * 2;
int dst = (y * w + x) * 4;
ret[dst + 0] = pixels[src];
ret[dst + 1] = pixels[src];
ret[dst + 2] = pixels[src];
ret[dst + 3] = pixels[src + 1];
}
}
break;
case LA4:
ret.resize(w * h * 4);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int src = ctrff::TileIndex(x, y, w);
int dst = (y * w + x) * 4;
uint8_t l = (pixels[src] & 0xf) * 0x11;
uint8_t a = ((pixels[src] >> 4) & 0xf) * 0x11;
ret[dst + 0] = l;
ret[dst + 1] = l;
ret[dst + 2] = l;
ret[dst + 3] = a;
}
}
break;
default:
throw std::runtime_error("[ctrff] Pica: Unsupported Color format: " +
std::to_string((int)src_color));
break;
}
}
} // namespace Pica
} // namespace ctrff
+5 -5
View File
@@ -18,12 +18,12 @@ CTRFF_API void ctrff::SMDH::Write(std::fstream &f) const {
} }
CTRFF_API void ctrff::SMDH::Read(std::fstream &f) { CTRFF_API void ctrff::SMDH::Read(std::fstream &f) {
/*f.seekg(0, std::ios::end); f.seekg(0, std::ios::end);
if (f.tellg() != SMDH_Size) { if (f.tellg() != SMDH_Size) {
throw std::runtime_error( throw std::runtime_error(
"SMDH: File size does not match the SMDH Header size!"); "SMDH: File size does not match the SMDH Header size!");
} }
f.seekg(0, std::ios::beg);*/ f.seekg(0, std::ios::beg);
f.read(reinterpret_cast<char *>(Magic), sizeof(Magic)); f.read(reinterpret_cast<char *>(Magic), sizeof(Magic));
if (std::string(Magic) != smdh_magic) { if (std::string(Magic) != smdh_magic) {
throw std::runtime_error("SMDH: Invalid SMDH file!"); throw std::runtime_error("SMDH: Invalid SMDH 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;
} }
+6 -77
View File
@@ -5,11 +5,11 @@
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <map> #include <map>
#include <palladium>
#include <string> #include <string>
#include <utility> #include <utility>
/** Import palladium stb image */ /** Import palladium stb image */
#define STB_IMAGE_IMPLEMENTATION
#include <pd/external/stb_image.h> #include <pd/external/stb_image.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h> #include <stb_image_write.h>
@@ -121,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)),
@@ -431,12 +431,7 @@ void LZ11Compress(const cf7::command::ArgumentList &data) {
std::make_pair(i, cf7::col(255, 210, 0)), std::make_pair(i, cf7::col(255, 210, 0)),
std::make_pair(FormatBytes(buf.size()), cf7::col(255, 255, 0)), std::make_pair(FormatBytes(buf.size()), cf7::col(255, 255, 0)),
}); });
std::vector<ctrff::u8> res; auto res = ctrff::LZ11::Compress(buf);
if (buf[0] == 0x11) {
res = ctrff::LZ11::Decompress(buf);
} else {
res = ctrff::LZ11::Compress(buf);
}
cf7::PrintFancy({ cf7::PrintFancy({
std::make_pair("Output", cf7::col(255, 165, 0)), std::make_pair("Output", cf7::col(255, 165, 0)),
std::make_pair(o, cf7::col(255, 210, 0)), std::make_pair(o, cf7::col(255, 210, 0)),
@@ -447,64 +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;
}
PD::Image::Ref img = PD::Image::New();
img->Load(i);
if (img->GetBuffer().empty()) {
std::cout << "[ctrff] BCLIM: Failed to load image " + i << std::endl;
return;
}
if (!PD::BitUtil::IsSingleBit(img->Width()) ||
!PD::BitUtil::IsSingleBit(img->Height())) {
std::cout << "[ctrff] BCLIM: Image with and height must be a power of 8!";
return;
}
img->Convert(img, img->RGBA);
std::vector<ctrff::u8> res;
ctrff::Pica::Color fmt = ctrff::Pica::A8;
if (f == "a4") {
fmt = ctrff::Pica::A4;
} else if (f == "l4") {
fmt = ctrff::Pica::L4;
} else if (f == "a8") {
fmt = ctrff::Pica::A8;
} else if (f == "l8") {
fmt = ctrff::Pica::L8;
} else if (f == "la4") {
fmt = ctrff::Pica::LA4;
} else if (f == "la8") {
fmt = ctrff::Pica::LA8;
} else if (f == "rgb565") {
fmt = ctrff::Pica::RGB565;
} else if (f == "rgb888") {
fmt = ctrff::Pica::RGB888;
} else if (f == "rgba4444") {
fmt = ctrff::Pica::RGBA4444;
} else if (f == "rgba5551") {
fmt = ctrff::Pica::RGBA5551;
} else if (f == "rgba8888") {
fmt = ctrff::Pica::RGBA8888;
}
ctrff::Pica::EncodeImage(res, img->GetBuffer(), img->Width(), img->Height(),
fmt);
ctrff::BCLIM file;
ctrff::BCLIM::Format _fmt = (ctrff::BCLIM::Format)fmt;
file.CreateByImage(res, img->Width(), img->Height(), _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");
@@ -548,7 +488,7 @@ int main(int argc, char *argv[]) {
"Output icon path!", false)) "Output icon path!", false))
.SetFunction(Read3DSX)); .SetFunction(Read3DSX));
mgr.AddCommand( mgr.AddCommand(
cf7::command("lz11", "Compress/Decompress a file with LZ11") cf7::command("lz11", "Creates a LZ11 Compressed File")
.AddSubEntry(cf7::command::sub("i", "input", "Input file path", true)) .AddSubEntry(cf7::command::sub("i", "input", "Input file path", true))
.AddSubEntry( .AddSubEntry(
cf7::command::sub("o", "output", "Output file path", true)) cf7::command::sub("o", "output", "Output file path", true))
@@ -557,17 +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 "
"rgba8888|rgb888|rgba4444|rgba5551|rgb565|a8|l8|a4|l4|la4|la8",
false))
.SetFunction(BCLIMMaker));
mgr.Execute(); mgr.Execute();
return 0; return 0;
} }
@@ -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);
-5
View File
@@ -1,5 +0,0 @@
cmake_minimum_required(VERSION 3.22)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../vendor/palladium palladium)
add_subdirectory(ctrff)
-22
View File
@@ -1,22 +0,0 @@
cmake_minimum_required(VERSION 3.22)
project(ctrff-cli)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED true)
add_executable(ctrff-cli source/main.cpp)
target_include_directories(ctrff-cli PUBLIC include
${CMAKE_CURRENT_SOURCE_DIR}/../../vendor/stb
${CMAKE_CURRENT_SOURCE_DIR}/../../vendor/cli-fancy/include
)
target_link_libraries(ctrff-cli PUBLIC ctrff palladium)
add_executable(test source/test.cpp)
target_include_directories(test PUBLIC include
${CMAKE_CURRENT_SOURCE_DIR}/../../vendor/stb
${CMAKE_CURRENT_SOURCE_DIR}/../../vendor/cli-fancy/include
)
target_link_libraries(test PUBLIC ctrff)
install(TARGETS ctrff-cli)