// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using dnlib.IO; using dnlib.PE; namespace dnlib.DotNet.Writer { /// /// .NET resources /// public sealed class NetResources : IReuseChunk { readonly List resources = new List(); readonly uint alignment; uint length; bool setOffsetCalled; FileOffset offset; RVA rva; internal bool IsEmpty => resources.Count == 0; /// public FileOffset FileOffset => offset; /// public RVA RVA => rva; /// /// Gets offset of next resource. This offset is relative to the start of /// the .NET resources and is always aligned. /// public uint NextOffset => Utils.AlignUp(length, alignment); /// /// Constructor /// /// Alignment of all resources public NetResources(uint alignment) => this.alignment = alignment; /// /// Adds a resource /// /// The resource data /// The resource data public DataReaderChunk Add(DataReader reader) { if (setOffsetCalled) throw new InvalidOperationException("SetOffset() has already been called"); length = NextOffset + 4 + reader.Length; var data = new DataReaderChunk(ref reader); resources.Add(data); return data; } bool IReuseChunk.CanReuse(RVA origRva, uint origSize) => length <= origSize; /// public void SetOffset(FileOffset offset, RVA rva) { setOffsetCalled = true; this.offset = offset; this.rva = rva; foreach (var resource in resources) { offset = offset.AlignUp(alignment); rva = rva.AlignUp(alignment); resource.SetOffset(offset + 4, rva + 4); uint len = 4 + resource.GetFileLength(); offset += len; rva += len; } } /// public uint GetFileLength() => length; /// public uint GetVirtualSize() => GetFileLength(); /// public uint CalculateAlignment() => 0; /// public void WriteTo(DataWriter writer) { var rva2 = rva; foreach (var resourceData in resources) { int padding = (int)rva2.AlignUp(alignment) - (int)rva2; writer.WriteZeroes(padding); rva2 += (uint)padding; writer.WriteUInt32(resourceData.GetFileLength()); resourceData.VerifyWriteTo(writer); rva2 += 4 + resourceData.GetFileLength(); } } } }