public static class RvaMapper
{
    public static int? RvaToFileOffset(uint rva, IReadOnlyList<SectionInfo> sections, uint sizeOfHeaders)
    {
        if (rva < sizeOfHeaders)
        {
            return (int)rva;
        }

        foreach (var section in sections)
        {
            var virtualSize = Math.Max(section.VirtualSize, section.SizeOfRawData);
            var start = section.VirtualAddress;
            var end = start + virtualSize;

            if (rva >= start && rva < end)
            {
                var delta = rva - start;
                if (delta >= section.SizeOfRawData)
                {
                    return null;
                }

                return checked((int)(section.PointerToRawData + delta));
            }
        }

        return null;
    }

    public static uint? FileOffsetToRva(uint fileOffset, IReadOnlyList<SectionInfo> sections, uint sizeOfHeaders)
    {
        if (fileOffset < sizeOfHeaders)
        {
            return fileOffset;
        }

        foreach (var section in sections)
        {
            var start = section.PointerToRawData;
            var end = start + section.SizeOfRawData;
            if (fileOffset >= start && fileOffset < end)
            {
                var delta = fileOffset - start;
                return section.VirtualAddress + delta;
            }
        }

        return null;
    }
}