85 lines
2.4 KiB
C#
85 lines
2.4 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
|
|
namespace Sarand.Net.Standard.Base.Utils
|
|
{
|
|
public static class AssemblyUtil
|
|
{
|
|
// --- Definitions ---
|
|
|
|
private const Int32 DosHeaderPeOffsetPosition = 0x3c;
|
|
private const UInt32 PeSignature = 0x00004550;
|
|
private const Int32 CoffTimeDateStampPosition = 8;
|
|
|
|
// --- Build Information ---
|
|
|
|
/// <summary>
|
|
/// Gets the UTC date and time represented by the assembly's PE/COFF timestamp.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Deterministic builds may not store the physical build time in this field.
|
|
/// Use <see cref="TryGetBuildDateTime(Assembly, out DateTime)"/> when the caller
|
|
/// needs to distinguish an unavailable timestamp from <see cref="DateTime.MinValue"/>.
|
|
/// </remarks>
|
|
|
|
public static DateTime GetBuildDateTime(this Assembly assembly)
|
|
{
|
|
return TryGetBuildDateTime(assembly, out DateTime buildDateTime)
|
|
? buildDateTime
|
|
: DateTime.MinValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to get the UTC date and time represented by the assembly's PE/COFF timestamp.
|
|
/// </summary>
|
|
public static Boolean TryGetBuildDateTime(this Assembly assembly, out DateTime buildDateTime)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(assembly);
|
|
|
|
if (String.IsNullOrEmpty(assembly.Location))
|
|
{
|
|
buildDateTime = DateTime.MinValue;
|
|
return false;
|
|
}
|
|
|
|
return TryGetBuildDateTime(assembly.Location, out buildDateTime);
|
|
}
|
|
|
|
// --- PE Header Parsing ---
|
|
|
|
internal static Boolean TryGetBuildDateTime(String assemblyPath, out DateTime buildDateTime)
|
|
{
|
|
buildDateTime = DateTime.MinValue;
|
|
|
|
try
|
|
{
|
|
using FileStream fileStream = new FileStream(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
using BinaryReader reader = new BinaryReader(fileStream);
|
|
|
|
fileStream.Position = DosHeaderPeOffsetPosition;
|
|
UInt32 coffHeaderOffset = reader.ReadUInt32();
|
|
fileStream.Position = coffHeaderOffset;
|
|
if (reader.ReadUInt32() != PeSignature)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
fileStream.Position = coffHeaderOffset + CoffTimeDateStampPosition;
|
|
UInt32 timeDateStamp = reader.ReadUInt32();
|
|
buildDateTime = DateTime.UnixEpoch.AddSeconds(timeDateStamp);
|
|
return true;
|
|
}
|
|
catch (Exception exception) when (exception is IOException
|
|
or UnauthorizedAccessException
|
|
or ArgumentException
|
|
or NotSupportedException)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// --- The End ---
|
|
}
|
|
}
|