2020-03-25 01:14:35 -07:00
using LibHac.Common ;
2019-05-31 17:31:10 -07:00
using LibHac.Fs ;
2020-09-01 13:08:59 -07:00
using LibHac.Fs.Fsa ;
2019-10-16 23:17:44 -07:00
using LibHac.FsSystem ;
using LibHac.FsSystem.NcaUtils ;
2019-10-15 17:30:36 -07:00
using Ryujinx.HLE.Exceptions ;
2018-11-18 11:37:41 -08:00
using Ryujinx.HLE.FileSystem ;
using Ryujinx.HLE.FileSystem.Content ;
2020-03-29 14:23:05 -07:00
using System ;
2019-11-22 18:15:15 -08:00
using System.Buffers.Binary ;
2018-08-15 11:59:51 -07:00
using System.Collections.Generic ;
using System.IO ;
2019-10-15 17:30:36 -07:00
2018-11-18 11:37:41 -08:00
using static Ryujinx . HLE . Utilities . FontUtils ;
2018-08-15 11:59:51 -07:00
2018-08-16 16:47:36 -07:00
namespace Ryujinx.HLE.HOS.Font
2018-08-15 11:59:51 -07:00
{
class SharedFontManager
{
2018-12-06 03:16:24 -08:00
private Switch _device ;
2018-08-15 11:59:51 -07:00
2020-05-03 15:54:50 -07:00
private ulong _physicalAddress ;
2018-08-15 11:59:51 -07:00
private struct FontInfo
{
public int Offset ;
public int Size ;
2018-12-06 03:16:24 -08:00
public FontInfo ( int offset , int size )
2018-08-15 11:59:51 -07:00
{
2018-12-06 03:16:24 -08:00
Offset = offset ;
Size = size ;
2018-08-15 11:59:51 -07:00
}
}
2018-12-06 03:16:24 -08:00
private Dictionary < SharedFontType , FontInfo > _fontData ;
2018-08-15 11:59:51 -07:00
2020-05-03 15:54:50 -07:00
public SharedFontManager ( Switch device , ulong physicalAddress )
2018-08-15 11:59:51 -07:00
{
2018-12-06 03:16:24 -08:00
_physicalAddress = physicalAddress ;
2020-03-29 14:23:05 -07:00
_device = device ;
2018-08-15 11:59:51 -07:00
}
2020-01-21 14:23:11 -08:00
public void Initialize ( ContentManager contentManager )
2020-01-11 18:10:55 -08:00
{
_fontData ? . Clear ( ) ;
_fontData = null ;
}
2020-01-21 14:23:11 -08:00
public void EnsureInitialized ( ContentManager contentManager )
2018-08-15 11:59:51 -07:00
{
2018-12-06 03:16:24 -08:00
if ( _fontData = = null )
2018-08-15 11:59:51 -07:00
{
2020-05-03 15:54:50 -07:00
_device . Memory . ZeroFill ( _physicalAddress , Horizon . FontSize ) ;
2018-08-15 11:59:51 -07:00
2018-12-06 03:16:24 -08:00
uint fontOffset = 0 ;
2018-08-15 11:59:51 -07:00
2018-12-06 03:16:24 -08:00
FontInfo CreateFont ( string name )
2018-08-15 11:59:51 -07:00
{
2019-05-31 17:31:10 -07:00
if ( contentManager . TryGetFontTitle ( name , out long fontTitle ) & &
contentManager . TryGetFontFilename ( name , out string fontFilename ) )
2018-11-18 11:37:41 -08:00
{
2019-10-16 23:17:44 -07:00
string contentPath = contentManager . GetInstalledContentPath ( fontTitle , StorageId . NandSystem , NcaContentType . Data ) ;
2018-12-06 03:16:24 -08:00
string fontPath = _device . FileSystem . SwitchPathToSystemPath ( contentPath ) ;
2018-11-18 11:37:41 -08:00
2018-12-06 03:16:24 -08:00
if ( ! string . IsNullOrWhiteSpace ( fontPath ) )
2018-11-18 11:37:41 -08:00
{
2019-01-04 16:41:49 -08:00
byte [ ] data ;
2020-05-03 15:54:50 -07:00
2019-05-31 17:31:10 -07:00
using ( IStorage ncaFileStream = new LocalStorage ( fontPath , FileAccess . Read , FileMode . Open ) )
2019-01-04 16:41:49 -08:00
{
2019-05-31 17:31:10 -07:00
Nca nca = new Nca ( _device . System . KeySet , ncaFileStream ) ;
IFileSystem romfs = nca . OpenFileSystem ( NcaSectionType . Data , _device . System . FsIntegrityCheckLevel ) ;
2018-11-18 11:37:41 -08:00
2020-03-25 01:14:35 -07:00
romfs . OpenFile ( out IFile fontFile , ( "/" + fontFilename ) . ToU8Span ( ) , OpenMode . Read ) . ThrowIfFailure ( ) ;
2019-10-16 23:17:44 -07:00
data = DecryptFont ( fontFile . AsStream ( ) ) ;
2019-01-04 16:41:49 -08:00
}
2020-05-03 15:54:50 -07:00
2018-12-06 03:16:24 -08:00
FontInfo info = new FontInfo ( ( int ) fontOffset , data . Length ) ;
2018-11-18 11:37:41 -08:00
2018-12-06 03:16:24 -08:00
WriteMagicAndSize ( _physicalAddress + fontOffset , data . Length ) ;
2018-11-18 11:37:41 -08:00
2018-12-06 03:16:24 -08:00
fontOffset + = 8 ;
2018-11-18 11:37:41 -08:00
2018-12-06 03:16:24 -08:00
uint start = fontOffset ;
2018-11-18 11:37:41 -08:00
2018-12-06 03:16:24 -08:00
for ( ; fontOffset - start < data . Length ; fontOffset + + )
2018-11-18 11:37:41 -08:00
{
2020-05-03 15:54:50 -07:00
_device . Memory . Write ( _physicalAddress + fontOffset , data [ fontOffset - start ] ) ;
2018-11-18 11:37:41 -08:00
}
2018-12-06 03:16:24 -08:00
return info ;
2018-11-18 11:37:41 -08:00
}
2020-03-29 14:23:05 -07:00
else
2018-08-15 11:59:51 -07:00
{
2020-03-29 14:23:05 -07:00
if ( ! contentManager . TryGetSystemTitlesName ( fontTitle , out string titleName ) )
{
titleName = "Unknown" ;
}
2018-08-15 11:59:51 -07:00
2020-03-29 14:23:05 -07:00
throw new InvalidSystemResourceException ( $"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/Ryujinx/Ryujinx#requirements for more information)" ) ;
}
2018-08-15 11:59:51 -07:00
}
2020-01-21 14:23:11 -08:00
else
2018-08-15 11:59:51 -07:00
{
2020-03-29 14:23:05 -07:00
throw new ArgumentException ( $"Unknown font \" { name } \ "!" ) ;
2018-08-15 11:59:51 -07:00
}
}
2018-12-06 03:16:24 -08:00
_fontData = new Dictionary < SharedFontType , FontInfo >
2018-08-15 11:59:51 -07:00
{
{ SharedFontType . JapanUsEurope , CreateFont ( "FontStandard" ) } ,
{ SharedFontType . SimplifiedChinese , CreateFont ( "FontChineseSimplified" ) } ,
{ SharedFontType . SimplifiedChineseEx , CreateFont ( "FontExtendedChineseSimplified" ) } ,
{ SharedFontType . TraditionalChinese , CreateFont ( "FontChineseTraditional" ) } ,
{ SharedFontType . Korean , CreateFont ( "FontKorean" ) } ,
{ SharedFontType . NintendoEx , CreateFont ( "FontNintendoExtended" ) }
} ;
2020-01-21 14:23:11 -08:00
if ( fontOffset > Horizon . FontSize )
2018-08-15 11:59:51 -07:00
{
throw new InvalidSystemResourceException (
$"The sum of all fonts size exceed the shared memory size. " +
$"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " +
2018-12-06 03:16:24 -08:00
$"(actual size: {fontOffset} bytes)." ) ;
2018-08-15 11:59:51 -07:00
}
}
}
2020-05-03 15:54:50 -07:00
private void WriteMagicAndSize ( ulong address , int size )
2018-08-15 11:59:51 -07:00
{
2018-12-06 03:16:24 -08:00
const int decMagic = 0x18029a7f ;
const int key = 0x49621806 ;
2018-08-15 11:59:51 -07:00
2019-11-22 18:15:15 -08:00
int encryptedSize = BinaryPrimitives . ReverseEndianness ( size ^ key ) ;
2018-08-15 11:59:51 -07:00
2020-05-03 15:54:50 -07:00
_device . Memory . Write ( address + 0 , decMagic ) ;
_device . Memory . Write ( address + 4 , encryptedSize ) ;
2018-08-15 11:59:51 -07:00
}
2018-12-06 03:16:24 -08:00
public int GetFontSize ( SharedFontType fontType )
2018-08-15 11:59:51 -07:00
{
2020-01-21 14:23:11 -08:00
EnsureInitialized ( _device . System . ContentManager ) ;
2018-08-15 11:59:51 -07:00
2018-12-06 03:16:24 -08:00
return _fontData [ fontType ] . Size ;
2018-08-15 11:59:51 -07:00
}
2018-12-06 03:16:24 -08:00
public int GetSharedMemoryAddressOffset ( SharedFontType fontType )
2018-08-15 11:59:51 -07:00
{
2020-01-21 14:23:11 -08:00
EnsureInitialized ( _device . System . ContentManager ) ;
2018-08-15 11:59:51 -07:00
2018-12-06 03:16:24 -08:00
return _fontData [ fontType ] . Offset + 8 ;
2018-08-15 11:59:51 -07:00
}
}
}