// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Versioning
{
using System;
using System.Collections.Generic;
///
/// WixVersion comparer.
///
public class WixVersionComparer : IEqualityComparer, IComparer
{
///
/// Default WixVersion comparer.
///
public static readonly WixVersionComparer Default = new WixVersionComparer();
///
public int Compare(WixVersion x, WixVersion y)
{
if ((object)x == y)
{
return 0;
}
if (x is null)
{
return -1;
}
if (y is null)
{
return 1;
}
var result = x.Major.CompareTo(y.Major);
if (result != 0)
{
return result;
}
result = x.Minor.CompareTo(y.Minor);
if (result != 0)
{
return result;
}
result = x.Patch.CompareTo(y.Patch);
if (result != 0)
{
return result;
}
result = x.Revision.CompareTo(y.Revision);
if (result != 0)
{
return result;
}
var xLabelCount = x.Labels?.Length ?? 0;
var yLabelCount = y.Labels?.Length ?? 0;
var maxLabelCount = Math.Max(xLabelCount, yLabelCount);
if (xLabelCount > 0)
{
if (yLabelCount == 0)
{
return -1;
}
}
else if (yLabelCount > 0)
{
return 1;
}
for (var i = 0; i < maxLabelCount; ++i)
{
var xLabel = i < xLabelCount ? x.Labels[i] : null;
var yLabel = i < yLabelCount ? y.Labels[i] : null;
result = CompareReleaseLabel(xLabel, yLabel);
if (result != 0)
{
return result;
}
}
var compareMetadata = false;
if (x.Invalid)
{
if (!y.Invalid)
{
return -1;
}
else
{
compareMetadata = true;
}
}
else if (y.Invalid)
{
return 1;
}
if (compareMetadata)
{
result = String.Compare(x.Metadata, y.Metadata, StringComparison.OrdinalIgnoreCase);
}
return (result == 0) ? 0 : (result < 0) ? -1 : 1;
}
///
public bool Equals(WixVersion x, WixVersion y)
{
if ((object)x == y)
{
return true;
}
if (x is null)
{
return false;
}
if (y is null)
{
return false;
}
if (x.Major != y.Major)
{
return false;
}
if (x.Minor != y.Minor)
{
return false;
}
if (x.Patch != y.Patch)
{
return false;
}
if (x.Revision != y.Revision)
{
return false;
}
var labelCount = x.Labels?.Length ?? 0;
if (labelCount != (y.Labels?.Length ?? 0))
{
return false;
}
for (var i = 0; i < labelCount; ++i)
{
var result = CompareReleaseLabel(x.Labels[i], y.Labels[i]);
if (result != 0)
{
return false;
}
}
if (x.Invalid)
{
if (y.Invalid)
{
return String.Equals(x.Metadata, y.Metadata, StringComparison.OrdinalIgnoreCase);
}
else
{
return false;
}
}
else if (y.Invalid)
{
return false;
}
return true;
}
///
public int GetHashCode(WixVersion version)
{
var hash = 23L;
hash = hash * 37 + (version.Prefix ?? '\0');
hash = hash * 37 + version.Major;
hash = hash * 37 + version.Minor;
hash = hash * 37 + version.Patch;
hash = hash * 37 + version.Revision;
hash = hash * 37 + (version.Invalid ? 1 : 0);
hash = hash * 37 + (version.HasMajor ? 1 : 0);
hash = hash * 37 + (version.HasMinor ? 1 : 0);
hash = hash * 37 + (version.HasPatch ? 1 : 0);
hash = hash * 37 + (version.HasRevision ? 1 : 0);
if (version.Labels != null)
{
foreach (var label in version.Labels)
{
hash = hash * 37 + label.Label.GetHashCode();
}
}
hash = hash * 37 + version.Metadata?.GetHashCode() ?? 0;
return unchecked((int)hash);
}
private static int CompareReleaseLabel(WixVersionLabel l1, WixVersionLabel l2)
{
if (l1 == l2)
{
return 0;
}
else if (l2 == null)
{
return 1;
}
else if (l1 == null)
{
return -1;
}
if (l1.Numeric.HasValue)
{
if (l2.Numeric.HasValue)
{
return l1.Numeric.Value.CompareTo(l2.Numeric.Value);
}
else
{
return -1;
}
}
else
{
if (l2.Numeric.HasValue)
{
return 1;
}
else
{
return String.Compare(l1.Label, l2.Label, StringComparison.OrdinalIgnoreCase);
}
}
}
}
}