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

📄 7zupdate.cpp

📁 压缩软件源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// UpdateMain.cpp

#include "StdAfx.h"

#include "7zUpdate.h"
#include "7zFolderInStream.h"
#include "7zEncode.h"
#include "7zHandler.h"
#include "7zOut.h"

#ifndef EXCLUDE_COM
#include "7zMethods.h"
#endif

#include "../../Compress/Copy/CopyCoder.h"
#include "../../Common/ProgressUtils.h"
#include "../../Common/LimitedStreams.h"
#include "../../Common/LimitedStreams.h"
#include "../Common/ItemNameUtils.h"

namespace NArchive {
namespace N7z {

static const wchar_t *kMatchFinderForBCJ2_LZMA = L"BT2";
static const UInt32 kDictionaryForBCJ2_LZMA = 1 << 20;
static const UInt32 kAlgorithmForBCJ2_LZMA = 2;
static const UInt32 kNumFastBytesForBCJ2_LZMA = 64;

static HRESULT CopyBlock(ISequentialInStream *inStream, 
    ISequentialOutStream *outStream, ICompressProgressInfo *progress)
{
  CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
  return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
}

static HRESULT WriteRange(
    ISequentialInStream *inStream, 
    ISequentialOutStream *outStream, 
    UInt64 size,
    IProgress *progress,
    UInt64 &currentComplexity)
{
  CLimitedSequentialInStream *streamSpec = new 
      CLimitedSequentialInStream;
  CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
  streamSpec->Init(inStream, size);

  CLocalProgress *localProgressSpec = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
  localProgressSpec->Init(progress, true);
  
  CLocalCompressProgressInfo *localCompressProgressSpec = 
      new CLocalCompressProgressInfo;
  CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;

  localCompressProgressSpec->Init(localProgress, &currentComplexity, &currentComplexity);

  HRESULT result = CopyBlock(inStreamLimited, outStream, compressProgress);
  currentComplexity += size;
  return result;
}


static HRESULT WriteRange(IInStream *inStream, 
    ISequentialOutStream *outStream, 
    UInt64 position,
    UInt64 size,
    IProgress *progress,
    UInt64 &currentComplexity)
{
  inStream->Seek(position, STREAM_SEEK_SET, 0);
  return WriteRange(inStream, outStream, 
    size, progress, currentComplexity);
}

int CUpdateItem::GetExtensionPos() const
{
  int slash1Pos = Name.ReverseFind(L'\\');
  int slash2Pos = Name.ReverseFind(L'/');
  int slashPos = MyMax(slash1Pos, slash2Pos);
  int dotPos = Name.ReverseFind(L'.');
  if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
    return Name.Length();
  return dotPos + 1;
}

UString CUpdateItem::GetExtension() const
{
  return Name.Mid(GetExtensionPos());
}

struct CFolderRef
{
  const CArchiveDatabaseEx *Database;
  int FolderIndex;
};

#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }

static int CompareMethodIDs(const CMethodID &a1, const CMethodID &a2)
{
  for (int i = 0; i < a1.IDSize && i < a2.IDSize; i++)
    RINOZ(MyCompare(a1.ID[i], a2.ID[i]));
  return MyCompare(a1.IDSize, a2.IDSize);
}

static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2)
{
  size_t c1 = a1.GetCapacity();
  size_t c2 = a2.GetCapacity();
  RINOZ(MyCompare(c1, c2));
  for (size_t i = 0; i < c1; i++)
    RINOZ(MyCompare(a1[i], a2[i]));
  return 0;
}

static int CompareAltCoders(const CAltCoderInfo &a1, const CAltCoderInfo &a2)
{
  RINOZ(CompareMethodIDs(a1.MethodID, a2.MethodID));
  return CompareBuffers(a1.Properties, a2.Properties);
}

static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2)
{
  RINOZ(MyCompare(c1.NumInStreams, c2.NumInStreams));
  RINOZ(MyCompare(c1.NumOutStreams, c2.NumOutStreams));
  int s1 = c1.AltCoders.Size();
  int s2 = c2.AltCoders.Size();
  RINOZ(MyCompare(s1, s2));
  for (int i = 0; i < s1; i++)
    RINOZ(CompareAltCoders(c1.AltCoders[i], c2.AltCoders[i]));
  return 0;
}

