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. Offset = offset;
  24. Size = size;
  25. }
  26. }
  27. private Dictionary<SharedFontType, FontInfo> _fontData;
  28. public SharedFontManager(Switch device, long physicalAddress)
  29. {
  30. _physicalAddress = physicalAddress;
  31. _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. }