mirror of
https://github.com/AssetRipper/Cpp2IL.git
synced 2026-11-13 04:26:33 -10:00
106 lines
2.9 KiB
C#
106 lines
2.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.IO.Compression;
|
|
|
|
namespace Cpp2IL.Core.Extensions;
|
|
|
|
public static class StreamExtensions
|
|
{
|
|
public static uint ReadUnityCompressedUint(this Stream stream)
|
|
{
|
|
if (stream.Position == stream.Length)
|
|
throw new EndOfStreamException();
|
|
|
|
var b = stream.ReadByte();
|
|
if (b < 128)
|
|
return (uint)b;
|
|
if (b == 240)
|
|
{
|
|
//Full Uint
|
|
#if NET7_0_OR_GREATER
|
|
Span<byte> buffer = stackalloc byte[4];
|
|
stream.ReadExactly(buffer);
|
|
return BitConverter.ToUInt32(buffer);
|
|
#elif NET5_0_OR_GREATER
|
|
Span<byte> buffer = stackalloc byte[4];
|
|
stream.Read(buffer);
|
|
return BitConverter.ToUInt32(buffer);
|
|
#else
|
|
var buffer = new byte[4];
|
|
stream.Read(buffer, 0, 4);
|
|
return BitConverter.ToUInt32(buffer, 0);
|
|
#endif
|
|
}
|
|
|
|
//Special constant values
|
|
if (b == byte.MaxValue)
|
|
return uint.MaxValue;
|
|
if (b == 254)
|
|
return uint.MaxValue - 1;
|
|
|
|
if ((b & 192) == 192)
|
|
{
|
|
//3 more to read
|
|
return (uint)((b & ~192U) << 24 | (uint)(stream.ReadByte() << 16) | (uint)(stream.ReadByte() << 8) | (uint)stream.ReadByte());
|
|
}
|
|
|
|
if ((b & 128) == 128)
|
|
{
|
|
//1 more to read
|
|
return (uint)((b & ~128U) << 8 | (uint)stream.ReadByte());
|
|
}
|
|
|
|
|
|
throw new Exception($"How did we even get here? Invalid compressed int first byte {b}");
|
|
}
|
|
|
|
public static int ReadUnityCompressedInt(this Stream stream)
|
|
{
|
|
//Ref libil2cpp, il2cpp\utils\ReadCompressedInt32
|
|
var unsigned = stream.ReadUnityCompressedUint();
|
|
|
|
if (unsigned == uint.MaxValue)
|
|
return int.MinValue;
|
|
|
|
var isNegative = (unsigned & 1) == 1;
|
|
unsigned >>= 1;
|
|
if (isNegative)
|
|
return -(int)(unsigned + 1);
|
|
|
|
return (int)unsigned;
|
|
}
|
|
|
|
public static string ReadUnicodeString(this BinaryReader reader)
|
|
{
|
|
List<byte> bytes = [];
|
|
var continueReading = true;
|
|
var lastWasNull = false;
|
|
while (continueReading)
|
|
{
|
|
var b = reader.ReadByte();
|
|
|
|
if (b == 0 && lastWasNull)
|
|
//Double null is a terminator for unicode strings
|
|
continueReading = false;
|
|
|
|
lastWasNull = b == 0;
|
|
bytes.Add(b);
|
|
}
|
|
|
|
bytes.Add(reader.ReadByte()); //Last byte of null terminator will always be skipped - unskip it
|
|
|
|
return Encoding.Unicode.GetString(bytes.ToArray()).TrimEnd('\0');
|
|
}
|
|
|
|
public static byte[] ReadBytes(this Stream stream)
|
|
{
|
|
using var ms = new MemoryStream();
|
|
stream.CopyTo(ms);
|
|
return ms.ToArray();
|
|
}
|
|
|
|
public static byte[] ReadBytes(this ZipArchiveEntry entry) => entry.Open().ReadBytes();
|
|
}
|