forked from jrsoftware/issrc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLZMADecompSmall.pas
209 lines (179 loc) · 5.97 KB
/
LZMADecompSmall.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
unit LZMADecompSmall;
{
Inno Setup
Copyright (C) 1997-2010 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
LzmaDecode, used by SetupLdr.
}
interface
{$I VERSION.INC}
uses
Windows, SysUtils, Compress, 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 = 'lzmadecompsmall: 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('lzmadecompsmall: %s', [Msg]);
end;
procedure LZMAInternalErrorFmt(const Msg: String; const Args: array of const);
begin
LZMAInternalError(Format(Msg, Args));
end;
{ TLZMA1SmallDecompressor }
{$L LzmaDecode\LzmaDecodeInno.obj}
type
TLzmaInCallback = record
Read: function(obj: Pointer; var buffer: Pointer; var bufferSize: Cardinal): Integer;
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; external;
procedure LzmaMyDecoderInit(var vs: TLZMAInternalDecoderState;
probsPtr: Pointer; dictionaryPtr: Pointer); external;
function LzmaDecode(var vs: TLZMAInternalDecoderState;
var inCallback: TLzmaInCallback; var outStream; outSize: Cardinal;
var outSizeProcessed: Cardinal): Integer; external;
type
TLZMADecompressorCallbackData = record
Callback: TLzmaInCallback;
Instance: TLZMA1SmallDecompressor;
end;
function ReadFunc(obj: Pointer; var buffer: Pointer; var bufferSize: Cardinal): Integer;
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.