⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 extractcallback.cpp

📁 7-Zip 3.11的源码
💻 CPP
字号:
// ExtractCallback.h

#include "StdAfx.h"

#include "ExtractCallback.h"
#include "UserInputUtils.h"

#include "ConsoleClose.h"
#include "Common/StdOutStream.h"
#include "Common/StdInStream.h"
#include "Common/Wildcard.h"
#include "Common/StringConvert.h"

#include "Windows/COM.h"
#include "Windows/FileDir.h"
#include "Windows/FileFind.h"
#include "Windows/Time.h"
#include "Windows/Defs.h"
#include "Windows/PropVariant.h"

#include "Windows/PropVariantConversions.h"

#include "../../Common/FilePathAutoRename.h"

#include "../Common/ExtractingFilePath.h"

using namespace NWindows;
using namespace NFile;
using namespace NDirectory;

static const char *kTestingString    =  "Testing     ";
static const char *kExtractingString =  "Extracting  ";
static const char *kSkippingString   =  "Skipping    ";

static const char *kCantAutoRename = "can not create file with auto name\n";
static const char *kCantRenameFile = "can not rename existing file\n";
static const char *kCantDeleteOutputFile = "can not delete output file ";
void CExtractCallbackImp::Init(IInArchive *archive,
    const UString &directoryPath, 
    const NExtraction::CInfo &extractModeInfo,
    const UStringVector &removePathParts,
    const UString &itemDefaultName,
    const FILETIME &utcLastWriteTimeDefault,
    UINT32 attributesDefault,
    bool passwordIsDefined, 
    const UString &password)
{
  m_PasswordIsDefined = passwordIsDefined;
  m_Password = password;
  m_NumErrors = 0;

  m_ItemDefaultName = itemDefaultName;
  m_UTCLastWriteTimeDefault = utcLastWriteTimeDefault;
  m_AttributesDefault = attributesDefault;
  
  m_RemovePathParts = removePathParts;
  m_ExtractModeInfo = extractModeInfo;
  m_ArchiveHandler = archive;
  m_DirectoryPath = directoryPath;
  NFile::NName::NormalizeDirPathPrefix(m_DirectoryPath);
}

bool CExtractCallbackImp::IsEncrypted(UINT32 index)
{
  NCOM::CPropVariant propVariant;
  if(m_ArchiveHandler->GetProperty(index, kpidEncrypted, &propVariant) != S_OK)
    return false;
  if (propVariant.vt != VT_BOOL)
    return false;
  return VARIANT_BOOLToBool(propVariant.boolVal);
}
  
STDMETHODIMP CExtractCallbackImp::SetTotal(UINT64 size)
{
  return S_OK;
}

STDMETHODIMP CExtractCallbackImp::SetCompleted(const UINT64 *completeValue)
{
  if (NConsoleClose::TestBreakSignal())
    return E_ABORT;
  return S_OK;
}

void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts)
{
  UString fullPath = m_DirectoryPath;
  for(int i = 0; i < dirPathParts.Size(); i++)
  {
    fullPath += dirPathParts[i];
    MyCreateDirectory(fullPath);
    fullPath += (wchar_t)NFile::NName::kDirDelimiter;
  }
}

static UString MakePathNameFromParts(const UStringVector &parts)
{
  UString result;
  for(int i = 0; i < parts.Size(); i++)
  {
    if(i != 0)
      result += wchar_t(NFile::NName::kDirDelimiter);
    result += parts[i];
  }
  return result;
}

