LZMADecomp.pas 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. unit LZMADecomp;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2012 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Interface to the "new" LZMA/LZMA2 SDK decompression OBJs in lzma2\Decoder,
  8. used by Setup.
  9. }
  10. interface
  11. {$I VERSION.INC}
  12. uses
  13. Windows, SysUtils, Int64Em, Compress;
  14. type
  15. TLZMACustomDecompressor = class(TCustomDecompressor)
  16. private
  17. FReachedEnd: Boolean;
  18. FHeaderProcessed: Boolean;
  19. FNextIn: ^Byte;
  20. FAvailIn: Cardinal;
  21. FBuffer: array[0..65535] of Byte;
  22. protected
  23. function DecodeToBuf(var Dest; var DestLen: Cardinal; const Src;
  24. var SrcLen: Cardinal; var Status: Integer): Integer; virtual; abstract;
  25. procedure FreeDecoder; virtual; abstract;
  26. procedure ProcessHeader; virtual; abstract;
  27. public
  28. destructor Destroy; override;
  29. procedure DecompressInto(var Buffer; Count: Longint); override;
  30. procedure Reset; override;
  31. end;
  32. { Internally-used records }
  33. TLZMA1InternalDecoderState = array[0..27] of LongWord;
  34. TLZMA2InternalDecoderState = array[0..34] of LongWord;
  35. TLZMA1Decompressor = class(TLZMACustomDecompressor)
  36. private
  37. FDecoderState: TLZMA1InternalDecoderState;
  38. protected
  39. function DecodeToBuf(var Dest; var DestLen: Cardinal; const Src;
  40. var SrcLen: Cardinal; var Status: Integer): Integer; override;
  41. procedure FreeDecoder; override;
  42. procedure ProcessHeader; override;
  43. end;
  44. TLZMA2Decompressor = class(TLZMACustomDecompressor)
  45. private
  46. FDecoderState: TLZMA2InternalDecoderState;
  47. protected
  48. function DecodeToBuf(var Dest; var DestLen: Cardinal; const Src;
  49. var SrcLen: Cardinal; var Status: Integer): Integer; override;
  50. procedure FreeDecoder; override;
  51. procedure ProcessHeader; override;
  52. end;
  53. implementation
  54. type
  55. TLZMASRes = type Integer;
  56. PLZMAISzAlloc = ^TLZMAISzAlloc;
  57. TLZMAISzAlloc = record
  58. Alloc: function(p: PLZMAISzAlloc; size: Cardinal): Pointer;
  59. Free: procedure(p: PLZMAISzAlloc; address: Pointer);
  60. end;
  61. const
  62. { SRes (TLZMASRes) }
  63. SZ_OK = 0;
  64. SZ_ERROR_DATA = 1;
  65. SZ_ERROR_MEM = 2;
  66. { ELzmaFinishMode }
  67. LZMA_FINISH_ANY = 0;
  68. LZMA_FINISH_END = 1;
  69. { ELzmaStatus }
  70. LZMA_STATUS_NOT_SPECIFIED = 0;
  71. LZMA_STATUS_FINISHED_WITH_MARK = 1;
  72. LZMA_STATUS_NOT_FINISHED = 2;
  73. LZMA_STATUS_NEEDS_MORE_INPUT = 3;
  74. LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK = 4;
  75. SLZMADecompDataError = 'lzmadecomp: Compressed data is corrupted (%d)';
  76. { To ensure we don't allocate inordinate amounts of memory in the event a
  77. stream's header is corrupted, we limit the dictionary size to the maximum
  78. size the compiler currently allows. }
  79. MaxDictionarySize = 1024 shl 20; { 1 GB }
  80. {$L lzma2\Decoder\ISLzmaDec.obj}
  81. {$L lzma2\Decoder\ISLzma2Dec.obj}
  82. function IS_LzmaDec_Init(var state: TLZMA1InternalDecoderState;
  83. stateSize: Cardinal; const props; propsSize: Cardinal;
  84. const alloc: TLZMAISzAlloc): TLZMASRes; external;
  85. function LzmaDec_DecodeToBuf(var state: TLZMA1InternalDecoderState; var dest;
  86. var destLen: Cardinal; const src; var srcLen: Cardinal; finishMode: Integer;
  87. var status: Integer): TLZMASRes; external;
  88. procedure LzmaDec_Free(var state: TLZMA1InternalDecoderState;
  89. const alloc: TLZMAISzAlloc); external;
  90. function IS_Lzma2Dec_Init(var state: TLZMA2InternalDecoderState;
  91. stateSize: Cardinal; prop: Byte; const alloc: TLZMAISzAlloc): TLZMASRes;
  92. external;
  93. function Lzma2Dec_DecodeToBuf(var state: TLZMA2InternalDecoderState; var dest;
  94. var destLen: Cardinal; const src; var srcLen: Cardinal; finishMode: Integer;
  95. var status: Integer): TLZMASRes; external;
  96. procedure IS_Lzma2Dec_Free(var state: TLZMA2InternalDecoderState;
  97. const alloc: TLZMAISzAlloc); external;
  98. procedure LzmaDec_Allocate; external;
  99. procedure LzmaDec_AllocateProbs; external;
  100. procedure LzmaDec_DecodeToDic; external;
  101. procedure LzmaDec_FreeProbs; external;
  102. procedure LzmaDec_Init; external;
  103. procedure LzmaDec_InitDicAndState; external;
  104. procedure LzmaProps_Decode; external;
  105. procedure LZMADecompInternalError(const Msg: String);
  106. begin
  107. raise ECompressInternalError.CreateFmt('lzmadecomp: %s', [Msg]);
  108. end;
  109. procedure LZMADecompDataError(const Id: Integer);
  110. begin
  111. raise ECompressDataError.CreateFmt(SLZMADecompDataError, [Id]);
  112. end;
  113. function LZMAAllocFunc(p: PLZMAISzAlloc; size: Cardinal): Pointer;
  114. begin
  115. if (size <> 0) and (size <= Cardinal(MaxDictionarySize)) then
  116. Result := VirtualAlloc(nil, size, MEM_COMMIT, PAGE_READWRITE)
  117. else
  118. Result := nil;
  119. end;
  120. procedure LZMAFreeFunc(p: PLZMAISzAlloc; address: Pointer);
  121. begin
  122. if Assigned(address) then
  123. VirtualFree(address, 0, MEM_RELEASE);
  124. end;
  125. const
  126. LZMAAlloc: TLZMAISzAlloc = (Alloc: LZMAAllocFunc; Free: LZMAFreeFunc);
  127. function _memcpy(dest, src: Pointer; n: Cardinal): Pointer; cdecl;
  128. begin
  129. Move(src^, dest^, n);
  130. Result := dest;
  131. end;
  132. { TLZMACustomDecompressor }
  133. destructor TLZMACustomDecompressor.Destroy;
  134. begin
  135. FreeDecoder;
  136. inherited;
  137. end;
  138. procedure TLZMACustomDecompressor.DecompressInto(var Buffer; Count: Longint);
  139. var
  140. NextOut: ^Byte;
  141. AvailOut: Longint;
  142. OutBytes, InBytes: Cardinal;
  143. Code: TLZMASRes;
  144. DecodeStatus: Integer;
  145. begin
  146. if not FHeaderProcessed then begin
  147. { Reset these following a reset }
  148. FNextIn := @FBuffer;
  149. FAvailIn := 0;
  150. ProcessHeader;
  151. FHeaderProcessed := True;
  152. end;
  153. NextOut := @Buffer;
  154. AvailOut := Count;
  155. while AvailOut > 0 do begin
  156. if (FAvailIn = 0) and not FReachedEnd then begin
  157. FNextIn := @FBuffer;
  158. FAvailIn := ReadProc(FBuffer, SizeOf(FBuffer));
  159. if FAvailIn = 0 then
  160. FReachedEnd := True; { not really necessary, but for consistency }
  161. end;
  162. OutBytes := AvailOut;
  163. InBytes := FAvailIn;
  164. Code := DecodeToBuf(NextOut^, OutBytes, FNextIn^, InBytes, DecodeStatus);
  165. case Code of
  166. SZ_OK: ;
  167. SZ_ERROR_DATA: LZMADecompDataError(3);
  168. else
  169. LZMADecompInternalError(Format('DecodeToBuf failed (%d)', [Code]));
  170. end;
  171. { No bytes in or out indicates corruption somewhere. Possibilities:
  172. - The caller is asking for too many bytes.
  173. - It needs more input but there isn't any left.
  174. - It encountered an "end mark" previously and is now refusing to
  175. process any further input. }
  176. if (InBytes = 0) and (OutBytes = 0) then
  177. LZMADecompDataError(4);
  178. Dec(AvailOut, OutBytes);
  179. Inc(NextOut, OutBytes);
  180. Dec(FAvailIn, InBytes);
  181. Inc(FNextIn, InBytes);
  182. end;
  183. end;
  184. procedure TLZMACustomDecompressor.Reset;
  185. begin
  186. FHeaderProcessed := False;
  187. FReachedEnd := False;
  188. end;
  189. { TLZMA1Decompressor }
  190. procedure TLZMA1Decompressor.FreeDecoder;
  191. begin
  192. LzmaDec_Free(FDecoderState, LZMAAlloc);
  193. end;
  194. procedure TLZMA1Decompressor.ProcessHeader;
  195. var
  196. Props: packed record { size = LZMA_PROPS_SIZE (5) }
  197. Misc: Byte;
  198. DictionarySize: LongWord; { little endian, unaligned }
  199. end;
  200. begin
  201. { Read header fields }
  202. if ReadProc(Props, SizeOf(Props)) <> SizeOf(Props) then
  203. LZMADecompDataError(1);
  204. if Props.DictionarySize > LongWord(MaxDictionarySize) then
  205. LZMADecompDataError(5);
  206. { Note: IS_LzmaDec_Init will re-use already-allocated memory if it can.
  207. FDecoderState is assumed to be initialized to zero on the first call. }
  208. case IS_LzmaDec_Init(FDecoderState, SizeOf(FDecoderState), Props,
  209. SizeOf(Props), LZMAAlloc) of
  210. SZ_OK: ;
  211. SZ_ERROR_MEM: OutOfMemoryError;
  212. else
  213. { SZ_ERROR_UNSUPPORTED and anything else }
  214. LZMADecompDataError(2);
  215. end;
  216. end;
  217. function TLZMA1Decompressor.DecodeToBuf(var Dest; var DestLen: Cardinal;
  218. const Src; var SrcLen: Cardinal; var Status: Integer): Integer;
  219. begin
  220. Result := LzmaDec_DecodeToBuf(FDecoderState, Dest, DestLen, Src, SrcLen,
  221. LZMA_FINISH_ANY, Status);
  222. end;
  223. { TLZMA2Decompressor }
  224. procedure TLZMA2Decompressor.FreeDecoder;
  225. begin
  226. IS_Lzma2Dec_Free(FDecoderState, LZMAAlloc);
  227. end;
  228. procedure TLZMA2Decompressor.ProcessHeader;
  229. { Macro from Lzma2Dec.c: }
  230. function LZMA2_DIC_SIZE_FROM_PROP(p: LongWord): LongWord;
  231. begin
  232. Result := (2 or (p and 1)) shl (p div 2 + 11);
  233. end;
  234. var
  235. Prop: Byte;
  236. begin
  237. { Read header fields }
  238. if ReadProc(Prop, SizeOf(Prop)) <> SizeOf(Prop) then
  239. LZMADecompDataError(1);
  240. if (Prop >= 40) or
  241. (LZMA2_DIC_SIZE_FROM_PROP(Prop) > LongWord(MaxDictionarySize)) then
  242. LZMADecompDataError(5);
  243. { Note: IS_Lzma2Dec_Init will re-use already-allocated memory if it can.
  244. FDecoderState is assumed to be initialized to zero on the first call. }
  245. case IS_Lzma2Dec_Init(FDecoderState, SizeOf(FDecoderState), Prop,
  246. LZMAAlloc) of
  247. SZ_OK: ;
  248. SZ_ERROR_MEM: OutOfMemoryError;
  249. else
  250. { SZ_ERROR_UNSUPPORTED and anything else }
  251. LZMADecompDataError(2);
  252. end;
  253. end;
  254. function TLZMA2Decompressor.DecodeToBuf(var Dest; var DestLen: Cardinal;
  255. const Src; var SrcLen: Cardinal; var Status: Integer): Integer;
  256. begin
  257. Result := Lzma2Dec_DecodeToBuf(FDecoderState, Dest, DestLen, Src, SrcLen,
  258. LZMA_FINISH_ANY, Status);
  259. end;
  260. end.