OSDN Git Service

作成できる書庫形式が一つもない場合に、書庫を作成しようとすると不正終了していたバグを修正。
[tpi/lychee.git] / src / lychee / dlg_make.cpp
1 /*******************************************************************************\r
2   TPI - flexible but useless plug-in framework.\r
3   Copyright (C) 2002-2009 Silky\r
4 \r
5   This library is free software; you can redistribute it and/or modify it under\r
6   the terms of the GNU Lesser General Public License as published by the Free\r
7   Software Foundation; either version 2.1 of the License, or (at your option)\r
8   any later version.\r
9 \r
10   This library is distributed in the hope that it will be useful, but WITHOUT\r
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \r
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License\r
13   for more details.\r
14 \r
15   You should have received a copy of the GNU Lesser General Public License along\r
16   with this library; if not, write to the Free Software Foundation, Inc.,\r
17   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
18 \r
19   $Id$\r
20 *******************************************************************************/\r
21 \r
22 #include "lychee.h"\r
23 \r
24 #include "dlg_make.h"\r
25 #include "frm_main.h"\r
26 #include "functions.h"\r
27 \r
28 #include <wx/dirdlg.h>\r
29 #include <wx/arrimpl.cpp>\r
30 \r
31 WX_DEFINE_OBJARRAY(ArrayTPI_FORMATINFO);\r
32 \r
33 //******************************************************************************\r
34 // MakeDialog\r
35 //******************************************************************************\r
36 \r
37 MakeDialog::MakeDialog(): wxDialog()\r
38 {\r
39         this->uCommand = TPI_COMMAND_CREATE;\r
40 }\r
41 \r
42 //******************************************************************************\r
43 // Event Table.\r
44 //******************************************************************************\r
45 \r
46 BEGIN_EVENT_TABLE(MakeDialog, wxDialog)\r
47         EVT_INIT_DIALOG(                 MakeDialog::OnInit)\r
48         EVT_BUTTON(XRCID("btnDefault"),  MakeDialog::OnBtnDefault)\r
49         EVT_BUTTON(XRCID("btnDesktop"),  MakeDialog::OnBtnDesktop)\r
50         EVT_BUTTON(XRCID("btnCurrent"),  MakeDialog::OnBtnCurrent)\r
51         EVT_BUTTON(XRCID("btnBrowse"),   MakeDialog::OnBtnBrowse)\r
52         EVT_BUTTON(XRCID("btnBrowseKF"), MakeDialog::OnBtnBrowseKF)\r
53         EVT_BUTTON(XRCID("btnOK"),       MakeDialog::OnBtnOK)\r
54         EVT_BUTTON(XRCID("btnCancel"),   MakeDialog::OnBtnCancel)\r
55         EVT_CHOICE(XRCID("chType"),      MakeDialog::OnChoice)\r
56         EVT_CHECKBOX(XRCID("cbUnmask"),  MakeDialog::OnCbUnmask)\r
57         EVT_CHECKBOX(XRCID("cbMakeSFX"), MakeDialog::OnCbMakeSFX)\r
58         EVT_NOTEBOOK_PAGE_CHANGED(XRCID("nbTabs"), MakeDialog::OnTabChanged)\r
59 END_EVENT_TABLE()\r
60 \r
61 //******************************************************************************\r
62 // Event handler.\r
63 //******************************************************************************\r
64 \r
65 void MakeDialog::OnInit(wxInitDialogEvent&)\r
66 {\r
67         // XRCと結びつけ。\r
68         // "General"タブ\r
69         this->cbDir             = XRCCTRL(* this, "cbDir",        wxComboBox);\r
70         this->cbFileName        = XRCCTRL(* this, "cbFileName",   wxComboBox);\r
71         this->cbOpenAfter       = XRCCTRL(* this, "cbOpenAfter",  wxCheckBox);\r
72         this->cbIgnorePath      = XRCCTRL(* this, "cbIgnorePath", wxCheckBox);\r
73         this->cbExitAfter       = XRCCTRL(* this, "cbExitAfter",  wxCheckBox);\r
74         this->chType            = XRCCTRL(* this, "chType",       wxChoice);\r
75         this->chDirMake         = XRCCTRL(* this, "chDirMake",    wxChoice);\r
76         // "Config"タブ\r
77         this->scLevel           = XRCCTRL(* this, "scLevel",      wxSpinCtrl);\r
78         this->scRR              = XRCCTRL(* this, "scRR",         wxSpinCtrl);\r
79         this->tcPassword        = XRCCTRL(* this, "tcPassword",   wxTextCtrl);\r
80         this->tcKeyfile         = XRCCTRL(* this, "tcKeyfile",    wxTextCtrl);\r
81         this->cbSplitSize       = XRCCTRL(* this, "cbSplitSize",  wxComboBox);\r
82         this->cbUnmask          = XRCCTRL(* this, "cbUnmask",     wxCheckBox);\r
83         this->cbEncryptHeader   = XRCCTRL(* this, "cbEncryptHeader", wxCheckBox);\r
84         this->cbSolid           = XRCCTRL(* this, "cbSolid",      wxCheckBox);\r
85         this->cbMMOptimize      = XRCCTRL(* this, "cbMMOptimize", wxCheckBox);\r
86         this->cbMakeSFX         = XRCCTRL(* this, "cbMakeSFX",    wxCheckBox);\r
87         // "Comment"タブ\r
88         this->tcComment         = XRCCTRL(* this, "tcComment",    wxTextCtrl);\r
89         // "Files"タブ\r
90         this->lcFiles           = XRCCTRL(* this, "lcFiles",      wxListCtrl);\r
91 \r
92         // 2回目以降は無視。\r
93         if (! this->cbDir->GetValue().IsEmpty())\r
94         {\r
95                 return;\r
96         }\r
97 \r
98         // ListCtrlに列を追加。\r
99         this->lcFiles->InsertColumn(0, _("Input"),  wxLIST_FORMAT_LEFT,  150);\r
100         this->lcFiles->InsertColumn(1, _("Output"), wxLIST_FORMAT_LEFT,  300);\r
101 \r
102         ::wxXmlResource::Get()->Unload(L_DIR_S_XRC wxT("dlg_make.xrc"));\r
103 \r
104         // 事前準備。\r
105         MainFrame * frm_main = (MainFrame *) this->GetParent();\r
106         wxString szArcPath = frm_main->fnArchive.GetPath(), szArcName = frm_main->fnArchive.GetName();\r
107 \r
108         // パス履歴読み込み。\r
109         for (size_t i = 0; i < frm_main->conf.GetHistoryCount(CONF_HISTORY_PATH); i++)\r
110         {\r
111                 wxString sz = frm_main->conf.ReadHistory(CONF_HISTORY_PATH, i);\r
112                 if (sz.IsEmpty())\r
113                 {\r
114                         continue;\r
115                 }\r
116 \r
117                 this->cbDir->Append(sz);\r
118         }\r
119         // 書庫名履歴読み込み。\r
120         for (size_t i = 0; i < frm_main->conf.GetHistoryCount(CONF_HISTORY_NAME); i++)\r
121         {\r
122                 wxString sz = frm_main->conf.ReadHistory(CONF_HISTORY_NAME, i);\r
123                 if (sz.IsEmpty())\r
124                 {\r
125                         continue;\r
126                 }\r
127 \r
128                 this->cbFileName->Append(sz);\r
129         }\r
130 \r
131         // パスを設定。\r
132         this->cbDir->SetValue(szArcPath);\r
133 \r
134         // コマンド別の処理。\r
135         switch (this->uCommand)\r
136         {\r
137         case TPI_COMMAND_EXTRACT:\r
138                 // 初期値を設定。\r
139                 this->SetTitle(_("Extract"));\r
140                 this->tcComment->SetValue(frm_main->aiArchive.szComment);\r
141 \r
142                 // 展開先を予測。ただしDTVスキャンに時間がかかる場合はスキップ可能。\r
143                 if (this->files.GetCount() < 3000 || ::AskDlg(_("This archive contains so many files that it takes long to check Directory Traversal Vulnerability(DTV) problem. If you are sure this archive is safe, you can skip this scanning process. Do you want to scan for DTV problem?"), this) == wxYES)\r
144                 {\r
145                         wxNotebookEvent e;\r
146                         e.SetSelection(-3);\r
147                         this->OnTabChanged(e);\r
148                 }\r
149 \r
150                 // コントロールを無効化。\r
151                 this->scLevel->Disable();\r
152                 this->scRR->Disable();\r
153                 this->cbEncryptHeader->Disable();\r
154                 this->cbSolid->Disable();\r
155                 this->cbMMOptimize->Disable();\r
156                 this->tcComment->SetEditable(false);\r
157         case TPI_COMMAND_ADD:\r
158                 // コントロールを無効化(展開時も)。\r
159                 this->cbFileName->Disable();\r
160                 this->chType->Disable();\r
161                 this->chDirMake->Enable();\r
162                 this->cbSplitSize->Disable();\r
163                 this->cbMakeSFX->Disable();\r
164 \r
165                 // 書庫名を設定。\r
166                 this->cbFileName->SetValue(szArcName);\r
167 \r
168                 // 書庫形式欄を設定。\r
169                 this->afInfo.Add(frm_main->aiArchive.fiInfo);\r
170                 this->chType->Append(frm_main->aiArchive.fiInfo.szTypeName);\r
171 \r
172                 // とりあえず最初の形式にしておく。\r
173                 this->chType->SetSelection(0);\r
174                 {\r
175                         wxCommandEvent e;\r
176                         e.SetInt(0);\r
177                         this->OnChoice(e);\r
178                 }\r
179 \r
180                 if (this->uCommand != TPI_COMMAND_ADD)\r
181                 {\r
182                         break;\r
183                 }\r
184                 this->SetTitle(_("Add"));\r
185 \r
186                 // コントロールを無効化(追加時のみ)。\r
187                 this->cbDir->Disable();\r
188                 this->chDirMake->Disable();\r
189                 break;\r
190         case TPI_COMMAND_CREATE:\r
191                 this->SetTitle(_("Create"));\r
192 \r
193                 // 書庫名を設定。初期化の都合上.を付加しておく。\r
194                 this->cbFileName->SetValue(szArcName + wxT('.'));\r
195 \r
196                 // ライブラリを検索。\r
197                 TPIHandle tpi;\r
198                 wxFileSystem fs;\r
199                 fs.ChangePathTo(L_DIR_B_LIB, true);\r
200                 wxString szTPIName = fs.FindFirst(wxT("*" TPI_EXT), wxFILE);\r
201                 while (! szTPIName.IsEmpty())\r
202                 {\r
203                         // ロード。\r
204                         if (tpi.InitLibrary(szTPIName, wxEmptyString, 0))\r
205                         {\r
206                                 // 対応する形式名を取得。\r
207                                 TPI_FORMATINFO fiInfo;\r
208                                 if (tpi.GetFormatInformation(& fiInfo, true))\r
209                                 {\r
210                                         do\r
211                                         {\r
212                                                 if (fiInfo.llSupportedCommand & TPI_COMMAND_CREATE && (this->files.GetCount() == 1 || fiInfo.fArchive))\r
213                                                 {\r
214                                                         fiInfo.szTPIName = szTPIName;\r
215                                                         this->afInfo.Add(fiInfo);\r
216                                                         this->chType->Append(fiInfo.szTypeName);\r
217                                                 }\r
218                                         }\r
219                                         while (tpi.GetFormatInformation(& fiInfo, false));\r
220                                 }\r
221                                 tpi.FreeLibrary();\r
222                         }\r
223                         szTPIName = fs.FindNext();\r
224                 }\r
225 \r
226                 if (this->chType->GetCount() == 0)\r
227                 {\r
228                         // 形式の候補が一つもない場合。\r
229                         XRCCTRL(* this, "btnOK", wxButton)->Disable();\r
230                         break;\r
231                 }\r
232 \r
233                 // とりあえず最初の形式にしておく。\r
234                 this->chType->SetSelection(0);\r
235                 wxCommandEvent e;\r
236                 e.SetInt(0);\r
237                 this->OnChoice(e);\r
238                 break;\r
239         }\r
240 }\r
241 \r
242 void MakeDialog::OnBtnDefault(wxCommandEvent&)\r
243 {\r
244         this->cbDir->SetValue(((MainFrame *) this->GetParent())->conf.ReadId(CONF_DEFAULT_PATH, (wxString) wxEmptyString));\r
245 }\r
246 \r
247 void MakeDialog::OnBtnDesktop(wxCommandEvent&)\r
248 {\r
249         wxFileName fn(wxFileName::GetHomeDir(), wxT("Desktop"));\r
250         this->cbDir->SetValue(fn.GetFullPath());\r
251 }\r
252 \r
253 void MakeDialog::OnBtnCurrent(wxCommandEvent&)\r
254 {\r
255         this->cbDir->SetValue(((MainFrame *) this->GetParent())->fnArchive.GetPath());\r
256 }\r
257 \r
258 void MakeDialog::OnBtnBrowse(wxCommandEvent&)\r
259 {\r
260         wxDirDialog dd(this);\r
261         dd.SetPath(this->cbDir->GetValue());\r
262         if (dd.ShowModal() == wxID_OK)\r
263         {\r
264                 this->cbDir->SetValue(dd.GetPath());\r
265         }\r
266 }\r
267 \r
268 void MakeDialog::OnBtnBrowseKF(wxCommandEvent&)\r
269 {\r
270         wxFileDialog fd(this);\r
271         fd.SetWindowStyleFlag(wxFD_OPEN | wxFD_FILE_MUST_EXIST);\r
272         if (fd.ShowModal() == wxID_OK)\r
273         {\r
274                 this->tcKeyfile->SetValue(fd.GetPath());\r
275         }\r
276 }\r
277 \r
278 void MakeDialog::OnBtnOK(wxCommandEvent&)\r
279 {\r
280         // 履歴書き込み。\r
281         if (this->uCommand != TPI_COMMAND_ADD)\r
282         {\r
283                 MainFrame * frm_main = (MainFrame *) this->GetParent();\r
284                 wxFileName fnCurrent(this->cbDir->GetValue(), this->uCommand == TPI_COMMAND_CREATE ? this->cbFileName->GetValue() : (wxString) wxEmptyString);\r
285                 frm_main->conf.WriteHistory(CONF_HISTORY_FULL, fnCurrent.GetFullPath());\r
286                 frm_main->conf.WriteHistory(CONF_HISTORY_PATH, fnCurrent.GetPath());\r
287                 frm_main->conf.WriteHistory(CONF_HISTORY_NAME, fnCurrent.GetFullName());\r
288         }\r
289         this->EndModal(wxID_OK);\r
290 }\r
291 \r
292 void MakeDialog::OnBtnCancel(wxCommandEvent&)\r
293 {\r
294         this->EndModal(wxID_CANCEL);\r
295 }\r
296 \r
297 void MakeDialog::OnChoice(wxCommandEvent& e)\r
298 {\r
299         TPI_FORMATINFO * fiInfo = & this->afInfo[e.GetInt()];\r
300         // 形式が各種設定に対応しているか。\r
301         // 作成時/追加時/展開時設定。\r
302         this->tcPassword->Enable(fiInfo->fEncryptPassword);\r
303         this->cbUnmask->Enable(fiInfo->fEncryptPassword);\r
304         this->tcKeyfile->Enable(fiInfo->fEncryptKeyFile);\r
305         if (this->uCommand == TPI_COMMAND_EXTRACT)\r
306         {\r
307                 return;\r
308         }\r
309 \r
310         // 作成時/追加時設定。\r
311         this->scLevel->SetRange(fiInfo->sCompressLevelMin, fiInfo->sCompressLevelMax);\r
312         this->scLevel->SetValue(fiInfo->sCompressLevelMax);\r
313         this->scLevel->Enable(fiInfo->sCompressLevelMin != fiInfo->sCompressLevelMax);\r
314         this->scRR->SetRange(fiInfo->sRecoveryRecordMin, fiInfo->sRecoveryRecordMax);\r
315         this->scRR->SetValue(fiInfo->sRecoveryRecordMin);\r
316         this->scRR->Enable(fiInfo->sRecoveryRecordMin != fiInfo->sRecoveryRecordMax);\r
317         this->cbEncryptHeader->Enable(fiInfo->fEncryptHeader);\r
318         this->cbSolid->Enable(fiInfo->fSolid);\r
319         this->cbMMOptimize->Enable(fiInfo->fMMOptimize);\r
320         this->tcComment->Enable(fiInfo->fComment);\r
321         if (this->uCommand == TPI_COMMAND_ADD)\r
322         {\r
323                 return;\r
324         }\r
325 \r
326         // 作成時設定。\r
327         this->cbSplitSize->Enable(fiInfo->fMultiVolume);\r
328         this->cbMakeSFX->Enable(fiInfo->fSFX);\r
329 \r
330         wxFileName fn(this->cbFileName->GetValue());\r
331         fn.SetExt(this->cbMakeSFX->IsEnabled() && this->cbMakeSFX->IsChecked() ? EXE_EXT : fiInfo->szSuffix.BeforeFirst(wxT(';')));\r
332         this->cbFileName->SetValue(fn.GetFullName());\r
333 }\r
334 \r
335 void MakeDialog::OnCbUnmask(wxCommandEvent&)\r
336 {\r
337         this->tcPassword->SetWindowStyle(this->tcPassword->GetWindowStyle() & (this->cbUnmask->IsChecked() ? ~ wxTE_PASSWORD : wxTE_PASSWORD));\r
338         this->tcPassword->Refresh();\r
339 }\r
340 \r
341 void MakeDialog::OnCbMakeSFX(wxCommandEvent&)\r
342 {\r
343         wxFileName fn(this->cbFileName->GetValue());\r
344         fn.SetExt(this->cbMakeSFX->IsChecked() ? EXE_EXT : this->afInfo[this->chType->GetSelection()].szSuffix.BeforeFirst(wxT(';')));\r
345         this->cbFileName->SetValue(fn.GetFullName());\r
346 }\r
347 \r
348 void MakeDialog::OnTabChanged(wxNotebookEvent& e)\r
349 {\r
350         // "Files"タブのときは処理。\r
351         bool bReallyShow = e.GetSelection() == 3;\r
352         if (abs(e.GetSelection()) != 3)\r
353         {\r
354                 return;\r
355         }\r
356 \r
357         // "Files"タブを表示する初回かどうか。\r
358         if (bReallyShow && this->lcFiles->GetItemCount() == 0)\r
359         {\r
360                 // ファイルリストを追加。\r
361                 for (size_t i = 0; i < this->files.GetCount(); i++)\r
362                 {\r
363                         this->lcFiles->InsertItem(i, this->files[i]);\r
364                 }\r
365         }\r
366 \r
367         switch (this->uCommand)\r
368         {\r
369         case TPI_COMMAND_EXTRACT:\r
370         {\r
371                 // ファイルの出力先を推測。\r
372                 wxString szOutputRootDir = WillMakeDirByArcName((MainFrame *) this->GetParent(), this) ? MakeDirPath(wxFileName::DirName(this->cbDir->GetValue()), wxFileName(this->cbFileName->GetValue()).GetName(), false).GetPath() : this->cbDir->GetValue();\r
373 \r
374                 // 各ファイルにパスを付加。\r
375                 bool fDTVWarning = false;\r
376                 for (size_t i = 0; i < this->files.GetCount(); i++)\r
377                 {\r
378                         wxString szOutputFile = szOutputRootDir + wxFileName::GetPathSeparator();\r
379                         wxFileName fnStored(this->files[i]);\r
380                         if (! this->cbIgnorePath->IsChecked())\r
381                         {\r
382                                 szOutputFile += fnStored.GetPathWithSep();\r
383                         }\r
384                         szOutputFile += fnStored.GetFullName();\r
385                         wxFileName fnOutput(szOutputFile);\r
386                         if (! fnOutput.Normalize() || ! fnOutput.GetFullPath().StartsWith(szOutputRootDir))\r
387                         {\r
388                                 fDTVWarning = true;\r
389                                 if (bReallyShow)\r
390                                 {\r
391                                         this->lcFiles->SetItemTextColour(i, * wxRED);\r
392                                 }\r
393                         }\r
394                         if (bReallyShow)\r
395                         {\r
396                                 this->lcFiles->SetItem(i, 1, fnOutput.GetFullPath());\r
397                         }\r
398                 }\r
399 \r
400                 if (fDTVWarning && ::AskDlg(_("This archive may have Directory Traversal Vulnerability(DTV) problem, and some danger files may be extracted to the unexpected system directory! It is strongly recommended to ignore file path. Would you like to do so?"), this) == wxYES)\r
401                 {\r
402                         this->cbIgnorePath->SetValue(true);\r
403                         if (bReallyShow)\r
404                         {\r
405                                 this->OnTabChanged(e);\r
406                         }\r
407                 }\r
408                 break;\r
409         }\r
410         case TPI_COMMAND_ADD:\r
411         case TPI_COMMAND_CREATE:\r
412                 // 格納パスを推測。\r
413                 for (size_t i = 0; i < this->files.GetCount(); i++)\r
414                 {\r
415                         if (bReallyShow)\r
416                         {\r
417                                 this->lcFiles->SetItem(i, 1, this->files[i]);\r
418                         }\r
419                 }\r
420                 break;\r
421         }\r
422 }\r