using System; using System.IO; using System.Text; using System.Globalization; using System.Security.Principal; using System.Reflection; using System.Diagnostics; using Microsoft.Win32; namespace NaGet { /// /// 雑多な便利メソッドを集めたクラス /// public sealed class Utils { /// /// 呼び出し禁止 /// private Utils() { } /// /// オブジェクトのフィールドをコピーしてクローン化する /// /// コピー元 /// コピー先。コピー元のクラスと同一か継承している型でなければならない 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) {} // アクセス不能は無視 } } /// /// パス変数に指定のフォルダを追加する /// /// 追加するフォルダ 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); } #region ファイル操作関数群 /// /// URLからそのファイル名を生成する /// /// 対象のurl public static string Url2filename(string url) { string filename = Path.GetFileName(UrlDecode(url, 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); } /// /// URLのデコードを行う /// /// 対象のurl文字列 /// デコードの処理に使う文字コード public static string UrlDecode(string s, Encoding e) { // mono の System.Net.HttpUtility より作成 if (null == s) return null; if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1) return s; if (e == null) e = Encoding.GetEncoding (28591); StringBuilder output = new StringBuilder (); long len = s.Length; NumberStyles hexa = NumberStyles.HexNumber; MemoryStream bytes = new MemoryStream (); for (int i = 0; i < len; i++) { if (s [i] == '%' && i + 2 < len) { if (s [i + 1] == 'u' && i + 5 < len) { if (bytes.Length > 0) { //output.Append (GetChars (bytes, e)); output.Append(e.GetChars(bytes.GetBuffer(), 0, (int) bytes.Length)); bytes.SetLength (0); } output.Append ((char) int.Parse(s.Substring (i + 2, 4), hexa)); i += 5; } else { bytes.WriteByte ((byte) int.Parse(s.Substring (i + 1, 2), hexa)); i += 2; } continue; } if (bytes.Length > 0) { //output.Append (GetChars (bytes, e)); output.Append(e.GetChars(bytes.GetBuffer(), 0, (int) bytes.Length)); bytes.SetLength (0); } if (s [i] == '+') { output.Append (' '); } else { output.Append (s [i]); } } if (bytes.Length > 0) { //output.Append (GetChars (bytes, e)); output.Append(e.GetChars(bytes.GetBuffer(), 0, (int) bytes.Length)); } bytes = null; return output.ToString (); } /// /// ファイルパスから、指定のパスセパレータの意味でファイル名を取り出す。 /// /// ファイルパス(またはURLパス) /// パスセパレータ public static string Basedir(string filepath, char separator) { int dirSep = filepath.LastIndexOf(separator); if (dirSep < 0) return ""; return filepath.Substring(0, dirSep); } /// /// 再帰的にファイルの属性を指定します。強制的にフォルダの再帰削除の前に読み込み専用属性を消すのに使います。 /// /// 設定するフォルダ /// 設定する属性値 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 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); System.Collections.Generic.List extended = new System.Collections.Generic.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}); } /// /// Converts a given absolute path and a given base path to a path that leads /// from the base path to the absoulte path. (as a relative path) /// public static string GetRelativePath(string baseDirectoryPath, string absPath) { // TODO SharpDevelopのICSharpCode.Core.FileUtilityからのコピペ(GPL) string[] bPath = splitPath(baseDirectoryPath); string[] aPath = splitPath(absPath); int indx = 0; for(; indx < Math.Min(bPath.Length, aPath.Length); ++indx){ if(!bPath[indx].Equals(aPath[indx], StringComparison.OrdinalIgnoreCase)) break; } if (indx == 0) { return absPath; } StringBuilder erg = new StringBuilder(); if(indx == bPath.Length) { // erg.Append('.'); // erg.Append(Path.DirectorySeparatorChar); } else { for (int i = indx; i < bPath.Length; ++i) { erg.Append(".."); erg.Append(Path.DirectorySeparatorChar); } } erg.Append(String.Join(Path.DirectorySeparatorChar.ToString(), aPath, indx, aPath.Length-indx)); return erg.ToString(); } /// /// 相対パスに含まれている".."などを消去する /// /// /// public static string GetDotsRemovedPath(string aPath) { string[] folders = splitPath(aPath); System.Collections.Generic.List newFolders = new System.Collections.Generic.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 XmlSerializer便利メソッド群 public static T GetDeserializedObject(string path) { T retVal = default(T); using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T)); retVal = (T) sr.Deserialize(fs); } return retVal; } 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権限を持っているか否かを返す /// public static bool IsAdministrators() { // TODO UAC はどうするんだ!!!! // 現在の 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 /// /// 任意データのイベント情報を表現するクラス /// public class AnyDataEventArgs : EventArgs { /// /// データ /// T data; public AnyDataEventArgs(T data) { this.data = data; } /// /// データを返す /// public T Data { get { return data; } } } } }