Ryujinx/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs
Ac_K 5d08e9b495
hos: Cleanup the project (#2634)
* hos: Cleanup the project

Since a lot of changes has been done on the HOS project, there are some leftover here and there, or class just used in one service, things at wrong places, and more.
This PR fixes that, additionnally to that, I've realigned some vars because I though it make the code more readable.

* Address gdkchan feedback

* addresses Thog feedback

* Revert ElfSymbol
2021-09-15 01:24:49 +02:00

116 lines
No EOL
4.2 KiB
C#

using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.Loader;
using Ryujinx.Common.Logging;
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace Ryujinx.HLE.Loaders.Executables
{
class NsoExecutable : IExecutable
{
public byte[] Program { get; }
public Span<byte> Text => Program.AsSpan().Slice((int)TextOffset, (int)TextSize);
public Span<byte> Ro => Program.AsSpan().Slice((int)RoOffset, (int)RoSize);
public Span<byte> Data => Program.AsSpan().Slice((int)DataOffset, (int)DataSize);
public uint TextOffset { get; }
public uint RoOffset { get; }
public uint DataOffset { get; }
public uint BssOffset => DataOffset + (uint)Data.Length;
public uint TextSize { get; }
public uint RoSize { get; }
public uint DataSize { get; }
public uint BssSize { get; }
public string Name;
public Buffer32 BuildId;
public NsoExecutable(IStorage inStorage, string name = null)
{
NsoReader reader = new NsoReader();
reader.Initialize(inStorage.AsFile(OpenMode.Read)).ThrowIfFailure();
TextOffset = reader.Header.Segments[0].MemoryOffset;
RoOffset = reader.Header.Segments[1].MemoryOffset;
DataOffset = reader.Header.Segments[2].MemoryOffset;
BssSize = reader.Header.BssSize;
reader.GetSegmentSize(NsoReader.SegmentType.Data, out uint uncompressedSize).ThrowIfFailure();
Program = new byte[DataOffset + uncompressedSize];
TextSize = DecompressSection(reader, NsoReader.SegmentType.Text, TextOffset);
RoSize = DecompressSection(reader, NsoReader.SegmentType.Ro, RoOffset);
DataSize = DecompressSection(reader, NsoReader.SegmentType.Data, DataOffset);
Name = name;
BuildId = reader.Header.ModuleId;
PrintRoSectionInfo();
}
private uint DecompressSection(NsoReader reader, NsoReader.SegmentType segmentType, uint offset)
{
reader.GetSegmentSize(segmentType, out uint uncompressedSize).ThrowIfFailure();
var span = Program.AsSpan().Slice((int)offset, (int)uncompressedSize);
reader.ReadSegment(segmentType, span).ThrowIfFailure();
return uncompressedSize;
}
private void PrintRoSectionInfo()
{
string rawTextBuffer = Encoding.ASCII.GetString(Ro);
StringBuilder stringBuilder = new StringBuilder();
string modulePath = null;
if (BitConverter.ToInt32(Ro.Slice(0, 4)) == 0)
{
int length = BitConverter.ToInt32(Ro.Slice(4, 4));
if (length > 0)
{
modulePath = Encoding.UTF8.GetString(Ro.Slice(8, length));
}
}
if (string.IsNullOrEmpty(modulePath))
{
Match moduleMatch = Regex.Match(rawTextBuffer, @"[a-z]:[\\/][ -~]{5,}\.nss", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
if (moduleMatch.Success)
{
modulePath = moduleMatch.Value;
}
}
stringBuilder.AppendLine($" Module: {modulePath}");
Match fsSdkMatch = Regex.Match(rawTextBuffer, @"sdk_version: ([0-9.]*)", RegexOptions.Compiled);
if (fsSdkMatch.Success)
{
stringBuilder.AppendLine($" FS SDK Version: {fsSdkMatch.Value.Replace("sdk_version: ", "")}");
}
MatchCollection sdkMwMatches = Regex.Matches(rawTextBuffer, @"SDK MW[ -~]*", RegexOptions.Compiled);
if (sdkMwMatches.Count != 0)
{
string libHeader = " SDK Libraries: ";
string libContent = string.Join($"\n{new string(' ', libHeader.Length)}", sdkMwMatches);
stringBuilder.AppendLine($"{libHeader}{libContent}");
}
if (stringBuilder.Length > 0)
{
Logger.Info?.Print(LogClass.Loader, $"{Name}:\n{stringBuilder.ToString().TrimEnd('\r', '\n')}");
}
}
}
}