123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- unit Compression.LZMA1SmallDecompressor;
- {
- Inno Setup
- Copyright (C) 1997-2024 Jordan Russell
- Portions by Martijn Laan
- For conditions of distribution and use, see LICENSE.TXT.
- Interface to the older, size-optimized LZMA SDK 4.43 decompression OBJ in
- Compression.LZMA1SmallDecompressor\LzmaDecode, used by SetupLdr.
- }
- interface
- uses
- Windows, SysUtils, Compression.Base, Shared.Int64Em;
- type
- { Internally-used record }
- TLZMAInternalDecoderState = record
- { NOTE: None of these fields are ever accessed directly by this unit.
- They are exposed purely for debugging purposes. }
- opaque_Properties: record
- lc: Integer;
- lp: Integer;
- pb: Integer;
- DictionarySize: LongWord;
- end;
- opaque_Probs: Pointer;
- opaque_Buffer: Pointer;
- opaque_BufferLim: Pointer;
- opaque_Dictionary: Pointer;
- opaque_Range: LongWord;
- opaque_Code: LongWord;
- opaque_DictionaryPos: LongWord;
- opaque_GlobalPos: LongWord;
- opaque_DistanceLimit: LongWord;
- opaque_Reps: array[0..3] of LongWord;
- opaque_State: Integer;
- opaque_RemainLen: Integer;
- opaque_TempDictionary: array[0..3] of Byte;
- end;
- TLZMA1SmallDecompressor = class(TCustomDecompressor)
- private
- FReachedEnd: Boolean;
- FHeaderProcessed: Boolean;
- FDecoderState: TLZMAInternalDecoderState;
- FHeapBase: Pointer;
- FHeapSize: Cardinal;
- FBuffer: array[0..65535] of Byte;
- procedure DestroyHeap;
- procedure DoRead(var Buffer: Pointer; var BufferSize: Cardinal);
- procedure ProcessHeader;
- public
- destructor Destroy; override;
- procedure DecompressInto(var Buffer; Count: Longint); override;
- procedure Reset; override;
- end;
- implementation
- const
- SLZMADataError = 'lzma1smalldecompressor: Compressed data is corrupted (%d)';
- procedure LZMADataError(const Id: Integer);
- begin
- raise ECompressDataError.CreateFmt(SLZMADataError, [Id]);
- end;
- procedure LZMAInternalError(const Msg: String);
- begin
- raise ECompressInternalError.CreateFmt('lzma1smalldecompressor: %s', [Msg]);
- end;
- procedure LZMAInternalErrorFmt(const Msg: String; const Args: array of const);
- begin
- LZMAInternalError(Format(Msg, Args));
- end;
- { TLZMA1SmallDecompressor }
- {$L Src\Compression.LZMA1SmallDecompressor\LzmaDecode\LzmaDecodeInno.obj}
- type
- TLzmaInCallback = record
- Read: function(obj: Pointer; var buffer: Pointer; var bufferSize: Cardinal): Integer; cdecl;
- end;
- const
- LZMA_RESULT_OK = 0;
- LZMA_RESULT_DATA_ERROR = 1;
- LZMA_PROPERTIES_SIZE = 5;
- function LzmaMyDecodeProperties(var vs: TLZMAInternalDecoderState;
- vsSize: Integer; const propsData; propsDataSize: Integer;
- var outPropsSize: LongWord; var outDictionarySize: LongWord): Integer; cdecl; external name '_LzmaMyDecodeProperties';
- procedure LzmaMyDecoderInit(var vs: TLZMAInternalDecoderState;
- probsPtr: Pointer; dictionaryPtr: Pointer); cdecl; external name '_LzmaMyDecoderInit';
- function LzmaDecode(var vs: TLZMAInternalDecoderState;
- var inCallback: TLzmaInCallback; var outStream; outSize: Cardinal;
- var outSizeProcessed: Cardinal): Integer; cdecl; external name '_LzmaDecode';
- type
- TLZMADecompressorCallbackData = record
- Callback: TLzmaInCallback;
- Instance: TLZMA1SmallDecompressor;
- end;
- function ReadFunc(obj: Pointer; var buffer: Pointer; var bufferSize: Cardinal): Integer; cdecl;
- begin
- TLZMADecompressorCallbackData(obj^).Instance.DoRead(buffer, bufferSize);
- { Don't bother returning any sort of failure code, because if DoRead failed,
- it would've raised an exception }
- Result := LZMA_RESULT_OK;
- end;
- destructor TLZMA1SmallDecompressor.Destroy;
- begin
- DestroyHeap;
- inherited;
- end;
- procedure TLZMA1SmallDecompressor.DestroyHeap;
- begin
- FHeapSize := 0;
- if Assigned(FHeapBase) then begin
- VirtualFree(FHeapBase, 0, MEM_RELEASE);
- FHeapBase := nil;
- end;
- end;
- procedure TLZMA1SmallDecompressor.DoRead(var Buffer: Pointer; var BufferSize: Cardinal);
- begin
- Buffer := @FBuffer;
- BufferSize := 0;
- if not FReachedEnd then begin
- BufferSize := ReadProc(FBuffer, SizeOf(FBuffer));
- if BufferSize = 0 then
- FReachedEnd := True; { not really necessary, but for consistency }
- end;
- end;
- procedure TLZMA1SmallDecompressor.ProcessHeader;
- var
- Props: array[0..LZMA_PROPERTIES_SIZE-1] of Byte;
- ProbsSize, DictionarySize: LongWord;
- NewHeapSize: Cardinal;
- begin
- { Read header fields }
- if ReadProc(Props, SizeOf(Props)) <> SizeOf(Props) then
- LZMADataError(1);
- { Initialize the LZMA decoder state structure, and calculate the size of
- the Probs and Dictionary }
- FillChar(FDecoderState, SizeOf(FDecoderState), 0);
- if LzmaMyDecodeProperties(FDecoderState, SizeOf(FDecoderState), Props,
- SizeOf(Props), ProbsSize, DictionarySize) <> LZMA_RESULT_OK then
- LZMADataError(3);
- if DictionarySize > LongWord(64 shl 20) then
- { sanity check: we only use dictionary sizes <= 64 MB }
- LZMADataError(7);
- { Allocate memory for the Probs and Dictionary, and pass the pointers over }
- NewHeapSize := ProbsSize + DictionarySize;
- if FHeapSize <> NewHeapSize then begin
- DestroyHeap;
- FHeapBase := VirtualAlloc(nil, NewHeapSize, MEM_COMMIT, PAGE_READWRITE);
- if FHeapBase = nil then
- OutOfMemoryError;
- FHeapSize := NewHeapSize;
- end;
- LzmaMyDecoderInit(FDecoderState, FHeapBase, Pointer(Cardinal(FHeapBase) + ProbsSize));
- FHeaderProcessed := True;
- end;
- procedure TLZMA1SmallDecompressor.DecompressInto(var Buffer; Count: Longint);
- var
- CallbackData: TLZMADecompressorCallbackData;
- Code: Integer;
- OutProcessed: Cardinal;
- begin
- if not FHeaderProcessed then
- ProcessHeader;
- CallbackData.Callback.Read := ReadFunc;
- CallbackData.Instance := Self;
- Code := LzmaDecode(FDecoderState, CallbackData.Callback, Buffer, Count,
- OutProcessed);
- case Code of
- LZMA_RESULT_OK: ;
- LZMA_RESULT_DATA_ERROR: LZMADataError(5);
- else
- LZMAInternalErrorFmt('LzmaDecode failed (%d)', [Code]);
- end;
- if OutProcessed <> Cardinal(Count) then
- LZMADataError(6);
- end;
- procedure TLZMA1SmallDecompressor.Reset;
- begin
- FHeaderProcessed := False;
- FReachedEnd := False;
- end;
- end.
|