1// ExtractCallbackConsole.h
2
3#include "StdAfx.h"
4
5#include "ExtractCallbackConsole.h"
6#include "UserInputUtils.h"
7#include "ConsoleClose.h"
8
9#include "Common/Wildcard.h"
10
11#include "Windows/FileDir.h"
12#include "Windows/FileFind.h"
13#include "Windows/Time.h"
14#include "Windows/Defs.h"
15#include "Windows/PropVariant.h"
16#include "Windows/Error.h"
17#include "Windows/PropVariantConversions.h"
18
19#include "../../Common/FilePathAutoRename.h"
20
21#include "../Common/ExtractingFilePath.h"
22
23using namespace NWindows;
24using namespace NFile;
25using namespace NDirectory;
26
27static const char *kTestString    =  "Testing     ";
28static const char *kExtractString =  "Extracting  ";
29static const char *kSkipString   =  "Skipping    ";
30
31// static const char *kCantAutoRename = "can not create file with auto name\n";
32// static const char *kCantRenameFile = "can not rename existing file\n";
33// static const char *kCantDeleteOutputFile = "can not delete output file ";
34static const char *kError = "ERROR: ";
35static const char *kMemoryExceptionMessage = "Can't allocate required memory!";
36
37static const char *kProcessing = "Processing archive: ";
38static const char *kEverythingIsOk = "Everything is Ok";
39static const char *kNoFiles = "No files to process";
40
41static const char *kUnsupportedMethod = "Unsupported Method";
42static const char *kCrcFailed = "CRC Failed";
43static const char *kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
44static const char *kDataError = "Data Error";
45static const char *kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
46static const char *kUnknownError = "Unknown Error";
47
48STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64)
49{
50  if (NConsoleClose::TestBreakSignal())
51    return E_ABORT;
52  return S_OK;
53}
54
55STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *)
56{
57  if (NConsoleClose::TestBreakSignal())
58    return E_ABORT;
59  return S_OK;
60}
61
62STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
63    const wchar_t *existName, const FILETIME *, const UInt64 *,
64    const wchar_t *newName, const FILETIME *, const UInt64 *,
65    Int32 *answer)
66{
67  (*OutStream) << "file " << existName <<
68    "\nalready exists. Overwrite with " << endl;
69  (*OutStream) << newName;
70
71  NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(OutStream);
72
73  switch(overwriteAnswer)
74  {
75    case NUserAnswerMode::kQuit:  return E_ABORT;
76    case NUserAnswerMode::kNo:     *answer = NOverwriteAnswer::kNo; break;
77    case NUserAnswerMode::kNoAll:  *answer = NOverwriteAnswer::kNoToAll; break;
78    case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break;
79    case NUserAnswerMode::kYes:    *answer = NOverwriteAnswer::kYes; break;
80    case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break;
81    default: return E_FAIL;
82  }
83  return S_OK;
84}
85
86STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, bool /* isFolder */, Int32 askExtractMode, const UInt64 *position)
87{
88  switch (askExtractMode)
89  {
90    case NArchive::NExtract::NAskMode::kExtract: (*OutStream) << kExtractString; break;
91    case NArchive::NExtract::NAskMode::kTest:    (*OutStream) << kTestString; break;
92    case NArchive::NExtract::NAskMode::kSkip:    (*OutStream) << kSkipString; break;
93  };
94  (*OutStream) << name;
95  if (position != 0)
96    (*OutStream) << " <" << *position << ">";
97  return S_OK;
98}
99
100STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
101{
102  (*OutStream) << message << endl;
103  NumFileErrorsInCurrentArchive++;
104  NumFileErrors++;
105  return S_OK;
106}
107
108STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 operationResult, bool encrypted)
109{
110  switch(operationResult)
111  {
112    case NArchive::NExtract::NOperationResult::kOK:
113      break;
114    default:
115    {
116      NumFileErrorsInCurrentArchive++;
117      NumFileErrors++;
118      (*OutStream) << "     ";
119      switch(operationResult)
120      {
121        case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
122          (*OutStream) << kUnsupportedMethod;
123          break;
124        case NArchive::NExtract::NOperationResult::kCRCError:
125          (*OutStream) << (encrypted ? kCrcFailedEncrypted: kCrcFailed);
126          break;
127        case NArchive::NExtract::NOperationResult::kDataError:
128          (*OutStream) << (encrypted ? kDataErrorEncrypted : kDataError);
129          break;
130        default:
131          (*OutStream) << kUnknownError;
132      }
133    }
134  }
135  (*OutStream) << endl;
136  return S_OK;
137}
138
139#ifndef _NO_CRYPTO
140
141HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
142{
143  PasswordIsDefined = true;
144  Password = password;
145  return S_OK;
146}
147
148STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
149{
150  if (!PasswordIsDefined)
151  {
152    Password = GetPassword(OutStream);
153    PasswordIsDefined = true;
154  }
155  return StringToBstr(Password, password);
156}
157
158#endif
159
160HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name)
161{
162  NumArchives++;
163  NumFileErrorsInCurrentArchive = 0;
164  (*OutStream) << endl << kProcessing << name << endl;
165  return S_OK;
166}
167
168HRESULT CExtractCallbackConsole::OpenResult(const wchar_t * /* name */, HRESULT result, bool encrypted)
169{
170  (*OutStream) << endl;
171  if (result != S_OK)
172  {
173    (*OutStream) << "Error: ";
174    if (result == S_FALSE)
175    {
176      (*OutStream) << (encrypted ?
177        "Can not open encrypted archive. Wrong password?" :
178        "Can not open file as archive");
179    }
180    else
181    {
182      if (result == E_OUTOFMEMORY)
183        (*OutStream) << "Can't allocate required memory";
184      else
185        (*OutStream) << NError::MyFormatMessage(result);
186    }
187    (*OutStream) << endl;
188    NumArchiveErrors++;
189  }
190  return S_OK;
191}
192
193HRESULT CExtractCallbackConsole::ThereAreNoFiles()
194{
195  (*OutStream) << endl << kNoFiles << endl;
196  return S_OK;
197}
198
199HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
200{
201  if (result == S_OK)
202  {
203    (*OutStream) << endl;
204    if (NumFileErrorsInCurrentArchive == 0)
205      (*OutStream) << kEverythingIsOk << endl;
206    else
207    {
208      NumArchiveErrors++;
209      (*OutStream) << "Sub items Errors: " << NumFileErrorsInCurrentArchive << endl;
210    }
211  }
212  if (result == S_OK)
213    return result;
214  NumArchiveErrors++;
215  if (result == E_ABORT || result == ERROR_DISK_FULL)
216    return result;
217  (*OutStream) << endl << kError;
218  if (result == E_OUTOFMEMORY)
219    (*OutStream) << kMemoryExceptionMessage;
220  else
221  {
222    UString message;
223    NError::MyFormatMessage(result, message);
224    (*OutStream) << message;
225  }
226  (*OutStream) << endl;
227  return S_OK;
228}
229