2020-04-26 09:35:01 +01:00
/*
2020-07-03 10:31:22 +01:00
* romfs . h
2020-04-26 09:35:01 +01:00
*
2020-12-23 17:48:57 +00:00
* Copyright ( c ) 2020 - 2021 , DarkMatterCore < pabloacurielz @ gmail . com > .
2020-07-03 10:31:22 +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-04-26 09:35:01 +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-04-26 09:35:01 +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-04-26 09:35:01 +01:00
*/
# pragma once
# ifndef __ROMFS_H__
# define __ROMFS_H__
# include "nca.h"
2021-03-24 17:25:19 +00:00
# ifdef __cplusplus
extern " C " {
# endif
2020-04-26 09:35:01 +01:00
# define ROMFS_OLD_HEADER_SIZE 0x28
# define ROMFS_HEADER_SIZE 0x50
# define ROMFS_VOID_ENTRY 0xFFFFFFFF
/// Header used by NCA0 RomFS sections.
typedef struct {
u32 header_size ; ///< Header size. Must be equal to ROMFS_OLD_HEADER_SIZE.
u32 directory_bucket_offset ; ///< Directory buckets table offset.
u32 directory_bucket_size ; ///< Directory buckets table size.
u32 directory_entry_offset ; ///< Directory entries table offset.
u32 directory_entry_size ; ///< Directory entries table size.
u32 file_bucket_offset ; ///< File buckets table offset.
u32 file_bucket_size ; ///< File buckets table size.
u32 file_entry_offset ; ///< File entries table offset.
u32 file_entry_size ; ///< File entries table size.
u32 body_offset ; ///< File data body offset.
} RomFileSystemInformationOld ;
2021-03-24 17:25:19 +00:00
NXDT_ASSERT ( RomFileSystemInformationOld , ROMFS_OLD_HEADER_SIZE ) ;
2020-04-26 09:35:01 +01:00
/// Header used by NCA2/NCA3 RomFS sections.
typedef struct {
u64 header_size ; ///< Header size. Must be equal to ROMFS_HEADER_SIZE.
u64 directory_bucket_offset ; ///< Directory buckets table offset.
u64 directory_bucket_size ; ///< Directory buckets table size.
u64 directory_entry_offset ; ///< Directory entries table offset.
u64 directory_entry_size ; ///< Directory entries table size.
u64 file_bucket_offset ; ///< File buckets table offset.
u64 file_bucket_size ; ///< File buckets table size.
u64 file_entry_offset ; ///< File entries table offset.
u64 file_entry_size ; ///< File entries table size.
u64 body_offset ; ///< File data body offset.
} RomFileSystemInformation ;
2021-03-24 17:25:19 +00:00
NXDT_ASSERT ( RomFileSystemInformation , ROMFS_HEADER_SIZE ) ;
2020-04-26 09:35:01 +01:00
/// Header union.
typedef struct {
union {
struct {
RomFileSystemInformationOld old_format ;
u8 padding [ ROMFS_OLD_HEADER_SIZE ] ;
} ;
RomFileSystemInformation cur_format ;
} ;
} RomFileSystemHeader ;
2021-03-24 17:25:19 +00:00
NXDT_ASSERT ( RomFileSystemHeader , ROMFS_HEADER_SIZE ) ;
2020-04-26 09:35:01 +01:00
/// Directory entry. Always aligned to a 4-byte boundary past the directory name.
typedef struct {
u32 parent_offset ; ///< Parent directory offset.
u32 next_offset ; ///< Next sibling directory offset.
u32 directory_offset ; ///< First child directory offset.
u32 file_offset ; ///< First child file offset.
u32 bucket_offset ; ///< Directory bucket offset.
u32 name_length ; ///< Name length.
char name [ ] ; ///< Name (UTF-8).
} RomFileSystemDirectoryEntry ;
2021-03-24 17:25:19 +00:00
NXDT_ASSERT ( RomFileSystemDirectoryEntry , 0x18 ) ;
2020-04-26 09:35:01 +01:00
/// Directory entry. Always aligned to a 4-byte boundary past the file name.
typedef struct {
u32 parent_offset ; ///< Parent directory offset.
u32 next_offset ; ///< Next sibling file offset.
u64 offset ; ///< File data offset.
u64 size ; ///< File data size.
u32 bucket_offset ; ///< File bucket offset.
u32 name_length ; ///< Name length.
char name [ ] ; ///< Name (UTF-8).
} RomFileSystemFileEntry ;
2021-03-24 17:25:19 +00:00
NXDT_ASSERT ( RomFileSystemFileEntry , 0x20 ) ;
2020-04-26 09:35:01 +01:00
typedef struct {
NcaFsSectionContext * nca_fs_ctx ; ///< Used to read NCA FS section data.
u64 offset ; ///< RomFS offset (relative to the start of the NCA FS section).
u64 size ; ///< RomFS size.
RomFileSystemHeader header ; ///< RomFS header.
u64 dir_table_size ; ///< RomFS directory entries table size.
RomFileSystemDirectoryEntry * dir_table ; ///< RomFS directory entries table.
u64 file_table_size ; ///< RomFS file entries table size.
RomFileSystemFileEntry * file_table ; ///< RomFS file entries table.
2020-04-26 11:04:31 +01:00
u64 body_offset ; ///< RomFS file data body offset (relative to the start of the RomFS).
2020-07-15 23:50:34 +01:00
u32 cur_dir_offset ; ///< Current RomFS directory offset (relative to the start of the directory entries table). Used for RomFS browsing.
2020-04-26 09:35:01 +01:00
} RomFileSystemContext ;
2020-04-28 09:58:17 +01:00
typedef struct {
bool use_old_format_patch ; ///< Old format patch flag.
2020-10-28 22:48:46 +00:00
bool written ; ///< Set to true if the patch has been completely written.
2020-04-28 09:58:17 +01:00
NcaHierarchicalSha256Patch old_format_patch ; ///< Used with NCA0 RomFS sections.
NcaHierarchicalIntegrityPatch cur_format_patch ; ///< Used with NCA2/NCA3 RomFS sections.
} RomFileSystemFileEntryPatch ;
2020-05-10 17:40:12 +01:00
typedef enum {
RomFileSystemPathIllegalCharReplaceType_None = 0 ,
RomFileSystemPathIllegalCharReplaceType_IllegalFsChars = 1 ,
RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly = 2
} RomFileSystemPathIllegalCharReplaceType ;
2020-04-26 09:35:01 +01:00
/// Initializes a RomFS context.
bool romfsInitializeContext ( RomFileSystemContext * out , NcaFsSectionContext * nca_fs_ctx ) ;
2020-04-26 11:04:31 +01:00
/// Reads raw filesystem data using a RomFS context.
2020-04-28 00:30:35 +01:00
/// Input offset must be relative to the start of the RomFS.
2020-04-26 11:04:31 +01:00
bool romfsReadFileSystemData ( RomFileSystemContext * ctx , void * out , u64 read_size , u64 offset ) ;
2020-04-26 09:35:01 +01:00
/// Reads data from a previously retrieved RomFileSystemFileEntry using a RomFS context.
2020-04-28 09:58:17 +01:00
/// Input offset must be relative to the start of the RomFS file entry data.
2020-04-26 09:35:01 +01:00
bool romfsReadFileEntryData ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , void * out , u64 read_size , u64 offset ) ;
/// Calculates the extracted RomFS size.
bool romfsGetTotalDataSize ( RomFileSystemContext * ctx , u64 * out_size ) ;
/// Calculates the extracted size from a RomFS directory.
2020-04-29 22:11:27 +01:00
bool romfsGetDirectoryDataSize ( RomFileSystemContext * ctx , RomFileSystemDirectoryEntry * dir_entry , u64 * out_size ) ;
2020-04-27 23:37:15 +01:00
/// Retrieves a RomFS directory entry by path.
/// Input path must have a leading slash ('/'). If just a single slash is provided, a pointer to the root directory entry shall be returned.
RomFileSystemDirectoryEntry * romfsGetDirectoryEntryByPath ( RomFileSystemContext * ctx , const char * path ) ;
/// Retrieves a RomFS file entry by path.
/// Input path must have a leading slash ('/').
RomFileSystemFileEntry * romfsGetFileEntryByPath ( RomFileSystemContext * ctx , const char * path ) ;
/// Generates a path string from a RomFS directory entry.
2020-05-10 17:40:12 +01:00
bool romfsGeneratePathFromDirectoryEntry ( RomFileSystemContext * ctx , RomFileSystemDirectoryEntry * dir_entry , char * out_path , size_t out_path_size , u8 illegal_char_replace_type ) ;
2020-04-27 23:37:15 +01:00
/// Generates a path string from a RomFS file entry.
2020-05-10 17:40:12 +01:00
bool romfsGeneratePathFromFileEntry ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , char * out_path , size_t out_path_size , u8 illegal_char_replace_type ) ;
2020-04-26 09:35:01 +01:00
2020-07-22 09:03:28 +01:00
/// Generates HierarchicalSha256 (NCA0) / HierarchicalIntegrity (NCA2/NCA3) FS section patch data using a RomFS context + file entry, which can be used to seamlessly replace NCA data.
2020-04-28 09:58:17 +01:00
/// Input offset must be relative to the start of the RomFS file entry data.
/// This function shares the same limitations as ncaGenerateHierarchicalSha256Patch() / ncaGenerateHierarchicalIntegrityPatch().
2020-07-22 21:35:23 +01:00
/// Use the romfsWriteFileEntryPatchToMemoryBuffer() wrapper to write patch data generated by this function.
2020-04-28 09:58:17 +01:00
bool romfsGenerateFileEntryPatch ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , const void * data , u64 data_size , u64 data_offset , RomFileSystemFileEntryPatch * out ) ;
2020-07-22 21:35:23 +01:00
/// Miscellaneous functions.
NX_INLINE void romfsFreeContext ( RomFileSystemContext * ctx )
2020-04-28 09:58:17 +01:00
{
2020-07-22 21:35:23 +01:00
if ( ! ctx ) return ;
if ( ctx - > dir_table ) free ( ctx - > dir_table ) ;
if ( ctx - > file_table ) free ( ctx - > file_table ) ;
memset ( ctx , 0 , sizeof ( RomFileSystemContext ) ) ;
2020-04-28 09:58:17 +01:00
}
2020-04-27 23:37:15 +01:00
NX_INLINE RomFileSystemDirectoryEntry * romfsGetDirectoryEntryByOffset ( RomFileSystemContext * ctx , u32 dir_entry_offset )
2020-04-26 09:35:01 +01:00
{
2020-04-26 11:04:31 +01:00
if ( ! ctx | | ! ctx - > dir_table | | ( dir_entry_offset + sizeof ( RomFileSystemDirectoryEntry ) ) > ctx - > dir_table_size ) return NULL ;
return ( RomFileSystemDirectoryEntry * ) ( ( u8 * ) ctx - > dir_table + dir_entry_offset ) ;
2020-04-26 09:35:01 +01:00
}
2020-04-27 23:37:15 +01:00
NX_INLINE RomFileSystemFileEntry * romfsGetFileEntryByOffset ( RomFileSystemContext * ctx , u32 file_entry_offset )
2020-04-26 09:35:01 +01:00
{
2020-04-26 11:04:31 +01:00
if ( ! ctx | | ! ctx - > file_table | | ( file_entry_offset + sizeof ( RomFileSystemFileEntry ) ) > ctx - > file_table_size ) return NULL ;
return ( RomFileSystemFileEntry * ) ( ( u8 * ) ctx - > file_table + file_entry_offset ) ;
2020-04-26 09:35:01 +01:00
}
2020-07-23 01:37:02 +01:00
NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer ( RomFileSystemContext * ctx , RomFileSystemFileEntryPatch * patch , void * buf , u64 buf_size , u64 buf_offset )
2020-07-22 21:35:23 +01:00
{
if ( ! ctx | | ! ctx - > nca_fs_ctx | | ! patch | | ( ! patch - > use_old_format_patch & & ctx - > nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ) | | \
( patch - > use_old_format_patch & & ctx - > nca_fs_ctx - > section_type ! = NcaFsSectionType_Nca0RomFs ) ) return ;
if ( patch - > use_old_format_patch )
{
ncaWriteHierarchicalSha256PatchToMemoryBuffer ( ( NcaContext * ) ctx - > nca_fs_ctx - > nca_ctx , & ( patch - > old_format_patch ) , buf , buf_size , buf_offset ) ;
2020-10-28 22:48:46 +00:00
patch - > written = patch - > old_format_patch . written ;
2020-07-22 21:35:23 +01:00
} else {
ncaWriteHierarchicalIntegrityPatchToMemoryBuffer ( ( NcaContext * ) ctx - > nca_fs_ctx - > nca_ctx , & ( patch - > cur_format_patch ) , buf , buf_size , buf_offset ) ;
2020-10-28 22:48:46 +00:00
patch - > written = patch - > cur_format_patch . written ;
2020-07-22 21:35:23 +01:00
}
}
NX_INLINE void romfsFreeFileEntryPatch ( RomFileSystemFileEntryPatch * patch )
{
if ( ! patch ) return ;
ncaFreeHierarchicalSha256Patch ( & ( patch - > old_format_patch ) ) ;
ncaFreeHierarchicalIntegrityPatch ( & ( patch - > cur_format_patch ) ) ;
2020-10-28 22:48:46 +00:00
memset ( patch , 0 , sizeof ( RomFileSystemFileEntryPatch ) ) ;
2020-07-22 21:35:23 +01:00
}
2021-03-23 14:06:52 +00:00
# ifdef __cplusplus
}
2021-03-24 17:25:19 +00:00
# endif
# endif /* __ROMFS_H__ */