mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2024-11-27 09:30:51 +01:00
d5c0de8362
* Implement IRoInterface This is required by Super Mario Party. This commit also adds MapProcessCodeMemory and UnmapProcessCodeMemory functions in KMemoryManager. Those two calls might not reflect what the SVC of the same names do. * Fix some code style issues * Use MakeError to clarify error code * Add NRR and NRO constants * Fix some codestyle issues * Fix InvalidMemoryState error code
127 lines
4.0 KiB
C#
127 lines
4.0 KiB
C#
using Ryujinx.HLE.Loaders.Compression;
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace Ryujinx.HLE.Loaders.Executables
|
|
{
|
|
class Nso : IExecutable
|
|
{
|
|
public string FilePath { get; private set; }
|
|
|
|
public byte[] Text { get; private set; }
|
|
public byte[] RO { get; private set; }
|
|
public byte[] Data { get; private set; }
|
|
|
|
public int Mod0Offset { get; private set; }
|
|
public int TextOffset { get; private set; }
|
|
public int ROOffset { get; private set; }
|
|
public int DataOffset { get; private set; }
|
|
public int BssSize { get; private set; }
|
|
|
|
public long SourceAddress { get; private set; }
|
|
public long BssAddress { get; private set; }
|
|
|
|
[Flags]
|
|
private enum NsoFlags
|
|
{
|
|
IsTextCompressed = 1 << 0,
|
|
IsROCompressed = 1 << 1,
|
|
IsDataCompressed = 1 << 2,
|
|
HasTextHash = 1 << 3,
|
|
HasROHash = 1 << 4,
|
|
HasDataHash = 1 << 5
|
|
}
|
|
|
|
public Nso(Stream Input, string FilePath)
|
|
{
|
|
this.FilePath = FilePath;
|
|
|
|
SourceAddress = 0;
|
|
BssAddress = 0;
|
|
|
|
BinaryReader Reader = new BinaryReader(Input);
|
|
|
|
Input.Seek(0, SeekOrigin.Begin);
|
|
|
|
int NsoMagic = Reader.ReadInt32();
|
|
int Version = Reader.ReadInt32();
|
|
int Reserved = Reader.ReadInt32();
|
|
int FlagsMsk = Reader.ReadInt32();
|
|
int TextOffset = Reader.ReadInt32();
|
|
int TextMemOffset = Reader.ReadInt32();
|
|
int TextDecSize = Reader.ReadInt32();
|
|
int ModNameOffset = Reader.ReadInt32();
|
|
int ROOffset = Reader.ReadInt32();
|
|
int ROMemOffset = Reader.ReadInt32();
|
|
int RODecSize = Reader.ReadInt32();
|
|
int ModNameSize = Reader.ReadInt32();
|
|
int DataOffset = Reader.ReadInt32();
|
|
int DataMemOffset = Reader.ReadInt32();
|
|
int DataDecSize = Reader.ReadInt32();
|
|
int BssSize = Reader.ReadInt32();
|
|
|
|
byte[] BuildId = Reader.ReadBytes(0x20);
|
|
|
|
int TextSize = Reader.ReadInt32();
|
|
int ROSize = Reader.ReadInt32();
|
|
int DataSize = Reader.ReadInt32();
|
|
|
|
Input.Seek(0x24, SeekOrigin.Current);
|
|
|
|
int DynStrOffset = Reader.ReadInt32();
|
|
int DynStrSize = Reader.ReadInt32();
|
|
int DynSymOffset = Reader.ReadInt32();
|
|
int DynSymSize = Reader.ReadInt32();
|
|
|
|
byte[] TextHash = Reader.ReadBytes(0x20);
|
|
byte[] ROHash = Reader.ReadBytes(0x20);
|
|
byte[] DataHash = Reader.ReadBytes(0x20);
|
|
|
|
NsoFlags Flags = (NsoFlags)FlagsMsk;
|
|
|
|
this.TextOffset = TextMemOffset;
|
|
this.ROOffset = ROMemOffset;
|
|
this.DataOffset = DataMemOffset;
|
|
this.BssSize = BssSize;
|
|
|
|
//Text segment
|
|
Input.Seek(TextOffset, SeekOrigin.Begin);
|
|
|
|
Text = Reader.ReadBytes(TextSize);
|
|
|
|
if (Flags.HasFlag(NsoFlags.IsTextCompressed) || true)
|
|
{
|
|
Text = Lz4.Decompress(Text, TextDecSize);
|
|
}
|
|
|
|
//Read-only data segment
|
|
Input.Seek(ROOffset, SeekOrigin.Begin);
|
|
|
|
RO = Reader.ReadBytes(ROSize);
|
|
|
|
if (Flags.HasFlag(NsoFlags.IsROCompressed) || true)
|
|
{
|
|
RO = Lz4.Decompress(RO, RODecSize);
|
|
}
|
|
|
|
//Data segment
|
|
Input.Seek(DataOffset, SeekOrigin.Begin);
|
|
|
|
Data = Reader.ReadBytes(DataSize);
|
|
|
|
if (Flags.HasFlag(NsoFlags.IsDataCompressed) || true)
|
|
{
|
|
Data = Lz4.Decompress(Data, DataDecSize);
|
|
}
|
|
|
|
using (MemoryStream TextMS = new MemoryStream(Text))
|
|
{
|
|
BinaryReader TextReader = new BinaryReader(TextMS);
|
|
|
|
TextMS.Seek(4, SeekOrigin.Begin);
|
|
|
|
Mod0Offset = TextReader.ReadInt32();
|
|
}
|
|
}
|
|
}
|
|
} |