2020-10-14 14:23:49 +01:00
/*
* bfttf . c
*
* Copyright ( c ) 2018 , simontime .
2024-04-12 10:47:36 +01:00
* Copyright ( c ) 2020 - 2024 , DarkMatterCore < pabloacurielz @ gmail . com > .
2020-10-14 14:23:49 +01:00
*
* This file is part of nxdumptool ( https : //github.com/DarkMatterCore/nxdumptool).
*
2021-03-25 19:26:58 +00:00
* nxdumptool is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
2020-10-14 14:23:49 +01:00
*
2021-03-25 19:26:58 +00:00
* nxdumptool is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2020-10-14 14:23:49 +01:00
*
* You should have received a copy of the GNU General Public License
2021-03-25 19:26:58 +00:00
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
2020-10-14 14:23:49 +01:00
*/
2024-04-30 22:01:42 +01:00
# include <core/nxdt_utils.h>
# include <core/bfttf.h>
# include <core/romfs.h>
# include <core/title.h>
2020-10-14 14:23:49 +01:00
/* Type definitions. */
typedef struct {
u64 title_id ; ///< System title ID.
char path [ 64 ] ; ///< Path to BFTTF file inside the RomFS section from the system title.
u32 size ;
u8 * data ;
} BfttfFontInfo ;
/* Global variables. */
static Mutex g_bfttfMutex = 0 ;
static bool g_bfttfInterfaceInit = false ;
static BfttfFontInfo g_fontInfo [ ] = {
{ 0x0100000000000811 , " /nintendo_udsg-r_std_003.bfttf " , 0 , NULL } , /* FontStandard. */
2021-03-29 19:27:35 +01:00
{ 0x0100000000000810 , " /nintendo_ext_003.bfttf " , 0 , NULL } , /* FontNintendoExtension. There's a secondary entry at "/nintendo_ext2_003.bfttf", but it's identical to this one. */
2020-10-14 14:23:49 +01:00
{ 0x0100000000000812 , " /nintendo_udsg-r_ko_003.bfttf " , 0 , NULL } , /* FontKorean. */
{ 0x0100000000000814 , " /nintendo_udsg-r_org_zh-cn_003.bfttf " , 0 , NULL } , /* FontChineseSimplified (1). */
{ 0x0100000000000814 , " /nintendo_udsg-r_ext_zh-cn_003.bfttf " , 0 , NULL } , /* FontChineseSimplified (2). */
{ 0x0100000000000813 , " /nintendo_udjxh-db_zh-tw_003.bfttf " , 0 , NULL } /* FontChineseTraditional. */
} ;
static const u32 g_fontInfoCount = MAX_ELEMENTS ( g_fontInfo ) ;
static const u32 g_bfttfKey = 0x06186249 ;
/* Function prototypes. */
static bool bfttfDecodeFont ( BfttfFontInfo * font_info ) ;
bool bfttfInitialize ( void )
{
NcaContext * nca_ctx = NULL ;
RomFileSystemContext romfs_ctx = { 0 } ;
2021-05-18 13:32:43 +01:00
bool ret = false ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
SCOPED_LOCK ( & g_bfttfMutex )
2020-10-14 14:23:49 +01:00
{
2021-05-18 13:32:43 +01:00
ret = g_bfttfInterfaceInit ;
if ( ret ) break ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
u32 count = 0 ;
u64 prev_title_id = 0 ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Allocate memory for a temporary NCA context. */
nca_ctx = calloc ( 1 , sizeof ( NcaContext ) ) ;
if ( ! nca_ctx )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to allocate memory for temporary NCA context! " ) ;
2021-05-18 13:32:43 +01:00
break ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Retrieve BFTTF data. */
for ( u32 i = 0 ; i < g_fontInfoCount ; i + + )
2020-10-14 14:23:49 +01:00
{
2021-05-18 13:32:43 +01:00
BfttfFontInfo * font_info = & ( g_fontInfo [ i ] ) ;
RomFileSystemFileEntry * romfs_file_entry = NULL ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Check if the title ID for the current font container matches the one from the previous font container. */
/* We won't have to reinitialize both NCA and RomFS contexts if that's the case. */
if ( font_info - > title_id ! = prev_title_id )
{
2023-05-24 20:05:34 +01:00
TitleInfo * title_info = NULL ;
2021-05-18 13:32:43 +01:00
/* Get title info. */
2024-08-18 14:29:57 +01:00
if ( ! ( title_info = titleGetTitleInfoEntryFromStorageByTitleId ( NcmStorageId_BuiltInSystem , font_info - > title_id ) ) )
2021-05-18 13:32:43 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to get title info for %016lX! " , font_info - > title_id ) ;
2021-05-18 13:32:43 +01:00
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Initialize NCA context. */
2021-06-05 22:06:29 +01:00
/* NCA contexts don't need to be freed beforehand. */
2023-05-24 20:05:34 +01:00
/* Don't allow invalid NCA signatures. */
2023-05-30 00:22:12 +01:00
bool nca_ctx_init = ( ncaInitializeContext ( nca_ctx , NcmStorageId_BuiltInSystem , 0 , & ( title_info - > meta_key ) , \
titleGetContentInfoByTypeAndIdOffset ( title_info , NcmContentType_Data , 0 ) , NULL ) & & nca_ctx - > valid_main_signature ) ;
2022-07-05 02:04:28 +01:00
2021-06-01 02:12:15 +01:00
/* Free title info. */
titleFreeTitleInfo ( & title_info ) ;
2022-07-05 02:04:28 +01:00
2021-06-01 02:12:15 +01:00
/* Check if NCA context initialization succeeded. */
if ( ! nca_ctx_init )
2021-05-18 13:32:43 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to initialize Data NCA context for %016lX! " , font_info - > title_id ) ;
2021-05-18 13:32:43 +01:00
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Initialize RomFS context. */
/* This will also free a previous RomFS context, if available. */
2022-07-04 13:30:48 +01:00
if ( ! romfsInitializeContext ( & romfs_ctx , & ( nca_ctx - > fs_ctx [ 0 ] ) , NULL ) )
2021-05-18 13:32:43 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to initialize RomFS context for Data NCA from %016lX! " , font_info - > title_id ) ;
2021-05-18 13:32:43 +01:00
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Update previous title ID. */
prev_title_id = font_info - > title_id ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Get RomFS file entry. */
if ( ! ( romfs_file_entry = romfsGetFileEntryByPath ( & romfs_ctx , font_info - > path ) ) )
2020-10-14 14:23:49 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve RomFS file entry in %016lX! " , font_info - > title_id ) ;
2020-10-14 14:23:49 +01:00
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Check file size. */
if ( ! romfs_file_entry - > size )
2020-10-14 14:23:49 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " File size for \" %s \" in %016lX is zero! " , font_info - > path , font_info - > title_id ) ;
2020-10-14 14:23:49 +01:00
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Allocate memory for BFTTF data. */
if ( ! ( font_info - > data = malloc ( romfs_file_entry - > size ) ) )
2020-10-14 14:23:49 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to allocate 0x%lX bytes for \" %s \" in %016lX! " , romfs_file_entry - > size , font_info - > path , font_info - > title_id ) ;
2020-10-14 14:23:49 +01:00
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Read BFTFF data. */
if ( ! romfsReadFileEntryData ( & romfs_ctx , romfs_file_entry , font_info - > data , romfs_file_entry - > size , 0 ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to read 0x%lX bytes long \" %s \" in %016lX! " , romfs_file_entry - > size , font_info - > path , font_info - > title_id ) ;
2021-05-18 13:32:43 +01:00
free ( font_info - > data ) ;
font_info - > data = NULL ;
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Update BFTTF size. */
font_info - > size = ( u32 ) romfs_file_entry - > size ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Decode BFTTF data. */
if ( ! bfttfDecodeFont ( font_info ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to decode 0x%lX bytes long \" %s \" in %016lX! " , romfs_file_entry - > size , font_info - > path , font_info - > title_id ) ;
2021-05-18 13:32:43 +01:00
free ( font_info - > data ) ;
font_info - > data = NULL ;
font_info - > size = 0 ;
continue ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Increase retrieved BFTTF count. */
count + + ;
2020-10-14 14:23:49 +01:00
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
/* Update flags. */
ret = g_bfttfInterfaceInit = ( count > 0 ) ;
2022-07-12 17:34:49 +01:00
if ( ! ret ) LOG_MSG_ERROR ( " No BFTTF fonts retrieved! " ) ;
2020-10-14 14:23:49 +01:00
}
2022-07-05 02:04:28 +01:00
2020-10-14 14:23:49 +01:00
romfsFreeContext ( & romfs_ctx ) ;
2022-07-05 02:04:28 +01:00
2020-10-14 14:23:49 +01:00
if ( nca_ctx ) free ( nca_ctx ) ;
2022-07-05 02:04:28 +01:00
2020-10-14 14:23:49 +01:00
return ret ;
}
void bfttfExit ( void )
{
2021-05-18 13:32:43 +01:00
SCOPED_LOCK ( & g_bfttfMutex )
2020-10-14 14:23:49 +01:00
{
2021-05-18 13:32:43 +01:00
/* Free BFTTF data. */
for ( u32 i = 0 ; i < g_fontInfoCount ; i + + )
{
BfttfFontInfo * font_info = & ( g_fontInfo [ i ] ) ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
font_info - > size = 0 ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
if ( font_info - > data )
{
free ( font_info - > data ) ;
font_info - > data = NULL ;
}
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
g_bfttfInterfaceInit = false ;
2020-10-14 14:23:49 +01:00
}
}
bool bfttfGetFontByType ( BfttfFontData * font_data , u8 font_type )
{
2023-07-17 00:03:05 +01:00
if ( ! font_data | | font_type > = BfttfFontType_Count )
2020-10-14 14:23:49 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-10-14 14:23:49 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
bool ret = false ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
SCOPED_LOCK ( & g_bfttfMutex )
2020-10-14 14:23:49 +01:00
{
2021-05-18 13:32:43 +01:00
BfttfFontInfo * font_info = & ( g_fontInfo [ font_type ] ) ;
if ( font_info - > size < = 8 | | ! font_info - > data )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " BFTTF font data unavailable for type 0x%02X! " , font_type ) ;
2021-05-18 13:32:43 +01:00
break ;
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
font_data - > type = font_type ;
font_data - > size = ( font_info - > size - 8 ) ;
font_data - > address = ( font_info - > data + 8 ) ;
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
ret = true ;
2020-10-14 14:23:49 +01:00
}
2022-07-05 02:04:28 +01:00
2021-05-18 13:32:43 +01:00
return ret ;
2020-10-14 14:23:49 +01:00
}
static bool bfttfDecodeFont ( BfttfFontInfo * font_info )
{
if ( ! font_info | | font_info - > size < = 8 | | ! IS_ALIGNED ( font_info - > size , 4 ) | | ! font_info - > data )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-10-14 14:23:49 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2021-03-07 23:22:49 +00:00
for ( u32 i = 8 ; i < font_info - > size ; i + = 4 )
2020-10-14 14:23:49 +01:00
{
u32 * ptr = ( u32 * ) ( font_info - > data + i ) ;
* ptr = ( * ptr ^ g_bfttfKey ) ;
}
2022-07-05 02:04:28 +01:00
2020-10-14 14:23:49 +01:00
return true ;
}