OSDN Git Service

714d8129d7a37fba1597ceed92d1564a19bb45c0
[applistation/AppliStation.git] / na-get-lib / NaGet.InteropServices / CommonArchiverExtracter.cs
1 using System;\r
2 using System.Runtime.InteropServices;\r
3 using System.IO;\r
4 \r
5 namespace NaGet.InteropServices\r
6 {\r
7         /// <summary>\r
8         /// CommonArchiverDllの設定\r
9         /// </summary>\r
10         public struct CommonArchiverDllConfig\r
11         {\r
12                 public CommonArchiverDllConfig(string dllName, string cmdName, string cmdLineFmt, int versionreq)\r
13                 {\r
14                         DllName = dllName;\r
15                         CmdName = cmdName;\r
16                         CmdLineFmt = cmdLineFmt;\r
17                         VersionMoreThan = versionreq;\r
18                 }\r
19                 \r
20                 /// <summary>\r
21                 /// DLLの名称。LoadLibraryに渡される\r
22                 /// </summary>\r
23                 public string DllName;\r
24                 /// <summary>\r
25                 /// コマンド名称。\r
26                 /// </summary>\r
27                 public string CmdName;\r
28                 /// <summary>\r
29                 /// コマンドライン形式"{0}"がアーカイブ名、"{1}"が展開先\r
30                 /// </summary>\r
31                 public string CmdLineFmt;\r
32                 /// <summary>\r
33                 /// 最低バージョン要求\r
34                 /// </summary>\r
35                 public int VersionMoreThan;\r
36         }\r
37         \r
38         /// <summary>\r
39         /// アーカイバDLLを使った書庫展開のエラー\r
40         /// </summary>\r
41         public class CommonArchiverDllExtractionException : ApplicationException\r
42         {\r
43                 /// <summary>\r
44                 /// DLLファイル名\r
45                 /// </summary>\r
46                 private string dllName;\r
47                 \r
48                 /// <summary>\r
49                 /// 戻り値\r
50                 /// </summary>\r
51                 private int returnValue;\r
52                 \r
53                 /// <summary>\r
54                 /// アーカイバDLLを使った書庫展開のエラー\r
55                 /// </summary>\r
56                 /// <param name="message">メッセージ</param>\r
57                 /// <param name="dllName">対象DLL名</param>\r
58                 /// <param name="returnValue">戻り値</param>\r
59                 public CommonArchiverDllExtractionException(string message, string dllName, int returnValue)\r
60                         : base(message)\r
61                 {\r
62                         this.dllName = dllName;\r
63                         this.returnValue = returnValue;\r
64                 }\r
65                 \r
66                 /// <summary>\r
67                 /// DLLファイルの名称\r
68                 /// </summary>\r
69                 public string DllName {\r
70                         get { return dllName; }\r
71                 }\r
72                 \r
73                 /// <summary>\r
74                 /// 戻り値(非0)\r
75                 /// </summary>\r
76                 public int ReturnValue {\r
77                         get { return returnValue; }\r
78                 }\r
79         }\r
80         \r
81         /// <summary>\r
82         /// アーカイバDLLを使った書庫展開器\r
83         /// </summary>\r
84         public class CommonArchiverExtracter\r
85         {\r
86                 \r
87                 #region DLL関数のdelegate\r
88                 \r
89                 /// <summary>\r
90                 /// DLL の版の取得\r
91                 /// </summary>\r
92                 private delegate ushort ArcGetVersion();\r
93                 \r
94                 /// <summary>\r
95                 /// DLL の実行状況の取得\r
96                 /// </summary>\r
97                 private delegate bool ArcGetRunning();\r
98                 \r
99                 /// <summary>\r
100                 /// 書庫のチェック\r
101                 /// </summary>\r
102                 private delegate bool ArcCheckArchive(string szFileName, ArchCheckFlag iMode);\r
103                 \r
104                 /// <summary>\r
105                 /// 書庫のチェックの精度\r
106                 /// </summary>\r
107                 private enum ArchCheckFlag {\r
108                         /// <summary>\r
109                         /// 簡易モード。先頭の数個のヘッダのみ確認\r
110                         /// </summary>\r
111                         RAPID = 0,\r
112                         /// <summary>\r
113                         /// 通常モード。すべてのヘッダを確認\r
114                         /// </summary>\r
115                         BASIC = 1,\r
116                         /// <summary>\r
117                         /// 厳密モード。CRCも含めすべて確認\r
118                         /// </summary>\r
119                         FULLCRC = 2,\r
120                         //RECOVERY = 4,\r
121                         //SFX = 8,\r
122                         //ALL = 16,\r
123                 }\r
124                 \r
125                 /// <summary>\r
126                 /// 格納ファイル数の取得\r
127                 /// </summary>\r
128                 private delegate int ArcGetFileCount(string szFileName);\r
129                 \r
130                 /// <summary>\r
131                 /// 書庫操作一般\r
132                 /// </summary>\r
133                 private delegate int ArcMain(IntPtr hWnd,\r
134                                             [MarshalAs(UnmanagedType.LPStr)] string szCmdLine,\r
135                                             [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder szOutput, uint dwSize);\r
136                 \r
137                 #endregion\r
138                 \r
139                 /// <summary>\r
140                 /// アーカイバDLLの設定\r
141                 /// </summary>\r
142                 public static readonly CommonArchiverDllConfig[] Configs = {\r
143                         new CommonArchiverDllConfig("7-ZIP32", "SevenZip", "x -y \"{0}\" \"-o{1}\"", 423),\r
144                         new CommonArchiverDllConfig("UNZIP32", "UnZip", "-x -o \"{0}\" \"{1}\" *", 541),\r
145                         new CommonArchiverDllConfig("UNLHA32", "Unlha", "x \"{0}\" \"{1}\" *", 240),\r
146                         new CommonArchiverDllConfig("CAB32", "Cab", "-x \"{0}\" \"{1}\" *", 98),\r
147                         new CommonArchiverDllConfig("TAR32", "Tar", "-x \"{0}\" -o \"{1}\"", 218),\r
148                         new CommonArchiverDllConfig("UNGCA32", "UnGCA", "e \"{0}\" \"{1}\"", 10), // いるかな?\r
149                         \r
150                         //new CommonArchiverDllConfig("UNRAR32", "Unrar", "x -y \"{0}\" \"{1}\" *", -1),\r
151                 };\r
152                 \r
153                 /// <summary>\r
154                 /// アーカイブを展開する。適切なDLLで自動的に展開する。\r
155                 /// </summary>\r
156                 /// <param name="arcFile">アーカイブのパス</param>\r
157                 /// <param name="targetDir">展開先ディレクトリ</param>\r
158                 /// <param name="output">アーカイバDLLの展開時の標準出力を格納する</param>\r
159                 /// <param name="hWnd">親フレーム</param>\r
160                 /// <returns>アーカイバDLLが見つかって正しく処理できたらtrue、DLLが見つからなかったらfalse</returns>\r
161                 public static bool ExtractArchive(string arcFile, string targetDir, System.Text.StringBuilder output, IntPtr hWnd)\r
162                 {\r
163                         bool ret = false;\r
164                         \r
165                         foreach (CommonArchiverDllConfig config in Configs) {\r
166                                 try {\r
167                                         ret = ExtractArchiveWith(arcFile, targetDir, config, output, hWnd);\r
168                                         if (ret == true) {\r
169                                                 break;\r
170                                         }\r
171                                 } catch (CommonArchiverDllExtractionException) {\r
172                                         throw;\r
173                                 } catch (DllNotFoundException) {\r
174                                 } catch (ApplicationException) {\r
175                                 }\r
176                         }\r
177                         \r
178                         return ret;\r
179                 }\r
180                 \r
181                 /// <summary>\r
182                 /// 指定したDLLの設定を使ってアーカイブを展開する\r
183                 /// </summary>\r
184                 /// <param name="arcFile">アーカイブのパス</param>\r
185                 /// <param name="targetDir">展開先ディレクトリ</param>\r
186                 /// <param name="config">使用するアーカイバDLLの設定</param>\r
187                 /// <param name="output">アーカイバDLLの展開時の標準出力を格納する</param>\r
188                 /// <param name="hWnd">親フレーム</param>\r
189                 /// <returns>アーカイバDLLの展開時のエラーコード(0なら正常終了)</returns>\r
190                 public static bool ExtractArchiveWith(string arcFile, string targetDir, CommonArchiverDllConfig config, System.Text.StringBuilder output, IntPtr hWnd)\r
191                 {\r
192                         if (! File.Exists(arcFile) ) {\r
193                                 throw new FileNotFoundException(string.Format("File not found: {0}", arcFile), arcFile);\r
194                         }\r
195                         if (! Directory.Exists(targetDir)) {\r
196                                 throw new DirectoryNotFoundException("Directory not found: " + targetDir);\r
197                         }\r
198                         \r
199                         // 統合アーカイバDLLの解凍先ディレクトリは\で終わらないといけない(重要)\r
200                         if (! targetDir.EndsWith("\\")) {\r
201                                 targetDir += "\\";\r
202                         }\r
203                         \r
204                         // DLLバージョンチェック\r
205                         using (DllAccess dll = new DllAccess(config.DllName)) {\r
206                                 ArcGetVersion GetVersion = (ArcGetVersion) dll.GetFunction(config.CmdName+"GetVersion", typeof(ArcGetVersion));\r
207                                 ushort version = GetVersion();\r
208                                 if (version < config.VersionMoreThan) {\r
209                                         throw new DllNotFoundException("Dll version is too old.");\r
210                                 }\r
211                         }\r
212                         \r
213                         string cmdLine = string.Format(config.CmdLineFmt, arcFile, targetDir);\r
214                         int retVal = ExtractArchiveWith(config.DllName, config.CmdName, cmdLine, arcFile, output, hWnd);\r
215                         if (retVal != 0) {\r
216                                 string errorMsg = string.Format("Extraction failure: {0}#{1}() returns {2}.", config.DllName, config.CmdName, retVal);\r
217                                 throw new CommonArchiverDllExtractionException(errorMsg, config.DllName, retVal);\r
218                         }\r
219                         \r
220                         return true;\r
221                 }\r
222                 \r
223                 protected static int ExtractArchiveWith(string dllName, string cmdName, string cmdLine, string arcFile, System.Text.StringBuilder output, IntPtr hWnd)\r
224                 {\r
225                         using (DllAccess dll = new DllAccess(dllName)) {\r
226                                 ArcGetRunning GetRunning = (ArcGetRunning) dll.GetFunction(cmdName+"GetRunning", typeof(ArcGetRunning));\r
227                                 if ( GetRunning() ) { // マルチスレッド対応でないのでビジー時には例外\r
228                                         throw new SystemException(dllName + " is busy");\r
229                                 }\r
230                                 \r
231                                 ArcCheckArchive CheckArchive = (ArcCheckArchive) dll.GetFunction(cmdName+"CheckArchive", typeof(ArcCheckArchive));\r
232                                 if (! CheckArchive(arcFile, ArchCheckFlag.BASIC)) {\r
233                                         throw new ApplicationException(dllName + " could not treat the archive file");\r
234                                 }\r
235                                 \r
236                                 ArcMain Exec = (ArcMain) dll.GetFunction(cmdName, typeof(ArcMain));\r
237                                 int retVal = Exec(hWnd, cmdLine, output, (uint)((output != null)? output.Capacity : 0) );\r
238                                 \r
239                                 return retVal;\r
240                         }\r
241                 }\r
242         }\r
243 }\r