tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ExtractCallbackConsole.cpp (19709B)


      1 // ExtractCallbackConsole.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../Common/IntToString.h"
      6 #include "../../../Common/Wildcard.h"
      7 
      8 #include "../../../Windows/FileDir.h"
      9 #include "../../../Windows/FileFind.h"
     10 #include "../../../Windows/TimeUtils.h"
     11 #include "../../../Windows/ErrorMsg.h"
     12 #include "../../../Windows/PropVariantConv.h"
     13 
     14 #ifndef _7ZIP_ST
     15 #include "../../../Windows/Synchronization.h"
     16 #endif
     17 
     18 #include "../../Common/FilePathAutoRename.h"
     19 
     20 #include "../Common/ExtractingFilePath.h"
     21 
     22 #include "ConsoleClose.h"
     23 #include "ExtractCallbackConsole.h"
     24 #include "UserInputUtils.h"
     25 
     26 using namespace NWindows;
     27 using namespace NFile;
     28 using namespace NDir;
     29 
     30 static HRESULT CheckBreak2()
     31 {
     32  return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
     33 }
     34 
     35 static const char * const kError = "ERROR: ";
     36 
     37 
     38 void CExtractScanConsole::StartScanning()
     39 {
     40  if (NeedPercents())
     41    _percent.Command = "Scan";
     42 }
     43 
     44 HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
     45 {
     46  if (NeedPercents())
     47  {
     48    _percent.Files = st.NumDirs + st.NumFiles;
     49    _percent.Completed = st.GetTotalBytes();
     50    _percent.FileName = fs2us(path);
     51    _percent.Print();
     52  }
     53 
     54  return CheckBreak2();
     55 }
     56 
     57 HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError)
     58 {
     59  ClosePercentsAndFlush();
     60  
     61  if (_se)
     62  {
     63    *_se << endl << kError << NError::MyFormatMessage(systemError) << endl;
     64    _se->NormalizePrint_UString(fs2us(path));
     65    *_se << endl << endl;
     66    _se->Flush();
     67  }
     68  return HRESULT_FROM_WIN32(systemError);
     69 }
     70 
     71 
     72 void Print_UInt64_and_String(AString &s, UInt64 val, const char *name)
     73 {
     74  char temp[32];
     75  ConvertUInt64ToString(val, temp);
     76  s += temp;
     77  s.Add_Space();
     78  s += name;
     79 }
     80 
     81 void PrintSize_bytes_Smart(AString &s, UInt64 val)
     82 {
     83  Print_UInt64_and_String(s, val, "bytes");
     84 
     85  if (val == 0)
     86    return;
     87 
     88  unsigned numBits = 10;
     89  char c = 'K';
     90  char temp[4] = { 'K', 'i', 'B', 0 };
     91       if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; }
     92  else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; }
     93  temp[0] = c;
     94  s += " (";
     95  Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp);
     96  s += ')';
     97 }
     98 
     99 void PrintSize_bytes_Smart_comma(AString &s, UInt64 val)
    100 {
    101  if (val == (UInt64)(Int64)-1)
    102    return;
    103  s += ", ";
    104  PrintSize_bytes_Smart(s, val);
    105 }
    106 
    107 
    108 
    109 void Print_DirItemsStat(AString &s, const CDirItemsStat &st)
    110 {
    111  if (st.NumDirs != 0)
    112  {
    113    Print_UInt64_and_String(s, st.NumDirs, st.NumDirs == 1 ? "folder" : "folders");
    114    s += ", ";
    115  }
    116  Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files");
    117  PrintSize_bytes_Smart_comma(s, st.FilesSize);
    118  if (st.NumAltStreams != 0)
    119  {
    120    s.Add_LF();
    121    Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams");
    122    PrintSize_bytes_Smart_comma(s, st.AltStreamsSize);
    123  }
    124 }
    125 
    126 
    127 void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st)
    128 {
    129  Print_DirItemsStat(s, (CDirItemsStat &)st);
    130  bool needLF = true;
    131  if (st.Anti_NumDirs != 0)
    132  {
    133    if (needLF)
    134      s.Add_LF();
    135    needLF = false;
    136    Print_UInt64_and_String(s, st.Anti_NumDirs, st.Anti_NumDirs == 1 ? "anti-folder" : "anti-folders");
    137  }
    138  if (st.Anti_NumFiles != 0)
    139  {
    140    if (needLF)
    141      s.Add_LF();
    142    else
    143      s += ", ";
    144    needLF = false;
    145    Print_UInt64_and_String(s, st.Anti_NumFiles, st.Anti_NumFiles == 1 ? "anti-file" : "anti-files");
    146  }
    147  if (st.Anti_NumAltStreams != 0)
    148  {
    149    if (needLF)
    150      s.Add_LF();
    151    else
    152      s += ", ";
    153    needLF = false;
    154    Print_UInt64_and_String(s, st.Anti_NumAltStreams, "anti-alternate-streams");
    155  }
    156 }
    157 
    158 
    159 void CExtractScanConsole::PrintStat(const CDirItemsStat &st)
    160 {
    161  if (_so)
    162  {
    163    AString s;
    164    Print_DirItemsStat(s, st);
    165    *_so << s << endl;
    166  }
    167 }
    168 
    169 
    170 
    171 
    172 
    173 
    174 
    175 #ifndef _7ZIP_ST
    176 static NSynchronization::CCriticalSection g_CriticalSection;
    177 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
    178 #else
    179 #define MT_LOCK
    180 #endif
    181 
    182 
    183 static const char * const kTestString    =  "T";
    184 static const char * const kExtractString =  "-";
    185 static const char * const kSkipString    =  ".";
    186 
    187 // static const char * const kCantAutoRename = "can not create file with auto name\n";
    188 // static const char * const kCantRenameFile = "can not rename existing file\n";
    189 // static const char * const kCantDeleteOutputFile = "can not delete output file ";
    190 
    191 static const char * const kMemoryExceptionMessage = "Can't allocate required memory!";
    192 
    193 static const char * const kExtracting = "Extracting archive: ";
    194 static const char * const kTesting = "Testing archive: ";
    195 
    196 static const char * const kEverythingIsOk = "Everything is Ok";
    197 static const char * const kNoFiles = "No files to process";
    198 
    199 static const char * const kUnsupportedMethod = "Unsupported Method";
    200 static const char * const kCrcFailed = "CRC Failed";
    201 static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
    202 static const char * const kDataError = "Data Error";
    203 static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
    204 static const char * const kUnavailableData = "Unavailable data";
    205 static const char * const kUnexpectedEnd = "Unexpected end of data";
    206 static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
    207 static const char * const kIsNotArc = "Is not archive";
    208 static const char * const kHeadersError = "Headers Error";
    209 static const char * const kWrongPassword = "Wrong password";
    210 
    211 static const char * const k_ErrorFlagsMessages[] =
    212 {
    213    "Is not archive"
    214  , "Headers Error"
    215  , "Headers Error in encrypted archive. Wrong password?"
    216  , "Unavailable start of archive"
    217  , "Unconfirmed start of archive"
    218  , "Unexpected end of archive"
    219  , "There are data after the end of archive"
    220  , "Unsupported method"
    221  , "Unsupported feature"
    222  , "Data Error"
    223  , "CRC Error"
    224 };
    225 
    226 STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64 size)
    227 {
    228  MT_LOCK
    229 
    230  if (NeedPercents())
    231  {
    232    _percent.Total = size;
    233    _percent.Print();
    234  }
    235  return CheckBreak2();
    236 }
    237 
    238 STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue)
    239 {
    240  MT_LOCK
    241 
    242  if (NeedPercents())
    243  {
    244    if (completeValue)
    245      _percent.Completed = *completeValue;
    246    _percent.Print();
    247  }
    248  return CheckBreak2();
    249 }
    250 
    251 static const char * const kTab = "  ";
    252 
    253 static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size)
    254 {
    255  *_so << kTab << "Path:     ";
    256  _so->NormalizePrint_wstr(path);
    257  *_so << endl;
    258  if (size && *size != (UInt64)(Int64)-1)
    259  {
    260    AString s;
    261    PrintSize_bytes_Smart(s, *size);
    262    *_so << kTab << "Size:     " << s << endl;
    263  }
    264  if (ft)
    265  {
    266    char temp[64];
    267    if (ConvertUtcFileTimeToString(*ft, temp, kTimestampPrintLevel_SEC))
    268      *_so << kTab << "Modified: " << temp << endl;
    269  }
    270 }
    271 
    272 STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
    273    const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
    274    const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
    275    Int32 *answer)
    276 {
    277  MT_LOCK
    278  
    279  RINOK(CheckBreak2());
    280 
    281  ClosePercentsAndFlush();
    282 
    283  if (_so)
    284  {
    285    *_so << endl << "Would you like to replace the existing file:\n";
    286    PrintFileInfo(_so, existName, existTime, existSize);
    287    *_so << "with the file from archive:\n";
    288    PrintFileInfo(_so, newName, newTime, newSize);
    289  }
    290  
    291  NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(_so);
    292  
    293  switch (overwriteAnswer)
    294  {
    295    case NUserAnswerMode::kQuit:  return E_ABORT;
    296    case NUserAnswerMode::kNo:     *answer = NOverwriteAnswer::kNo; break;
    297    case NUserAnswerMode::kNoAll:  *answer = NOverwriteAnswer::kNoToAll; break;
    298    case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break;
    299    case NUserAnswerMode::kYes:    *answer = NOverwriteAnswer::kYes; break;
    300    case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break;
    301    case NUserAnswerMode::kEof:  return E_ABORT;
    302    case NUserAnswerMode::kError:  return E_FAIL;
    303    default: return E_FAIL;
    304  }
    305  
    306  if (_so)
    307  {
    308    *_so << endl;
    309    if (NeedFlush)
    310      _so->Flush();
    311  }
    312  
    313  return CheckBreak2();
    314 }
    315 
    316 STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 /* isFolder */, Int32 askExtractMode, const UInt64 *position)
    317 {
    318  MT_LOCK
    319  
    320  _currentName = name;
    321  
    322  const char *s;
    323  unsigned requiredLevel = 1;
    324 
    325  switch (askExtractMode)
    326  {
    327    case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break;
    328    case NArchive::NExtract::NAskMode::kTest:    s = kTestString; break;
    329    case NArchive::NExtract::NAskMode::kSkip:    s = kSkipString; requiredLevel = 2; break;
    330    default: s = "???"; requiredLevel = 2;
    331  };
    332 
    333  bool show2 = (LogLevel >= requiredLevel && _so);
    334 
    335  if (show2)
    336  {
    337    ClosePercents_for_so();
    338    
    339    _tempA = s;
    340    if (name)
    341      _tempA.Add_Space();
    342    *_so << _tempA;
    343 
    344    _tempU.Empty();
    345    if (name)
    346    {
    347      _tempU = name;
    348      _so->Normalize_UString(_tempU);
    349    }
    350    _so->PrintUString(_tempU, _tempA);
    351    if (position)
    352      *_so << " <" << *position << ">";
    353    *_so << endl;
    354 
    355    if (NeedFlush)
    356      _so->Flush();
    357  }
    358 
    359  if (NeedPercents())
    360  {
    361    if (PercentsNameLevel >= 1)
    362    {
    363      _percent.FileName.Empty();
    364      _percent.Command.Empty();
    365      if (PercentsNameLevel > 1 || !show2)
    366      {
    367        _percent.Command = s;
    368        if (name)
    369          _percent.FileName = name;
    370      }
    371    }
    372    _percent.Print();
    373  }
    374 
    375  return CheckBreak2();
    376 }
    377 
    378 STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
    379 {
    380  MT_LOCK
    381  
    382  RINOK(CheckBreak2());
    383 
    384  NumFileErrors_in_Current++;
    385  NumFileErrors++;
    386 
    387  ClosePercentsAndFlush();
    388  if (_se)
    389  {
    390    *_se << kError << message << endl;
    391    _se->Flush();
    392  }
    393 
    394  return CheckBreak2();
    395 }
    396 
    397 void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest)
    398 {
    399  dest.Empty();
    400    const char *s = NULL;
    401    
    402    switch (opRes)
    403    {
    404      case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
    405        s = kUnsupportedMethod;
    406        break;
    407      case NArchive::NExtract::NOperationResult::kCRCError:
    408        s = (encrypted ? kCrcFailedEncrypted : kCrcFailed);
    409        break;
    410      case NArchive::NExtract::NOperationResult::kDataError:
    411        s = (encrypted ? kDataErrorEncrypted : kDataError);
    412        break;
    413      case NArchive::NExtract::NOperationResult::kUnavailable:
    414        s = kUnavailableData;
    415        break;
    416      case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
    417        s = kUnexpectedEnd;
    418        break;
    419      case NArchive::NExtract::NOperationResult::kDataAfterEnd:
    420        s = kDataAfterEnd;
    421        break;
    422      case NArchive::NExtract::NOperationResult::kIsNotArc:
    423        s = kIsNotArc;
    424        break;
    425      case NArchive::NExtract::NOperationResult::kHeadersError:
    426        s = kHeadersError;
    427        break;
    428      case NArchive::NExtract::NOperationResult::kWrongPassword:
    429        s = kWrongPassword;
    430        break;
    431    }
    432    
    433    dest += kError;
    434    if (s)
    435      dest += s;
    436    else
    437    {
    438      dest += "Error #";
    439      dest.Add_UInt32(opRes);
    440    }
    441 }
    442 
    443 STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted)
    444 {
    445  MT_LOCK
    446  
    447  if (opRes == NArchive::NExtract::NOperationResult::kOK)
    448  {
    449    if (NeedPercents())
    450    {
    451      _percent.Command.Empty();
    452      _percent.FileName.Empty();
    453      _percent.Files++;
    454    }
    455  }
    456  else
    457  {
    458    NumFileErrors_in_Current++;
    459    NumFileErrors++;
    460    
    461    if (_se)
    462    {
    463      ClosePercentsAndFlush();
    464      
    465      AString s;
    466      SetExtractErrorMessage(opRes, encrypted, s);
    467      
    468      *_se << s;
    469      if (!_currentName.IsEmpty())
    470      {
    471        *_se << " : ";
    472        _se->NormalizePrint_UString(_currentName);
    473      }
    474      *_se << endl;
    475      _se->Flush();
    476    }
    477  }
    478  
    479  return CheckBreak2();
    480 }
    481 
    482 STDMETHODIMP CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)
    483 {
    484  if (opRes != NArchive::NExtract::NOperationResult::kOK)
    485  {
    486    _currentName = name;
    487    return SetOperationResult(opRes, encrypted);
    488  }
    489 
    490  return CheckBreak2();
    491 }
    492 
    493 
    494 
    495 #ifndef _NO_CRYPTO
    496 
    497 HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
    498 {
    499  PasswordIsDefined = true;
    500  Password = password;
    501  return S_OK;
    502 }
    503 
    504 STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
    505 {
    506  COM_TRY_BEGIN
    507  MT_LOCK
    508  return Open_CryptoGetTextPassword(password);
    509  COM_TRY_END
    510 }
    511 
    512 #endif
    513 
    514 HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)
    515 {
    516  RINOK(CheckBreak2());
    517 
    518  NumTryArcs++;
    519  ThereIsError_in_Current = false;
    520  ThereIsWarning_in_Current = false;
    521  NumFileErrors_in_Current = 0;
    522  
    523  ClosePercents_for_so();
    524  if (_so)
    525  {
    526    *_so << endl << (testMode ? kTesting : kExtracting);
    527    _so->NormalizePrint_wstr(name);
    528    *_so << endl;
    529  }
    530 
    531  if (NeedPercents())
    532    _percent.Command = "Open";
    533  return S_OK;
    534 }
    535 
    536 HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
    537 HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
    538 
    539 static AString GetOpenArcErrorMessage(UInt32 errorFlags)
    540 {
    541  AString s;
    542  
    543  for (unsigned i = 0; i < ARRAY_SIZE(k_ErrorFlagsMessages); i++)
    544  {
    545    UInt32 f = (1 << i);
    546    if ((errorFlags & f) == 0)
    547      continue;
    548    const char *m = k_ErrorFlagsMessages[i];
    549    if (!s.IsEmpty())
    550      s.Add_LF();
    551    s += m;
    552    errorFlags &= ~f;
    553  }
    554  
    555  if (errorFlags != 0)
    556  {
    557    char sz[16];
    558    sz[0] = '0';
    559    sz[1] = 'x';
    560    ConvertUInt32ToHex(errorFlags, sz + 2);
    561    if (!s.IsEmpty())
    562      s.Add_LF();
    563    s += sz;
    564  }
    565  
    566  return s;
    567 }
    568 
    569 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags)
    570 {
    571  if (errorFlags == 0)
    572    return;
    573  so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
    574 }
    575 
    576 void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType)
    577 {
    578  s.Add_LF();
    579  s += pre;
    580  s += " as [";
    581  s += arcType;
    582  s += "] archive";
    583 }
    584 
    585 void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc)
    586 {
    587  const CArcErrorInfo &er = arc.ErrorInfo;
    588  
    589  *_so << "WARNING:\n";
    590  _so->NormalizePrint_UString(arc.Path);
    591  UString s;
    592  if (arc.FormatIndex == er.ErrorFormatIndex)
    593  {
    594    s.Add_LF();
    595    s += "The archive is open with offset";
    596  }
    597  else
    598  {
    599    Add_Messsage_Pre_ArcType(s, "Can not open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex));
    600    Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex));
    601  }
    602  
    603  *_so << s << endl << endl;
    604 }
    605        
    606 
    607 HRESULT CExtractCallbackConsole::OpenResult(
    608    const CCodecs *codecs, const CArchiveLink &arcLink,
    609    const wchar_t *name, HRESULT result)
    610 {
    611  ClosePercents();
    612 
    613  if (NeedPercents())
    614  {
    615    _percent.Files = 0;
    616    _percent.Command.Empty();
    617    _percent.FileName.Empty();
    618  }
    619 
    620 
    621  ClosePercentsAndFlush();
    622 
    623  FOR_VECTOR (level, arcLink.Arcs)
    624  {
    625    const CArc &arc = arcLink.Arcs[level];
    626    const CArcErrorInfo &er = arc.ErrorInfo;
    627    
    628    UInt32 errorFlags = er.GetErrorFlags();
    629 
    630    if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
    631    {
    632      if (_se)
    633      {
    634        *_se << endl;
    635        if (level != 0)
    636        {
    637          _se->NormalizePrint_UString(arc.Path);
    638          *_se << endl;
    639        }
    640      }
    641      
    642      if (errorFlags != 0)
    643      {
    644        if (_se)
    645          PrintErrorFlags(*_se, "ERRORS:", errorFlags);
    646        NumOpenArcErrors++;
    647        ThereIsError_in_Current = true;
    648      }
    649      
    650      if (!er.ErrorMessage.IsEmpty())
    651      {
    652        if (_se)
    653          *_se << "ERRORS:" << endl << er.ErrorMessage << endl;
    654        NumOpenArcErrors++;
    655        ThereIsError_in_Current = true;
    656      }
    657      
    658      if (_se)
    659      {
    660        *_se << endl;
    661        _se->Flush();
    662      }
    663    }
    664    
    665    UInt32 warningFlags = er.GetWarningFlags();
    666 
    667    if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
    668    {
    669      if (_so)
    670      {
    671        *_so << endl;
    672        if (level != 0)
    673        {
    674          _so->NormalizePrint_UString(arc.Path);
    675          *_so << endl;
    676        }
    677      }
    678      
    679      if (warningFlags != 0)
    680      {
    681        if (_so)
    682          PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
    683        NumOpenArcWarnings++;
    684        ThereIsWarning_in_Current = true;
    685      }
    686      
    687      if (!er.WarningMessage.IsEmpty())
    688      {
    689        if (_so)
    690          *_so << "WARNINGS:" << endl << er.WarningMessage << endl;
    691        NumOpenArcWarnings++;
    692        ThereIsWarning_in_Current = true;
    693      }
    694      
    695      if (_so)
    696      {
    697        *_so << endl;
    698        if (NeedFlush)
    699          _so->Flush();
    700      }
    701    }
    702 
    703  
    704    if (er.ErrorFormatIndex >= 0)
    705    {
    706      if (_so)
    707      {
    708        Print_ErrorFormatIndex_Warning(_so, codecs, arc);
    709        if (NeedFlush)
    710          _so->Flush();
    711      }
    712      ThereIsWarning_in_Current = true;
    713    }
    714  }
    715      
    716  if (result == S_OK)
    717  {
    718    if (_so)
    719    {
    720      RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink));
    721      *_so << endl;
    722    }
    723  }
    724  else
    725  {
    726    NumCantOpenArcs++;
    727    if (_so)
    728      _so->Flush();
    729    if (_se)
    730    {
    731      *_se << kError;
    732      _se->NormalizePrint_wstr(name);
    733      *_se << endl;
    734      HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
    735      RINOK(res);
    736      if (result == S_FALSE)
    737      {
    738      }
    739      else
    740      {
    741        if (result == E_OUTOFMEMORY)
    742          *_se << "Can't allocate required memory";
    743        else
    744          *_se << NError::MyFormatMessage(result);
    745        *_se << endl;
    746      }
    747      _se->Flush();
    748    }
    749  }
    750  
    751  
    752  return CheckBreak2();
    753 }
    754  
    755 HRESULT CExtractCallbackConsole::ThereAreNoFiles()
    756 {
    757  ClosePercents_for_so();
    758 
    759  if (_so)
    760  {
    761    *_so << endl << kNoFiles << endl;
    762    if (NeedFlush)
    763      _so->Flush();
    764  }
    765  return CheckBreak2();
    766 }
    767 
    768 HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
    769 {
    770  MT_LOCK
    771  
    772  if (NeedPercents())
    773  {
    774    _percent.ClosePrint(true);
    775    _percent.Command.Empty();
    776    _percent.FileName.Empty();
    777  }
    778 
    779  if (_so)
    780    _so->Flush();
    781 
    782  if (result == S_OK)
    783  {
    784    if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current)
    785    {
    786      if (ThereIsWarning_in_Current)
    787        NumArcsWithWarnings++;
    788      else
    789        NumOkArcs++;
    790      if (_so)
    791        *_so << kEverythingIsOk << endl;
    792    }
    793    else
    794    {
    795      NumArcsWithError++;
    796      if (_so)
    797      {
    798        *_so << endl;
    799        if (NumFileErrors_in_Current != 0)
    800          *_so << "Sub items Errors: " << NumFileErrors_in_Current << endl;
    801      }
    802    }
    803    if (_so && NeedFlush)
    804      _so->Flush();
    805  }
    806  else
    807  {
    808    NumArcsWithError++;
    809    if (result == E_ABORT || result == ERROR_DISK_FULL)
    810      return result;
    811    
    812    if (_se)
    813    {
    814      *_se << endl << kError;
    815      if (result == E_OUTOFMEMORY)
    816        *_se << kMemoryExceptionMessage;
    817      else
    818        *_se << NError::MyFormatMessage(result);
    819      *_se << endl;
    820      _se->Flush();
    821    }
    822  }
    823 
    824  return CheckBreak2();
    825 }