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