STDMETHODIMP CExtractCallbackImp::GetStream(UINT32 index,
    ISequentialOutStream **outStream, INT32 askExtractMode)
{
  *outStream = NULL;
  if (NConsoleClose::TestBreakSignal())
    return E_ABORT;
  m_OutFileStream.Release();
  NCOM::CPropVariant propVariantName;
  RINOK(m_ArchiveHandler->GetProperty(index, kpidPath, &propVariantName));
  UString fullPath;
  if(propVariantName.vt == VT_EMPTY)
    fullPath = m_ItemDefaultName;
  else 
  {
    if(propVariantName.vt != VT_BSTR)
      return E_FAIL;
    fullPath = propVariantName.bstrVal;
  }

  m_FilePath = fullPath;

  UString fullPathCorrect = GetCorrectPath(fullPath);

  if(askExtractMode == NArchive::NExtract::NAskMode::kExtract)
  {
    NCOM::CPropVariant propVariant;
    RINOK(m_ArchiveHandler->GetProperty(index, kpidAttributes, &propVariant));
    if (propVariant.vt == VT_EMPTY)
    {
      m_ProcessedFileInfo.Attributes = m_AttributesDefault;
      m_ProcessedFileInfo.AttributesAreDefined = false;
    }
    else
    {
      if (propVariant.vt != VT_UI4)
        throw "incorrect item";
      m_ProcessedFileInfo.Attributes = propVariant.ulVal;
      m_ProcessedFileInfo.AttributesAreDefined = true;
    }

    RINOK(m_ArchiveHandler->GetProperty(index, kpidIsFolder, &propVariant));
    m_ProcessedFileInfo.IsDirectory = VARIANT_BOOLToBool(propVariant.boolVal);

    bool isAnti = false;
    {
      NCOM::CPropVariant propVariantTemp;
      RINOK(m_ArchiveHandler->GetProperty(index, kpidIsAnti, 
          &propVariantTemp));
      if (propVariantTemp.vt == VT_BOOL)
        isAnti = VARIANT_BOOLToBool(propVariantTemp.boolVal);
    }

    RINOK(m_ArchiveHandler->GetProperty(index, kpidLastWriteTime, &propVariant));
    switch(propVariant.vt)
    {
      case VT_EMPTY:
        m_ProcessedFileInfo.UTCLastWriteTime = m_UTCLastWriteTimeDefault;
        break;
      case VT_FILETIME:
        m_ProcessedFileInfo.UTCLastWriteTime = propVariant.filetime;
        break;
      default:
        return E_FAIL;
    }

    // GetPropertyValue(anItemIDList, kpidSize, &propVariant);
    // UINT64 newFileSize = ConvertPropVariantToUINT64(propVariant);

    UStringVector pathParts; 
    SplitPathToParts(fullPathCorrect, pathParts);
    if(pathParts.IsEmpty())
      return E_FAIL;
    UString processedPath;
    switch(m_ExtractModeInfo.PathMode)
    {
      case NExtraction::NPathMode::kFullPathnames:
      {
        processedPath = fullPathCorrect;
        break;
      }
      case NExtraction::NPathMode::kCurrentPathnames:
      {
        int numRemovePathParts = m_RemovePathParts.Size();
        if(pathParts.Size() <= numRemovePathParts)
          return E_FAIL;
        for(int i = 0; i < numRemovePathParts; i++)
          if(m_RemovePathParts[i].CollateNoCase(pathParts[i]) != 0)
            return E_FAIL;
        pathParts.Delete(0, numRemovePathParts);
        processedPath = MakePathNameFromParts(pathParts);
        break;
      }
      case NExtraction::NPathMode::kNoPathnames:
      {
        processedPath = pathParts.Back(); 
        pathParts.Delete(0, pathParts.Size() - 1); // Test it!!
        break;
      }
    }
    if(!m_ProcessedFileInfo.IsDirectory)
      pathParts.DeleteBack();
    if (!pathParts.IsEmpty())
    {
      if (!isAnti)
        CreateComplexDirectory(pathParts);
    }

    UString fullProcessedPath = m_DirectoryPath + GetCorrectPath(processedPath);

    if(m_ProcessedFileInfo.IsDirectory)
    {
      m_DiskFilePath = fullProcessedPath;

      if (isAnti)
        MyRemoveDirectory(m_DiskFilePath);
      return S_OK;
    }

    NFile::NFind::CFileInfoW fileInfo;
    if(NFile::NFind::FindFile(fullProcessedPath, fileInfo))
    {
      switch(m_ExtractModeInfo.OverwriteMode)
      {
        case NExtraction::NOverwriteMode::kSkipExisting:
          return S_OK;
        case NExtraction::NOverwriteMode::kAskBefore:
        {
          /*
          NOverwriteDialog::CFileInfo oldFileInfo, newFileInfo;
          oldFileInfo.Time = fileInfo.LastWriteTime;
          oldFileInfo.Size = fileInfo.Size;
          oldFileInfo.Name = fullProcessedPath;
          
          newFileInfo.Time = m_ProcessedFileInfo.UTCLastWriteTime;
          newFileInfo.Size = newFileSize;
          newFileInfo.Name = fullPath;

          NOverwriteDialog::NResult::EEnum result = 
              NOverwriteDialog::Execute(oldFileInfo, newFileInfo);
          */

          g_StdOut << "file " << fullProcessedPath << 
              "\nalready exists. Overwrite with " << endl;
          g_StdOut << fullPathCorrect;

          NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit();

          switch(overwriteAnswer)
          {
          case NUserAnswerMode::kQuit:
            return E_ABORT;
          case NUserAnswerMode::kNo:
            return S_OK;
          case NUserAnswerMode::kNoAll:
            m_ExtractModeInfo.OverwriteMode = NExtraction::NOverwriteMode::kSkipExisting;
            return S_OK;
          case NUserAnswerMode::kYesAll:
            m_ExtractModeInfo.OverwriteMode = NExtraction::NOverwriteMode::kWithoutPrompt;
            break;
          case NUserAnswerMode::kYes:
            break;
          case NUserAnswerMode::kAutoRename:
            m_ExtractModeInfo.OverwriteMode = NExtraction::NOverwriteMode::kAutoRename;
            break;
          default:
            throw 20413;
          }
          break;
        }
      }
      if (m_ExtractModeInfo.OverwriteMode == NExtraction::NOverwriteMode::kAutoRename)
      {
        if (!AutoRenamePath(fullProcessedPath))
        {
          g_StdOut << kCantAutoRename;
          g_StdOut << fullProcessedPath;
          return E_ABORT;
        }
      }
      else if (m_ExtractModeInfo.OverwriteMode == NExtraction::NOverwriteMode::kAutoRenameExisting)
      {
        UString existPath = fullProcessedPath;
        if (!AutoRenamePath(existPath))
        {
          g_StdOut << kCantAutoRename;
          g_StdOut << fullProcessedPath;
          return E_ABORT;
        }
        if(!MyMoveFile(fullProcessedPath, existPath))
        {
          g_StdOut << kCantRenameFile;
          return E_ABORT;
        }
      }
      else
        if (!DeleteFileAlways(fullProcessedPath))
        {
          g_StdOut << kCantDeleteOutputFile << endl;
          g_StdOut << fullProcessedPath;
          return E_ABORT;
        }
    }

    if (!isAnti)
    {
      m_OutFileStreamSpec = new COutFileStream;
      CMyComPtr<ISequentialOutStream> outStreamLoc(m_OutFileStreamSpec);
      if (!m_OutFileStreamSpec->Open(fullProcessedPath))
      {
        m_NumErrors++;
        g_StdOut << "Can not open output file " << endl;
        g_StdOut << fullProcessedPath << endl;
        return S_OK;
      }
      m_OutFileStream = outStreamLoc;
      *outStream = outStreamLoc.Detach();
    }
    m_DiskFilePath = fullProcessedPath;
  }
  else
  {
    *outStream = NULL;
  }
  return S_OK;
}

