diff --git a/Components/Lzma2/Util/7z/7zMain.c b/Components/Lzma2/Util/7z/7zMain.c index b9a6d53db..dd637c2e3 100644 --- a/Components/Lzma2/Util/7z/7zMain.c +++ b/Components/Lzma2/Util/7z/7zMain.c @@ -7,6 +7,7 @@ -Add specific error text for SZ_ERROR_ARCHIVE, SZ_ERROR_NO_ARCHIVE, and SZ_ERROR_PROGRESS -Return res on errors instead of always returning 1 -Add optional progress reporting with abort option + -Add optional output of SzArEx_Extract's output buffer sizes Otherwise unchanged */ #include "Precomp.h" @@ -535,6 +536,19 @@ static void PrintError_WRes(const char *message, WRes wres) PrintLF(); } +#ifdef REPORT_OUTBUFFERSIZE +static void PrintInt(const char *message, UInt64 value) +{ + Print(message); + { + char s[32]; + UInt64ToStr(value, s, 1); + Print(s); + } + PrintLF(); +} +#endif + static void GetAttribString(UInt32 wa, BoolInt isDir, char *s) { #ifdef USE_WINDOWS_FILE @@ -674,6 +688,9 @@ int Z7_CDECL mainW(int numargs, WCHAR *args[]) UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ + #ifdef REPORT_OUTBUFFERSIZE + size_t prevOutBufferSize = -1; /* it must be -1 before first call for each new archive. */ + #endif for (i = 0; i < db.NumFiles; i++) { @@ -768,6 +785,14 @@ int Z7_CDECL mainW(int numargs, WCHAR *args[]) &allocImp, &allocTempImp); if (res != SZ_OK) break; + #ifdef REPORT_OUTBUFFERSIZE + if (prevOutBufferSize == -1 || outBufferSize != prevOutBufferSize) + { + PrintLF(); + PrintInt("Used new buffer size ", outBufferSize); + prevOutBufferSize = outBufferSize; + } + #endif } if (!testCommand) diff --git a/Files/islzma32.exe b/Files/islzma32.exe index 63048e566..9b653f8a0 100644 Binary files a/Files/islzma32.exe and b/Files/islzma32.exe differ diff --git a/Files/islzma64.exe b/Files/islzma64.exe index 8e50156de..ee1b50390 100644 Binary files a/Files/islzma64.exe and b/Files/islzma64.exe differ diff --git a/ISHelp/isxfunc.xml b/ISHelp/isxfunc.xml index 7bef6be7a..b4a47aeb7 100644 --- a/ISHelp/isxfunc.xml +++ b/ISHelp/isxfunc.xml @@ -1845,7 +1845,7 @@ end; function Extract7ZipFile(const FileName, DestDir: String; const FullPaths: Boolean): Integer;

Extracts the specified 7-Zip archive to the specified directory, with or without using path names. Returns zero if successful, nonzero otherwise

The archive must not be encrypted.

-

Uses an embedded version of the "7z ANSI-C Decoder" from the LZMA SDK by Igor Pavlov, as-is, except that Unicode support was improved.

+

Uses an embedded version of the "7z ANSI-C Decoder" from the LZMA SDK by Igor Pavlov, as-is, except that Unicode support and error messages were improved and that it outputs memory requirements.

All output of the decoder is logged if logging is enabled, including error messages but excluding empty lines.

The decoder has the following limitations, as written by Igor Pavlov in the LZMA SDK:

