// dnlib: See LICENSE.txt for more info using System.IO; using dnlib.IO; using dnlib.PE; namespace dnlib.DotNet.Writer { /// /// Data that gets written to the file /// public interface IChunk { /// /// Gets the file offset. This is valid only after has been called. /// FileOffset FileOffset { get; } /// /// Gets the RVA. This is valid only after has been called. /// RVA RVA { get; } /// /// Called when the file offset and RVA are known /// /// File offset of this chunk /// RVA of this chunk void SetOffset(FileOffset offset, RVA rva); /// /// Gets the raw file length of this chunk. Must only be called after /// has been called. /// /// Length of this chunk uint GetFileLength(); /// /// Gets the virtual size of this chunk. Must only be called after /// has been called. /// /// Virtual size of this chunk uint GetVirtualSize(); /// /// Calculates the requires alignment of this chunk. /// Returns 0 for default/no alignment. /// /// Required alignment uint CalculateAlignment(); /// /// Writes all data to at its current location. It's only /// called after and have been called. /// You cannot assume that 's file position is the same as this /// chunk's file position. /// /// Destination void WriteTo(DataWriter writer); } /// /// Implemented by s that can reuse the old data location in the original PE file /// interface IReuseChunk : IChunk { /// /// Returns true if this chunk fits in the old location /// /// Original RVA of data /// Size of the original location /// bool CanReuse(RVA origRva, uint origSize); } public static partial class Extensions { /// /// Writes all data to and verifies that all bytes were written /// /// this /// Destination /// Not all bytes were written 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}"); /// /// Writes a data directory /// /// Writer /// The data 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)); } } } }