static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2)
{
  RINOZ(MyCompare(b1.InIndex, b2.InIndex));
  return MyCompare(b1.OutIndex, b2.OutIndex);
}

static int CompareFolders(const CFolder &f1, const CFolder &f2)
{
  int s1 = f1.Coders.Size();
  int s2 = f2.Coders.Size();
  RINOZ(MyCompare(s1, s2));
  int i;
  for (i = 0; i < s1; i++)
    RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i]));
  s1 = f1.BindPairs.Size();
  s2 = f2.BindPairs.Size();
  RINOZ(MyCompare(s1, s2));
  for (i = 0; i < s1; i++)
    RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
  return 0;
}

static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
{
  return MyStringCollateNoCase(f1.Name, f2.Name);
}

static int __cdecl CompareFolderRefs(const void *p1, const void *p2)
{
  const CFolderRef &a1 = *((const CFolderRef *)p1);
  const CFolderRef &a2 = *((const CFolderRef *)p2);
  const CArchiveDatabaseEx &d1 = *a1.Database;
  const CArchiveDatabaseEx &d2 = *a2.Database;
  RINOZ(CompareFolders(
      d1.Folders[a1.FolderIndex],
      d2.Folders[a2.FolderIndex]));
  RINOZ(MyCompare(
      d1.NumUnPackStreamsVector[a1.FolderIndex],
      d2.NumUnPackStreamsVector[a2.FolderIndex]));
  if (d1.NumUnPackStreamsVector[a1.FolderIndex] == 0)
    return 0;
  return CompareFiles(
      d1.Files[d1.FolderStartFileIndex[a1.FolderIndex]],
      d2.Files[d2.FolderStartFileIndex[a2.FolderIndex]]);
}

////////////////////////////////////////////////////////////

static int __cdecl CompareEmptyItems(const void *p1, const void *p2)
{
  const CUpdateItem &u1 = **((CUpdateItem **)p1);
  const CUpdateItem &u2 = **((CUpdateItem **)p2);
  if (u1.IsDirectory != u2.IsDirectory)
  {
    if (u1.IsDirectory)
      return u1.IsAnti ? 1: -1;
    return u2.IsAnti ? -1: 1;
  }
  if (u1.IsDirectory)
  {
    if (u1.IsAnti != u2.IsAnti)
      return (u1.IsAnti ? 1 : -1);
    int n = MyStringCollateNoCase(u1.Name, u2.Name);
    return (u1.IsAnti ? (-n) : n);
  }
  if (u1.IsAnti != u2.IsAnti)
    return (u1.IsAnti ? 1 : -1);
  return MyStringCollateNoCase(u1.Name, u2.Name);
}

struct CRefItem
{
  UInt32 Index;
  const CUpdateItem *UpdateItem;
  UInt32 ExtensionPos;
  UInt32 NamePos;
  bool SortByType;
  CRefItem(UInt32 index, const CUpdateItem &updateItem, bool sortByType):
    SortByType(sortByType),
    Index(index),
    UpdateItem(&updateItem),
    ExtensionPos(0),
    NamePos(0)
  {
    if (sortByType)
    {
      int slash1Pos = updateItem.Name.ReverseFind(L'\\');
      int slash2Pos = updateItem.Name.ReverseFind(L'/');
      int slashPos = MyMax(slash1Pos, slash2Pos);
      if (slashPos >= 0)
        NamePos = slashPos + 1;
      else
        NamePos = 0;
      int dotPos = updateItem.Name.ReverseFind(L'.');
      if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
        ExtensionPos = updateItem.Name.Length();
      else 
        ExtensionPos = dotPos + 1;
    }
  }
};