-It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
diff --git a/Projects/Src/Compiler.CompressionHandler.pas b/Projects/Src/Compiler.CompressionHandler.pas index 54b22cfeb..9708f462e 100644 --- a/Projects/Src/Compiler.CompressionHandler.pas +++ b/Projects/Src/Compiler.CompressionHandler.pas @@ -231,15 +231,15 @@ procedure TCompressionHandler.NewChunk(const ACompressorClass: TCustomCompressor procedure TCompressionHandler.EndChunk; begin - if Assigned(FCompressor) then begin - FCompressor.Finish; - { In case we didn't get a ProgressProc call after the final block: } - FCompiler.SetBytesCompressedSoFar(FInitialBytesCompressedSoFar); - FCompiler.AddBytesCompressedSoFar(FChunkBytesRead); - FCompiler.CallIdleProc; - end; - + if not FChunkStarted then + Exit; FChunkStarted := False; + + FCompressor.Finish; + { In case we didn't get a ProgressProc call after the final block: } + FCompiler.SetBytesCompressedSoFar(FInitialBytesCompressedSoFar); + FCompiler.AddBytesCompressedSoFar(FChunkBytesRead); + FCompiler.CallIdleProc; end; procedure TCompressionHandler.CompressFile(const SourceFile: TFile; @@ -315,4 +315,4 @@ procedure TCompressionHandler.ProgressProc(BytesProcessed: Cardinal); FCompiler.CallIdleProc; end; -end. \ No newline at end of file +end. diff --git a/Projects/Src/Compression.LZMACompressor.pas b/Projects/Src/Compression.LZMACompressor.pas index 46e62f7f0..8f721a63c 100644 --- a/Projects/Src/Compression.LZMACompressor.pas +++ b/Projects/Src/Compression.LZMACompressor.pas @@ -14,7 +14,7 @@ interface uses Windows, SysUtils, - Compression.Base, Shared.Int64Em; + Compression.Base; function LZMAInitCompressFunctions(Module: HMODULE): Boolean; function LZMAGetLevel(const Value: String; var Level: Integer): Boolean; @@ -67,16 +67,14 @@ TLZMACompressorSharedEvents = record StartEncodeEvent: THandle; EndWaitOnInputEvent: THandle; EndWaitOnOutputEvent: THandle; - EndWaitOnProgressEvent: THandle; WorkerWaitingOnInputEvent: THandle; WorkerWaitingOnOutputEvent: THandle; - WorkerHasProgressEvent: THandle; WorkerEncodeFinishedEvent: THandle; end; PLZMACompressorSharedData = ^TLZMACompressorSharedData; TLZMACompressorSharedData = record + ProgressBytes: Int64; NoMoreInput: BOOL; - ProgressKB: LongWord; EncodeResult: TLZMASRes; InputBuffer: TLZMACompressorRingBuffer; OutputBuffer: TLZMACompressorRingBuffer; @@ -101,11 +99,13 @@ TLZMACompressor = class(TCustomCompressor) FEncodeStarted: Boolean; FEncodeFinished: Boolean; FLastInputWriteCount: LongWord; - FLastProgressKB: LongWord; + FLastProgressBytes: Int64; + FProgressTimer: THandle; + FProgressTimerSignaled: Boolean; procedure FlushOutputBuffer(const OnlyOptimalSize: Boolean); procedure InitializeProps(const CompressionLevel: Integer; const ACompressorProps: TCompressorProps); - class function IsEventSet(const AEvent: THandle): Boolean; + class function IsObjectSignaled(const AObject: THandle): Boolean; class procedure SatisfyWorkerWait(const AWorkerEvent, AMainEvent: THandle); procedure SatisfyWorkerWaitOnInput; procedure SatisfyWorkerWaitOnOutput; @@ -145,7 +145,7 @@ TLZMACompressorCustomWorker = class implementation const - ISLZMA_EXE_VERSION = 101; + ISLZMA_EXE_VERSION = 102; type TLZMACompressorHandle = type Pointer; @@ -155,10 +155,10 @@ TLZMAWorkerThread = class(TLZMACompressorCustomWorker) FThread: THandle; FLZMAHandle: TLZMACompressorHandle; FReadLock, FWriteLock, FProgressLock: Integer; - FLastProgressTick: DWORD; + function CheckTerminateWorkerEvent: HRESULT; function FillBuffer(const AWrite: Boolean; const Data: Pointer; Size: Cardinal; var ProcessedSize: Cardinal): HRESULT; - function ProgressMade(const TotalBytesProcessed: Integer64): HRESULT; + function ProgressMade(const TotalBytesProcessed: UInt64): HRESULT; function Read(var Data; Size: Cardinal; var ProcessedSize: Cardinal): HRESULT; function WakeMainAndWaitUntil(const AWakeEvent, AWaitEvent: THandle): HRESULT; procedure WorkerThreadProc; @@ -199,7 +199,7 @@ TLZMASeqOutStream = record end; PLZMACompressProgress = ^TLZMACompressProgress; TLZMACompressProgress = record - Progress: function(p: PLZMACompressProgress; inSize, outSize: Integer64): TLZMASRes; stdcall; + Progress: function(p: PLZMACompressProgress; inSize, outSize: UInt64): TLZMASRes; stdcall; Instance: TLZMAWorkerThread; end; @@ -223,17 +223,6 @@ TLZMACompressProgress = record SZ_ERROR_PROGRESS = 10; SZ_ERROR_FAIL = 11; -function InterlockedExchangeAdd(var Addend: Longint; Value: Longint): Longint; - stdcall; external kernel32; - -function GetNumberOfProcessors: Cardinal; -var - SysInfo: TSystemInfo; -begin - GetSystemInfo(SysInfo); - Result := SysInfo.dwNumberOfProcessors; -end; - function LZMAInitCompressFunctions(Module: HMODULE): Boolean; begin LZMADLLInitialized := False; @@ -312,7 +301,7 @@ function LZMASeqOutStreamWriteWrapper(p: PLZMASeqOutStream; const buf; end; function LZMACompressProgressProgressWrapper(p: PLZMACompressProgress; - inSize, outSize: Integer64): TLZMASRes; stdcall; + inSize, outSize: UInt64): TLZMASRes; stdcall; begin if p.Instance.ProgressMade(inSize) = S_OK then Result := SZ_OK @@ -550,6 +539,17 @@ function TLZMAWorkerThread.WakeMainAndWaitUntil(const AWakeEvent, end; end; +function TLZMAWorkerThread.CheckTerminateWorkerEvent: HRESULT; +begin + case WaitForSingleObject(FEvents.TerminateWorkerEvent, 0) of + WAIT_OBJECT_0 + 0: Result := E_ABORT; + WAIT_TIMEOUT: Result := S_OK; + else + SetEvent(FEvents.TerminateWorkerEvent); + Result := E_FAIL; + end; +end; + function TLZMAWorkerThread.FillBuffer(const AWrite: Boolean; const Data: Pointer; Size: Cardinal; var ProcessedSize: Cardinal): HRESULT; { Called from worker thread (or a thread spawned by the worker thread) } @@ -629,34 +629,22 @@ function TLZMAWorkerThread.Write(const Data; Size: Cardinal; InterlockedExchange(FWriteLock, 0); end; -function TLZMAWorkerThread.ProgressMade(const TotalBytesProcessed: Integer64): HRESULT; +function TLZMAWorkerThread.ProgressMade(const TotalBytesProcessed: UInt64): HRESULT; { Called from worker thread (or a thread spawned by the worker thread) } -var - T: DWORD; - KBProcessed: Integer64; begin - T := GetTickCount; - if Cardinal(T - FLastProgressTick) >= Cardinal(100) then begin - { Sanity check: Make sure we're the only thread inside Progress } - if InterlockedExchange(FProgressLock, 1) <> 0 then begin - Result := E_FAIL; - Exit; - end; - FLastProgressTick := T; - { Make sure TotalBytesProcessed isn't negative. LZMA's Types.h says - "-1 for size means unknown value", though I don't see any place - where LzmaEnc actually does call Progress with inSize = -1. } - if Longint(TotalBytesProcessed.Hi) >= 0 then begin - KBProcessed := TotalBytesProcessed; - Div64(KBProcessed, 1024); - FShared.ProgressKB := KBProcessed.Lo; - end; - Result := WakeMainAndWaitUntil(FEvents.WorkerHasProgressEvent, - FEvents.EndWaitOnProgressEvent); - InterlockedExchange(FProgressLock, 0); - end - else - Result := S_OK; + { Sanity check: Make sure we're the only thread inside Progress } + if InterlockedExchange(FProgressLock, 1) <> 0 then begin + Result := E_FAIL; + Exit; + end; + { An Interlocked function is used to ensure the 64-bit value is written + atomically (not with two separate 32-bit writes). + TLZMACompressor will ignore negative values. LZMA SDK's 7zTypes.h says + "-1 for size means unknown value", though I don't see any place + where LzmaEnc actually does call Progress with inSize = -1. } + InterlockedExchange64(FShared.ProgressBytes, Int64(TotalBytesProcessed)); + Result := CheckTerminateWorkerEvent; + InterlockedExchange(FProgressLock, 0); end; { TLZMAWorkerProcess } @@ -727,10 +715,8 @@ procedure TLZMAWorkerProcess.SetProps(const LZMA2: Boolean; DupeEvent(Src.StartEncodeEvent, Dest.StartEncodeEvent); DupeEvent(Src.EndWaitOnInputEvent, Dest.EndWaitOnInputEvent); DupeEvent(Src.EndWaitOnOutputEvent, Dest.EndWaitOnOutputEvent); - DupeEvent(Src.EndWaitOnProgressEvent, Dest.EndWaitOnProgressEvent); DupeEvent(Src.WorkerWaitingOnInputEvent, Dest.WorkerWaitingOnInputEvent); DupeEvent(Src.WorkerWaitingOnOutputEvent, Dest.WorkerWaitingOnOutputEvent); - DupeEvent(Src.WorkerHasProgressEvent, Dest.WorkerHasProgressEvent); DupeEvent(Src.WorkerEncodeFinishedEvent, Dest.WorkerEncodeFinishedEvent); end; @@ -820,11 +806,12 @@ constructor TLZMACompressor.Create(AWriteProc: TCompressorWriteProc; FEvents.StartEncodeEvent := LZMACreateEvent(False); { auto reset } FEvents.EndWaitOnInputEvent := LZMACreateEvent(False); { auto reset } FEvents.EndWaitOnOutputEvent := LZMACreateEvent(False); { auto reset } - FEvents.EndWaitOnProgressEvent := LZMACreateEvent(False); { auto reset } FEvents.WorkerWaitingOnInputEvent := LZMACreateEvent(True); { manual reset } FEvents.WorkerWaitingOnOutputEvent := LZMACreateEvent(True); { manual reset } - FEvents.WorkerHasProgressEvent := LZMACreateEvent(True); { manual reset } FEvents.WorkerEncodeFinishedEvent := LZMACreateEvent(True); { manual reset } + FProgressTimer := CreateWaitableTimer(nil, False, nil); { auto reset } + if FProgressTimer = 0 then + LZMAWin32Error('CreateWaitableTimer'); InitializeProps(CompressionLevel, ACompressorProps); end; @@ -838,11 +825,10 @@ destructor TLZMACompressor.Destroy; begin FWorker.Free; + DestroyEvent(FProgressTimer); DestroyEvent(FEvents.WorkerEncodeFinishedEvent); - DestroyEvent(FEvents.WorkerHasProgressEvent); DestroyEvent(FEvents.WorkerWaitingOnOutputEvent); DestroyEvent(FEvents.WorkerWaitingOnInputEvent); - DestroyEvent(FEvents.EndWaitOnProgressEvent); DestroyEvent(FEvents.EndWaitOnOutputEvent); DestroyEvent(FEvents.EndWaitOnInputEvent); DestroyEvent(FEvents.StartEncodeEvent); @@ -907,21 +893,21 @@ procedure TLZMACompressor.InitializeProps(const CompressionLevel: Integer; FWorker.SetProps(FUseLZMA2, EncProps); end; -class function TLZMACompressor.IsEventSet(const AEvent: THandle): Boolean; +class function TLZMACompressor.IsObjectSignaled(const AObject: THandle): Boolean; begin Result := False; - case WaitForSingleObject(AEvent, 0) of + case WaitForSingleObject(AObject, 0) of WAIT_OBJECT_0: Result := True; WAIT_TIMEOUT: ; else - LZMAInternalError('IsEventSet: WaitForSingleObject failed'); + LZMAInternalError('IsObjectSignaled: WaitForSingleObject failed'); end; end; class procedure TLZMACompressor.SatisfyWorkerWait(const AWorkerEvent, AMainEvent: THandle); begin - if IsEventSet(AWorkerEvent) then begin + if IsObjectSignaled(AWorkerEvent) then begin if not ResetEvent(AWorkerEvent) then LZMAWin32Error('SatisfyWorkerWait: ResetEvent'); if not SetEvent(AMainEvent) then @@ -940,28 +926,42 @@ procedure TLZMACompressor.SatisfyWorkerWaitOnOutput; end; procedure TLZMACompressor.UpdateProgress; +const + MaxBytesPerProgressProcCall = 1 shl 30; { 1 GB } var - NewProgressKB: LongWord; - Bytes: Integer64; + NewProgressBytes, Bytes: Int64; + LimitedBytes: Cardinal; begin - if IsEventSet(FEvents.WorkerHasProgressEvent) then begin + { Check if the timer is signaled. Because it's an auto-reset timer, this + also resets it to non-signaled. Note that WaitForWorkerEvent also waits + on the timer and sets FProgressTimerSignaled. } + if IsObjectSignaled(FProgressTimer) then + FProgressTimerSignaled := True; + + if FProgressTimerSignaled then begin + FProgressTimerSignaled := False; if Assigned(ProgressProc) then begin - NewProgressKB := FShared.ProgressKB; - Bytes.Hi := 0; - Bytes.Lo := NewProgressKB - FLastProgressKB; { wraparound is OK } - Mul64(Bytes, 1024); - FLastProgressKB := NewProgressKB; - while Bytes.Hi <> 0 do begin - ProgressProc(Cardinal($80000000)); - ProgressProc(Cardinal($80000000)); - Dec(Bytes.Hi); - end; - ProgressProc(Bytes.Lo); + { An Interlocked function is used to ensure the 64-bit value is read + atomically (not with two separate 32-bit reads). } + NewProgressBytes := InterlockedExchangeAdd64(FShared.ProgressBytes, 0); + + { Make sure the new value isn't negative or going backwards. A call + to ProgressProc is always made, even if the byte count is 0. } + if NewProgressBytes > FLastProgressBytes then begin + Bytes := NewProgressBytes - FLastProgressBytes; + FLastProgressBytes := NewProgressBytes; + end else + Bytes := 0; + + repeat + if Bytes >= MaxBytesPerProgressProcCall then + LimitedBytes := MaxBytesPerProgressProcCall + else + LimitedBytes := Cardinal(Bytes); + ProgressProc(LimitedBytes); + Dec(Bytes, LimitedBytes); + until Bytes = 0; end; - if not ResetEvent(FEvents.WorkerHasProgressEvent) then - LZMAWin32Error('UpdateProgress: ResetEvent'); - if not SetEvent(FEvents.EndWaitOnProgressEvent) then - LZMAWin32Error('UpdateProgress: SetEvent'); end; end; @@ -993,19 +993,39 @@ procedure TLZMACompressor.FlushOutputBuffer(const OnlyOptimalSize: Boolean); end; procedure TLZMACompressor.StartEncode; + + procedure StartProgressTimer; + const + { This interval was chosen because: + - It's two system timer ticks, rounded up: + (1000 / 64) * 2 = 31.25 + - The keyboard repeat rate is 30/s by default: + 1000 / 30 = 33.333 + So if an edit control is focused and the ProgressProc is processing + messages, the caret should move at full speed when an arrow key is + held down. } + Interval = 32; + begin + FProgressTimerSignaled := False; + var DueTime := Int64(-10000) * Interval; + if not SetWaitableTimer(FProgressTimer, DueTime, Interval, nil, nil, False) then + LZMAWin32Error('SetWaitableTimer'); + end; + begin if not FEncodeStarted then begin FShared.NoMoreInput := False; - FShared.ProgressKB := 0; + FShared.ProgressBytes := 0; FShared.EncodeResult := -1; RingBufferReset(FShared.InputBuffer); RingBufferReset(FShared.OutputBuffer); FLastInputWriteCount := 0; - FLastProgressKB := 0; + FLastProgressBytes := 0; FEncodeFinished := False; FEncodeStarted := True; if not ResetEvent(FEvents.WorkerEncodeFinishedEvent) then LZMAWin32Error('StartEncode: ResetEvent'); + StartProgressTimer; if not SetEvent(FEvents.StartEncodeEvent) then LZMAWin32Error('StartEncode: SetEvent'); end; @@ -1026,13 +1046,13 @@ procedure TLZMACompressor.WaitForWorkerEvent; events. } H[0] := FWorker.GetExitHandle; H[1] := FEvents.WorkerEncodeFinishedEvent; - H[2] := FEvents.WorkerHasProgressEvent; + H[2] := FProgressTimer; H[3] := FEvents.WorkerWaitingOnInputEvent; H[4] := FEvents.WorkerWaitingOnOutputEvent; case WaitForMultipleObjects(5, @H, False, INFINITE) of WAIT_OBJECT_0 + 0: FWorker.UnexpectedTerminationError; WAIT_OBJECT_0 + 1: FEncodeFinished := True; - WAIT_OBJECT_0 + 2, + WAIT_OBJECT_0 + 2: FProgressTimerSignaled := True; WAIT_OBJECT_0 + 3, WAIT_OBJECT_0 + 4: ; else @@ -1120,6 +1140,8 @@ procedure TLZMACompressor.DoFinish; [FShared.InputBuffer.Count]); FEncodeStarted := False; + if not CancelWaitableTimer(FProgressTimer) then + LZMAWin32Error('CancelWaitableTimer'); end; { TLZMA2Compressor } diff --git a/Projects/Src/Compression.LZMACompressor/islzma/islzma_exe.c b/Projects/Src/Compression.LZMACompressor/islzma/islzma_exe.c index e780a928a..768ca4f8c 100644 --- a/Projects/Src/Compression.LZMACompressor/islzma/islzma_exe.c +++ b/Projects/Src/Compression.LZMACompressor/islzma/islzma_exe.c @@ -10,8 +10,9 @@ LZMA.pas revision 1.49.2.3. Intentional deviations from the original Pascal code: - - The WaitForMultipleObjects() calls in WakeMainAndWaitUntil and - BeginEncode additionally wait on ProcessData.ParentProcess. + - The WaitForMultipleObjects() calls in WakeMainAndWaitUntil, + CheckTerminateWorkerEvent, and BeginEncode additionally wait on + ProcessData.ParentProcess. Everything else *should* be 100% consistent. */ @@ -20,7 +21,7 @@ #include "../../../../Components/Lzma2/7zTypes.h" #include "islzma.h" -#define ISLZMA_EXE_VERSION 101 +#define ISLZMA_EXE_VERSION 102 typedef BYTE Byte; typedef LONG Longint; @@ -41,16 +42,14 @@ struct TLZMACompressorSharedEvents { THandle32 StartEncodeEvent; THandle32 EndWaitOnInputEvent; THandle32 EndWaitOnOutputEvent; - THandle32 EndWaitOnProgressEvent; THandle32 WorkerWaitingOnInputEvent; THandle32 WorkerWaitingOnOutputEvent; - THandle32 WorkerHasProgressEvent; THandle32 WorkerEncodeFinishedEvent; }; struct TLZMACompressorSharedData { + volatile Int64 ProgressBytes; volatile BOOL NoMoreInput; - volatile LongWord ProgressKB; volatile SRes EncodeResult; struct TLZMACompressorRingBuffer InputBuffer; struct TLZMACompressorRingBuffer OutputBuffer; @@ -70,7 +69,6 @@ static struct TLZMACompressorProcessData ProcessData; static struct TLZMACompressorSharedEvents *FEvents; static struct TLZMACompressorSharedData *FShared; static volatile LONG FReadLock, FWriteLock, FProgressLock; -static volatile DWORD FLastProgressTick; static Longint RingBufferInternalWriteOrRead(struct TLZMACompressorRingBuffer *Ring, const BOOL AWrite, Longint *Offset, void *Data, Longint Size) @@ -158,6 +156,24 @@ static HRESULT WakeMainAndWaitUntil(HANDLE AWakeEvent, HANDLE AWaitEvent) } } +static HRESULT CheckTerminateWorkerEvent(void) +{ + HANDLE H[2]; + + H[0] = THandle32ToHandle(FEvents->TerminateWorkerEvent); + H[1] = THandle32ToHandle(ProcessData.ParentProcess); + switch (WaitForMultipleObjects(2, H, FALSE, 0)) { + case WAIT_OBJECT_0 + 0: + case WAIT_OBJECT_0 + 1: + return E_ABORT; + case WAIT_TIMEOUT: + return S_OK; + default: + SetEvent(THandle32ToHandle(FEvents->TerminateWorkerEvent)); + return E_FAIL; + } +} + static HRESULT FillBuffer(const BOOL AWrite, void *Data, size_t Size, size_t *ProcessedSize) /* Called from worker thread (or a thread spawned by the worker thread) */ @@ -244,32 +260,20 @@ static HRESULT Write(const void *Data, size_t Size, size_t *ProcessedSize) static HRESULT ProgressMade(const UInt64 TotalBytesProcessed) /* Called from worker thread (or a thread spawned by the worker thread) */ { - DWORD T; - UInt64 KBProcessed; HRESULT Result; - T = GetTickCount(); - if (T - FLastProgressTick >= 100) { - /* Sanity check: Make sure we're the only thread inside Progress */ - if (InterlockedExchange(&FProgressLock, 1) != 0) { - return E_FAIL; - } - FLastProgressTick = T; - /* Make sure TotalBytesProcessed isn't negative. LZMA's Types.h says - "-1 for size means unknown value", though I don't see any place - where LzmaEnc actually does call Progress with inSize = -1. */ - if ((Int64)TotalBytesProcessed >= 0) { - KBProcessed = TotalBytesProcessed; - KBProcessed /= 1024; - FShared->ProgressKB = (LongWord)KBProcessed; - } - Result = WakeMainAndWaitUntil( - THandle32ToHandle(FEvents->WorkerHasProgressEvent), - THandle32ToHandle(FEvents->EndWaitOnProgressEvent)); - InterlockedExchange(&FProgressLock, 0); - } else { - Result = S_OK; + /* Sanity check: Make sure we're the only thread inside Progress */ + if (InterlockedExchange(&FProgressLock, 1) != 0) { + return E_FAIL; } + /* An Interlocked function is used to ensure the 64-bit value is written + atomically (not with two separate 32-bit writes). + TLZMACompressor will ignore negative values. LZMA SDK's 7zTypes.h says + "-1 for size means unknown value", though I don't see any place + where LzmaEnc actually does call Progress with inSize = -1. */ + InterlockedExchange64(&FShared->ProgressBytes, (Int64)TotalBytesProcessed); + Result = CheckTerminateWorkerEvent(); + InterlockedExchange(&FProgressLock, 0); return Result; } diff --git a/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.c b/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.c index 31f4e9985..a074030d5 100644 --- a/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.c +++ b/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.c @@ -86,6 +86,7 @@ int _fputs(char const* str, FILE* stream); /* Include all needed SDK code. None of these require changes for the helper function to work but 7zMain.c was changed for better Unicode support */ +#define REPORT_OUTBUFFERSIZE #define REPORT_PROGRESS #include "../../../../Components/Lzma2/Util/7z/7zMain.c" diff --git a/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.obj b/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.obj index 0e233961a..df6c6e655 100644 Binary files a/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.obj and b/Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.obj differ