OSDN Git Service

819d741e6655c69eb97bc77037523185428063a1
[applistation/AppliStation.git] / na-get-lib / NaGet / Utils.cs
1 using System;\r
2 using System.IO;\r
3 using System.Text;\r
4 using System.Globalization;\r
5 using System.Security.Principal;\r
6 using System.Reflection;\r
7 using System.Diagnostics;\r
8 using Microsoft.Win32;\r
9 \r
10 namespace NaGet\r
11 {\r
12 \r
13         /// <summary>\r
14         /// 雑多な便利メソッドを集めたクラス\r
15         /// </summary>\r
16         public sealed class Utils\r
17         {\r
18                 /// <summary>\r
19                 /// 呼び出し禁止\r
20                 /// </summary>\r
21                 private Utils()\r
22                 {\r
23                 }\r
24                 \r
25                 /// <summary>\r
26                 /// オブジェクトのフィールドをコピーしてクローン化する\r
27                 /// </summary>\r
28                 /// <param name="from">コピー元</param>\r
29                 /// <param name="target">コピー先。コピー元のクラスと同一か継承している型でなければならない</param>\r
30                 public static void FieldCopy<T,U>(T from, ref U target) where U : T\r
31                 {\r
32                         foreach(FieldInfo member in typeof(T).GetFields()) {\r
33                                 try {\r
34                                         member.SetValue(target, member.GetValue(from));\r
35                                 } catch (FieldAccessException) {} // アクセス不能は無視\r
36                         }\r
37                 }\r
38                 \r
39                 /// <summary>\r
40                 /// パス変数に指定のフォルダを追加する\r
41                 /// </summary>\r
42                 /// <param name="dir">追加するフォルダ</param>\r
43                 public static void AddDirectoryToPath(string dir)\r
44                 {\r
45                         string path = Environment.GetEnvironmentVariable("PATH");\r
46                         \r
47                         if (path.IndexOf(dir) < 0) {\r
48                                 path = dir + Path.PathSeparator + path;\r
49                                 Environment.SetEnvironmentVariable("PATH", path);\r
50                         }\r
51                 }\r
52                 \r
53                 /// <summary>\r
54                 /// バイト単位で表現された容量を接尾語を活用して適切な文字列に変換\r
55                 /// </summary>\r
56                 /// <param name="bytes">バイト単位の容量</param>\r
57                 /// <returns>読みやすい形に直された容量文字列</returns>\r
58         public static string FormatSize(double bytes)\r
59         {\r
60                 string[] units = new string[] {"B", "KB", "MB", "GB", "TB"};\r
61                 \r
62                 double size = bytes;\r
63                 int i;\r
64                 for (i = 0; size >= 1024 && i < units.Length-1 ; i++) {\r
65                         size /= 1024.0;\r
66                 }\r
67                 \r
68                 return string.Format("{0:F2}{1}", size, units[i]);\r
69         }\r
70         \r
71         public static string FormatSize(long bytes)\r
72         {\r
73                 return FormatSize((double) bytes);\r
74         }\r
75                 \r
76                 #region ファイル操作関数群\r
77                 \r
78                 /// <summary>\r
79                 /// URLからそのファイル名を生成する\r
80                 /// </summary>\r
81                 /// <param name="url">対象のurl</param>\r
82                 public static string Url2filename(string url)\r
83                 {\r
84                         string filename = Path.GetFileName(UrlDecode(url, Encoding.UTF8));\r
85                         \r
86                         int pos;\r
87                         if ((pos = filename.IndexOfAny(Path.GetInvalidFileNameChars())) >= 0) {\r
88                                 // 不正な文字が含まれているならば、それ以降を削除\r
89                                 filename = filename.Substring(0, pos);\r
90                                 // そうしてしまったら文字の内容がまったくなくなってしまったら、ランダムな名に\r
91                                 if (filename.Length == 0) {\r
92                                         filename = Path.GetFileName(Path.GetTempFileName());\r
93                                 }\r
94                         }\r
95                         return filename;\r
96                         //return UrlDecode(Path.GetFileName(url), Encoding.UTF8);\r
97                 }\r
98                 \r
99                 /// <summary>\r
100                 /// URLのデコードを行う\r
101                 /// </summary>\r
102                 /// <param name="s">対象のurl文字列</param>\r
103                 /// <param name="e">デコードの処理に使う文字コード</param>\r
104                 public static string UrlDecode(string s, Encoding e)\r
105                 {\r
106                         // mono の System.Net.HttpUtility より作成\r
107                         \r
108                         if (null == s)\r
109                                 return null;\r
110 \r
111                         if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)\r
112                                 return s;\r
113 \r
114                         if (e == null)\r
115                                 e = Encoding.GetEncoding (28591);\r
116 \r
117                         StringBuilder output = new StringBuilder ();\r
118                         long len = s.Length;\r
119                         NumberStyles hexa = NumberStyles.HexNumber;\r
120                         MemoryStream bytes = new MemoryStream ();\r
121 \r
122                         for (int i = 0; i < len; i++) {\r
123                                 if (s [i] == '%' && i + 2 < len) {\r
124                                         if (s [i + 1] == 'u' && i + 5 < len) {\r
125                                                 if (bytes.Length > 0) {\r
126                                                         //output.Append (GetChars (bytes, e));\r
127                                                         output.Append(e.GetChars(bytes.GetBuffer(), 0, (int) bytes.Length));\r
128                                                         bytes.SetLength (0);\r
129                                                 }\r
130                                                 \r
131                                                 output.Append ((char) int.Parse(s.Substring (i + 2, 4), hexa));\r
132                                                 i += 5;\r
133                                         } else {\r
134                                                 bytes.WriteByte ((byte) int.Parse(s.Substring (i + 1, 2), hexa));\r
135                                                 i += 2;\r
136                                         }\r
137                                         continue;\r
138                                 }\r
139 \r
140                                 if (bytes.Length > 0) {\r
141                                         //output.Append (GetChars (bytes, e));\r
142                                         output.Append(e.GetChars(bytes.GetBuffer(), 0, (int) bytes.Length));\r
143                                         bytes.SetLength (0);\r
144                                 }\r
145 \r
146                                 if (s [i] == '+') {\r
147                                         output.Append (' ');\r
148                                 } else {\r
149                                         output.Append (s [i]);\r
150                                 }\r
151                         }\r
152 \r
153                         if (bytes.Length > 0) {\r
154                                 //output.Append (GetChars (bytes, e));\r
155                                 output.Append(e.GetChars(bytes.GetBuffer(), 0, (int) bytes.Length));\r
156                         }\r
157 \r
158                         bytes = null;\r
159                         return output.ToString ();\r
160                 }\r
161                 \r
162                 /// <summary>\r
163                 /// ファイルパスから、指定のパスセパレータの意味でファイル名を取り出す。\r
164                 /// </summary>\r
165                 /// <param name="filepath">ファイルパス(またはURLパス)</param>\r
166                 /// <param name="separator">パスセパレータ</param>\r
167                 public static string Basedir(string filepath, char separator)\r
168                 {\r
169                         int dirSep = filepath.LastIndexOf(separator);\r
170                         if (dirSep < 0) return "";\r
171 \r
172                         return filepath.Substring(0, dirSep);\r
173                 }\r
174                 \r
175                 /// <summary>\r
176                 /// 再帰的にファイルの属性を指定します。強制的にフォルダの再帰削除の前に読み込み専用属性を消すのに使います。\r
177                 /// </summary>\r
178                 /// <param name="path">設定するフォルダ</param>\r
179                 /// <param name="attr">設定する属性値</param>\r
180                 public static void SetAttributeRecursive(string path, FileAttributes attr)\r
181                 {\r
182                         // 自分自身の属性を変更\r
183                         File.SetAttributes(path, attr);\r
184                         \r
185                         // 子ファイルの属性変更\r
186                         foreach (string file in Directory.GetFiles(path)) {\r
187                                 File.SetAttributes(file, attr);\r
188                         }\r
189                         \r
190                         // 子フォルダを再帰的に属性変更\r
191                         foreach (string file in Directory.GetDirectories(path)) {\r
192                                 SetAttributeRecursive(file, attr);\r
193                         }\r
194                 }\r
195                 \r
196                 /// <summary>\r
197                 /// ファイルまたはフォルダの容量を算出して返す\r
198                 /// </summary>\r
199                 /// <param name="path">\r
200                 /// 対象ファイル及びフォルダのパス\r
201                 /// </param>\r
202                 /// <returns>\r
203                 /// 計算された容量(バイト単位)\r
204                 /// </returns>\r
205                 public static ulong GetFileSize(string path)\r
206                 {\r
207                         return ((File.GetAttributes(path) & FileAttributes.Directory) != 0)?\r
208                                 GetDirectoryFileSize(new DirectoryInfo(path)) : ((ulong) (new FileInfo(path)).Length);\r
209                 }\r
210                 \r
211                 /// <summary>\r
212                 /// フォルダの容量を算出して返す\r
213                 /// </summary>\r
214                 /// <param name="dirInfo">\r
215                 /// 対象フォルダ\r
216                 /// </param>\r
217                 /// <returns>\r
218                 /// 計算された容量(バイト単位)\r
219                 /// </returns>\r
220                 public static ulong GetDirectoryFileSize(DirectoryInfo dirInfo)\r
221                 {\r
222                         ulong size = 0;\r
223                         foreach (FileInfo child in dirInfo.GetFiles("*", SearchOption.AllDirectories)) {\r
224                                 size += (ulong) child.Length;\r
225                         }\r
226                         return size;\r
227                 }\r
228                                 \r
229                 /// <summary>\r
230                 /// ワイルドカードを展開したファイルパス文字列を作り出す。\r
231                 /// 戻り値のそれぞれの文字列はフルパスとなる。\r
232                 /// </summary>\r
233                 /// <param name="baseDir">ベース(基点)のディレクトリ</param>\r
234                 /// <param name="pattern">ワイルドカードパターン</param>\r
235                 /// <returns>展開したファイルパス</returns>\r
236                 public static string[] ExtendWildcardFile(string baseDir, string pattern)\r
237                 {\r
238                         if (pattern.IndexOfAny(new char[]{'*','?'}) < 0) {\r
239                                 return new string[]{Path.Combine(baseDir, pattern)}; // ワイルドカードがなければそのまま返す\r
240                         }\r
241 \r
242                         string[] pathArray = pattern.Split(Path.DirectorySeparatorChar);\r
243                         System.Collections.Generic.List<string> extended = new System.Collections.Generic.List<string>();\r
244                         try {\r
245                                 if (pathArray.Length == 1) {\r
246                                         extended.AddRange(Directory.GetFiles(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));\r
247                                         extended.AddRange(Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));\r
248                                 } else { // pathArray.Length > 1\r
249                                         string subPattern = string.Join(Path.DirectorySeparatorChar.ToString(), pathArray, 1, pathArray.Length-1);\r
250                                         \r
251                                         foreach (string subDir in Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)) {\r
252                                                 // 再帰的に追加してゆく\r
253                                                 extended.AddRange(ExtendWildcardFile(subDir, subPattern));\r
254                                         }\r
255                                 }\r
256                         } catch (UnauthorizedAccessException) {\r
257                         }\r
258                         \r
259                         // 存在しないパスは消去する\r
260                         extended.RemoveAll(\r
261                                 delegate(string path) {\r
262                                         return ! File.Exists(path);\r
263                                 }\r
264                         );\r
265                         \r
266                         return extended.ToArray();\r
267                 }\r
268                 \r
269                 /// <summary>\r
270                 /// パスをパス区切り文字列ごとに分割した配列を返す\r
271                 /// </summary>\r
272                 /// <param name="path">パス文字列。相対・絶対は区別しない</param>\r
273                 /// <returns>フォルダ名ごとに分けられた文字列配列</returns>\r
274                 private static string[] splitPath(string path)\r
275                 {\r
276                         return path.Split(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar});\r
277                 }\r
278                 \r
279                 /// <summary>\r
280                 /// Converts a given absolute path and a given base path to a path that leads\r
281                 /// from the base path to the absoulte path. (as a relative path)\r
282                 /// </summary>\r
283                 public static string GetRelativePath(string baseDirectoryPath, string absPath)\r
284                 {\r
285                         // TODO SharpDevelopのICSharpCode.Core.FileUtilityからのコピペ(GPL)\r
286                         \r
287                         string[] bPath = splitPath(baseDirectoryPath);\r
288                         string[] aPath = splitPath(absPath);\r
289                         int indx = 0;\r
290                         for(; indx < Math.Min(bPath.Length, aPath.Length); ++indx){\r
291                                 if(!bPath[indx].Equals(aPath[indx], StringComparison.OrdinalIgnoreCase))\r
292                                         break;\r
293                         }\r
294 \r
295                         if (indx == 0) {\r
296                                 return absPath;\r
297                         }\r
298 \r
299                         StringBuilder erg = new StringBuilder();\r
300 \r
301                         if(indx == bPath.Length) {\r
302 //                              erg.Append('.');\r
303 //                              erg.Append(Path.DirectorySeparatorChar);\r
304                         } else {\r
305                                 for (int i = indx; i < bPath.Length; ++i) {\r
306                                         erg.Append("..");\r
307                                         erg.Append(Path.DirectorySeparatorChar);\r
308                                 }\r
309                         }\r
310                         erg.Append(String.Join(Path.DirectorySeparatorChar.ToString(), aPath, indx, aPath.Length-indx));\r
311                         return erg.ToString();\r
312                 }\r
313                 \r
314                 /// <summary>\r
315                 /// 相対パスに含まれている".."などを消去する\r
316                 /// </summary>\r
317                 /// <param name="aPath"></param>\r
318                 /// <returns></returns>\r
319                 public static string GetDotsRemovedPath(string aPath)\r
320                 {\r
321                         string[] folders = splitPath(aPath);\r
322                         System.Collections.Generic.List<string> newFolders = new System.Collections.Generic.List<string>();\r
323                         \r
324                         foreach (string fol in folders) {\r
325                                 if (fol == ".") {\r
326                                         // 無視\r
327                                 } else if (fol == "..") {\r
328                                         // 一つ前のフォルダを消す\r
329                                         newFolders.RemoveAt(newFolders.Count-1);\r
330                                 } else {\r
331                                         newFolders.Add(fol);\r
332                                 }\r
333                         }\r
334                         \r
335                         return string.Join(Path.DirectorySeparatorChar.ToString(), newFolders.ToArray());\r
336                 }\r
337                 \r
338                 #endregion\r
339                 \r
340                 #region シリアル化関連\r
341                 \r
342                 /// <summary>\r
343                 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する\r
344                 /// </summary>\r
345                 /// <param name="path">XMLファイルのパス</param>\r
346                 /// <returns>デシリアル化されたオブジェクト</returns>\r
347                 public static T GetDeserializedObject<T>(string path)\r
348                 {\r
349                         T retVal = default(T);\r
350                         using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {\r
351                                 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));\r
352                                 retVal = (T) sr.Deserialize(fs);\r
353                         }\r
354                         return retVal;\r
355                 }\r
356                 \r
357                 /// <summary>\r
358                 /// オブジェクトをXMLでシリアル化してファイルに書き込む\r
359                 /// </summary>\r
360                 /// <param name="path">XMLファイルのパス</param>\r
361                 /// <param name="obj">シリアル化する対象のオブジェクト</param>\r
362                 public static void PutSerializeObject<T>(string path, T obj)\r
363                 {\r
364                         using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {\r
365                                 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));\r
366                                 sr.Serialize(fs, obj);\r
367                         }\r
368                 }\r
369                 \r
370                 #endregion\r
371                 \r
372                 #region 権限関連関数群\r
373                 \r
374                 /// <summary>\r
375                 /// 現在のユーザがAdministrators権限を持っているか否かを返す\r
376                 /// </summary>\r
377                 public static bool IsAdministrators()\r
378                 {\r
379                         // TODO UAC はどうするんだ!!!!\r
380                         \r
381                         // 現在の Windows ユーザーを現在のスレッドのプリンシパルに反映する\r
382                         AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal );\r
383                         IPrincipal prin = System.Threading.Thread.CurrentPrincipal;\r
384                         return prin.IsInRole(@"BUILTIN\Administrators");\r
385                 }\r
386                 \r
387                 /// <summary>\r
388                 /// 現在のPCがUACが有効になっているか否かを返す。\r
389                 /// レジストリのHKLM\SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System\EnableLUAの値を見る。\r
390                 /// </summary>\r
391                 /// <returns>UACが有効ならばtrue</returns>\r
392                 public static bool IsUACEnabled()\r
393                 {\r
394                         try {\r
395                                 using(RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System")) {\r
396                                         return ((int) key.GetValue("EnableLUA", 0)) == 1;\r
397                                 }\r
398                         } catch (Exception) {\r
399                                 return false;\r
400                         }\r
401                 }\r
402                 \r
403                 #endregion\r
404 \r
405                 #region プロセス関連便利メソッド群\r
406                 \r
407                 /// <summary>\r
408                 /// プロセスに出力をリダイレクトした上で実行\r
409                 /// </summary>\r
410                 /// <param name="procInfo">プロセス起動情報</param>\r
411                 /// <param name="outputReceived">標準出力用リスナ(null可)</param>\r
412                 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>\r
413                 /// <returns>実行プロセス</returns>\r
414                 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,\r
415                                                   DataReceivedEventHandler outputReceived,\r
416                                                   DataReceivedEventHandler errorReceived)\r
417                 {\r
418                         if (outputReceived != null) {\r
419                                 procInfo.RedirectStandardOutput = true;\r
420                         }\r
421                         if (errorReceived != null) {\r
422                                 procInfo.RedirectStandardError = true;\r
423                         }\r
424                         procInfo.UseShellExecute = false;\r
425                         \r
426                         Process hProcess = Process.Start(procInfo);\r
427                         if (outputReceived != null) {\r
428                                 hProcess.OutputDataReceived += outputReceived;\r
429                                 hProcess.BeginOutputReadLine();\r
430                         }\r
431                         if (errorReceived != null) {\r
432                                 hProcess.ErrorDataReceived += errorReceived;    \r
433                                 hProcess.BeginErrorReadLine();\r
434                         }\r
435                         \r
436                         return hProcess;\r
437                 }\r
438                 \r
439                 \r
440                 /// <summary>\r
441                 /// プロセスに出力をリダイレクトした上で実行\r
442                 /// </summary>\r
443                 /// <param name="procInfo">プロセス起動情報</param>\r
444                 /// <param name="outputReceived">標準出力用リスナ(null可)</param>\r
445                 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>\r
446                 /// <returns>実行プロセス</returns>\r
447                 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,\r
448                                                   EventHandler<AnyDataEventArgs<string>> outputReceived,\r
449                                                   EventHandler<AnyDataEventArgs<string>> errorReceived)\r
450                 {\r
451                         return ProcessStartWithOutputCapture(procInfo,\r
452                                                              ConvertToDataReceivedEventHandler(outputReceived),\r
453                                                              ConvertToDataReceivedEventHandler(errorReceived));\r
454                 }\r
455                 \r
456                 public static DataReceivedEventHandler ConvertToDataReceivedEventHandler(EventHandler<AnyDataEventArgs<string>> handler)\r
457                 {\r
458                         if (handler == null) return null;\r
459                         return delegate (object sender, DataReceivedEventArgs e) {\r
460                                 AnyDataEventArgs<string> args = new AnyDataEventArgs<string>(e.Data);\r
461                                 handler.Invoke(sender, args);\r
462                         };\r
463                 }\r
464                 \r
465                 #endregion\r
466 \r
467                 \r
468                 /// <summary>\r
469                 /// 任意データのイベント情報を表現するクラス\r
470                 /// </summary>\r
471                 public class AnyDataEventArgs<T> : EventArgs\r
472                 {\r
473                         /// <summary>\r
474                         /// データ\r
475                         /// </summary>\r
476                         T data;\r
477                         \r
478                         public AnyDataEventArgs(T data)\r
479                         {\r
480                                 this.data = data;\r
481                         }\r
482                         \r
483                         /// <summary>\r
484                         /// データを返す\r
485                         /// </summary>\r
486                         public T Data {\r
487                                 get { return data; }\r
488                         }\r
489                 }\r
490         }\r
491 }\r