static int __cdecl CompareUpdateItems(const void *p1, const void *p2)
{
  const CRefItem &a1 = *((CRefItem *)p1);
  const CRefItem &a2 = *((CRefItem *)p2);
  const CUpdateItem &u1 = *a1.UpdateItem;
  const CUpdateItem &u2 = *a2.UpdateItem;
  int n;
  if (u1.IsDirectory != u2.IsDirectory)
  {
    if (u1.IsDirectory)
      return u1.IsAnti ? 1: -1;
    return u2.IsAnti ? -1: 1;
  }
  if (u1.IsDirectory)
  {
    if (u1.IsAnti != u2.IsAnti)
      return (u1.IsAnti ? 1 : -1);
    n = MyStringCollateNoCase(u1.Name, u2.Name);
    return (u1.IsAnti ? (-n) : n);
  }
  if (a1.SortByType)
  {
    RINOZ(MyStringCollateNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));
    RINOZ(MyStringCollateNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos));
    if (u1.LastWriteTimeIsDefined && u2.LastWriteTimeIsDefined)
      RINOZ(CompareFileTime(&u1.LastWriteTime, &u2.LastWriteTime));
    RINOZ(MyCompare(u1.Size, u2.Size))
  }
  return MyStringCollateNoCase(u1.Name, u2.Name);
}

struct CSolidGroup
{
  CCompressionMethodMode Method;
  CRecordVector<UInt32> Indices;
};

static wchar_t *g_ExeExts[] =
{
  L"dll",
  L"exe",
  L"ocx",
  L"sfx",
  L"sys"
};

static bool IsExeFile(const UString &ext)
{
  for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++)
    if (ext.CompareNoCase(g_ExeExts[i]) == 0)
      return true;
  return false;
}

static CMethodID k_BCJ_X86 = { { 0x3, 0x3, 0x1, 0x3 }, 4 };
static CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 };
static CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 };

static bool GetMethodFull(const CMethodID &methodID, 
    UInt32 numInStreams, CMethodFull &methodResult)
{
  methodResult.MethodID = methodID;
  methodResult.NumInStreams = numInStreams;
  methodResult.NumOutStreams = 1;

  #ifndef EXCLUDE_COM
  CMethodInfo methodInfo;
  if (!GetMethodInfo(methodID, methodInfo))
    return false;
  if (!methodInfo.EncoderIsAssigned)
    return false;
  methodResult.EncoderClassID = methodInfo.Encoder;
  methodResult.FilePath = methodInfo.FilePath;
  if (methodInfo.NumOutStreams != 1 || methodInfo.NumInStreams != numInStreams)
    return false;
  #endif
  return true;
}

static bool MakeExeMethod(const CCompressionMethodMode &method, 
    bool bcj2Filter, CCompressionMethodMode &exeMethod)
{
  exeMethod = method;
  if (bcj2Filter)
  {
    CMethodFull methodFull;
    if (!GetMethodFull(k_BCJ2, 4, methodFull))
      return false;
    exeMethod.Methods.Insert(0, methodFull);
    if (!GetMethodFull(k_LZMA, 1, methodFull))
      return false;
    {
      CProperty property;
      property.PropID = NCoderPropID::kAlgorithm;
      property.Value = kAlgorithmForBCJ2_LZMA;
      methodFull.CoderProperties.Add(property);
    }
    {
      CProperty property;
      property.PropID = NCoderPropID::kMatchFinder;
      property.Value = kMatchFinderForBCJ2_LZMA;
      methodFull.CoderProperties.Add(property);
    }
    {
      CProperty property;
      property.PropID = NCoderPropID::kDictionarySize;
      property.Value = kDictionaryForBCJ2_LZMA;
      methodFull.CoderProperties.Add(property);
    }
    {
      CProperty property;
      property.PropID = NCoderPropID::kNumFastBytes;
      property.Value = kNumFastBytesForBCJ2_LZMA;
      methodFull.CoderProperties.Add(property);
    }

    exeMethod.Methods.Add(methodFull);
    exeMethod.Methods.Add(methodFull);
    CBind bind;

    bind.OutCoder = 0;
    bind.InStream = 0;

    bind.InCoder = 1;
    bind.OutStream = 0;
    exeMethod.Binds.Add(bind);

    bind.InCoder = 2;
    bind.OutStream = 1;
    exeMethod.Binds.Add(bind);

    bind.InCoder = 3;
    bind.OutStream = 2;
    exeMethod.Binds.Add(bind);
  }
  else
  {
    CMethodFull methodFull;
    if (!GetMethodFull(k_BCJ_X86, 1, methodFull))
      return false;
    exeMethod.Methods.Insert(0, methodFull);
    CBind bind;
    bind.OutCoder = 0;
    bind.InStream = 0;
    bind.InCoder = 1;
    bind.OutStream = 0;
    exeMethod.Binds.Add(bind);
  }
  return true;
}   

