obfuz/Plugins/dnlib/DotNet/Writer/IChunk.cs

116 lines
3.9 KiB
C#

// dnlib: See LICENSE.txt for more info
using System.IO;
using dnlib.IO;
using dnlib.PE;
namespace dnlib.DotNet.Writer {
/// <summary>
/// Data that gets written to the file
/// </summary>
public interface IChunk {
/// <summary>
/// Gets the file offset. This is valid only after <see cref="SetOffset"/> has been called.
/// </summary>
FileOffset FileOffset { get; }
/// <summary>
/// Gets the RVA. This is valid only after <see cref="SetOffset"/> has been called.
/// </summary>
RVA RVA { get; }
/// <summary>
/// Called when the file offset and RVA are known
/// </summary>
/// <param name="offset">File offset of this chunk</param>
/// <param name="rva">RVA of this chunk</param>
void SetOffset(FileOffset offset, RVA rva);
/// <summary>
/// Gets the raw file length of this chunk. Must only be called after <see cref="SetOffset"/>
/// has been called.
/// </summary>
/// <returns>Length of this chunk</returns>
uint GetFileLength();
/// <summary>
/// Gets the virtual size of this chunk. Must only be called after <see cref="SetOffset"/>
/// has been called.
/// </summary>
/// <returns>Virtual size of this chunk</returns>
uint GetVirtualSize();
/// <summary>
/// Calculates the requires alignment of this chunk.
/// Returns 0 for default/no alignment.
/// </summary>
/// <returns>Required alignment</returns>
uint CalculateAlignment();
/// <summary>
/// Writes all data to <paramref name="writer"/> at its current location. It's only
/// called after <see cref="SetOffset"/> and <see cref="GetFileLength"/> have been called.
/// You cannot assume that <paramref name="writer"/>'s file position is the same as this
/// chunk's file position.
/// </summary>
/// <param name="writer">Destination</param>
void WriteTo(DataWriter writer);
}
/// <summary>
/// Implemented by <see cref="IChunk"/>s that can reuse the old data location in the original PE file
/// </summary>
interface IReuseChunk : IChunk {
/// <summary>
/// Returns true if this chunk fits in the old location
/// </summary>
/// <param name="origRva">Original RVA of data</param>
/// <param name="origSize">Size of the original location</param>
/// <returns></returns>
bool CanReuse(RVA origRva, uint origSize);
}
public static partial class Extensions {
/// <summary>
/// Writes all data to <paramref name="writer"/> and verifies that all bytes were written
/// </summary>
/// <param name="chunk">this</param>
/// <param name="writer">Destination</param>
/// <exception cref="IOException">Not all bytes were written</exception>
public static void VerifyWriteTo(this IChunk chunk, DataWriter writer) {
long pos = writer.Position;
// Uncomment this to add some debug info, useful when comparing old vs new version
//System.Diagnostics.Debug.WriteLine($" RVA 0x{(uint)chunk.RVA:X8} OFFS 0x{(uint)chunk.FileOffset:X8} VSIZE 0x{chunk.GetVirtualSize():X8} {chunk.GetType().FullName}");
chunk.WriteTo(writer);
if (writer.Position - pos != chunk.GetFileLength())
VerifyWriteToThrow(chunk);
}
static void VerifyWriteToThrow(IChunk chunk) =>
throw new IOException($"Did not write all bytes: {chunk.GetType().FullName}");
/// <summary>
/// Writes a data directory
/// </summary>
/// <param name="writer">Writer</param>
/// <param name="chunk">The data</param>
internal static void WriteDataDirectory(this DataWriter writer, IChunk chunk) {
if (chunk is null || chunk.GetVirtualSize() == 0)
writer.WriteUInt64(0);
else {
writer.WriteUInt32((uint)chunk.RVA);
writer.WriteUInt32(chunk.GetVirtualSize());
}
}
internal static void WriteDebugDirectory(this DataWriter writer, DebugDirectory chunk) {
if (chunk is null || chunk.GetVirtualSize() == 0)
writer.WriteUInt64(0);
else {
writer.WriteUInt32((uint)chunk.RVA);
writer.WriteUInt32((uint)(chunk.Count * DebugDirectory.HEADER_SIZE));
}
}
}
}