OSDN Git Service

19ab0dd26fe24a5fa5104292e5e8c5e37b998f5e
[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->cbSolid           = XRCCTRL(* this, "cbSolid",      wxCheckBox);\r
80         this->cbMMOptimize      = XRCCTRL(* this, "cbMMOptimize", wxCheckBox);\r
81         this->cbCompressHeader  = XRCCTRL(* this, "cbCompressHeader", wxCheckBox);\r
82         this->cbMakeSFX         = XRCCTRL(* this, "cbMakeSFX",    wxCheckBox);\r
83         // "Comment"タブ\r
84         this->tcComment         = XRCCTRL(* this, "tcComment",    wxTextCtrl);\r
85         // "Encryption"タブ\r
86         this->tcPassword        = XRCCTRL(* this, "tcPassword",   wxTextCtrl);\r
87         this->tcKeyfile         = XRCCTRL(* this, "tcKeyfile",    wxTextCtrl);\r
88         this->cbSplitSize       = XRCCTRL(* this, "cbSplitSize",  wxComboBox);\r
89         this->cbUnmask          = XRCCTRL(* this, "cbUnmask",     wxCheckBox);\r
90         this->cbEncryptHeader   = XRCCTRL(* this, "cbEncryptHeader", wxCheckBox);\r
91         this->chEncryptMethod   = XRCCTRL(* this, "chEncryptMethod", wxChoice);\r
92         // "Files"タブ\r
93         this->lcFiles           = XRCCTRL(* this, "lcFiles",      myListCtrl2);\r
94 \r
95         // ListCtrlに列を追加。\r
96         // wxGTKでは直接wxLC_VIRTUALを指定しないと反映されない。\r
97         this->lcFiles->SetSingleStyle(wxLC_VIRTUAL);\r
98         this->lcFiles->InsertColumn(0, _("Input"),  wxLIST_FORMAT_LEFT,  150);\r
99         this->lcFiles->InsertColumn(1, _("Output"), wxLIST_FORMAT_LEFT,  290);\r
100         this->lcFiles->asInput = & this->files;\r
101         this->lcFiles->atDangerItem.SetTextColour(* wxRED);\r
102 \r
103         ::wxXmlResource::Get()->Unload(L_DIR_S_XRC wxT("dlg_make.xrc"));\r
104 \r
105         // 事前準備。\r
106         MainFrame * frm_main = (MainFrame *) this->GetParent();\r
107         wxString szArcPath = frm_main->fnArchive.GetPath();\r
108 \r
109         // パス履歴読み込み。\r
110         for (size_t i = 0; i < frm_main->conf.GetHistoryCount(CONF_HISTORY_PATH); i++)\r
111         {\r
112                 wxString sz = frm_main->conf.ReadHistory(CONF_HISTORY_PATH, i);\r
113                 if (sz.IsEmpty())\r
114                 {\r
115                         continue;\r
116                 }\r
117 \r
118                 this->cbDir->Append(sz);\r
119         }\r
120         // 書庫名履歴読み込み。\r
121         for (size_t i = 0; i < frm_main->conf.GetHistoryCount(CONF_HISTORY_NAME); i++)\r
122         {\r
123                 wxString sz = frm_main->conf.ReadHistory(CONF_HISTORY_NAME, i);\r
124                 if (sz.IsEmpty())\r
125                 {\r
126                         continue;\r
127                 }\r
128 \r
129                 this->cbFileName->Append(sz);\r
130         }\r
131 \r
132         // パスを設定。\r
133         this->cbDir->SetValue(szArcPath);\r
134 \r
135         // コマンド別の処理。\r
136         switch (this->uCommand)\r
137         {\r
138         case TPI_COMMAND_EXTRACT:\r
139                 // 初期値を設定。\r
140                 this->SetTitle(_("Extract"));\r
141                 this->tcComment->SetValue(frm_main->aiArchive.szComment);\r
142 \r
143                 // コントロールを無効化。\r
144                 this->scLevel->Disable();\r
145                 this->scRR->Disable();\r
146                 this->cbSolid->Disable();\r
147                 this->cbMMOptimize->Disable();\r
148                 this->tcComment->SetEditable(false);\r
149                 this->cbEncryptHeader->Disable();\r
150                 this->chEncryptMethod->Disable();\r
151         case TPI_COMMAND_ADD:\r
152                 // コントロールを無効化(展開時も)。\r
153                 this->cbFileName->Disable();\r
154                 this->chType->Disable();\r
155                 this->chDirMake->Enable();\r
156                 this->cbSplitSize->Disable();\r
157                 this->cbCompressHeader->Disable();\r
158                 this->cbMakeSFX->Disable();\r
159 \r
160                 // 書庫名を設定。\r
161                 this->cbFileName->SetValue(frm_main->fnArchive.GetFullName());\r
162 \r
163                 // 書庫形式欄を設定。\r
164                 this->afInfo.Add(frm_main->aiArchive.fiInfo);\r
165                 this->chType->Append(frm_main->aiArchive.fiInfo.szTypeName);\r
166                 this->chType->SetSelection(0);\r
167                 {\r
168                         wxCommandEvent e;\r
169                         e.SetInt(0);\r
170                         this->OnChoice(e);\r
171                 }\r
172 \r
173                 if (this->uCommand != TPI_COMMAND_ADD)\r
174                 {\r
175                         break;\r
176                 }\r
177                 this->SetTitle(_("Add"));\r
178 \r
179                 // コントロールを無効化(追加時のみ)。\r
180                 this->cbDir->Disable();\r
181                 this->chDirMake->Disable();\r
182                 XRCCTRL(* this, "btnDefault", wxButton)->Disable();\r
183                 XRCCTRL(* this, "btnDesktop", wxButton)->Disable();\r
184                 XRCCTRL(* this, "btnCurrent", wxButton)->Disable();\r
185                 XRCCTRL(* this, "btnBrowse",  wxButton)->Disable();\r
186                 break;\r
187         case TPI_COMMAND_CREATE:\r
188                 this->SetTitle(_("Create"));\r
189 \r
190                 // 書庫名を設定。初期化の都合上.を付加しておく。\r
191                 this->cbFileName->SetValue(frm_main->fnArchive.GetName() + wxT('.'));\r
192 \r
193                 // ライブラリを検索。\r
194                 TPIHandle tpi;\r
195                 wxDir fs(L_DIR_B_LIB);\r
196                 wxString szTPIName;\r
197                 if (fs.GetFirst(& szTPIName,wxT("*" TPI_EXT)))\r
198                 {\r
199                         do\r
200                         {\r
201                                 // ロード。\r
202                                 wxString szLibName = L_DIR_B_LIB + szTPIName;\r
203                                 if (tpi.InitLibrary(szLibName, wxEmptyString))\r
204                                 {\r
205                                         // 対応する形式名を取得。\r
206                                         TPI_FORMATINFO fiInfo;\r
207                                         if (tpi.GetFormatInformation(& fiInfo, true))\r
208                                         {\r
209                                                 do\r
210                                                 {\r
211                                                         if (fiInfo.eSupportedCommand & TPI_COMMAND_CREATE && (this->lcFiles->asInput->GetCount() == 1 || fiInfo.fArchive))\r
212                                                         {\r
213                                                                 fiInfo.szTPIName = szLibName;\r
214                                                                 this->afInfo.Add(fiInfo);\r
215                                                                 this->chType->Append(fiInfo.szTypeName);\r
216                                                         }\r
217                                                 }\r
218                                                 while (tpi.GetFormatInformation(& fiInfo));\r
219                                         }\r
220                                         tpi.FreeLibrary();\r
221                                 }\r
222                         }\r
223                         while (fs.GetNext(& szTPIName));\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         // 展開/格納先を予測。ただしDTVスキャンに時間がかかる場合はスキップ可能。\r
242         if (this->lcFiles->asInput->GetCount() < 3000 ||\r
243                 ::AskDlg(\r
244                         this->uCommand == TPI_COMMAND_EXTRACT ?\r
245                                 _("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?") :\r
246                                 _("The files you want to store are too many, so it takes long to check Directory Traversal Vulnerability(DTV) problem. If you are sure the path of the files are no problem, you can skip this scanning process. Do you want to scan for DTV problem?"),\r
247                         this\r
248                 ) == wxYES)\r
249         {\r
250                 wxNotebookEvent e;\r
251                 e.SetSelection(4);\r
252                 this->OnTabChanged(e);\r
253         }\r
254 \r
255         this->Raise();\r
256 }\r
257 \r
258 void MakeDialog::OnBtnDefault(wxCommandEvent&)\r
259 {\r
260         this->cbDir->SetValue(((MainFrame *) this->GetParent())->conf.ReadId(CONF_DEFAULT_PATH, (wxString) wxEmptyString));\r
261 }\r
262 \r
263 void MakeDialog::OnBtnDesktop(wxCommandEvent&)\r
264 {\r
265         wxFileName fn(wxFileName::GetHomeDir(), wxT("Desktop"));\r
266         this->cbDir->SetValue(fn.GetFullPath());\r
267 }\r
268 \r
269 void MakeDialog::OnBtnCurrent(wxCommandEvent&)\r
270 {\r
271         this->cbDir->SetValue(((MainFrame *) this->GetParent())->fnArchive.GetPath());\r
272 }\r
273 \r
274 void MakeDialog::OnBtnBrowse(wxCommandEvent&)\r
275 {\r
276         wxDirDialog dd(this);\r
277         dd.SetPath(this->cbDir->GetValue());\r
278         if (dd.ShowModal() == wxID_OK)\r
279         {\r
280                 this->cbDir->SetValue(dd.GetPath());\r
281         }\r
282 }\r
283 \r
284 void MakeDialog::OnBtnBrowseKF(wxCommandEvent&)\r
285 {\r
286         wxFileDialog fd(this);\r
287         fd.SetWindowStyleFlag(wxFD_OPEN | wxFD_FILE_MUST_EXIST);\r
288         if (fd.ShowModal() == wxID_OK)\r
289         {\r
290                 this->tcKeyfile->SetValue(fd.GetPath());\r
291         }\r
292 }\r
293 \r
294 void MakeDialog::OnBtnOK(wxCommandEvent&)\r
295 {\r
296         // 履歴書き込み。\r
297         if (this->uCommand != TPI_COMMAND_ADD)\r
298         {\r
299                 MainFrame * frm_main = (MainFrame *) this->GetParent();\r
300                 wxFileName fnCurrent(this->cbDir->GetValue(), this->uCommand == TPI_COMMAND_CREATE ? this->cbFileName->GetValue() : (wxString) wxEmptyString);\r
301                 frm_main->conf.WriteHistory(CONF_HISTORY_FULL, fnCurrent.GetFullPath());\r
302                 frm_main->conf.WriteHistory(CONF_HISTORY_PATH, fnCurrent.GetPath());\r
303                 frm_main->conf.WriteHistory(CONF_HISTORY_NAME, fnCurrent.GetFullName());\r
304         }\r
305         this->EndModal(wxID_OK);\r
306 }\r
307 \r
308 void MakeDialog::OnBtnCancel(wxCommandEvent&)\r
309 {\r
310         this->EndModal(wxID_CANCEL);\r
311 }\r
312 \r
313 void MakeDialog::OnChoice(wxCommandEvent& e)\r
314 {\r
315         TPI_FORMATINFO * fiInfo = & this->afInfo[e.GetInt()];\r
316         // 形式が各種設定に対応しているか。\r
317         // 作成時/追加時/展開時設定。\r
318         this->tcPassword->Enable(fiInfo->fEncryptPassword);\r
319         this->tcKeyfile->Enable(fiInfo->fEncryptKeyFile);\r
320         this->cbUnmask->Enable(fiInfo->fEncryptPassword);\r
321         this->chEncryptMethod->Enable(fiInfo->fEncryptPassword || fiInfo->fEncryptKeyFile);\r
322         XRCCTRL(* this, "btnBrowseKF", wxButton)->Enable(fiInfo->fEncryptKeyFile);\r
323         if (this->uCommand == TPI_COMMAND_EXTRACT)\r
324         {\r
325                 return;\r
326         }\r
327 \r
328         // 作成時/追加時設定。\r
329         this->scLevel->SetRange(fiInfo->nCompressLevelMin, fiInfo->nCompressLevelMax);\r
330         this->scLevel->SetValue(fiInfo->nCompressLevelMax);\r
331         this->scLevel->Enable(fiInfo->nCompressLevelMin != fiInfo->nCompressLevelMax);\r
332         this->scRR->SetRange(fiInfo->nRecoveryRecordMin, fiInfo->nRecoveryRecordMax);\r
333         this->scRR->SetValue(fiInfo->nRecoveryRecordMin);\r
334         this->scRR->Enable(fiInfo->nRecoveryRecordMin != fiInfo->nRecoveryRecordMax);\r
335         this->cbEncryptHeader->Enable(fiInfo->fEncryptHeader);\r
336         this->cbCompressHeader->Enable(fiInfo->fCompressHeader);\r
337         this->cbSolid->Enable(fiInfo->fSolid);\r
338         this->cbMMOptimize->Enable(fiInfo->fMMOptimize);\r
339         this->tcComment->Enable(fiInfo->fComment);\r
340         if (this->uCommand == TPI_COMMAND_ADD)\r
341         {\r
342                 return;\r
343         }\r
344 \r
345         // 作成時設定。\r
346         this->cbSplitSize->Enable(fiInfo->fMultiVolume);\r
347         this->cbMakeSFX->Enable(fiInfo->fSFX);\r
348 \r
349         wxFileName fn(this->cbFileName->GetValue());\r
350         fn.SetExt(this->cbMakeSFX->IsEnabled() && this->cbMakeSFX->IsChecked() ? EXE_EXT : fiInfo->szSuffix.BeforeFirst(wxT(';')));\r
351         this->cbFileName->SetValue(fn.GetFullName());\r
352 }\r
353 \r
354 void MakeDialog::OnCbUnmask(wxCommandEvent&)\r
355 {\r
356         this->tcPassword->SetWindowStyle(this->tcPassword->GetWindowStyle() & (this->cbUnmask->IsChecked() ? ~ wxTE_PASSWORD : wxTE_PASSWORD));\r
357         this->tcPassword->Refresh();\r
358 }\r
359 \r
360 void MakeDialog::OnCbMakeSFX(wxCommandEvent&)\r
361 {\r
362         wxFileName fn(this->cbFileName->GetValue());\r
363         fn.SetExt(this->cbMakeSFX->IsChecked() ? EXE_EXT : this->afInfo[this->chType->GetSelection()].szSuffix.BeforeFirst(wxT(';')));\r
364         this->cbFileName->SetValue(fn.GetFullName());\r
365 }\r
366 \r
367 void MakeDialog::OnTabChanged(wxNotebookEvent& e)\r
368 {\r
369         // "Files"タブのときは処理。\r
370         if (e.GetSelection() != 4)\r
371         {\r
372                 return;\r
373         }\r
374         this->lcFiles->DeleteAllItems();\r
375         this->lcFiles->asOutput.Clear();\r
376         this->lcFiles->apItem.Clear();\r
377 \r
378         bool fDTVWarning = false;\r
379         switch (this->uCommand)\r
380         {\r
381         case TPI_COMMAND_EXTRACT:\r
382         {\r
383                 // ファイルの出力先を推測。\r
384                 wxString szOutputRootDir = WillMakeDirByArcName((MainFrame *) this->GetParent(), this) ? MakeDirPath(wxFileName::DirName(this->cbDir->GetValue()), wxFileName(this->cbFileName->GetValue()).GetName(), false).GetPath() : this->cbDir->GetValue();\r
385 \r
386                 // 各ファイルにパスを付加。\r
387                 for (size_t i = 0; i < this->lcFiles->asInput->GetCount(); i++)\r
388                 {\r
389                         wxString szOutputFile = szOutputRootDir + wxFileName::GetPathSeparator();\r
390                         wxFileName fnStored(this->lcFiles->asInput->Item(i));\r
391                         if (! this->cbIgnorePath->IsChecked())\r
392                         {\r
393                                 szOutputFile += fnStored.GetPathWithSep();\r
394                         }\r
395                         wxFileName fnOutput(szOutputFile + fnStored.GetFullName());\r
396                         if (! fnOutput.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE | wxPATH_NORM_LONG) || ! fnOutput.GetFullPath().StartsWith(szOutputRootDir))\r
397                         {\r
398                                 fDTVWarning = true;\r
399                                 this->lcFiles->apItem.Add(& this->lcFiles->atDangerItem);\r
400                         }\r
401                         else\r
402                         {\r
403                                 this->lcFiles->apItem.Add(NULL);\r
404                         }\r
405                         this->lcFiles->asOutput.Add(fnOutput.GetFullPath());\r
406                 }\r
407                 break;\r
408         }\r
409         case TPI_COMMAND_ADD:\r
410         case TPI_COMMAND_CREATE:\r
411                 // 格納パスを推測。\r
412                 for (size_t i = 0; i < this->lcFiles->asInput->GetCount(); i++)\r
413                 {\r
414                         wxFileName fnStored(this->lcFiles->asInput->Item(i));\r
415                         this->lcFiles->asOutput.Add(this->cbIgnorePath->IsChecked() ? fnStored.GetFullName() : fnStored.GetFullPath());\r
416                         fnStored = wxFileName(this->lcFiles->asOutput.Item(i));\r
417                         if (fnStored.GetPathWithSep(wxPATH_UNIX).Find(wxT("../")) != wxNOT_FOUND)\r
418                         {\r
419                                 fDTVWarning = true;\r
420                                 this->lcFiles->apItem.Add(& this->lcFiles->atDangerItem);\r
421                         }\r
422                         else\r
423                         {\r
424                                 this->lcFiles->apItem.Add(NULL);\r
425                         }\r
426                 }\r
427                 break;\r
428         }\r
429 \r
430         // DTV検査で異常があれば警告。\r
431         if (fDTVWarning)\r
432         {\r
433                 wxString sz;\r
434                 sz.Printf(\r
435                         _("This archive may have Directory Traversal Vulnerability(DTV) problem, %s It is strongly recommended to ignore file path. Would you like to do so?"),\r
436                         (this->uCommand == TPI_COMMAND_EXTRACT ?\r
437                                 _("and some danger files may be extracted to the unexpected system directory!") :\r
438                                 _("and some danger files may be stored!")\r
439                         )\r
440                 );\r
441                 if (::AskDlg(sz, this) == wxYES)\r
442                 {\r
443                         this->cbIgnorePath->SetValue(true);\r
444                         this->OnTabChanged(e);\r
445                 }\r
446         }\r
447 \r
448         // リストビューに表示。\r
449         this->lcFiles->SetItemCount(this->lcFiles->asInput->GetCount());\r
450 }\r
451 \r
452 //******************************************************************************\r
453 // myListCtrl2\r
454 //******************************************************************************\r
455 \r
456 IMPLEMENT_DYNAMIC_CLASS(myListCtrl2, wxListView)\r
457 \r
458 //******************************************************************************\r
459 // Event handler.\r
460 //******************************************************************************\r
461 wxString myListCtrl2::OnGetItemText(long i, long column) const\r
462 {\r
463         // リストビューに項目を追加。\r
464         switch (column)\r
465         {\r
466         case 0:\r
467                 return this->asInput->Item(i);\r
468         case 1:\r
469                 return this->asOutput[i];\r
470         default:\r
471                 return wxEmptyString;\r
472         }\r
473 }\r
474 \r
475 wxListItemAttr * myListCtrl2::OnGetItemAttr(long i) const\r
476 {\r
477         return (wxListItemAttr *) this->apItem[i];\r
478 }\r