static void SplitFilesToGroups(
    const CCompressionMethodMode &method, 
    bool useFilters, bool maxFilter,
    const CObjectVector<CUpdateItem> &updateItems,
    CObjectVector<CSolidGroup> &groups)
{
  if (method.Methods.Size() != 1 || method.Binds.Size() != 0)
    useFilters = false;
  groups.Clear();
  groups.Add(CSolidGroup());
  groups.Add(CSolidGroup());
  CSolidGroup &generalGroup = groups[0];
  CSolidGroup &exeGroup = groups[1];
  generalGroup.Method = method;
  int i;
  for (i = 0; i < updateItems.Size(); i++)
  {
    const CUpdateItem &updateItem = updateItems[i];
    if (!updateItem.NewData)
      continue;
    if (!updateItem.HasStream())
      continue;
    if (useFilters)
    {
      const UString name = updateItem.Name;
      int dotPos = name.ReverseFind(L'.');
      if (dotPos >= 0)
      {
        UString ext = name.Mid(dotPos + 1);
        if (IsExeFile(ext))
        {
          exeGroup.Indices.Add(i);
          continue;
        }
      }
    }
    generalGroup.Indices.Add(i);
  }
  if (exeGroup.Indices.Size() > 0)
    if (!MakeExeMethod(method, maxFilter, exeGroup.Method))
      exeGroup.Method = method;
  for (i = 0; i < groups.Size();)
    if (groups[i].Indices.Size() == 0)
      groups.Delete(i);
    else
      i++;
}

static void FromUpdateItemToFileItem(const CUpdateItem &updateItem, 
    CFileItem &file)
{
  file.Name = NItemName::MakeLegalName(updateItem.Name);
  if (updateItem.AttributesAreDefined)
    file.SetAttributes(updateItem.Attributes);
  
  // if (updateItem.CreationTimeIsDefined)
  //   file.SetCreationTime(updateItem.ItemInfo.CreationTime);
  
  if (updateItem.LastWriteTimeIsDefined)
    file.SetLastWriteTime(updateItem.LastWriteTime);
  
  file.UnPackSize = updateItem.Size;
  file.IsDirectory = updateItem.IsDirectory;
  file.IsAnti = updateItem.IsAnti;
  file.HasStream = updateItem.HasStream();
}

static HRESULT Update2(
    IInStream *inStream,
    const CArchiveDatabaseEx *database,
    CObjectVector<CUpdateItem> &updateItems,
    ISequentialOutStream *seqOutStream,
    IArchiveUpdateCallback *updateCallback,
    const CUpdateOptions &options)
{
  UInt64 numSolidFiles = options.NumSolidFiles;
  if (numSolidFiles == 0)
    numSolidFiles = 1;
  /*
  CMyComPtr<IOutStream> outStream;
  RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
  if (!outStream)
    return E_NOTIMPL;
  */

  UInt64 startBlockSize = database != 0 ? 
      database->ArchiveInfo.StartPosition: 0;
  if (startBlockSize > 0 && !options.RemoveSfxBlock)
  {
    CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
    CMyComPtr<ISequentialInStream> limitedStream(streamSpec);
    RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
    streamSpec->Init(inStream, startBlockSize);
    RINOK(CopyBlock(limitedStream, seqOutStream, NULL));
  }

  CRecordVector<int> fileIndexToUpdateIndexMap;
  if (database != 0)
  {
    fileIndexToUpdateIndexMap.Reserve(database->Files.Size());
    for (int i = 0; i < database->Files.Size(); i++)
      fileIndexToUpdateIndexMap.Add(-1);
  }
  int i;
  for(i = 0; i < updateItems.Size(); i++)
  {
    int index = updateItems[i].IndexInArchive;
    if (index != -1)
      fileIndexToUpdateIndexMap[index] = i;
  }

  CRecordVector<CFolderRef> folderRefs;
  if (database != 0)
  {
  for(i = 0; i < database->Folders.Size(); i++)
  {
    CNum indexInFolder = 0;
    CNum numCopyItems = 0;

⌨️ 快捷键说明

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