using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Globalization; using System.Security.Principal; using System.Security.AccessControl; using System.Reflection; using System.Diagnostics; using Microsoft.Win32; namespace NaGet { /// /// 雑多な便利メソッドを集めたクラス /// public static class Utils { #region 汎用的なオブジェクト操作メソッド /// /// オブジェクトのフィールドをコピーしてクローン化する /// /// コピー元 /// コピー先。コピー元のクラスと同一か継承している型でなければならない public static void FieldCopy(T from, ref U target) where U : T { foreach(FieldInfo member in typeof(T).GetFields()) { try { member.SetValue(target, member.GetValue(from)); } catch (FieldAccessException) {} // アクセス不能は無視 } } #endregion #region リスト関連関数 /// /// イテレータを結合して、返す /// /// 元となる複数のイテレータ /// 結合されたイテレータ public static IEnumerable MergeEnumerable(params IEnumerable[] enus) { foreach (IEnumerable enu in enus) { if (enu == null) continue; foreach (T elem in enu) { yield return elem; } } } /// /// イテレータを結合して、返す /// /// 元となる複数のイテレータ /// 結合されたイテレータ public static IEnumerable MergeEnumerable(params IEnumerator[] enus) { foreach (IEnumerator enu in enus) { if (enu == null) continue; try { while (enu.MoveNext()) { yield return enu.Current; } } finally { enu.Dispose(); } } } /// /// イテレータを結合して、Listとして返す /// /// 元となる複数のイテレータ /// 結合されたイテレータ public static List MergeList(params IEnumerable[] enus) { List list = new List(); foreach (IEnumerable enu in enus) { if (enu == null) continue; list.AddRange(enu); } return list; } /// /// イテレータを配列に効率的に変換する /// /// 与えられる型が具体的にわかっているならば、それに特化した手続きをとる方が好ましい /// 元となるイテレータ /// 変換された配列 public static T[] IEnumerable2Array(IEnumerable enu) { T[] retval = enu as T[]; if (retval == null) { List list = enu as List; if (list == null) { list = new List(enu); } retval = list.ToArray(); } return retval; } /// /// リストに対して指定した2つの要素の位置を入れ替える /// /// 操作対象のリスト /// 位置 /// 位置 public static void ListSwap(System.Collections.IList list, int indexA, int indexB) { if ((indexA < 0) || (list.Count <= indexA) || (indexB < 0) || (list.Count <= indexB)) { throw new IndexOutOfRangeException(); } else if (indexA != indexB) { object temp = list[indexA]; list[indexA] = list[indexB]; list[indexB] = temp; } } #endregion #region ファイル情報関連ユーテイリティ関数 /// /// パス変数に指定のフォルダーを追加する /// /// 追加するフォルダー public static void AddDirectoryToPath(string dir) { string path = Environment.GetEnvironmentVariable("PATH"); if (path.IndexOf(dir) < 0) { path = dir + Path.PathSeparator + path; Environment.SetEnvironmentVariable("PATH", path); } } /// /// バイト単位で表現された容量を接尾語を活用して適切な文字列に変換 /// /// バイト単位の容量 /// 読みやすい形に直された容量文字列 public static string FormatSize(double bytes) { string[] units = new string[] {"B", "KB", "MB", "GB", "TB"}; double size = bytes; int i; for (i = 0; size >= 1024 && i < units.Length-1 ; i++) { size /= 1024.0; } return string.Format("{0:F2}{1}", size, units[i]); } public static string FormatSize(long bytes) { return FormatSize((double) bytes); } /// /// URLからそのファイル名を生成する /// /// 対象のurl public static string Url2filename(Uri url) { string filename = Path.GetFileName(System.Web.HttpUtility.UrlDecode(url.ToString(), Encoding.UTF8)); int pos; if ((pos = filename.IndexOfAny(Path.GetInvalidFileNameChars())) >= 0) { // 不正な文字が含まれているならば、それ以降を削除 filename = filename.Substring(0, pos); // そうしてしまったら文字の内容がまったくなくなってしまったら、ランダムな名に if (filename.Length == 0) { filename = Path.GetFileName(Path.GetTempFileName()); } } return filename; //return UrlDecode(Path.GetFileName(url), Encoding.UTF8); } /// /// 再帰的にファイルの属性を指定します。強制的にフォルダーの再帰削除の前に読み込み専用属性を消すのに使います。 /// /// 設定するフォルダー /// 設定する属性値 public static void SetAttributeRecursive(string path, FileAttributes attr) { // 自分自身の属性を変更 File.SetAttributes(path, attr); // 子ファイルの属性変更 foreach (string file in Directory.GetFiles(path)) { File.SetAttributes(file, attr); } // 子フォルダーを再帰的に属性変更 foreach (string file in Directory.GetDirectories(path)) { SetAttributeRecursive(file, attr); } } /// /// 再帰的にファイルのアクセス権限(ユーザ権限など)を設定します /// /// 設定するフォルダー /// 変更先権限 public static void SetAccessControlRecursive(string path, FileSecurity filesec) { // 自分自身の権限を変更 File.SetAccessControl(path, filesec); // 子ファイルの権限を変更 foreach (string file in Directory.GetFiles(path)) { File.SetAccessControl(file, filesec); } // 子フォルダーを再帰的に権限変更 foreach (string file in Directory.GetDirectories(path)) { SetAccessControlRecursive(file, filesec); } } /// /// ファイルまたはフォルダーの容量を算出して返す /// /// /// 対象ファイル及びフォルダーのパス /// /// /// 計算された容量(バイト単位) /// public static ulong GetFileSize(string path) { return ((File.GetAttributes(path) & FileAttributes.Directory) != 0)? GetDirectoryFileSize(new DirectoryInfo(path)) : ((ulong) (new FileInfo(path)).Length); } /// /// フォルダーの容量を算出して返す /// /// /// 対象フォルダー /// /// /// 計算された容量(バイト単位) /// public static ulong GetDirectoryFileSize(DirectoryInfo dirInfo) { ulong size = 0; foreach (FileInfo child in dirInfo.GetFiles("*", SearchOption.AllDirectories)) { size += (ulong) child.Length; } return size; } /// /// ワイルドカードを展開したファイルパス文字列を作り出す。 /// 戻り値のそれぞれの文字列はフルパスとなる。 /// /// ベース(基点)のディレクトリ /// ワイルドカードパターン /// 展開したファイルパス public static string[] ExtendWildcardFile(string baseDir, string pattern) { if (pattern.IndexOfAny(new char[]{'*','?'}) < 0) { return new string[]{Path.Combine(baseDir, pattern)}; // ワイルドカードがなければそのまま返す } string[] pathArray = pattern.Split(Path.DirectorySeparatorChar); List extended = new List(); try { if (pathArray.Length == 1) { extended.AddRange(Directory.GetFiles(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)); extended.AddRange(Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)); } else { // pathArray.Length > 1 string subPattern = string.Join(Path.DirectorySeparatorChar.ToString(), pathArray, 1, pathArray.Length-1); foreach (string subDir in Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)) { // 再帰的に追加してゆく extended.AddRange(ExtendWildcardFile(subDir, subPattern)); } } } catch (UnauthorizedAccessException) { } // 存在しないパスは消去する extended.RemoveAll( delegate(string path) { return ! File.Exists(path); } ); return extended.ToArray(); } /// /// パスをパス区切り文字列ごとに分割した配列を返す /// /// パス文字列。相対・絶対は区別しない /// フォルダー名ごとに分けられた文字列配列 private static string[] splitPath(string path) { return path.Split(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}); } /// /// パスがフォルダーのとき、最後がパスセパレータで終了するようにする。 /// /// パス /// 処理されたパス private static string fixLastPathCharForDirectory(string path) { string fixedPath = path; if (Directory.Exists(path) && path[path.Length-1] != Path.DirectorySeparatorChar) { fixedPath += Path.DirectorySeparatorChar; } return fixedPath; } /// /// 絶対パスを相対パスに変換して返します。 /// /// 相対パスの基準のフォルダー /// 絶対パス /// absPathの絶対パス表現 public static string GetRelativePath(string baseDirectoryPath, string absPath) { Uri baseuri = new Uri(fixLastPathCharForDirectory(baseDirectoryPath)); Uri absuri = new Uri(fixLastPathCharForDirectory(absPath)); string relative = baseuri.MakeRelativeUri(absuri).ToString(); relative = System.Web.HttpUtility.UrlDecode(relative); relative = relative.Replace('/', Path.DirectorySeparatorChar); return relative; } /// /// 相対パスに含まれている".."などを消去する /// /// /// public static string GetDotsRemovedPath(string aPath) { string[] folders = splitPath(aPath); List newFolders = new List(); foreach (string fol in folders) { if (fol == ".") { // 無視 } else if (fol == "..") { // 一つ前のフォルダーを消す newFolders.RemoveAt(newFolders.Count-1); } else { newFolders.Add(fol); } } return string.Join(Path.DirectorySeparatorChar.ToString(), newFolders.ToArray()); } #endregion #region シリアル化関連 /// /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する /// /// XMLファイルのパス /// シリアライザ /// デシリアル化されたオブジェクト public static object GetDeserializedObject(string path, System.Xml.Serialization.XmlSerializer sr) { object retVal = null; using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { retVal = sr.Deserialize(fs); } return retVal; } /// /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する /// /// XMLファイルのパス /// デシリアル化されたオブジェクト public static T GetDeserializedObject(string path) { T retVal = default(T); System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T)); retVal = (T) GetDeserializedObject(path, sr); return retVal; } /// /// オブジェクトをXMLでシリアル化してファイルに書き込む /// /// XMLファイルのパス /// シリアル化する対象のオブジェクト public static void PutSerializeObject(string path, T obj) { using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) { System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T)); sr.Serialize(fs, obj); } } #endregion #region 権限関連関数群 /// /// 現在のユーザがAdministrators権限を持っているか否かを返す。 /// /// UAC有効時には権限昇格後になってtrueを返すようになります public static bool IsAdministrators() { // 現在の Windows ユーザーを現在のスレッドのプリンシパルに反映する AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal ); IPrincipal prin = System.Threading.Thread.CurrentPrincipal; return prin.IsInRole(@"BUILTIN\Administrators"); } /// /// 現在のPCがUACが有効になっているか否かを返す。 /// レジストリのHKLM\SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System\EnableLUAの値を見る。 /// /// UACが有効ならばtrue public static bool IsUACEnabled() { try { using(RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System")) { return ((int) key.GetValue("EnableLUA", 0)) == 1; } } catch (Exception) { return false; } } #endregion #region プロセス関連便利メソッド群 /// /// プロセスに出力をリダイレクトした上で実行 /// /// プロセス起動情報 /// 標準出力用リスナ(null可) /// エラー出力用リスナ(null可) /// 実行プロセス public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo, DataReceivedEventHandler outputReceived, DataReceivedEventHandler errorReceived) { if (outputReceived != null) { procInfo.RedirectStandardOutput = true; } if (errorReceived != null) { procInfo.RedirectStandardError = true; } procInfo.UseShellExecute = false; Process hProcess = Process.Start(procInfo); if (outputReceived != null) { hProcess.OutputDataReceived += outputReceived; hProcess.BeginOutputReadLine(); } if (errorReceived != null) { hProcess.ErrorDataReceived += errorReceived; hProcess.BeginErrorReadLine(); } return hProcess; } /// /// プロセスに出力をリダイレクトした上で実行 /// /// プロセス起動情報 /// 標準出力用リスナ(null可) /// エラー出力用リスナ(null可) /// 実行プロセス public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo, EventHandler> outputReceived, EventHandler> errorReceived) { return ProcessStartWithOutputCapture(procInfo, ConvertToDataReceivedEventHandler(outputReceived), ConvertToDataReceivedEventHandler(errorReceived)); } public static DataReceivedEventHandler ConvertToDataReceivedEventHandler(EventHandler> handler) { if (handler == null) return null; return delegate (object sender, DataReceivedEventArgs e) { AnyDataEventArgs args = new AnyDataEventArgs(e.Data); handler.Invoke(sender, args); }; } #endregion #region イベント情報 /// /// 任意データのイベント情報を表現するクラス /// public class AnyDataEventArgs : EventArgs { /// /// データ /// T data; public AnyDataEventArgs(T data) { this.data = data; } /// /// データを返す /// public T Data { get { return data; } } } #endregion } }