make MapFileOffsetToVA return ulong.MaxValue instead of throwing to improve perf and debugging experience, other elf improvements

This commit is contained in:
LukeFZ
2023-11-29 19:50:56 +01:00
parent 7c8e0eee3e
commit e6355bb1b4
2 changed files with 865 additions and 850 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,320 +1,326 @@
/* /*
Copyright 2017-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty Copyright 2017-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
All rights reserved. All rights reserved.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using NoisyCowStudios.Bin2Object; using NoisyCowStudios.Bin2Object;
namespace Il2CppInspector namespace Il2CppInspector
{ {
public interface IFileFormatStream public interface IFileFormatStream
{ {
double Version { get; set; } double Version { get; set; }
long Length { get; } long Length { get; }
uint NumImages { get; } uint NumImages { get; }
string DefaultFilename { get; } string DefaultFilename { get; }
bool IsModified { get; internal set; } bool IsModified { get; internal set; }
IEnumerable<IFileFormatStream> Images { get; } // Each child image of this object (eg. 32/64-bit versions in Fat MachO file) IEnumerable<IFileFormatStream> Images { get; } // Each child image of this object (eg. 32/64-bit versions in Fat MachO file)
IFileFormatStream this[uint index] { get; } // With no additional override, one object = one file, this[0] == this IFileFormatStream this[uint index] { get; } // With no additional override, one object = one file, this[0] == this
long Position { get; set; } long Position { get; set; }
string Format { get; } string Format { get; }
string Arch { get; } string Arch { get; }
int Bits { get; } int Bits { get; }
ulong GlobalOffset { get; } // The virtual address where the code section (.text) would be loaded in memory ulong GlobalOffset { get; } // The virtual address where the code section (.text) would be loaded in memory
ulong ImageBase { get; } // The virtual address of where the image would be loaded in memory (same as GlobalOffset except for PE) ulong ImageBase { get; } // The virtual address of where the image would be loaded in memory (same as GlobalOffset except for PE)
IEnumerable<IFileFormatStream> TryNextLoadStrategy(); // Some images can be loaded multiple ways, eg. default, packed IEnumerable<IFileFormatStream> TryNextLoadStrategy(); // Some images can be loaded multiple ways, eg. default, packed
Dictionary<string, Symbol> GetSymbolTable(); Dictionary<string, Symbol> GetSymbolTable();
uint[] GetFunctionTable(); uint[] GetFunctionTable();
IEnumerable<Export> GetExports(); IEnumerable<Export> GetExports();
IEnumerable<Section> GetSections(); IEnumerable<Section> GetSections();
bool TryGetSections(out IEnumerable<Section> sections); bool TryGetSections(out IEnumerable<Section> sections);
uint MapVATR(ulong uiAddr); uint MapVATR(ulong uiAddr);
bool TryMapVATR(ulong uiAddr, out uint fileOffset); bool TryMapVATR(ulong uiAddr, out uint fileOffset);
ulong MapFileOffsetToVA(uint offset); ulong MapFileOffsetToVA(uint offset);
bool TryMapFileOffsetToVA(uint offset, out ulong va); bool TryMapFileOffsetToVA(uint offset, out ulong va);
byte ReadByte(); byte ReadByte();
byte ReadByte(long uiAddr); byte ReadByte(long uiAddr);
byte[] ReadBytes(int count); byte[] ReadBytes(int count);
byte[] ReadBytes(long uiAddr, int count); byte[] ReadBytes(long uiAddr, int count);
bool ReadBoolean(); bool ReadBoolean();
bool ReadBoolean(long uiAddr); bool ReadBoolean(long uiAddr);
long ReadInt64(); long ReadInt64();
long ReadInt64(long uiAddr); long ReadInt64(long uiAddr);
int ReadInt32(); int ReadInt32();
int ReadInt32(long uiAddr); int ReadInt32(long uiAddr);
short ReadInt16(); short ReadInt16();
short ReadInt16(long uiAddr); short ReadInt16(long uiAddr);
ulong ReadUInt64(); ulong ReadUInt64();
ulong ReadUInt64(long uiAddr); ulong ReadUInt64(long uiAddr);
uint ReadUInt32(); uint ReadUInt32();
uint ReadUInt32(long uiAddr); uint ReadUInt32(long uiAddr);
ushort ReadUInt16(); ushort ReadUInt16();
ushort ReadUInt16(long uiAddr); ushort ReadUInt16(long uiAddr);
U ReadObject<U>() where U : new(); U ReadObject<U>() where U : new();
U ReadObject<U>(long uiAddr) where U : new(); U ReadObject<U>(long uiAddr) where U : new();
U[] ReadArray<U>(int count) where U : new(); U[] ReadArray<U>(int count) where U : new();
U[] ReadArray<U>(long uiAddr, int count) where U : new(); U[] ReadArray<U>(long uiAddr, int count) where U : new();
string ReadNullTerminatedString(Encoding encoding = null); string ReadNullTerminatedString(Encoding encoding = null);
string ReadNullTerminatedString(long uiAddr, Encoding encoding = null); string ReadNullTerminatedString(long uiAddr, Encoding encoding = null);
string ReadFixedLengthString(int length, Encoding encoding = null); string ReadFixedLengthString(int length, Encoding encoding = null);
string ReadFixedLengthString(long uiAddr, int length, Encoding encoding = null); string ReadFixedLengthString(long uiAddr, int length, Encoding encoding = null);
long ReadWord(); long ReadWord();
long ReadWord(long uiAddr); long ReadWord(long uiAddr);
long[] ReadWordArray(int count); long[] ReadWordArray(int count);
long[] ReadWordArray(long uiAddr, int count); long[] ReadWordArray(long uiAddr, int count);
byte ReadMappedByte(ulong uiAddr); byte ReadMappedByte(ulong uiAddr);
byte[] ReadMappedBytes(ulong uiAddr, int count); byte[] ReadMappedBytes(ulong uiAddr, int count);
bool ReadMappedBoolean(ulong uiAddr); bool ReadMappedBoolean(ulong uiAddr);
long ReadMappedInt64(ulong uiAddr); long ReadMappedInt64(ulong uiAddr);
int ReadMappedInt32(ulong uiAddr); int ReadMappedInt32(ulong uiAddr);
short ReadMappedInt16(ulong uiAddr); short ReadMappedInt16(ulong uiAddr);
ulong ReadMappedUInt64(ulong uiAddr); ulong ReadMappedUInt64(ulong uiAddr);
uint ReadMappedUInt32(ulong uiAddr); uint ReadMappedUInt32(ulong uiAddr);
ushort ReadMappedUInt16(ulong uiAddr); ushort ReadMappedUInt16(ulong uiAddr);
U ReadMappedObject<U>(ulong uiAddr) where U : new(); U ReadMappedObject<U>(ulong uiAddr) where U : new();
U[] ReadMappedArray<U>(ulong uiAddr, int count) where U : new(); U[] ReadMappedArray<U>(ulong uiAddr, int count) where U : new();
string ReadMappedNullTerminatedString(ulong uiAddr, Encoding encoding = null); string ReadMappedNullTerminatedString(ulong uiAddr, Encoding encoding = null);
string ReadMappedFixedLengthString(ulong uiAddr, int length, Encoding encoding = null); string ReadMappedFixedLengthString(ulong uiAddr, int length, Encoding encoding = null);
long ReadMappedWord(ulong uiAddr); long ReadMappedWord(ulong uiAddr);
long[] ReadMappedWordArray(ulong uiAddr, int count); long[] ReadMappedWordArray(ulong uiAddr, int count);
List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new(); List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new();
void WriteEndianBytes(byte[] bytes); void WriteEndianBytes(byte[] bytes);
void Write(long int64); void Write(long int64);
void Write(ulong uint64); void Write(ulong uint64);
void Write(int int32); void Write(int int32);
void Write(uint uint32); void Write(uint uint32);
void Write(short int16); void Write(short int16);
void Write(ushort uint16); void Write(ushort uint16);
void Write(long addr, byte[] bytes); void Write(long addr, byte[] bytes);
void Write(long addr, long int64); void Write(long addr, long int64);
void Write(long addr, ulong uint64); void Write(long addr, ulong uint64);
void Write(long addr, int int32); void Write(long addr, int int32);
void Write(long addr, uint uint32); void Write(long addr, uint uint32);
void Write(long addr, short int16); void Write(long addr, short int16);
void Write(long addr, ushort uint16); void Write(long addr, ushort uint16);
void Write(long addr, byte value); void Write(long addr, byte value);
void Write(long addr, bool value); void Write(long addr, bool value);
void WriteObject<T>(long addr, T obj); void WriteObject<T>(long addr, T obj);
void WriteObject<T>(T obj); void WriteObject<T>(T obj);
void WriteArray<T>(long addr, T[] array); void WriteArray<T>(long addr, T[] array);
void WriteArray<T>(T[] array); void WriteArray<T>(T[] array);
void WriteNullTerminatedString(long addr, string str, Encoding encoding = null); void WriteNullTerminatedString(long addr, string str, Encoding encoding = null);
void WriteNullTerminatedString(string str, Encoding encoding = null); void WriteNullTerminatedString(string str, Encoding encoding = null);
void WriteFixedLengthString(long addr, string str, int size = -1, Encoding encoding = null); void WriteFixedLengthString(long addr, string str, int size = -1, Encoding encoding = null);
void WriteFixedLengthString(string str, int size = -1, Encoding encoding = null); void WriteFixedLengthString(string str, int size = -1, Encoding encoding = null);
EventHandler<string> OnStatusUpdate { get; set; } EventHandler<string> OnStatusUpdate { get; set; }
public void AddPrimitiveMapping(Type objType, Type streamType); public void AddPrimitiveMapping(Type objType, Type streamType);
public void CopyTo(Stream stream); public void CopyTo(Stream stream);
} }
public class FileFormatStream public class FileFormatStream
{ {
// Helper method to try all defined file formats when the contents of the binary is unknown // Helper method to try all defined file formats when the contents of the binary is unknown
public static IFileFormatStream Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) public static IFileFormatStream Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null)
=> Load(new FileStream(filename, FileMode.Open, FileAccess.Read), loadOptions, statusCallback); => Load(new FileStream(filename, FileMode.Open, FileAccess.Read), loadOptions, statusCallback);
public static IFileFormatStream Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) { public static IFileFormatStream Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
var types = Assembly.GetExecutingAssembly().DefinedTypes var types = Assembly.GetExecutingAssembly().DefinedTypes
.Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatStream)) .Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatStream))
&& !x.IsGenericTypeDefinition && !x.IsAbstract && !x.IsInterface); && !x.IsGenericTypeDefinition && !x.IsAbstract && !x.IsInterface);
// Copy to memory-based stream // Copy to memory-based stream
var binaryObjectStream = new BinaryObjectStream(); var binaryObjectStream = new BinaryObjectStream();
stream.Position = 0; stream.Position = 0;
stream.CopyTo(binaryObjectStream); stream.CopyTo(binaryObjectStream);
binaryObjectStream.Position = 0; binaryObjectStream.Position = 0;
// Plugin hook to pre-process image before we determine its format // Plugin hook to pre-process image before we determine its format
var preProcessResult = PluginHooks.PreProcessImage(binaryObjectStream); var preProcessResult = PluginHooks.PreProcessImage(binaryObjectStream);
foreach (var type in types) { foreach (var type in types) {
try { try {
if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public, if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public,
null, new[] { typeof(BinaryObjectStream), typeof(LoadOptions), typeof(EventHandler<string>) }, null) null, new[] { typeof(BinaryObjectStream), typeof(LoadOptions), typeof(EventHandler<string>) }, null)
.Invoke(null, new object[] { binaryObjectStream, loadOptions, statusCallback }) is IFileFormatStream loaded) { .Invoke(null, new object[] { binaryObjectStream, loadOptions, statusCallback }) is IFileFormatStream loaded) {
loaded.IsModified |= preProcessResult.IsStreamModified; loaded.IsModified |= preProcessResult.IsStreamModified;
return loaded; return loaded;
} }
} }
catch (TargetInvocationException ex) { catch (TargetInvocationException ex) {
throw ex.InnerException; throw ex.InnerException;
} }
} }
return null; return null;
} }
} }
public abstract class FileFormatStream<T> : BinaryObjectStream, IFileFormatStream where T : FileFormatStream<T> public abstract class FileFormatStream<T> : BinaryObjectStream, IFileFormatStream where T : FileFormatStream<T>
{ {
public abstract string DefaultFilename { get; } public abstract string DefaultFilename { get; }
bool IFileFormatStream.IsModified { get => IsModified; set => IsModified = value; } bool IFileFormatStream.IsModified { get => IsModified; set => IsModified = value; }
public bool IsModified { get; protected set; } = false; public bool IsModified { get; protected set; } = false;
public uint NumImages { get; protected set; } = 1; public uint NumImages { get; protected set; } = 1;
public ulong GlobalOffset { get; protected set; } public ulong GlobalOffset { get; protected set; }
public virtual ulong ImageBase => GlobalOffset; public virtual ulong ImageBase => GlobalOffset;
public virtual string Format => throw new NotImplementedException(); public virtual string Format => throw new NotImplementedException();
public virtual string Arch => throw new NotImplementedException(); public virtual string Arch => throw new NotImplementedException();
public virtual int Bits => throw new NotImplementedException(); public virtual int Bits => throw new NotImplementedException();
// Extra parameters to be passed to a loader // Extra parameters to be passed to a loader
protected LoadOptions LoadOptions; protected LoadOptions LoadOptions;
public EventHandler<string> OnStatusUpdate { get; set; } public EventHandler<string> OnStatusUpdate { get; set; }
protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status); protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status);
public IEnumerable<IFileFormatStream> Images { public IEnumerable<IFileFormatStream> Images {
get { get {
for (uint i = 0; i < NumImages; i++) for (uint i = 0; i < NumImages; i++)
yield return this[i]; yield return this[i];
} }
} }
public static T Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) { public static T Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
return Load(new BinaryObjectStream(File.ReadAllBytes(filename)), loadOptions, statusCallback); return Load(new BinaryObjectStream(File.ReadAllBytes(filename)), loadOptions, statusCallback);
} }
public static T Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) { public static T Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
var binary = (T) Activator.CreateInstance(typeof(T)); var binary = (T) Activator.CreateInstance(typeof(T));
if (stream.CanSeek) if (stream.CanSeek)
stream.Position = 0; stream.Position = 0;
stream.CopyTo(binary); stream.CopyTo(binary);
return binary.InitImpl(loadOptions, statusCallback) ? binary : null; return binary.InitImpl(loadOptions, statusCallback) ? binary : null;
} }
private bool InitImpl(LoadOptions loadOptions, EventHandler<string> statusCallback) { private bool InitImpl(LoadOptions loadOptions, EventHandler<string> statusCallback) {
LoadOptions = loadOptions; LoadOptions = loadOptions;
OnStatusUpdate = statusCallback; OnStatusUpdate = statusCallback;
Position = 0; Position = 0;
if (Init()) { if (Init()) {
// Call post-process plugin hook if load succeeded // Call post-process plugin hook if load succeeded
IsModified |= PluginHooks.PostProcessImage(this).IsStreamModified; IsModified |= PluginHooks.PostProcessImage(this).IsStreamModified;
return true; return true;
} }
return false; return false;
} }
// Confirm file is valid and set up RVA mappings // Confirm file is valid and set up RVA mappings
protected virtual bool Init() => throw new NotImplementedException(); protected virtual bool Init() => throw new NotImplementedException();
// Choose an image within the file for multi-architecture binaries // Choose an image within the file for multi-architecture binaries
public virtual IFileFormatStream this[uint index] => (index == 0)? this : throw new IndexOutOfRangeException("Binary image index out of bounds"); public virtual IFileFormatStream this[uint index] => (index == 0)? this : throw new IndexOutOfRangeException("Binary image index out of bounds");
// For images that can be loaded and then tested with Il2CppBinary in multiple ways, get the next possible version of the image // For images that can be loaded and then tested with Il2CppBinary in multiple ways, get the next possible version of the image
public virtual IEnumerable<IFileFormatStream> TryNextLoadStrategy() { yield return this; } public virtual IEnumerable<IFileFormatStream> TryNextLoadStrategy() { yield return this; }
// Find search locations in the symbol table for Il2Cpp data // Find search locations in the symbol table for Il2Cpp data
public virtual Dictionary<string, Symbol> GetSymbolTable() => new Dictionary<string, Symbol>(); public virtual Dictionary<string, Symbol> GetSymbolTable() => new Dictionary<string, Symbol>();
// Find search locations in the machine code for Il2Cpp data // Find search locations in the machine code for Il2Cpp data
public virtual uint[] GetFunctionTable() => throw new NotImplementedException(); public virtual uint[] GetFunctionTable() => throw new NotImplementedException();
// Find all symbol exports for the image // Find all symbol exports for the image
public virtual IEnumerable<Export> GetExports() => null; public virtual IEnumerable<Export> GetExports() => null;
// Get all sections for the image in a universal format // Get all sections for the image in a universal format
public virtual IEnumerable<Section> GetSections() => throw new NotImplementedException(); public virtual IEnumerable<Section> GetSections() => throw new NotImplementedException();
public bool TryGetSections(out IEnumerable<Section> sections) { public bool TryGetSections(out IEnumerable<Section> sections) {
try { try {
sections = GetSections(); sections = GetSections();
return true; return true;
} catch (NotImplementedException) { } catch (NotImplementedException) {
sections = null; sections = null;
return false; return false;
} }
} }
// Map an RVA to an offset into the file image // Map an RVA to an offset into the file image
// No mapping by default // No mapping by default
public virtual uint MapVATR(ulong uiAddr) => (uint) uiAddr; public virtual uint MapVATR(ulong uiAddr) => (uint) uiAddr;
// Try to map an RVA to an offset in the file image // Try to map an RVA to an offset in the file image
public bool TryMapVATR(ulong uiAddr, out uint fileOffset) { public bool TryMapVATR(ulong uiAddr, out uint fileOffset) {
try { try {
fileOffset = MapVATR(uiAddr); fileOffset = MapVATR(uiAddr);
return true; return true;
} catch (InvalidOperationException) { } catch (InvalidOperationException) {
fileOffset = 0; fileOffset = 0;
return false; return false;
} }
} }
// Map an offset into the file image to an RVA // Map an offset into the file image to an RVA
// No mapping by default // No mapping by default
public virtual ulong MapFileOffsetToVA(uint offset) => offset; public virtual ulong MapFileOffsetToVA(uint offset) => offset;
// Try to map an offset into the file image to an RVA // Try to map an offset into the file image to an RVA
public bool TryMapFileOffsetToVA(uint offset, out ulong va) { public bool TryMapFileOffsetToVA(uint offset, out ulong va) {
try { try {
va = MapFileOffsetToVA(offset); va = MapFileOffsetToVA(offset);
return true; if (va == ulong.MaxValue)
} {
catch (InvalidOperationException) { va = 0;
va = 0; return false;
return false; }
}
} return true;
}
// Read a file format dependent word (32 or 64 bits) catch (InvalidOperationException) {
// The primitive mappings in Bin2Object will automatically read a uint if the file is 32-bit va = 0;
public long ReadWord() => ReadObject<long>(); return false;
public long ReadWord(long uiAddr) => ReadObject<long>(uiAddr); }
public long[] ReadWordArray(int count) => ReadArray<long>(count); }
public long[] ReadWordArray(long uiAddr, int count) => ReadArray<long>(uiAddr, count);
// Read a file format dependent word (32 or 64 bits)
// Retrieve items from specified RVA(s) // The primitive mappings in Bin2Object will automatically read a uint if the file is 32-bit
public byte ReadMappedByte(ulong uiAddr) => ReadByte(MapVATR(uiAddr)); public long ReadWord() => ReadObject<long>();
public byte[] ReadMappedBytes(ulong uiAddr, int count) => count > 0? ReadBytes(MapVATR(uiAddr), count) : new byte[0]; public long ReadWord(long uiAddr) => ReadObject<long>(uiAddr);
public bool ReadMappedBoolean(ulong uiAddr) => ReadBoolean(MapVATR(uiAddr)); public long[] ReadWordArray(int count) => ReadArray<long>(count);
public long ReadMappedInt64(ulong uiAddr) => ReadInt64(MapVATR(uiAddr)); public long[] ReadWordArray(long uiAddr, int count) => ReadArray<long>(uiAddr, count);
public int ReadMappedInt32(ulong uiAddr) => ReadInt32(MapVATR(uiAddr));
public short ReadMappedInt16(ulong uiAddr) => ReadInt16(MapVATR(uiAddr)); // Retrieve items from specified RVA(s)
public ulong ReadMappedUInt64(ulong uiAddr) => ReadUInt64(MapVATR(uiAddr)); public byte ReadMappedByte(ulong uiAddr) => ReadByte(MapVATR(uiAddr));
public uint ReadMappedUInt32(ulong uiAddr) => ReadUInt32(MapVATR(uiAddr)); public byte[] ReadMappedBytes(ulong uiAddr, int count) => count > 0? ReadBytes(MapVATR(uiAddr), count) : new byte[0];
public ushort ReadMappedUInt16(ulong uiAddr) => ReadUInt16(MapVATR(uiAddr)); public bool ReadMappedBoolean(ulong uiAddr) => ReadBoolean(MapVATR(uiAddr));
public long ReadMappedInt64(ulong uiAddr) => ReadInt64(MapVATR(uiAddr));
public U ReadMappedObject<U>(ulong uiAddr) where U : new() => ReadObject<U>(MapVATR(uiAddr)); public int ReadMappedInt32(ulong uiAddr) => ReadInt32(MapVATR(uiAddr));
public U[] ReadMappedArray<U>(ulong uiAddr, int count) where U : new() => count > 0 ? ReadArray<U>(MapVATR(uiAddr), count) : new U[0]; public short ReadMappedInt16(ulong uiAddr) => ReadInt16(MapVATR(uiAddr));
public string ReadMappedNullTerminatedString(ulong uiAddr, Encoding encoding = null) => ReadNullTerminatedString(MapVATR(uiAddr), encoding); public ulong ReadMappedUInt64(ulong uiAddr) => ReadUInt64(MapVATR(uiAddr));
public string ReadMappedFixedLengthString(ulong uiAddr, int length, Encoding encoding = null) => ReadFixedLengthString(MapVATR(uiAddr), length, encoding); public uint ReadMappedUInt32(ulong uiAddr) => ReadUInt32(MapVATR(uiAddr));
public ushort ReadMappedUInt16(ulong uiAddr) => ReadUInt16(MapVATR(uiAddr));
// Read a file format dependent array of words (32 or 64 bits)
// The primitive mappings in Bin2Object will automatically read a uint if the file is 32-bit public U ReadMappedObject<U>(ulong uiAddr) where U : new() => ReadObject<U>(MapVATR(uiAddr));
public long ReadMappedWord(ulong uiAddr) => ReadWord(MapVATR(uiAddr)); public U[] ReadMappedArray<U>(ulong uiAddr, int count) where U : new() => count > 0 ? ReadArray<U>(MapVATR(uiAddr), count) : new U[0];
public long[] ReadMappedWordArray(ulong uiAddr, int count) => count > 0 ? ReadArray<long>(MapVATR(uiAddr), count) : new long[0]; public string ReadMappedNullTerminatedString(ulong uiAddr, Encoding encoding = null) => ReadNullTerminatedString(MapVATR(uiAddr), encoding);
public string ReadMappedFixedLengthString(ulong uiAddr, int length, Encoding encoding = null) => ReadFixedLengthString(MapVATR(uiAddr), length, encoding);
// Reads a list of pointers, then reads each object pointed to
public List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new() { // Read a file format dependent array of words (32 or 64 bits)
var pointers = ReadMappedArray<ulong>(uiAddr, count); // The primitive mappings in Bin2Object will automatically read a uint if the file is 32-bit
var array = new List<U>(); public long ReadMappedWord(ulong uiAddr) => ReadWord(MapVATR(uiAddr));
for (int i = 0; i < count; i++) public long[] ReadMappedWordArray(ulong uiAddr, int count) => count > 0 ? ReadArray<long>(MapVATR(uiAddr), count) : new long[0];
array.Add(ReadMappedObject<U>(pointers[i]));
return array; // Reads a list of pointers, then reads each object pointed to
} public List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new() {
} var pointers = ReadMappedArray<ulong>(uiAddr, count);
var array = new List<U>();
for (int i = 0; i < count; i++)
array.Add(ReadMappedObject<U>(pointers[i]));
return array;
}
}
} }