// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using dnlib.IO; using dnlib.PE; namespace dnlib.DotNet.Writer { /// /// Base class of chunk list types /// /// Chunk type public abstract class ChunkListBase : IChunk where T : IChunk { /// All chunks protected List chunks; uint length; uint virtualSize; /// true if has been called protected bool setOffsetCalled; FileOffset offset; RVA rva; internal bool IsEmpty => chunks.Count == 0; /// /// Helper struct /// protected readonly struct Elem { /// Data public readonly T chunk; /// Alignment public readonly uint alignment; /// /// Constructor /// /// Chunk /// Alignment public Elem(T chunk, uint alignment) { this.chunk = chunk; this.alignment = alignment; } } /// /// Equality comparer for /// protected sealed class ElemEqualityComparer : IEqualityComparer { IEqualityComparer chunkComparer; /// /// Constructor /// /// Compares the chunk type public ElemEqualityComparer(IEqualityComparer chunkComparer) => this.chunkComparer = chunkComparer; /// public bool Equals(Elem x, Elem y) => x.alignment == y.alignment && chunkComparer.Equals(x.chunk, y.chunk); /// public int GetHashCode(Elem obj) => (int)obj.alignment + chunkComparer.GetHashCode(obj.chunk); } /// public FileOffset FileOffset => offset; /// public RVA RVA => rva; /// public virtual void SetOffset(FileOffset offset, RVA rva) { setOffsetCalled = true; this.offset = offset; this.rva = rva; length = 0; virtualSize = 0; foreach (var elem in chunks) { uint paddingF = (uint)offset.AlignUp(elem.alignment) - (uint)offset; uint paddingV = (uint)rva.AlignUp(elem.alignment) - (uint)rva; offset += paddingF; rva += paddingV; elem.chunk.SetOffset(offset, rva); if (elem.chunk.GetVirtualSize() == 0) { offset -= paddingF; rva -= paddingV; } else { uint chunkLenF = elem.chunk.GetFileLength(); uint chunkLenV = elem.chunk.GetVirtualSize(); offset += chunkLenF; rva += chunkLenV; length += paddingF + chunkLenF; virtualSize += paddingV + chunkLenV; } } } /// public uint GetFileLength() => length; /// public uint GetVirtualSize() => virtualSize; /// public void WriteTo(DataWriter writer) { var offset2 = offset; foreach (var elem in chunks) { if (elem.chunk.GetVirtualSize() == 0) continue; int paddingF = (int)offset2.AlignUp(elem.alignment) - (int)offset2; writer.WriteZeroes(paddingF); elem.chunk.VerifyWriteTo(writer); offset2 += (uint)paddingF + elem.chunk.GetFileLength(); } } /// public virtual uint CalculateAlignment() { uint alignment = 0; for (int i = 0; i < chunks.Count; i++) { var elem = chunks[i]; uint newAlignment = Math.Max(elem.alignment, elem.chunk.CalculateAlignment()); chunks[i] = new Elem(elem.chunk, newAlignment); alignment = Math.Max(alignment, newAlignment); } return alignment; } } }