STDMETHODIMP CExtractCallbackImp::PrepareOperation(INT32 askExtractMode)
{
  m_ExtractMode = false;
  switch (askExtractMode)
  {
    case NArchive::NExtract::NAskMode::kExtract:
      m_ExtractMode = true;
      g_StdOut << kExtractingString;
      break;
    case NArchive::NExtract::NAskMode::kTest:
      g_StdOut << kTestingString;
      break;
    case NArchive::NExtract::NAskMode::kSkip:
      g_StdOut << kSkippingString;
      break;
  };
  g_StdOut << m_FilePath;
  return S_OK;
}

STDMETHODIMP CExtractCallbackImp::SetOperationResult(INT32 resultEOperationResult)
{
  switch(resultEOperationResult)
  {
    case NArchive::NExtract::NOperationResult::kOK:
    {
      break;
    }
    default:
    {
      m_NumErrors++;
      switch(resultEOperationResult)
      {
        case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
          g_StdOut << "     Unsupported Method";
          break;
        case NArchive::NExtract::NOperationResult::kCRCError:
          g_StdOut << "     CRC Failed";
          break;
        case NArchive::NExtract::NOperationResult::kDataError:
          g_StdOut << "     Data Error";
          break;
        default:
          g_StdOut << "     Unknown Error";
          // m_OutFileStream.Release();
          // return E_FAIL;
      }
    }
  }
  if(m_OutFileStream != NULL)
    m_OutFileStreamSpec->File.SetLastWriteTime(&m_ProcessedFileInfo.UTCLastWriteTime);
  m_OutFileStream.Release();
  if (m_ExtractMode && m_ProcessedFileInfo.AttributesAreDefined)
    MySetFileAttributes(m_DiskFilePath, m_ProcessedFileInfo.Attributes);
  g_StdOut << endl;
  return S_OK;
}

STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)
{
  if (!m_PasswordIsDefined)
  {
    g_StdOut << "\nEnter password:";
    AString oemPassword = g_StdIn.ScanStringUntilNewLine();
    m_Password = MultiByteToUnicodeString(oemPassword, CP_OEMCP); 
    m_PasswordIsDefined = true;
  }
  CMyComBSTR tempName(m_Password);
  *password = tempName.Detach();
  return S_OK;
}
  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -