2020-03-25 09:14:35 +01:00
using LibHac.Common ;
2019-06-01 02:31:10 +02:00
using LibHac.Fs ;
2019-10-17 08:17:44 +02:00
using LibHac.FsSystem ;
using LibHac.FsSystem.NcaUtils ;
2020-03-29 23:23:05 +02:00
using Ryujinx.Common.Logging ;
2019-10-16 02:30:36 +02:00
using Ryujinx.HLE.Exceptions ;
2018-11-18 20:37:41 +01:00
using Ryujinx.HLE.FileSystem ;
using Ryujinx.HLE.FileSystem.Content ;
2020-03-29 23:23:05 +02:00
using System ;
2019-11-23 03:15:15 +01:00
using System.Buffers.Binary ;
2018-08-15 20:59:51 +02:00
using System.Collections.Generic ;
using System.IO ;
2019-10-16 02:30:36 +02:00
2018-11-18 20:37:41 +01:00
using static Ryujinx . HLE . Utilities . FontUtils ;
2018-08-15 20:59:51 +02:00
2018-08-17 01:47:36 +02:00
namespace Ryujinx.HLE.HOS.Font
2018-08-15 20:59:51 +02:00
{
class SharedFontManager
{
2018-12-06 12:16:24 +01:00
private Switch _device ;
2018-08-15 20:59:51 +02:00
2018-12-06 12:16:24 +01:00
private long _physicalAddress ;
2018-08-15 20:59:51 +02:00
private struct FontInfo
{
public int Offset ;
public int Size ;
2018-12-06 12:16:24 +01:00
public FontInfo ( int offset , int size )
2018-08-15 20:59:51 +02:00
{
2018-12-06 12:16:24 +01:00
Offset = offset ;
Size = size ;
2018-08-15 20:59:51 +02:00
}
}
2018-12-06 12:16:24 +01:00
private Dictionary < SharedFontType , FontInfo > _fontData ;
2018-08-15 20:59:51 +02:00
2018-12-06 12:16:24 +01:00
public SharedFontManager ( Switch device , long physicalAddress )
2018-08-15 20:59:51 +02:00
{
2018-12-06 12:16:24 +01:00
_physicalAddress = physicalAddress ;
2020-03-29 23:23:05 +02:00
_device = device ;
2018-08-15 20:59:51 +02:00
}
2020-01-21 23:23:11 +01:00
public void Initialize ( ContentManager contentManager )
2020-01-12 03:10:55 +01:00
{
_fontData ? . Clear ( ) ;
_fontData = null ;
}
2020-01-21 23:23:11 +01:00
public void EnsureInitialized ( ContentManager contentManager )
2018-08-15 20:59:51 +02:00
{
2018-12-06 12:16:24 +01:00
if ( _fontData = = null )
2018-08-15 20:59:51 +02:00
{
2018-12-06 12:16:24 +01:00
_device . Memory . FillWithZeros ( _physicalAddress , Horizon . FontSize ) ;
2018-08-15 20:59:51 +02:00
2018-12-06 12:16:24 +01:00
uint fontOffset = 0 ;
2018-08-15 20:59:51 +02:00
2018-12-06 12:16:24 +01:00
FontInfo CreateFont ( string name )
2018-08-15 20:59:51 +02:00
{
2019-06-01 02:31:10 +02:00
if ( contentManager . TryGetFontTitle ( name , out long fontTitle ) & &
contentManager . TryGetFontFilename ( name , out string fontFilename ) )
2018-11-18 20:37:41 +01:00
{
2019-10-17 08:17:44 +02:00
string contentPath = contentManager . GetInstalledContentPath ( fontTitle , StorageId . NandSystem , NcaContentType . Data ) ;
2018-12-06 12:16:24 +01:00
string fontPath = _device . FileSystem . SwitchPathToSystemPath ( contentPath ) ;
2018-11-18 20:37:41 +01:00
2018-12-06 12:16:24 +01:00
if ( ! string . IsNullOrWhiteSpace ( fontPath ) )
2018-11-18 20:37:41 +01:00
{
2019-01-05 01:41:49 +01:00
byte [ ] data ;
2019-06-01 02:31:10 +02:00
using ( IStorage ncaFileStream = new LocalStorage ( fontPath , FileAccess . Read , FileMode . Open ) )
2019-01-05 01:41:49 +01:00
{
2019-06-01 02:31:10 +02:00
Nca nca = new Nca ( _device . System . KeySet , ncaFileStream ) ;
IFileSystem romfs = nca . OpenFileSystem ( NcaSectionType . Data , _device . System . FsIntegrityCheckLevel ) ;
2018-11-18 20:37:41 +01:00
2020-03-25 09:14:35 +01:00
romfs . OpenFile ( out IFile fontFile , ( "/" + fontFilename ) . ToU8Span ( ) , OpenMode . Read ) . ThrowIfFailure ( ) ;
2019-10-17 08:17:44 +02:00
data = DecryptFont ( fontFile . AsStream ( ) ) ;
2019-01-05 01:41:49 +01:00
}
2018-12-06 12:16:24 +01:00
FontInfo info = new FontInfo ( ( int ) fontOffset , data . Length ) ;
2018-11-18 20:37:41 +01:00
2018-12-06 12:16:24 +01:00
WriteMagicAndSize ( _physicalAddress + fontOffset , data . Length ) ;
2018-11-18 20:37:41 +01:00
2018-12-06 12:16:24 +01:00
fontOffset + = 8 ;
2018-11-18 20:37:41 +01:00
2018-12-06 12:16:24 +01:00
uint start = fontOffset ;
2018-11-18 20:37:41 +01:00
2018-12-06 12:16:24 +01:00
for ( ; fontOffset - start < data . Length ; fontOffset + + )
2018-11-18 20:37:41 +01:00
{
2018-12-06 12:16:24 +01:00
_device . Memory . WriteByte ( _physicalAddress + fontOffset , data [ fontOffset - start ] ) ;
2018-11-18 20:37:41 +01:00
}
2018-12-06 12:16:24 +01:00
return info ;
2018-11-18 20:37:41 +01:00
}
2020-03-29 23:23:05 +02:00
else
2018-08-15 20:59:51 +02:00
{
2020-03-29 23:23:05 +02:00
if ( ! contentManager . TryGetSystemTitlesName ( fontTitle , out string titleName ) )
{
titleName = "Unknown" ;
}
2018-08-15 20:59:51 +02:00
2020-03-29 23:23:05 +02: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 20:59:51 +02:00
}
2020-01-21 23:23:11 +01:00
else
2018-08-15 20:59:51 +02:00
{
2020-03-29 23:23:05 +02:00
throw new ArgumentException ( $"Unknown font \" { name } \ "!" ) ;
2018-08-15 20:59:51 +02:00
}
}
2018-12-06 12:16:24 +01:00
_fontData = new Dictionary < SharedFontType , FontInfo >
2018-08-15 20:59:51 +02: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 23:23:11 +01:00
if ( fontOffset > Horizon . FontSize )
2018-08-15 20:59:51 +02: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 12:16:24 +01:00
$"(actual size: {fontOffset} bytes)." ) ;
2018-08-15 20:59:51 +02:00
}
}
}
2018-12-06 12:16:24 +01:00
private void WriteMagicAndSize ( long position , int size )
2018-08-15 20:59:51 +02:00
{
2018-12-06 12:16:24 +01:00
const int decMagic = 0x18029a7f ;
const int key = 0x49621806 ;
2018-08-15 20:59:51 +02:00
2019-11-23 03:15:15 +01:00
int encryptedSize = BinaryPrimitives . ReverseEndianness ( size ^ key ) ;
2018-08-15 20:59:51 +02:00
2018-12-06 12:16:24 +01:00
_device . Memory . WriteInt32 ( position + 0 , decMagic ) ;
_device . Memory . WriteInt32 ( position + 4 , encryptedSize ) ;
2018-08-15 20:59:51 +02:00
}
2018-12-06 12:16:24 +01:00
public int GetFontSize ( SharedFontType fontType )
2018-08-15 20:59:51 +02:00
{
2020-01-21 23:23:11 +01:00
EnsureInitialized ( _device . System . ContentManager ) ;
2018-08-15 20:59:51 +02:00
2018-12-06 12:16:24 +01:00
return _fontData [ fontType ] . Size ;
2018-08-15 20:59:51 +02:00
}
2018-12-06 12:16:24 +01:00
public int GetSharedMemoryAddressOffset ( SharedFontType fontType )
2018-08-15 20:59:51 +02:00
{
2020-01-21 23:23:11 +01:00
EnsureInitialized ( _device . System . ContentManager ) ;
2018-08-15 20:59:51 +02:00
2018-12-06 12:16:24 +01:00
return _fontData [ fontType ] . Offset + 8 ;
2018-08-15 20:59:51 +02:00
}
}
}