using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace Yaulw.Other
{
///
/// Interface of Versioning, to check if the passed in version is supported by the Versioning Object
///
public interface IVersionSupported
{
bool IsSupported(string Version);
bool IsSupported(Versioning Version);
bool IsSupported(Version Version);
}
///
/// Allows us to easily wrap Versioning Functionallity,
/// into Objects. Similar to Assembly.Version Class, however,
/// it allows the * character. This character specifies all and
/// allows for wildchar versioning schemes useful for certain
/// scenarios via IVersionSupported.
/// ---------------------------------------------------
/// [Major version].[Minor version].[Build number].[Revision number]
/// ---------------------------------------------------
/// Major version can be any valid uint as well as *
/// Minor version can be any valid uint as well as *
/// Build number can be any valid uint as well as *
/// Revision number can be any valid uint as well as *
///
public class Versioning : ICloneable, IComparable, IVersionSupported
{
#region Public consts
///
/// Int value indicating a * (wildcard) character
///
public const int STAR_ALL = -1;
#endregion
#region Private Members
private int _MajorVersion = STAR_ALL;
private int _MinorVersion = STAR_ALL;
private int _BuildNumber = STAR_ALL;
private int _RevisionNumber = STAR_ALL;
#endregion
#region Construction
///
/// Use this to initialize the class with a version string, can not contain multiple versions seperated by ";"
///
/// any version string in the format [Major].[Minor].[Build].[Revision], like 5.3.3.1 or 5.4.*.*
/// if Major,Minor,Build, or Revision < -1
public Versioning(string strVersion)
{
if (!IsValidVersionStr(strVersion) || strVersion.Contains(";"))
throw new ArgumentException("Invalid Version String");
ParseVersion(strVersion, out this._MajorVersion, out this._MinorVersion, out this._BuildNumber, out this._RevisionNumber);
}
///
/// Initialize Versioning with a single MajorVersion and MinorVersion.
///
/// Major Version
/// Minor Version
/// if Major,Minor,Build, or Revision < -1
public Versioning(int MajorVersion, int MinorVersion)
{
if (MajorVersion >= STAR_ALL && MinorVersion >= STAR_ALL)
{
_MajorVersion = MajorVersion;
_MinorVersion = MinorVersion;
}
else
throw new ArgumentException("MajorVersion or MinorVersion is invalid");
}
///
/// Initialize Versioning with a single MajorVersion,MinorVersion, and BuildNumber.
///
/// Major Version
/// Minor Version
/// Build Number
/// if Major,Minor,Build, or Revision < -1
public Versioning(int MajorVersion, int MinorVersion, int BuildNumber)
{
if (MajorVersion >= STAR_ALL && MinorVersion >= STAR_ALL && _BuildNumber >= STAR_ALL)
{
_MajorVersion = MajorVersion;
_MinorVersion = MinorVersion;
_BuildNumber = BuildNumber;
}
else
throw new ArgumentException("MajorVersion,MinorVersion, or BuildNumber is invalid");
}
///
/// Initialize Versioning with a single MajorVersion,MinorVersion,BuildNumber and RevisionNumber.
///
/// Major Version
/// Minor Version
/// Build Number
/// Revision Number
/// if Major,Minor,Build, or Revision < -1
public Versioning(int MajorVersion, int MinorVersion, int BuildNumber, int RevisionNumber)
{
if (MajorVersion >= STAR_ALL && MinorVersion >= STAR_ALL && _BuildNumber >= STAR_ALL && RevisionNumber >= STAR_ALL)
{
_MajorVersion = MajorVersion;
_MinorVersion = MinorVersion;
_BuildNumber = BuildNumber;
_RevisionNumber = RevisionNumber;
}
else
throw new ArgumentException("MajorVersion,MinorVersion, BuildNumber, or RevisionNumber is invalid");
}
///
/// Initialize Versioning with a .Net Version Object
///
/// a .Net Version Object
public Versioning(Version version)
{
_MajorVersion = version.Major;
_MinorVersion = version.Minor;
_BuildNumber = version.Build;
_RevisionNumber = version.Revision;
}
#endregion
#region Versioning Getter/Setter
///
/// Set/Retrieve Version
///
public String Version
{
get
{
return VersionToVersionString(_MajorVersion, _MinorVersion, _BuildNumber, _RevisionNumber);
}
set
{
if (IsValidVersionStr(value) && !value.Contains(";"))
ParseVersion(value, out this._MajorVersion, out this._MinorVersion, out this._BuildNumber, out this._RevisionNumber);
else
throw new ArgumentException("Invalid Version String");
}
}
#endregion
#region Public Static Helpers
///
/// Gets a Versioning object for the Version Information of a File
///
/// Full File Name and Path
/// returns a new Versioning Object for a File, or null if error occured
public static Versioning GetFileVersioning(string FileNameNPath)
{
if (!string.IsNullOrEmpty(FileNameNPath) && System.IO.File.Exists(FileNameNPath))
{
try
{
FileVersionInfo info = FileVersionInfo.GetVersionInfo(FileNameNPath);
return new Versioning(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart);
}
catch (Exception) { /* ignore */ }
}
return null;
}
///
/// Parses out a single Version from a string
///
/// pass in a Version format [Major].[Minor].[Build], like 5.3.3 or 5.4.*
/// returns an int or STAR_ALL
/// returns an int or STAR_ALL
/// returns an int or STAR_ALL
/// returns an int or STAR_ALL
public static void ParseVersion(string strVersion, out int MajorVersion, out int MinorVersion, out int BuildNumber, out int RevisionNumber)
{
if (!IsValidVersionStr(strVersion) || strVersion.Contains(";"))
throw new ArgumentException("Invalid Version String");
MajorVersion = STAR_ALL;
MinorVersion = STAR_ALL;
BuildNumber = STAR_ALL;
RevisionNumber = STAR_ALL;
string[] MajorMinorPossBuildVersion = strVersion.Split('.');
try
{
for (int i = 0; i < MajorMinorPossBuildVersion.Length; ++i)
{
if (i == 0)
{
if (MajorMinorPossBuildVersion[0] != "*")
MajorVersion = int.Parse(MajorMinorPossBuildVersion[0]);
}
else if (i == 1)
{
if (MajorMinorPossBuildVersion[1] != "*")
MinorVersion = int.Parse(MajorMinorPossBuildVersion[1]);
}
else if (i == 2)
{
if (MajorMinorPossBuildVersion[2] != "*")
BuildNumber = int.Parse(MajorMinorPossBuildVersion[2]);
}
else if (i == 3)
{
if (MajorMinorPossBuildVersion[2] != "*")
RevisionNumber = int.Parse(MajorMinorPossBuildVersion[3]);
}
}
}
catch (Exception) { /* Ignore */ }
}
///
/// Turns Version Numbers into a Version String
///
/// Major Version
/// Minor Version, can be *
/// Build Number, can be * or UNINITIALIZED
/// the Version String
public static string VersionToVersionString(int MajorVersion, int MinorVersion = STAR_ALL, int BuildNumber = STAR_ALL, int RevisionNumber = STAR_ALL)
{
string strRetVal = String.Empty;
if (MajorVersion >= STAR_ALL)
{
// Major Version
if (MajorVersion == STAR_ALL)
strRetVal += "*";
else
strRetVal += MajorVersion.ToString();
// Minor Version
if (MinorVersion >= STAR_ALL)
{
strRetVal += ".";
if (MinorVersion == STAR_ALL)
strRetVal += "*";
else
strRetVal += MinorVersion.ToString();
}
// Build Number
if (BuildNumber >= STAR_ALL)
{
strRetVal += ".";
if (BuildNumber == STAR_ALL)
strRetVal += "*";
else
strRetVal += BuildNumber.ToString();
}
// Revision Number
if (RevisionNumber >= STAR_ALL)
{
strRetVal += ".";
if (RevisionNumber == STAR_ALL)
strRetVal += "*";
else
strRetVal += RevisionNumber.ToString();
}
}
return strRetVal;
}
#endregion
#region Private Stats - Validation
private const string CharSet_AllowedNumeric = "0123456789";
private const string CharSet_AllowedVersionChars = CharSet_AllowedNumeric + "*;.";
///
/// Generic Function to use with Allowed Character Sets above
///
/// string to evaluate
/// Pass in one of the legal character consts declared above
/// true if valid, false otherwise
private static bool ContainsOnlyLegalChars(string TextToEvaluate, string TextToEvaluateWith)
{
foreach (char c in TextToEvaluate.ToCharArray())
{
bool bFound = (TextToEvaluateWith.IndexOf(c) >= 0);
if (!bFound)
return false;
}
return true;
}
///
/// Used to Validate a Version string of format 12.1.12;12.2.*;12.2.1
///
/// a Version String
/// true if valid, false otherwise
public static bool IsValidVersionStr(string VersionStr)
{
if (String.IsNullOrEmpty(VersionStr))
{
return false;
}
else if (VersionStr.Length < 1 && VersionStr.Length > 14) // restrict Version String Length
{
return false;
}
else if (!ContainsOnlyLegalChars(VersionStr, CharSet_AllowedVersionChars))
{
return false;
}
else
{
return true;
}
}
#endregion
#region ICloneable Members
///
/// Clone the Object
///
/// a copy of this Versioning Object
public object Clone()
{
Versioning versioning = new Versioning(this._MajorVersion, this._MinorVersion, this._BuildNumber, this._RevisionNumber);
return versioning;
}
#endregion
#region IComparable Members
///
/// Compare two Versioning Objects
///
/// a Versioning Object
/// -1, 0, +1
public int CompareTo(object obj)
{
if (obj is Versioning)
{
Versioning v = (Versioning)obj;
//*.*.*
//*.2.*
//1.*.*
//1.1.*
//1.1.1
//2.2.2
//2.2.*
int nCompare = 0;
nCompare = this._MajorVersion.CompareTo(v._MajorVersion);
if(nCompare == 0)
nCompare = this._MinorVersion.CompareTo(v._MinorVersion);
if(nCompare == 0)
nCompare = this._BuildNumber.CompareTo(v._BuildNumber);
if (nCompare == 0)
nCompare = this._RevisionNumber.CompareTo(v._BuildNumber);
return nCompare;
}
else
{
throw new ArgumentException("object is not a Versioning");
}
}
#endregion
#region IVersionSupported Members
///
/// Returns true if the Version String passed in is supported/matches Versioning for this object
///
/// a Versioning string to validate against
/// true if supported, false otherwise
public bool IsSupported(string Version)
{
Versioning version = new Versioning(Version);
return IsSupported(version);
}
///
/// Returns true if the Version passed in is supported/matches Versioning for this object
///
/// a Versioning Object to validate against
/// true if supported, false otherwise
public bool IsSupported(Versioning Version)
{
if (Version != null)
{
int nCompare = this.CompareTo(Version);
if (nCompare == 0)
{
return true;
}
else if (nCompare == 1)
{
return false;
}
else if (nCompare == -1)
{
if (((this._MajorVersion == STAR_ALL) || (this._MajorVersion == Version._MajorVersion)) &&
((this._MinorVersion == STAR_ALL) || (this._MinorVersion == Version._MinorVersion)) &&
((this._BuildNumber == STAR_ALL) || (this._BuildNumber == Version._BuildNumber)) &&
((this._RevisionNumber == STAR_ALL) || (this._RevisionNumber == Version._RevisionNumber))
)
{
return true;
}
else
{
return false;
}
}
}
return false;
}
///
/// Returns true if the Version passed in is supported/matches Versioning for this object
///
/// a Version Object to Validate against
/// true if supported, false otherwise
public bool IsSupported(Version Version)
{
Versioning version = new Versioning(Version.Major, Version.Minor, Version.Build, Version.Revision);
return true;
}
#endregion
}
///
/// Allows us to easily parse/sort/search multiple versioning classes
///
public static class Versionings
{
///
/// Used to parse multiple ";" seperated versions from a string
///
/// single/multiple version strings, seperated by ";", in the format [Major].[Minor].[Build].[Revision], like 5.3.3.1 or 5.4.*.*
/// a sorted array of versionings or null if error occured
public static Versioning[] ParseVersions(string strVersions)
{
if (!Versioning.IsValidVersionStr(strVersions))
return null;
List RetValueVersions = new List();
string[] Versions = strVersions.Split(';');
foreach (string Version in Versions)
RetValueVersions.Add(new Versioning(Version));
RetValueVersions.Sort();
return RetValueVersions.ToArray();
}
#region IsSupportedFile
///
/// Use this to find out if a File Version is supported by the passed in Versions string
///
/// single/multiple version strings, seperated by ";", in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.*
/// Full File Name and Path
/// true if the File Version is supported by the Versions string
public static bool IsSupportedFile(string strVersions, string FileNameNPath)
{
return IsSupported(ParseVersions(strVersions), Versioning.GetFileVersioning(FileNameNPath));
}
///
/// Use this to find out if a File Version is supported by the passed in Versions []
///
/// single/multiple versioning objects
/// Full File Name and Path
/// true if the File Version is supported by the Versions string
public static bool IsSupportedFile(Versioning[] Versions, string FileNameNPath)
{
return IsSupported(Versions, Versioning.GetFileVersioning(FileNameNPath));
}
#endregion
#region IsSupported
///
/// Pass in a Versions string, and a Version to check against. Returns true, if the Version is IVersionSupported by
/// the passed in Versions string.
///
/// single/multiple version strings, seperated by ";", in the format [Major].[Minor].[Build].[Revision], like 5.3.3 or 5.4.*
/// any version string in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.*
/// true, if a Versioning Object in the Versions returns true for IVersionSupported, false otherwise
public static bool IsSupported(string strVersions, string strVersion)
{
return IsSupported(ParseVersions(strVersions), new Versioning(strVersion));
}
///
/// Pass in a single/multipe Versions object, and a Version object to check against. Returns true, if the Version is IVersionSupported by
/// the passed in Versions Objects.
///
/// single/multiple versioning objects
/// single versioning object
/// true, if a Versioning Object in the Versions returns true for IVersionSupported, false otherwise
public static bool IsSupported(Versioning[] Versions, Versioning Version)
{
// Let IVersionSupported do all the work
foreach (Versioning _version in Versions)
{
if (_version.IsSupported(Version))
return true;
}
return false;
}
///
/// Pass in a single/multipe Versions object, and a Version object to check against. Returns true, if the Version is IVersionSupported by
/// the passed in Versions Objects.
///
/// single/multiple versioning objects
/// single version object
/// true, if a Versioning Object in the Versions returns true for IVersionSupported, false otherwise
public static bool IsSupported(Versioning[] Versions, Version Version)
{
// Let IVersionSupported do all the work
foreach (Versioning _version in Versions)
{
if (_version.IsSupported(Version))
return true;
}
return false;
}
#endregion
}
}