Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '7zip/Archive/Zip/ZipUpdate.cpp')
-rwxr-xr-x7zip/Archive/Zip/ZipUpdate.cpp669
1 files changed, 521 insertions, 148 deletions
diff --git a/7zip/Archive/Zip/ZipUpdate.cpp b/7zip/Archive/Zip/ZipUpdate.cpp
index 68ed571b..349e780a 100755
--- a/7zip/Archive/Zip/ZipUpdate.cpp
+++ b/7zip/Archive/Zip/ZipUpdate.cpp
@@ -2,6 +2,8 @@
#include "StdAfx.h"
+#include <stdio.h>
+
#include "ZipUpdate.h"
#include "ZipAddCommon.h"
#include "ZipOut.h"
@@ -10,180 +12,246 @@
#include "Common/AutoPtr.h"
#include "Common/StringConvert.h"
#include "Windows/Defs.h"
+#include "Windows/Thread.h"
#include "../../Common/ProgressUtils.h"
+#ifdef COMPRESS_MT
+#include "../../Common/ProgressMt.h"
+#endif
#include "../../Common/LimitedStreams.h"
-#include "../../Compress/Copy/CopyCoder.h"
+#include "../../Common/OutMemStream.h"
-#include "../Common/InStreamWithCRC.h"
+#include "../../Compress/Copy/CopyCoder.h"
+using namespace NWindows;
+using namespace NSynchronization;
namespace NArchive {
namespace NZip {
+class CCriticalSectionLock2
+{
+ CCriticalSection *_object;
+ void Unlock() { if (_object != 0) _object->Leave(); }
+public:
+ CCriticalSectionLock2(): _object(0) {}
+ void Set(CCriticalSection &object) { _object = &object; _object->Enter(); }
+ ~CCriticalSectionLock2() { Unlock(); }
+};
+
static const Byte kMadeByHostOS = NFileHeader::NHostOS::kFAT;
static const Byte kExtractHostOS = NFileHeader::NHostOS::kFAT;
static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored;
static const Byte kExtractVersionForDirectory = NFileHeader::NCompressionMethod::kStoreExtractVersion;
-static HRESULT CopyBlock(ISequentialInStream *inStream,
- ISequentialOutStream *outStream, ICompressProgressInfo *progress)
-{
- CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
- return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
-}
-
-HRESULT CopyBlockToArchive(ISequentialInStream *inStream,
+static HRESULT CopyBlockToArchive(ISequentialInStream *inStream,
COutArchive &outArchive, ICompressProgressInfo *progress)
{
CMyComPtr<ISequentialOutStream> outStream;
outArchive.CreateStreamForCopying(&outStream);
- return CopyBlock(inStream, outStream, progress);
+ CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+ return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
}
-static HRESULT WriteRange(IInStream *inStream,
- COutArchive &outArchive,
- const CUpdateRange &range,
- IProgress *progress,
- UInt64 &currentComplexity)
+static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
+ const CUpdateRange &range, ICompressProgressInfo *progress)
{
UInt64 position;
- inStream->Seek(range.Position, STREAM_SEEK_SET, &position);
+ RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position));
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
- streamSpec->Init(inStream, range.Size);
-
- CLocalProgress *localProgressSpec = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
- localProgressSpec->Init(progress, true);
-
- CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo;
- CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(range.Size);
- localCompressProgressSpec->Init(localProgress, &currentComplexity, &currentComplexity);
-
- HRESULT result = CopyBlockToArchive(inStreamLimited, outArchive, compressProgress);
- currentComplexity += range.Size;
- return result;
+ RINOK(CopyBlockToArchive(inStreamLimited, outArchive, progress));
+ return progress->SetRatioInfo(&range.Size, &range.Size);
}
-
-static HRESULT UpdateOneFile(IInStream *inStream,
+static void SetFileHeader(
COutArchive &archive,
const CCompressionMethodMode &options,
- CAddCommon &compressor,
const CUpdateItem &updateItem,
- UInt64 &currentComplexity,
- IArchiveUpdateCallback *updateCallback,
- CItemEx &fileHeader,
- CMyComPtr<ISequentialInStream> &fileInStream2)
+ CItem &item)
{
- CMyComPtr<IInStream> fileInStream;
- if (fileInStream2)
- {
- RINOK(fileInStream2.QueryInterface(IID_IInStream, &fileInStream));
- }
-
+ item.UnPackSize = updateItem.Size;
bool isDirectory;
- UInt64 fileSize = updateItem.Size;
- fileHeader.UnPackSize = fileSize;
if (updateItem.NewProperties)
{
isDirectory = updateItem.IsDirectory;
- fileHeader.Name = updateItem.Name;
- fileHeader.ExternalAttributes = updateItem.Attributes;
- fileHeader.Time = updateItem.Time;
+ item.Name = updateItem.Name;
+ item.ExternalAttributes = updateItem.Attributes;
+ item.Time = updateItem.Time;
}
else
- isDirectory = fileHeader.IsDirectory();
+ isDirectory = item.IsDirectory();
- archive.PrepareWriteCompressedData(fileHeader.Name.Length(), fileSize);
-
- fileHeader.LocalHeaderPosition = archive.GetCurrentPosition();
- fileHeader.MadeByVersion.HostOS = kMadeByHostOS;
- fileHeader.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ item.MadeByVersion.HostOS = kMadeByHostOS;
+ item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
- fileHeader.ExtractVersion.HostOS = kExtractHostOS;
+ item.ExtractVersion.HostOS = kExtractHostOS;
- fileHeader.InternalAttributes = 0; // test it
- fileHeader.ClearFlags();
- if(isDirectory)
+ item.InternalAttributes = 0; // test it
+ item.ClearFlags();
+ item.SetEncrypted(!isDirectory && options.PasswordIsDefined);
+ if (isDirectory)
{
- fileHeader.ExtractVersion.Version = kExtractVersionForDirectory;
- fileHeader.CompressionMethod = kMethodForDirectory;
-
- fileHeader.PackSize = 0;
- fileHeader.FileCRC = 0; // test it
+ item.ExtractVersion.Version = kExtractVersionForDirectory;
+ item.CompressionMethod = kMethodForDirectory;
+ item.PackSize = 0;
+ item.FileCRC = 0; // test it
}
- else
+}
+
+static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
+ bool isAesMode, Byte aesKeyMode, CItem &item)
+{
+ item.ExtractVersion.Version = compressingResult.ExtractVersion;
+ item.CompressionMethod = compressingResult.Method;
+ item.FileCRC = compressingResult.CRC;
+ item.UnPackSize = compressingResult.UnpackSize;
+ item.PackSize = compressingResult.PackSize;
+
+ item.LocalExtra.Clear();
+ item.CentralExtra.Clear();
+
+ if (isAesMode)
{
- {
- CSequentialInStreamWithCRC *inSecStreamSpec = 0;
- CInStreamWithCRC *inStreamSpec = 0;
- CMyComPtr<ISequentialInStream> fileSecInStream;
- if (fileInStream)
- {
- inStreamSpec = new CInStreamWithCRC;
- fileSecInStream = inStreamSpec;
- inStreamSpec->Init(fileInStream);
- }
- else
- {
- inSecStreamSpec = new CSequentialInStreamWithCRC;
- fileSecInStream = inSecStreamSpec;
- inSecStreamSpec->Init(fileInStream2);
- }
+ CWzAesExtraField wzAesField;
+ wzAesField.Strength = aesKeyMode;
+ wzAesField.Method = compressingResult.Method;
+ item.CompressionMethod = NFileHeader::NCompressionMethod::kWzAES;
+ item.FileCRC = 0;
+ CExtraSubBlock sb;
+ wzAesField.SetSubBlock(sb);
+ item.LocalExtra.SubBlocks.Add(sb);
+ item.CentralExtra.SubBlocks.Add(sb);
+ }
+}
- CCompressingResult compressingResult;
- CMyComPtr<IOutStream> outStream;
- archive.CreateStreamForCompressing(&outStream);
+#ifdef COMPRESS_MT
- CLocalProgress *localProgressSpec = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
- localProgressSpec->Init(updateCallback, true);
+static DWORD WINAPI CoderThread(void *threadCoderInfo);
+
+struct CThreadInfo
+{
+ NWindows::CThread Thread;
+ CAutoResetEvent *CompressEvent;
+ CAutoResetEvent *CompressionCompletedEvent;
+ bool ExitThread;
+
+ CMtCompressProgress *ProgressSpec;
+ CMyComPtr<ICompressProgressInfo> Progress;
+
+ COutMemStream *OutStreamSpec;
+ CMyComPtr<IOutStream> OutStream;
+ CMyComPtr<ISequentialInStream> InStream;
+
+ CAddCommon Coder;
+ HRESULT Result;
+ CCompressingResult CompressingResult;
+
+ bool IsFree;
+ UInt32 UpdateIndex;
+
+ CThreadInfo(const CCompressionMethodMode &options):
+ CompressEvent(NULL),
+ CompressionCompletedEvent(NULL),
+ ExitThread(false),
+ ProgressSpec(0),
+ OutStreamSpec(0),
+ Coder(options)
+ {}
- CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo;
- CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
+ void CreateEvents()
+ {
+ CompressEvent = new CAutoResetEvent(false);
+ CompressionCompletedEvent = new CAutoResetEvent(false);
+ }
+ bool CreateThread() { return Thread.Create(CoderThread, this); }
+ ~CThreadInfo();
- localCompressProgressSpec->Init(localProgress, &currentComplexity, NULL);
+ void WaitAndCode();
+ void StopWaitClose()
+ {
+ ExitThread = true;
+ if (OutStreamSpec != 0)
+ OutStreamSpec->StopWriting(E_ABORT);
+ if (CompressEvent != NULL)
+ CompressEvent->Set();
+ Thread.Wait();
+ Thread.Close();
+ }
- RINOK(compressor.Compress(fileSecInStream, outStream, fileSize, compressProgress, compressingResult));
+};
- fileHeader.PackSize = compressingResult.PackSize;
- fileHeader.CompressionMethod = compressingResult.Method;
- fileHeader.ExtractVersion.Version = compressingResult.ExtractVersion;
- if (inStreamSpec != 0)
- {
- fileHeader.FileCRC = inStreamSpec->GetCRC();
- fileHeader.UnPackSize = inStreamSpec->GetSize();
- }
- else
- {
- fileHeader.FileCRC = inSecStreamSpec->GetCRC();
- fileHeader.UnPackSize = inSecStreamSpec->GetSize();
- }
- }
- }
- fileHeader.SetEncrypted(!isDirectory && options.PasswordIsDefined);
- /*
- fileHeader.CommentSize = (updateItem.Commented) ?
- WORD(updateItem.CommentRange.Size) : 0;
- */
+CThreadInfo::~CThreadInfo()
+{
+ if (CompressEvent != NULL)
+ delete CompressEvent;
+ if (CompressionCompletedEvent != NULL)
+ delete CompressionCompletedEvent;
+}
- fileHeader.LocalExtraSize = 0;
-
- // fileHeader.CentralExtraSize = 0;
+void CThreadInfo::WaitAndCode()
+{
+ for (;;)
+ {
+ CompressEvent->Lock();
+ if (ExitThread)
+ return;
+ Result = Coder.Compress(InStream, OutStream, Progress, CompressingResult);
+ if (Result == S_OK && Progress)
+ Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
+ CompressionCompletedEvent->Set();
+ }
+}
- RINOK(archive.WriteLocalHeader(fileHeader));
- currentComplexity += fileSize;
- return updateCallback->SetOperationResult(
- NArchive::NUpdate::NOperationResult::kOK);
+static DWORD WINAPI CoderThread(void *threadCoderInfo)
+{
+ ((CThreadInfo *)threadCoderInfo)->WaitAndCode();
+ return 0;
}
+class CThreads
+{
+public:
+ CObjectVector<CThreadInfo> Threads;
+ ~CThreads()
+ {
+ for (int i = 0; i < Threads.Size(); i++)
+ Threads[i].StopWaitClose();
+ }
+};
+
+struct CMemBlocks2: public CMemLockBlocks
+{
+ CCompressingResult CompressingResult;
+ bool Defined;
+ bool Skip;
+ CMemBlocks2(): Defined(false), Skip(false) {}
+};
+
+class CMemRefs
+{
+public:
+ CMemBlockManagerMt *Manager;
+ CObjectVector<CMemBlocks2> Refs;
+ CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ;
+ ~CMemRefs()
+ {
+ for (int i = 0; i < Refs.Size(); i++)
+ Refs[i].FreeOpt(Manager);
+ }
+};
+
+#endif
+
static HRESULT Update2(COutArchive &archive,
+ CInArchive *inArchive,
IInStream *inStream,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
@@ -192,6 +260,8 @@ static HRESULT Update2(COutArchive &archive,
IArchiveUpdateCallback *updateCallback)
{
UInt64 complexity = 0;
+ UInt64 numFilesToCompress = 0;
+ UInt64 numBytesToCompress = 0;
int i;
for(i = 0; i < updateItems.Size(); i++)
@@ -200,6 +270,8 @@ static HRESULT Update2(COutArchive &archive,
if (updateItem.NewData)
{
complexity += updateItem.Size;
+ numBytesToCompress += updateItem.Size;
+ numFilesToCompress++;
/*
if (updateItem.Commented)
complexity += updateItem.CommentRange.Size;
@@ -207,7 +279,9 @@ static HRESULT Update2(COutArchive &archive,
}
else
{
- const CItemEx &inputItem = inputItems[updateItem.IndexInArchive];
+ CItemEx inputItem = inputItems[updateItem.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK)
+ return E_NOTIMPL;
complexity += inputItem.GetLocalFullSize();
// complexity += inputItem.GetCentralExtraPlusCommentSize();
}
@@ -217,51 +291,345 @@ static HRESULT Update2(COutArchive &archive,
if (comment != 0)
complexity += comment.GetCapacity();
-
complexity++; // end of central
-
updateCallback->SetTotal(complexity);
- CMyAutoPtr<CAddCommon> compressor;
+
+ CAddCommon compressor(*options);
complexity = 0;
CObjectVector<CItem> items;
- CRecordVector<UInt32> updateIndices;
- for(i = 0; i < updateItems.Size(); i++)
+ CLocalProgress *localProgressSpec = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
+ localProgressSpec->Init(updateCallback, true);
+
+ CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo;
+ CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
+
+
+ #ifdef COMPRESS_MT
+
+ const size_t kNumMaxThreads = (1 << 10);
+ UInt32 numThreads = options->NumThreads;
+ if (numThreads > kNumMaxThreads)
+ numThreads = kNumMaxThreads;
+
+ const size_t kMemPerThread = (1 << 25);
+ const size_t kBlockSize = 1 << 16;
+
+ CCompressionMethodMode options2;
+ if (options != 0)
+ options2 = *options;
+
+ bool mtMode = ((options != 0) && (numThreads > 1));
+
+ if (numFilesToCompress <= 1)
+ mtMode = false;
+
+ if (mtMode)
{
- const CUpdateItem &updateItem = updateItems[i];
- RINOK(updateCallback->SetCompleted(&complexity));
+ Byte method = options->MethodSequence.Front();
+ if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined)
+ mtMode = false;
+ if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ UInt64 averageSize = numBytesToCompress / numFilesToCompress;
+ UInt32 blockSize = options->DicSize;
+ if (blockSize == 0)
+ blockSize = 1;
+ UInt64 averageNumberOfBlocks = averageSize / blockSize;
+ UInt32 numBZip2Threads = 32;
+ if (averageNumberOfBlocks < numBZip2Threads)
+ numBZip2Threads = (UInt32)averageNumberOfBlocks;
+ if (numBZip2Threads < 1)
+ numBZip2Threads = 1;
+ numThreads = numThreads / numBZip2Threads;
+ options2.NumThreads = numBZip2Threads;
+ if (numThreads <= 1)
+ mtMode = false;
+ }
+ }
+
+
+ CMtCompressProgressMixer mtCompressProgressMixer;
+ mtCompressProgressMixer.Init(numThreads + 1, localProgress);
+
+ // we need one item for main stream
+ CMtCompressProgress *progressMainSpec = new CMtCompressProgress();
+ CMyComPtr<ICompressProgressInfo> progressMain = progressMainSpec;
+ progressMainSpec->Init(&mtCompressProgressMixer, (int)numThreads);
+
+ CMemBlockManagerMt memManager(kBlockSize);
+ CMemRefs refs(&memManager);
+
+ CThreads threads;
+ CRecordVector<HANDLE> compressingCompletedEvents;
+ CRecordVector<int> threadIndices; // list threads in order of updateItems
+
+ if (mtMode)
+ {
+ if (!memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize)))
+ return E_OUTOFMEMORY;
+ for(i = 0; i < updateItems.Size(); i++)
+ refs.Refs.Add(CMemBlocks2());
+
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ threads.Threads.Add(CThreadInfo(options2));
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ threadInfo.CreateEvents();
+ threadInfo.OutStreamSpec = new COutMemStream(&memManager);
+ threadInfo.OutStream = threadInfo.OutStreamSpec;
+ threadInfo.IsFree = true;
+ threadInfo.ProgressSpec = new CMtCompressProgress();
+ threadInfo.Progress = threadInfo.ProgressSpec;
+ threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i);
+ if (!threadInfo.CreateThread())
+ return ::GetLastError();
+ }
+ }
+ int mtItemIndex = 0;
+
+ #endif
+
+ int itemIndex = 0;
+ int lastRealStreamItemIndex = -1;
+
+ while(itemIndex < updateItems.Size())
+ {
+ #ifdef COMPRESS_MT
+ if (!mtMode)
+ #endif
+ {
+ RINOK(updateCallback->SetCompleted(&complexity));
+ }
+
+ #ifdef COMPRESS_MT
+ if (mtMode && (UInt32)threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
+ {
+ const CUpdateItem &updateItem = updateItems[mtItemIndex++];
+ if (!updateItem.NewData)
+ continue;
+ CItemEx item;
+ if (updateItem.NewProperties)
+ {
+ if (updateItem.IsDirectory)
+ continue;
+ }
+ else
+ {
+ item = inputItems[updateItem.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ if (item.IsDirectory())
+ continue;
+ }
+ CMyComPtr<ISequentialInStream> fileInStream;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(mtCompressProgressMixer.CriticalSection);
+ HRESULT res = updateCallback->GetStream(updateItem.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ complexity += updateItem.Size;
+ complexity++;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ refs.Refs[mtItemIndex - 1].Skip = true;
+ continue;
+ }
+ RINOK(res);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+
+ for (UInt32 i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ if (threadInfo.IsFree)
+ {
+ threadInfo.IsFree = false;
+ threadInfo.InStream = fileInStream;
+ threadInfo.OutStreamSpec->Init();
+ threadInfo.ProgressSpec->Reinit();
+ threadInfo.CompressEvent->Set();
+ threadInfo.UpdateIndex = mtItemIndex - 1;
+
+ compressingCompletedEvents.Add(*threadInfo.CompressionCompletedEvent);
+ threadIndices.Add(i);
+ break;
+ }
+ }
+ continue;
+ }
+ if (mtMode)
+ if (refs.Refs[itemIndex].Skip)
+ {
+ itemIndex++;
+ continue;
+ }
+ #endif
+
+ const CUpdateItem &updateItem = updateItems[itemIndex];
CItemEx item;
if (!updateItem.NewProperties || !updateItem.NewData)
+ {
item = inputItems[updateItem.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ }
+
+
+ bool isDirectory;
+ if (updateItem.NewProperties)
+ isDirectory = updateItem.IsDirectory;
+ else
+ isDirectory = item.IsDirectory();
if (updateItem.NewData)
{
- if(compressor.get() == NULL)
+ #ifdef COMPRESS_MT
+ if (mtMode && !isDirectory)
{
- CMyAutoPtr<CAddCommon> tmp(new CAddCommon(*options));
- compressor = tmp;
+ if (lastRealStreamItemIndex < itemIndex)
+ {
+ lastRealStreamItemIndex = itemIndex;
+ SetFileHeader(archive, *options, updateItem, item);
+ // file Size can be 64-bit !!!
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), updateItem.Size, options->IsAesMode);
+ }
+
+ CMemBlocks2 &memRef = refs.Refs[itemIndex];
+ if (memRef.Defined)
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ memRef.WriteToStream(memManager.GetBlockSize(), outStream);
+ SetItemInfoFromCompressingResult(memRef.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, updateItem, item);
+ RINOK(archive.WriteLocalHeader(item));
+ complexity += item.UnPackSize;
+ // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ memRef.FreeOpt(&memManager);
+ }
+ else
+ {
+ {
+ CThreadInfo &thread = threads.Threads[threadIndices.Front()];
+ if (!thread.OutStreamSpec->WasUnlockEventSent())
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ thread.OutStreamSpec->SetOutStream(outStream);
+ thread.OutStreamSpec->SetRealStreamMode();
+ }
+ }
+
+ DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(),
+ &compressingCompletedEvents.Front(), FALSE, INFINITE);
+ int t = (int)(result - WAIT_OBJECT_0);
+ CThreadInfo &threadInfo = threads.Threads[threadIndices[t]];
+ threadInfo.InStream.Release();
+ threadInfo.IsFree = true;
+ RINOK(threadInfo.Result);
+ threadIndices.Delete(t);
+ compressingCompletedEvents.Delete(t);
+ if (t == 0)
+ {
+ RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
+ threadInfo.OutStreamSpec->ReleaseOutStream();
+ SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, updateItem, item);
+ RINOK(archive.WriteLocalHeader(item));
+ complexity += item.UnPackSize;
+ }
+ else
+ {
+ CMemBlocks2 &memRef = refs.Refs[threadInfo.UpdateIndex];
+ threadInfo.OutStreamSpec->DetachData(memRef);
+ memRef.CompressingResult = threadInfo.CompressingResult;
+ memRef.Defined = true;
+ continue;
+ }
+ }
}
- CMyComPtr<ISequentialInStream> fileInStream2;
- HRESULT res = updateCallback->GetStream(updateItem.IndexInClient, &fileInStream2);
- if (res == S_FALSE)
+ else
+ #endif
{
- complexity += updateItem.Size;
- complexity++;
- RINOK(updateCallback->SetOperationResult(
- NArchive::NUpdate::NOperationResult::kOK));
- continue;
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ {
+ #ifdef COMPRESS_MT
+ CCriticalSectionLock2 lock;
+ if (mtMode)
+ lock.Set(mtCompressProgressMixer.CriticalSection);
+ #endif
+ HRESULT res = updateCallback->GetStream(updateItem.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ complexity += updateItem.Size;
+ complexity++;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ itemIndex++;
+ continue;
+ }
+ RINOK(res);
+
+ #ifdef COMPRESS_MT
+ if (mtMode)
+ {
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+ #endif
+ }
+ // file Size can be 64-bit !!!
+ SetFileHeader(archive, *options, updateItem, item);
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), updateItem.Size, options->IsAesMode);
+
+ if(!isDirectory)
+ {
+ CCompressingResult compressingResult;
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+
+ localCompressProgressSpec->Init(localProgress, &complexity, NULL);
+
+ RINOK(compressor.Compress(fileInStream, outStream, compressProgress, compressingResult));
+
+ SetItemInfoFromCompressingResult(compressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ }
+ }
+ RINOK(archive.WriteLocalHeader(item));
+ complexity += item.UnPackSize;
+ #ifdef COMPRESS_MT
+ if (!mtMode)
+ #endif
+ {
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
}
- RINOK(res);
- RINOK(UpdateOneFile(inStream, archive, *options,
- *compressor, updateItem, complexity, updateCallback, item,
- fileInStream2));
}
else
{
// item = inputItems[copyIndices[copyIndexIndex++]];
+
+ #ifdef COMPRESS_MT
+ if (mtMode)
+ progressMainSpec->Reinit();
+ #endif
+
+ localCompressProgressSpec->Init(localProgress, &complexity, NULL);
+ ICompressProgressInfo *progress = compressProgress;
+ #ifdef COMPRESS_MT
+ if (mtMode)
+ progress = progressMain;
+ #endif
+
if (updateItem.NewProperties)
{
if (item.HasDescriptor())
@@ -275,13 +643,14 @@ static HRESULT Update2(COutArchive &archive,
// Test it
item.Name = updateItem.Name;
item.Time = updateItem.Time;
- item.CentralExtra.Clear();
- item.LocalExtraSize = 0;
+ item.CentralExtra.RemoveUnknownSubBlocks();
+ item.LocalExtra.RemoveUnknownSubBlocks();
- archive.PrepareWriteCompressedData2(item.Name.Length(), item.UnPackSize, item.PackSize);
+ archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField());
item.LocalHeaderPosition = archive.GetCurrentPosition();
archive.SeekToPackedDataPosition();
- RINOK(WriteRange(inStream, archive, range, updateCallback, complexity));
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
archive.WriteLocalHeader(item);
}
else
@@ -291,15 +660,15 @@ static HRESULT Update2(COutArchive &archive,
// set new header position
item.LocalHeaderPosition = archive.GetCurrentPosition();
- RINOK(WriteRange(inStream, archive, range, updateCallback, complexity));
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
archive.MoveBasePosition(range.Size);
}
}
items.Add(item);
- updateIndices.Add(i);
complexity += NFileHeader::kLocalBlockSize;
+ itemIndex++;
}
-
archive.WriteCentralDir(items, comment);
return S_OK;
}
@@ -319,7 +688,11 @@ HRESULT Update(
CInArchiveInfo archiveInfo;
if(inArchive != 0)
+ {
inArchive->GetArchiveInfo(archiveInfo);
+ if (archiveInfo.Base != 0)
+ return E_NOTIMPL;
+ }
else
archiveInfo.StartPosition = 0;
@@ -336,7 +709,7 @@ HRESULT Update(
if(inArchive != 0)
inStream.Attach(inArchive->CreateStream());
- return Update2(outArchive, inStream,
+ return Update2(outArchive, inArchive, inStream,
inputItems, updateItems,
compressionMethodMode,
archiveInfo.Comment, updateCallback);