using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; namespace Sdaleo.Internal { /// /// Interface of Versioning, to check if the passed in version is supported by the Versioning Object /// internal interface IVersionSupported { bool IsSupported(string Version); bool IsSupported(Versioning Version); } /// /// Allows us to easily wrap Versioning Functionallity, /// into Objects. /// [Major version].[Minor version].[Build 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 * /// internal class Versioning : ICloneable, IComparable, IVersionSupported { #region Internal consts internal const int STAR_ALL = -1; #endregion #region Private Members private int _MajorVersion = STAR_ALL; private int _MinorVersion = STAR_ALL; private int _BuildNumber = 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], like 5.3.3 or 5.4.* internal 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); } /// /// Initialize Versioning with a single MajorVersion and MinorVersion. /// /// Major Version /// Minor Version internal 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 internal 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"); } #endregion #region Versioning Getter/Setter /// /// Set/Retrieve Version /// internal String Version { get { return VersionToVersionString(_MajorVersion, _MinorVersion, _BuildNumber); } set { if (IsValidVersionStr(value) && !value.Contains(";")) ParseVersion(value, out this._MajorVersion, out this._MinorVersion, out this._BuildNumber); else throw new ArgumentException("Invalid Version String"); } } #endregion #region internal 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 internal static Versioning GetFileVersioning(string FileNameNPath) { if (!string.IsNullOrEmpty(FileNameNPath) && File.Exists(FileNameNPath)) { try { FileVersionInfo info = FileVersionInfo.GetVersionInfo(FileNameNPath); return new Versioning(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart); } 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, or UNINITIALIZED, if error occured /// returns an int or STAR_ALL, or UNINITIALIZED, if error occured /// returns an int or STAR_ALL, or UNINITIALIZED, if error occured internal static void ParseVersion(string strVersion, out int MajorVersion, out int MinorVersion, out int BuildNumber) { if (!IsValidVersionStr(strVersion) || strVersion.Contains(";")) throw new ArgumentException("Invalid Version String"); MajorVersion = STAR_ALL; MinorVersion = STAR_ALL; BuildNumber = 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]); } } } 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 internal static string VersionToVersionString(int MajorVersion, int MinorVersion = STAR_ALL, int BuildNumber = 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(); } } return strRetVal; } #endregion #region 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 > 50) // restrice Version String Length { return false; } else if (!ContainsOnlyLegalChars(VersionStr, CharSet_AllowedVersionChars)) { return false; } else { return true; } } #endregion #region ICloneable Members public object Clone() { Versioning versioning = new Versioning(this._MajorVersion, this._MinorVersion, this._BuildNumber); return versioning; } #endregion #region IComparable Members 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); 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 Version 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 Version 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)) ) { return true; } else { return false; } } } return false; } #endregion } /// /// Allows us to easily parse/sort/search multiple versioning classes /// internal static class Versionings { /// /// Used to parse multiple ";" seperated versions from a string /// /// single/multiple version strings, seperated by ";", in the format [Major].[Minor].[Build], like 5.3.3 or 5.4.* /// a sorted array of versionings or null if error occured internal 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 internal 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 internal 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], 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 internal 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 internal 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; } #endregion } }