Switched to Ryujinx's implementation of LZ4

Fixed stream handling in Nso.cs
This commit is contained in:
shadowninja108 2018-09-22 21:46:15 -07:00
parent 73b472befa
commit e694833e0c
3 changed files with 103 additions and 13 deletions

View file

@ -27,7 +27,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="lz4net" Version="1.0.15.93" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" Condition=" '$(TargetFramework)' == 'net46' " />
</ItemGroup>

78
libhac/Lz4.cs Normal file
View file

@ -0,0 +1,78 @@
using System;
namespace Ryujinx.HLE.Loaders.Compression
{
static class Lz4
{
public static byte[] Decompress(byte[] Cmp, int DecLength)
{
byte[] Dec = new byte[DecLength];
int CmpPos = 0;
int DecPos = 0;
int GetLength(int Length)
{
byte Sum;
if (Length == 0xf)
{
do
{
Length += (Sum = Cmp[CmpPos++]);
}
while (Sum == 0xff);
}
return Length;
}
do
{
byte Token = Cmp[CmpPos++];
int EncCount = (Token >> 0) & 0xf;
int LitCount = (Token >> 4) & 0xf;
//Copy literal chunck
LitCount = GetLength(LitCount);
Buffer.BlockCopy(Cmp, CmpPos, Dec, DecPos, LitCount);
CmpPos += LitCount;
DecPos += LitCount;
if (CmpPos >= Cmp.Length)
{
break;
}
//Copy compressed chunck
int Back = Cmp[CmpPos++] << 0 |
Cmp[CmpPos++] << 8;
EncCount = GetLength(EncCount) + 4;
int EncPos = DecPos - Back;
if (EncCount <= Back)
{
Buffer.BlockCopy(Dec, EncPos, Dec, DecPos, EncCount);
DecPos += EncCount;
}
else
{
while (EncCount-- > 0)
{
Dec[DecPos++] = Dec[EncPos++];
}
}
}
while (CmpPos < Cmp.Length &&
DecPos < Dec.Length);
return Dec;
}
}
}

View file

@ -1,5 +1,5 @@
using LibHac.Streams;
using LZ4;
using Ryujinx.HLE.Loaders.Compression;
using System;
using System.Collections;
using System.Collections.Generic;
@ -15,19 +15,20 @@ namespace LibHac
public uint BssSize;
public byte[] BuildID = new byte[0x20];
private BinaryReader reader;
private SharedStreamSource StreamSource;
public Nso(Stream stream)
{
reader = new BinaryReader(stream);
StreamSource = new SharedStreamSource(stream);
BinaryReader reader = new BinaryReader(StreamSource.CreateStream());
if (reader.ReadAscii(4) != "NSO0")
throw new InvalidDataException("NSO magic is incorrect!");
reader.ReadUInt32(); // Version
reader.ReadUInt32(); // Reserved/Unused
BitArray flags = new BitArray(new int[] { (int) reader.ReadUInt32() });
NsoSection textSection = new NsoSection(stream);
NsoSection rodataSection = new NsoSection(stream);
NsoSection dataSection = new NsoSection(stream);
NsoSection textSection = new NsoSection(StreamSource);
NsoSection rodataSection = new NsoSection(StreamSource);
NsoSection dataSection = new NsoSection(StreamSource);
textSection.IsCompressed = flags[0];
textSection.CheckHash = flags[3];
rodataSection.IsCompressed = flags[1];
@ -56,26 +57,31 @@ namespace LibHac
reader.Read(dataSection.Hash, 0, 0x20);
Sections = new NsoSection[] {textSection, rodataSection, dataSection };
reader.Close();
}
public void ReadSegmentHeader(NsoSection section)
{
BinaryReader reader = new BinaryReader(StreamSource.CreateStream());
section.FileOffset = reader.ReadUInt32();
section.MemoryOffset = reader.ReadUInt32();
section.DecompressedSize = reader.ReadUInt32();
reader.Close();
}
public RodataRelativeExtent ReadRodataRelativeExtent()
{
BinaryReader reader = new BinaryReader(StreamSource.CreateStream());
RodataRelativeExtent extent = new RodataRelativeExtent();
extent.RegionRodataOffset = reader.ReadUInt32();
extent.RegionSize = reader.ReadUInt32();
reader.Close();
return extent;
}
public class NsoSection
{
private Stream Stream;
private readonly SharedStreamSource StreamSource;
public bool IsCompressed,
CheckHash;
@ -85,19 +91,26 @@ namespace LibHac
CompressedSize;
public byte[] Hash = new byte[0x20];
public NsoSection(Stream stream)
public NsoSection(SharedStreamSource streamSource)
{
Stream = stream;
StreamSource = streamSource;
}
public Stream OpenCompressedStream()
{
return new SubStream(Stream, FileOffset, CompressedSize);
return StreamSource.CreateStream(FileOffset, CompressedSize);
}
public Stream OpenDecompressedStream()
{
return new LZ4Stream(OpenCompressedStream(), LZ4StreamMode.Decompress);
return new MemoryStream(Decompress());
}
public byte[] Decompress()
{
byte[] compressed = new byte[CompressedSize];
OpenCompressedStream().Read(compressed, 0, (int) CompressedSize);
return Lz4.Decompress(compressed, (int) DecompressedSize);
}
}