Editor/RbxlReader/Chunks/RbxlBinaryReader.cs
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace RbxlReader.Chunks;
/// <summary>
/// Binary Reader best suited for reading .rbxl files.
///
/// Credits to Roblox-File-Format (MIT) repo. By CloneTrooper1019 (MaximumADHD)
/// </summary>
public class RbxlBinaryReader(Stream stream) : BinaryReader(stream) {
private byte[] lastStringBuffer = Array.Empty<byte>();
/// <summary>
/// credits to CloneTrooper for this code is stole
/// </summary>
public T[] ReadInterleaved<T>(int count, Func<byte[], int, T> transform) where T : struct {
int sizeof_T = Marshal.SizeOf<T>();
int blobSize = count * sizeof_T;
var blob = ReadBytes(blobSize);
var work = new byte[sizeof_T];
var values = new T[count];
for (int offset = 0; offset < count; offset++) {
for (int i = 0; i < sizeof_T; i++) {
int index = (i * count) + offset;
work[sizeof_T - i - 1] = blob[index];
}
values[offset] = transform(work, 0);
}
return values;
}
public int RotateInt32(byte[] buffer, int startIndex) {
int value = BitConverter.ToInt32(buffer, startIndex);
return (int)((uint)value >> 1) ^ (-(value & 1));
}
public long RotateInt64(byte[] buffer, int startIndex) {
long value = BitConverter.ToInt64(buffer, startIndex);
return (long)((ulong)value >> 1) ^ (-(value & 1));
}
public float RotateFloat(byte[] buffer, int startIndex) {
uint u = BitConverter.ToUInt32(buffer, startIndex);
uint i = (u >> 1) | (u << 31);
byte[] b = BitConverter.GetBytes(i);
return BitConverter.ToSingle(b, 0);
}
public List<int> ReadInstanceIds(int count) {
int[] values = ReadInterleaved(count, RotateInt32);
for (int i = 1; i < count; ++i)
values[i] += values[i - 1];
return values.ToList();
}
/// <summary>
/// Overriden ReadString()
/// </summary>
/// <returns></returns>
public override string ReadString() {
int length = ReadInt32();
byte[] buffer = ReadBytes(length);
return Encoding.UTF8.GetString(buffer);
}
public float ReadFloat() => ReadSingle();
public byte[] GetLastStringBuffer() {
return lastStringBuffer;
}
}