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

📄 update.cpp

📁 7z一个高压缩比的压缩程序源代码,重要的是里面的算法值得学习
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    outStream = volStreamSpec;
    volStreamSpec->Sizes = volumesSizes;
    volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
    volStreamSpec->TempFiles = &tempFiles;
    volStreamSpec->Init();

    /*
    updateCallbackSpec->VolumesSizes = volumesSizes;
    updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
    if (!archivePath.VolExtension.IsEmpty())
      updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
    */
  }

  RINOK(SetProperties(outArchive, compressionMethod.Properties));

  if (sfxMode)
  {
    CInFileStream *sfxStreamSpec = new CInFileStream;
    CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
    if (!sfxStreamSpec->Open(sfxModule))
    {
      errorInfo.SystemError = ::GetLastError();
      errorInfo.Message = L"Can't open sfx module";
      errorInfo.FileName = sfxModule;
      return E_FAIL;
    }

    CMyComPtr<ISequentialOutStream> sfxOutStream;
    COutFileStream *outStreamSpec = NULL;
    if (volumesSizes.Size() == 0)
      sfxOutStream = outStream;
    else
    {
      outStreamSpec = new COutFileStream;
      sfxOutStream = outStreamSpec;
      UString realPath = archivePath.GetFinalPath();
      if (!outStreamSpec->Create(realPath, false))
      {
        errorInfo.SystemError = ::GetLastError();
        errorInfo.FileName = realPath;
        errorInfo.Message = L"Can not open file";
        return E_FAIL;
      }
    }
    RINOK(CopyBlock(sfxStream, sfxOutStream));
    if (outStreamSpec)
    {
      RINOK(outStreamSpec->Close());
    }
  }

  HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback);
  callback->Finilize();
  RINOK(result);
  if (outStreamSpec)
    result = outStreamSpec->Close();
  else if (volStreamSpec)
    result = volStreamSpec->Close();
  return result;
}

HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
    IInArchive *archive,
    const UString &defaultItemName,
    const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
    CObjectVector<CArcItem> &arcItems)
{
  arcItems.Clear();
  UInt32 numItems;
  RINOK(archive->GetNumberOfItems(&numItems));
  arcItems.Reserve(numItems);
  for (UInt32 i = 0; i < numItems; i++)
  {
    CArcItem ai;

    RINOK(GetArchiveItemPath(archive, i, ai.Name));
    // check it: defaultItemName !!!
    if (ai.Name.IsEmpty())
      ai.Name = defaultItemName;
    RINOK(IsArchiveItemFolder(archive, i, ai.IsDir));
    ai.Censored = censor.CheckPath(ai.Name, !ai.IsDir);
    RINOK(GetArchiveItemFileTime(archive, i, archiveFileInfo.MTime, ai.MTime));

    {
      CPropVariant prop;
      RINOK(archive->GetProperty(i, kpidSize, &prop));
      ai.SizeDefined = (prop.vt != VT_EMPTY);
      if (ai.SizeDefined)
        ai.Size = ConvertPropVariantToUInt64(prop);
    }

    {
      CPropVariant prop;
      RINOK(archive->GetProperty(i, kpidTimeType, &prop));
      if (prop.vt == VT_UI4)
      {
        ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal;
        switch(ai.TimeType)
        {
          case NFileTimeType::kWindows:
          case NFileTimeType::kUnix:
          case NFileTimeType::kDOS:
            break;
          default:
            return E_FAIL;
        }
      }
    }

    ai.IndexInServer = i;
    arcItems.Add(ai);
  }
  return S_OK;
}


static HRESULT UpdateWithItemLists(
    CCodecs *codecs,
    CUpdateOptions &options,
    IInArchive *archive,
    const CObjectVector<CArcItem> &arcItems,
    CDirItems &dirItems,
    CTempFiles &tempFiles,
    CUpdateErrorInfo &errorInfo,
    IUpdateCallbackUI2 *callback)
{
  for(int i = 0; i < options.Commands.Size(); i++)
  {
    CUpdateArchiveCommand &command = options.Commands[i];
    if (options.StdOutMode)
    {
      RINOK(callback->StartArchive(0, archive != 0));
    }
    else
    {
      RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(),
          i == 0 && options.UpdateArchiveItself && archive != 0));
    }

    RINOK(Compress(
        codecs,
        command.ActionSet, archive,
        options.MethodMode,
        command.ArchivePath,
        arcItems,
        options.OpenShareForWrite,
        options.StdInMode,
        /* options.StdInFileName, */
        options.StdOutMode,
        dirItems,
        options.SfxMode, options.SfxModule,
        options.VolumesSizes,
        tempFiles,
        errorInfo, callback));

    RINOK(callback->FinishArchive());
  }
  return S_OK;
}

