LZMADecompSmall.pas 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. unit LZMADecompSmall;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2010 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Interface to the older, size-optimized LZMA SDK 4.43 decompression OBJ in
  8. LzmaDecode, used by SetupLdr.
  9. }
  10. interface
  11. {$I VERSION.INC}
  12. uses
  13. Windows, SysUtils, Compress, Int64Em;
  14. type
  15. { Internally-used record }
  16. TLZMAInternalDecoderState = record
  17. { NOTE: None of these fields are ever accessed directly by this unit.
  18. They are exposed purely for debugging purposes. }
  19. opaque_Properties: record
  20. lc: Integer;
  21. lp: Integer;
  22. pb: Integer;
  23. DictionarySize: LongWord;
  24. end;
  25. opaque_Probs: Pointer;
  26. opaque_Buffer: Pointer;
  27. opaque_BufferLim: Pointer;
  28. opaque_Dictionary: Pointer;
  29. opaque_Range: LongWord;
  30. opaque_Code: LongWord;
  31. opaque_DictionaryPos: LongWord;
  32. opaque_GlobalPos: LongWord;
  33. opaque_DistanceLimit: LongWord;
  34. opaque_Reps: array[0..3] of LongWord;
  35. opaque_State: Integer;
  36. opaque_RemainLen: Integer;
  37. opaque_TempDictionary: array[0..3] of Byte;
  38. end;
  39. TLZMA1SmallDecompressor = class(TCustomDecompressor)
  40. private
  41. FReachedEnd: Boolean;
  42. FHeaderProcessed: Boolean;
  43. FDecoderState: TLZMAInternalDecoderState;
  44. FHeapBase: Pointer;
  45. FHeapSize: Cardinal;
  46. FBuffer: array[0..65535] of Byte;
  47. procedure DestroyHeap;
  48. procedure DoRead(var Buffer: Pointer; var BufferSize: Cardinal);
  49. procedure ProcessHeader;
  50. public
  51. destructor Destroy; override;
  52. procedure DecompressInto(var Buffer; Count: Longint); override;
  53. procedure Reset; override;
  54. end;
  55. implementation
  56. const
  57. SLZMADataError = 'lzmadecompsmall: Compressed data is corrupted (%d)';
  58. procedure LZMADataError(const Id: Integer);
  59. begin
  60. raise ECompressDataError.CreateFmt(SLZMADataError, [Id]);
  61. end;
  62. procedure LZMAInternalError(const Msg: String);
  63. begin
  64. raise ECompressInternalError.CreateFmt('lzmadecompsmall: %s', [Msg]);
  65. end;
  66. procedure LZMAInternalErrorFmt(const Msg: String; const Args: array of const);
  67. begin
  68. LZMAInternalError(Format(Msg, Args));
  69. end;
  70. { TLZMA1SmallDecompressor }
  71. {$L LzmaDecode\LzmaDecodeInno.obj}
  72. type
  73. TLzmaInCallback = record
  74. Read: function(obj: Pointer; var buffer: Pointer; var bufferSize: Cardinal): Integer;
  75. end;
  76. const
  77. LZMA_RESULT_OK = 0;
  78. LZMA_RESULT_DATA_ERROR = 1;
  79. LZMA_PROPERTIES_SIZE = 5;
  80. function LzmaMyDecodeProperties(var vs: TLZMAInternalDecoderState;
  81. vsSize: Integer; const propsData; propsDataSize: Integer;
  82. var outPropsSize: LongWord; var outDictionarySize: LongWord): Integer; external;
  83. procedure LzmaMyDecoderInit(var vs: TLZMAInternalDecoderState;
  84. probsPtr: Pointer; dictionaryPtr: Pointer); external;
  85. function LzmaDecode(var vs: TLZMAInternalDecoderState;
  86. var inCallback: TLzmaInCallback; var outStream; outSize: Cardinal;
  87. var outSizeProcessed: Cardinal): Integer; external;
  88. type
  89. TLZMADecompressorCallbackData = record
  90. Callback: TLzmaInCallback;
  91. Instance: TLZMA1SmallDecompressor;
  92. end;
  93. function ReadFunc(obj: Pointer; var buffer: Pointer; var bufferSize: Cardinal): Integer;
  94. begin
  95. TLZMADecompressorCallbackData(obj^).Instance.DoRead(buffer, bufferSize);
  96. { Don't bother returning any sort of failure code, because if DoRead failed,
  97. it would've raised an exception }
  98. Result := LZMA_RESULT_OK;
  99. end;
  100. destructor TLZMA1SmallDecompressor.Destroy;
  101. begin
  102. DestroyHeap;
  103. inherited;
  104. end;
  105. procedure TLZMA1SmallDecompressor.DestroyHeap;
  106. begin
  107. FHeapSize := 0;
  108. if Assigned(FHeapBase) then begin
  109. VirtualFree(FHeapBase, 0, MEM_RELEASE);
  110. FHeapBase := nil;
  111. end;
  112. end;
  113. procedure TLZMA1SmallDecompressor.DoRead(var Buffer: Pointer; var BufferSize: Cardinal);
  114. begin
  115. Buffer := @FBuffer;
  116. BufferSize := 0;
  117. if not FReachedEnd then begin
  118. BufferSize := ReadProc(FBuffer, SizeOf(FBuffer));
  119. if BufferSize = 0 then
  120. FReachedEnd := True; { not really necessary, but for consistency }
  121. end;
  122. end;
  123. procedure TLZMA1SmallDecompressor.ProcessHeader;
  124. var
  125. Props: array[0..LZMA_PROPERTIES_SIZE-1] of Byte;
  126. ProbsSize, DictionarySize: LongWord;
  127. NewHeapSize: Cardinal;
  128. begin
  129. { Read header fields }
  130. if ReadProc(Props, SizeOf(Props)) <> SizeOf(Props) then
  131. LZMADataError(1);
  132. { Initialize the LZMA decoder state structure, and calculate the size of
  133. the Probs and Dictionary }
  134. FillChar(FDecoderState, SizeOf(FDecoderState), 0);
  135. if LzmaMyDecodeProperties(FDecoderState, SizeOf(FDecoderState), Props,
  136. SizeOf(Props), ProbsSize, DictionarySize) <> LZMA_RESULT_OK then
  137. LZMADataError(3);
  138. if DictionarySize > LongWord(64 shl 20) then
  139. { sanity check: we only use dictionary sizes <= 64 MB }
  140. LZMADataError(7);
  141. { Allocate memory for the Probs and Dictionary, and pass the pointers over }
  142. NewHeapSize := ProbsSize + DictionarySize;
  143. if FHeapSize <> NewHeapSize then begin
  144. DestroyHeap;
  145. FHeapBase := VirtualAlloc(nil, NewHeapSize, MEM_COMMIT, PAGE_READWRITE);
  146. if FHeapBase = nil then
  147. OutOfMemoryError;
  148. FHeapSize := NewHeapSize;
  149. end;
  150. LzmaMyDecoderInit(FDecoderState, FHeapBase, Pointer(Cardinal(FHeapBase) + ProbsSize));
  151. FHeaderProcessed := True;
  152. end;
  153. procedure TLZMA1SmallDecompressor.DecompressInto(var Buffer; Count: Longint);
  154. var
  155. CallbackData: TLZMADecompressorCallbackData;
  156. Code: Integer;
  157. OutProcessed: Cardinal;
  158. begin
  159. if not FHeaderProcessed then
  160. ProcessHeader;
  161. CallbackData.Callback.Read := ReadFunc;
  162. CallbackData.Instance := Self;
  163. Code := LzmaDecode(FDecoderState, CallbackData.Callback, Buffer, Count,
  164. OutProcessed);
  165. case Code of
  166. LZMA_RESULT_OK: ;
  167. LZMA_RESULT_DATA_ERROR: LZMADataError(5);
  168. else
  169. LZMAInternalErrorFmt('LzmaDecode failed (%d)', [Code]);
  170. end;
  171. if OutProcessed <> Cardinal(Count) then
  172. LZMADataError(6);
  173. end;
  174. procedure TLZMA1SmallDecompressor.Reset;
  175. begin
  176. FHeaderProcessed := False;
  177. FReachedEnd := False;
  178. end;
  179. end.