// 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));
}
}
}
}