#ifdef _WIN32
class CCurrentDirRestorer
{
  UString m_CurrentDirectory;
public:
  CCurrentDirRestorer()
    { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); }
  ~CCurrentDirRestorer()
    { RestoreDirectory();}
  bool RestoreDirectory()
    { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(m_CurrentDirectory)); }
};
#endif

struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
{
  IUpdateCallbackUI2 *Callback;
  HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path)
  {
    return Callback->ScanProgress(numFolders, numFiles, path);
  }
};

#ifdef _WIN32
typedef ULONG (FAR PASCAL MY_MAPISENDDOCUMENTS)(
  ULONG_PTR ulUIParam,
  LPSTR lpszDelimChar,
  LPSTR lpszFilePaths,
  LPSTR lpszFileNames,
  ULONG ulReserved
);
typedef MY_MAPISENDDOCUMENTS FAR *MY_LPMAPISENDDOCUMENTS;
#endif

HRESULT UpdateArchive(
    CCodecs *codecs,
    const NWildcard::CCensor &censor,
    CUpdateOptions &options,
    CUpdateErrorInfo &errorInfo,
    IOpenCallbackUI *openCallback,
    IUpdateCallbackUI2 *callback)
{
  if (options.StdOutMode && options.EMailMode)
    return E_FAIL;

  if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
    return E_NOTIMPL;

  if (options.SfxMode)
  {
    CProperty property;
    property.Name = L"rsfx";
    property.Value = L"on";
    options.MethodMode.Properties.Add(property);
    if (options.SfxModule.IsEmpty())
    {
      errorInfo.Message = L"sfx file is not specified";
      return E_FAIL;
    }
    UString name = options.SfxModule;
    if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
    {
      errorInfo.Message = L"can't find specified sfx module";
      return E_FAIL;
    }
  }

  const UString archiveName = options.ArchivePath.GetFinalPath();

  UString defaultItemName;
  NFind::CFileInfoW archiveFileInfo;

  CArchiveLink archiveLink;
  IInArchive *archive = 0;
  if (NFind::FindFile(archiveName, archiveFileInfo))
  {
    if (archiveFileInfo.IsDir())
      throw "there is no such archive";
    if (options.VolumesSizes.Size() > 0)
      return E_NOTIMPL;
    CIntVector formatIndices;
    if (options.MethodMode.FormatIndex >= 0)
      formatIndices.Add(options.MethodMode.FormatIndex);
    HRESULT result = MyOpenArchive(codecs, formatIndices, archiveName, archiveLink, openCallback);
    if (result == E_ABORT)
      return result;
    RINOK(callback->OpenResult(archiveName, result));
    RINOK(result);
    if (archiveLink.VolumePaths.Size() > 1)
    {
      errorInfo.SystemError = (DWORD)E_NOTIMPL;
      errorInfo.Message = L"Updating for multivolume archives is not implemented";
      return E_NOTIMPL;
    }
    archive = archiveLink.GetArchive();
    defaultItemName = archiveLink.GetDefaultItemName();
  }
  else
  {
    /*
    if (archiveType.IsEmpty())
      throw "type of archive is not specified";
    */
  }

  CDirItems dirItems;
  if (options.StdInMode)
  {
    CDirItem di;
    di.Name = options.StdInFileName;
    di.Size = (UInt64)(Int64)-1;
    di.Attrib = 0;
    NTime::GetCurUtcFileTime(di.MTime);
    di.CTime = di.ATime = di.MTime;
    dirItems.Items.Add(di);
  }
  else
  {
    bool needScanning = false;
    for(int i = 0; i < options.Commands.Size(); i++)
      if (options.Commands[i].ActionSet.NeedScanning())
        needScanning = true;
    if (needScanning)
    {
      CEnumDirItemUpdateCallback enumCallback;
      enumCallback.Callback = callback;
      RINOK(callback->StartScanning());
      UStringVector errorPaths;
      CRecordVector<DWORD> errorCodes;
      HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes);
      for (int i = 0; i < errorPaths.Size(); i++)
      {
        RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i]));
      }
      if (res != S_OK)
      {
        if (res != E_ABORT)
          errorInfo.Message = L"Scanning error";
        // errorInfo.FileName = errorPath;
        return res;
      }
      RINOK(callback->FinishScanning());
    }
  }

  UString tempDirPrefix;
  bool usesTempDir = false;
  
  #ifdef _WIN32
  NDirectory::CTempDirectoryW tempDirectory;
  if (options.EMailMode && options.EMailRemoveAfter)
  {
    tempDirectory.Create(kTempFolderPrefix);
    tempDirPrefix = tempDirectory.GetPath();
    NormalizeDirPathPrefix(tempDirPrefix);
    usesTempDir = true;
  }
  #endif

  CTempFiles tempFiles;

  bool createTempFile = false;
  if(!options.StdOutMode && options.UpdateArchiveItself)
  {
    CArchivePath &ap = options.Commands[0].ArchivePath;
    ap = options.ArchivePath;
    // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
    if ((archive != 0 || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
    {
      createTempFile = true;
      ap.Temp = true;
      if (!options.WorkingDir.IsEmpty())
      {
        ap.TempPrefix = options.WorkingDir;
        NormalizeDirPathPrefix(ap.TempPrefix);
      }
    }
  }

  for(int i = 0; i < options.Commands.Size(); i++)
  {
    CArchivePath &ap = options.Commands[i].ArchivePath;
    if (usesTempDir)
    {
      // Check it
      ap.Prefix = tempDirPrefix;
      // ap.Temp = true;
      // ap.TempPrefix = tempDirPrefix;
    }
    if (i > 0 || !createTempFile)
    {
      const UString &path = ap.GetFinalPath();
      if (NFind::DoesFileExist(path))
      {
        errorInfo.SystemError = 0;
        errorInfo.Message = L"File already exists";
        errorInfo.FileName = path;
        return E_FAIL;
      }
    }
  }

  CObjectVector<CArcItem> arcItems;
  if (archive != NULL)
  {
    RINOK(EnumerateInArchiveItems(censor,
        archive, defaultItemName, archiveFileInfo, arcItems));
  }

  RINOK(UpdateWithItemLists(codecs, options, archive, arcItems, dirItems,
      tempFiles, errorInfo, callback));

  if (archive != NULL)
  {
    RINOK(archiveLink.Close());
    archiveLink.Release();
  }

  tempFiles.Paths.Clear();
  if(createTempFile)
  {
    try
    {
      CArchivePath &ap = options.Commands[0].ArchivePath;
      const UString &tempPath = ap.GetTempPath();
      if (archive != NULL)
        if (!NDirectory::DeleteFileAlways(archiveName))
        {
          errorInfo.SystemError = ::GetLastError();
          errorInfo.Message = L"delete file error";
          errorInfo.FileName = archiveName;
          return E_FAIL;
        }
      if (!NDirectory::MyMoveFile(tempPath, archiveName))
      {
        errorInfo.SystemError = ::GetLastError();
        errorInfo.Message = L"move file error";
        errorInfo.FileName = tempPath;
        errorInfo.FileName2 = archiveName;
        return E_FAIL;
      }
    }
    catch(...)
    {
      throw;
    }
  }

  #ifdef _WIN32
  if (options.EMailMode)
  {
    NDLL::CLibrary mapiLib;
    if (!mapiLib.Load(TEXT("Mapi32.dll")))
    {
      errorInfo.SystemError = ::GetLastError();
      errorInfo.Message = L"can not load Mapi32.dll";
      return E_FAIL;
    }
    MY_LPMAPISENDDOCUMENTS fnSend = (MY_LPMAPISENDDOCUMENTS)
        mapiLib.GetProcAddress("MAPISendDocuments");
    if (fnSend == 0)
    {
      errorInfo.SystemError = ::GetLastError();
      errorInfo.Message = L"can not find MAPISendDocuments function";
      return E_FAIL;
    }
    UStringVector fullPaths;
    int i;
    for(i = 0; i < options.Commands.Size(); i++)
    {
      CArchivePath &ap = options.Commands[i].ArchivePath;
      UString arcPath;
      if(!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
      {
        errorInfo.SystemError = ::GetLastError();
        return E_FAIL;
      }
      fullPaths.Add(arcPath);
    }
    CCurrentDirRestorer curDirRestorer;
    for(i = 0; i < fullPaths.Size(); i++)
    {
      UString arcPath = fullPaths[i];
      UString fileName = ExtractFileNameFromPath(arcPath);
      AString path = GetAnsiString(arcPath);
      AString name = GetAnsiString(fileName);
      // Warning!!! MAPISendDocuments function changes Current directory
      fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
    }
  }
  #endif
  return S_OK;
}

⌨️ 快捷键说明

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