7zupdate.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 1,034 行 · 第 1/2 页

CPP
1,034
字号
// 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);}static int GetReverseSlashPos(const UString &name){  int slashPos = name.ReverseFind(L'/');  #ifdef _WIN32  int slash1Pos = name.ReverseFind(L'\\');  slashPos = MyMax(slashPos, slash1Pos);  #endif  return slashPos;}int CUpdateItem::GetExtensionPos() const{  int slashPos = GetReverseSlashPos(Name);  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 MyStringCompareNoCase(f1.Name, f2.Name);}static int CompareFolderRefs(const int *p1, const int *p2, void *param){  int i1 = *p1;  int i2 = *p2;  const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param;  RINOZ(CompareFolders(      db.Folders[i1],      db.Folders[i2]));  RINOZ(MyCompare(      db.NumUnPackStreamsVector[i1],      db.NumUnPackStreamsVector[i2]));  if (db.NumUnPackStreamsVector[i1] == 0)    return 0;  return CompareFiles(      db.Files[db.FolderStartFileIndex[i1]],      db.Files[db.FolderStartFileIndex[i2]]);}////////////////////////////////////////////////////////////static int CompareEmptyItems(const int *p1, const int *p2, void *param){  const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;  const CUpdateItem &u1 = updateItems[*p1];  const CUpdateItem &u2 = updateItems[*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 = MyStringCompareNoCase(u1.Name, u2.Name);    return (u1.IsAnti ? (-n) : n);  }  if (u1.IsAnti != u2.IsAnti)    return (u1.IsAnti ? 1 : -1);  return MyStringCompareNoCase(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 slashPos = GetReverseSlashPos(updateItem.Name);      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 CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param){  const CRefItem &a1 = *p1;  const CRefItem &a2 = *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 = MyStringCompareNoCase(u1.Name, u2.Name);    return (u1.IsAnti ? (-n) : n);  }  if (a1.SortByType)  {    RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));    RINOZ(MyStringCompareNoCase(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 MyStringCompareNoCase(u1.Name, u2.Name);}struct CSolidGroup{  CCompressionMethodMode Method;  CRecordVector<UInt32> Indices;};#ifdef _WIN32static 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;}#endifstatic 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)    {#ifdef _WIN32      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;        }      }#else      if (updateItem.Attributes & FILE_ATTRIBUTE_UNIX_EXTENSION) {         unsigned short st_mode =  updateItem.Attributes >> 16;         if ((st_mode & 00111) && (updateItem.Size >= 2048))         {	     // the "big" file has execute permission (so is not a shell ?)             exeGroup.Indices.Add(i);             continue;         }      }#endif    }    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,    const 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)

⌨️ 快捷键说明

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