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 } }