SharedFontManager.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using LibHac;
  2. using Ryujinx.HLE.FileSystem;
  3. using Ryujinx.HLE.FileSystem.Content;
  4. using Ryujinx.HLE.Resource;
  5. using Ryujinx.HLE.Utilities;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using static Ryujinx.HLE.Utilities.FontUtils;
  10. namespace Ryujinx.HLE.HOS.Font
  11. {
  12. class SharedFontManager
  13. {
  14. private Switch Device;
  15. private long PhysicalAddress;
  16. private string FontsPath;
  17. private struct FontInfo
  18. {
  19. public int Offset;
  20. public int Size;
  21. public FontInfo(int Offset, int Size)
  22. {
  23. this.Offset = Offset;
  24. this.Size = Size;
  25. }
  26. }
  27. private Dictionary<SharedFontType, FontInfo> FontData;
  28. public SharedFontManager(Switch Device, long PhysicalAddress)
  29. {
  30. this.PhysicalAddress = PhysicalAddress;
  31. this.Device = Device;
  32. FontsPath = Path.Combine(Device.FileSystem.GetSystemPath(), "fonts");
  33. }
  34. public void EnsureInitialized(ContentManager ContentManager)
  35. {
  36. if (FontData == null)
  37. {
  38. Device.Memory.FillWithZeros(PhysicalAddress, Horizon.FontSize);
  39. uint FontOffset = 0;
  40. FontInfo CreateFont(string Name)
  41. {
  42. if (ContentManager.TryGetFontTitle(Name, out long FontTitle))
  43. {
  44. string ContentPath = ContentManager.GetInstalledContentPath(FontTitle, StorageId.NandSystem, ContentType.Data);
  45. string FontPath = Device.FileSystem.SwitchPathToSystemPath(ContentPath);
  46. if (!string.IsNullOrWhiteSpace(FontPath))
  47. {
  48. int FileIndex = 0;
  49. //Use second file in Chinese Font title for standard
  50. if(Name == "FontChineseSimplified")
  51. {
  52. FileIndex = 1;
  53. }
  54. FileStream NcaFileStream = new FileStream(FontPath, FileMode.Open, FileAccess.Read);
  55. Nca Nca = new Nca(Device.System.KeySet, NcaFileStream, false);
  56. NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
  57. Romfs Romfs = new Romfs(Nca.OpenSection(RomfsSection.SectionNum, false, Device.System.FsIntegrityCheckLevel));
  58. Stream FontFile = Romfs.OpenFile(Romfs.Files[FileIndex]);
  59. byte[] Data = DecryptFont(FontFile);
  60. FontInfo Info = new FontInfo((int)FontOffset, Data.Length);
  61. WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);
  62. FontOffset += 8;
  63. uint Start = FontOffset;
  64. for (; FontOffset - Start < Data.Length; FontOffset++)
  65. {
  66. Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
  67. }
  68. NcaFileStream.Dispose();
  69. Nca.Dispose();
  70. return Info;
  71. }
  72. }
  73. string FontFilePath = Path.Combine(FontsPath, Name + ".ttf");
  74. if (File.Exists(FontFilePath))
  75. {
  76. byte[] Data = File.ReadAllBytes(FontFilePath);
  77. FontInfo Info = new FontInfo((int)FontOffset, Data.Length);
  78. WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);
  79. FontOffset += 8;
  80. uint Start = FontOffset;
  81. for (; FontOffset - Start < Data.Length; FontOffset++)
  82. {
  83. Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
  84. }
  85. return Info;
  86. }
  87. else
  88. {
  89. throw new InvalidSystemResourceException($"Font \"{Name}.ttf\" not found. Please provide it in \"{FontsPath}\".");
  90. }
  91. }
  92. FontData = new Dictionary<SharedFontType, FontInfo>()
  93. {
  94. { SharedFontType.JapanUsEurope, CreateFont("FontStandard") },
  95. { SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") },
  96. { SharedFontType.SimplifiedChineseEx, CreateFont("FontExtendedChineseSimplified") },
  97. { SharedFontType.TraditionalChinese, CreateFont("FontChineseTraditional") },
  98. { SharedFontType.Korean, CreateFont("FontKorean") },
  99. { SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") }
  100. };
  101. if (FontOffset > Horizon.FontSize)
  102. {
  103. throw new InvalidSystemResourceException(
  104. $"The sum of all fonts size exceed the shared memory size. " +
  105. $"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " +
  106. $"(actual size: {FontOffset} bytes).");
  107. }
  108. }
  109. }
  110. private void WriteMagicAndSize(long Position, int Size)
  111. {
  112. const int DecMagic = 0x18029a7f;
  113. const int Key = 0x49621806;
  114. int EncryptedSize = EndianSwap.Swap32(Size ^ Key);
  115. Device.Memory.WriteInt32(Position + 0, DecMagic);
  116. Device.Memory.WriteInt32(Position + 4, EncryptedSize);
  117. }
  118. public int GetFontSize(SharedFontType FontType)
  119. {
  120. EnsureInitialized(Device.System.ContentManager);
  121. return FontData[FontType].Size;
  122. }
  123. public int GetSharedMemoryAddressOffset(SharedFontType FontType)
  124. {
  125. EnsureInitialized(Device.System.ContentManager);
  126. return FontData[FontType].Offset + 8;
  127. }
  128. }
  129. }