2 using System.Runtime.InteropServices;
\r
5 namespace NaGet.InteropServices
\r
8 /// CommonArchiverDllの設定
\r
10 public struct CommonArchiverDllConfig
\r
12 public CommonArchiverDllConfig(string dllName, string cmdName, string cmdLineFmt, int versionreq)
\r
16 CmdLineFmt = cmdLineFmt;
\r
17 VersionMoreThan = versionreq;
\r
21 /// DLLの名称。LoadLibraryに渡される
\r
23 public string DllName;
\r
27 public string CmdName;
\r
29 /// コマンドライン形式"{0}"がアーカイブ名、"{1}"が展開先
\r
31 public string CmdLineFmt;
\r
35 public int VersionMoreThan;
\r
39 /// アーカイバDLLを使った書庫展開器
\r
41 public class CommonArchiverExtracter
\r
44 #region DLL関数のdelegate
\r
49 private delegate ushort ArcGetVersion();
\r
54 private delegate bool ArcGetRunning();
\r
59 private delegate bool ArcCheckArchive(string szFileName, ArchCheckFlag iMode);
\r
64 private enum ArchCheckFlag {
\r
66 /// 簡易モード。先頭の数個のヘッダのみ確認
\r
70 /// 通常モード。すべてのヘッダを確認
\r
74 /// 厳密モード。CRCも含めすべて確認
\r
85 private delegate int ArcGetFileCount(string szFileName);
\r
90 private delegate int ArcMain(IntPtr hWnd,
\r
91 [MarshalAs(UnmanagedType.LPStr)] string szCmdLine,
\r
92 [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder szOutput, uint dwSize);
\r
99 public static readonly CommonArchiverDllConfig[] Configs = {
\r
100 new CommonArchiverDllConfig("UNZIP32", "UnZip", "-x -o \"{0}\" \"{1}\" *", 541),
\r
101 new CommonArchiverDllConfig("7-ZIP32", "SevenZip", "x -y \"{0}\" \"-o{1}\"", 423),
\r
102 new CommonArchiverDllConfig("UNLHA32", "Unlha", "x \"{0}\" \"{1}\" *", 240),
\r
103 new CommonArchiverDllConfig("CAB32", "Cab", "-x \"{0}\" \"{1}\" *", 98),
\r
104 new CommonArchiverDllConfig("TAR32", "Tar", "-x \"{0}\" -o \"{1}\"", 218),
\r
105 new CommonArchiverDllConfig("UNGCA32", "UnGCA", "e \"{0}\" \"{1}\"", 10), // いるかな?
\r
107 //new CommonArchiverDllConfig("UNRAR32", "Unrar", "x -y \"{0}\" \"{1}\" *", -1),
\r
111 /// アーカイブを展開する。適切なDLLで自動的に展開する。
\r
113 /// <param name="arcFile">アーカイブのパス</param>
\r
114 /// <param name="targetDir">展開先ディレクトリ</param>
\r
115 /// <param name="output">アーカイバDLLの展開時の標準出力を格納する</param>
\r
116 /// <param name="hWnd">親フレーム</param>
\r
117 /// <returns>アーカイバDLLの展開時のエラーコード(0なら正常終了)</returns>
\r
118 public static int ExtractArchive(string arcFile, string targetDir, System.Text.StringBuilder output, IntPtr hWnd)
\r
120 foreach (CommonArchiverDllConfig config in Configs) {
\r
122 return ExtractArchiveWith(arcFile, targetDir, config, output, hWnd);
\r
123 } catch (DllNotFoundException) {
\r
124 } catch (ApplicationException) {
\r
127 throw new DllNotFoundException("Not found dll matched for " + arcFile);
\r
131 /// 指定したDLLの設定を使ってアーカイブを展開する
\r
133 /// <param name="arcFile">アーカイブのパス</param>
\r
134 /// <param name="targetDir">展開先ディレクトリ</param>
\r
135 /// <param name="config">使用するアーカイバDLLの設定</param>
\r
136 /// <param name="output">アーカイバDLLの展開時の標準出力を格納する</param>
\r
137 /// <param name="hWnd">親フレーム</param>
\r
138 /// <returns>アーカイバDLLの展開時のエラーコード(0なら正常終了)</returns>
\r
139 public static int ExtractArchiveWith(string arcFile, string targetDir, CommonArchiverDllConfig config, System.Text.StringBuilder output, IntPtr hWnd)
\r
141 if (! File.Exists(arcFile) ) {
\r
142 throw new FileNotFoundException("File not found: ", arcFile);
\r
144 if (! Directory.Exists(targetDir)) {
\r
145 throw new DirectoryNotFoundException("Directory not found: " + targetDir);
\r
148 // 統合アーカイバDLLの解凍先ディレクトリは\で終わらないといけない(重要)
\r
149 if (! targetDir.EndsWith("\\")) {
\r
154 using (DllAccess dll = new DllAccess(config.DllName)) {
\r
155 ArcGetVersion GetVersion = (ArcGetVersion) dll.GetFunction(config.CmdName+"GetVersion", typeof(ArcGetVersion));
\r
156 ushort version = GetVersion();
\r
157 if (version < config.VersionMoreThan) {
\r
158 throw new DllNotFoundException("Dll version is too old.");
\r
162 string cmdLine = string.Format(config.CmdLineFmt, arcFile, targetDir);
\r
163 return ExtractArchiveWith(config.DllName, config.CmdName, cmdLine, arcFile, output, hWnd);
\r
166 protected static int ExtractArchiveWith(string dllName, string cmdName, string cmdLine, string arcFile, System.Text.StringBuilder output, IntPtr hWnd)
\r
168 using (DllAccess dll = new DllAccess(dllName)) {
\r
169 ArcGetRunning GetRunning = (ArcGetRunning) dll.GetFunction(cmdName+"GetRunning", typeof(ArcGetRunning));
\r
170 if ( GetRunning() ) { // マルチスレッド対応でないのでビジー時には例外
\r
171 throw new SystemException(dllName + " is busy");
\r
174 ArcCheckArchive CheckArchive = (ArcCheckArchive) dll.GetFunction(cmdName+"CheckArchive", typeof(ArcCheckArchive));
\r
175 if (! CheckArchive(arcFile, ArchCheckFlag.BASIC)) {
\r
176 throw new ApplicationException(dllName + " could not treat the archive file");
\r
179 ArcMain Exec = (ArcMain) dll.GetFunction(cmdName, typeof(ArcMain));
\r
180 int retVal = Exec(hWnd, cmdLine, output, (uint)((output != null)? output.Capacity : 0) );
\r