-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathuXCompress.pas
213 lines (183 loc) · 6.44 KB
/
uXCompress.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
210
211
212
213
{
******************************************************
DoubleFine Explorer
By Bennyboy
Http://quickandeasysoftware.net
******************************************************
}
//Adapted from https://github.com/indirivacua/RAGE-Console-Texture-Editor/blob/master/Compression.LZX.pas
unit uXCompress;
interface
uses
Classes, Windows, Sysutils,
MemoryModule;
type
EXCompressDecompressionError = class (exception);
LZXBlockSize = record
UnCompressedSize,
CompressedSize: WORD;
end;
XMEMCODEC_TYPE = ( XMEMCODEC_DEFAULT = 0, XMEMCODEC_LZX = 1 );
XMEMCODEC_PARAMETERS_LZX = packed record
Flags: Integer;
WindowSize: Integer;
CompressionPartitionSize: Integer;
end;
var
DllLib : PMemoryModule;
XMemCreateDecompressionContext: function(CodecType: XMEMCODEC_TYPE; pCodecParams: Pointer; Flags: Integer; pContext: PInteger): HRESULT; stdcall;
XMemDestroyDecompressionContext: procedure (Context: Integer); stdcall;
XMemResetDecompressionContext: function(Context: Integer): HRESULT; stdcall;
XMemDecompressStream: function(Context: Integer; pDestination: Pointer; pDestSize: PInteger; pSource: Pointer; pSrcSize: PInteger): HRESULT; stdcall;
XDecompress: function(inData: PAnsiChar; inlen: integer; outdata: PAnsiChar; outlen: integer): integer; cdecl;
LZXinit: function (window: integer): Integer; cdecl;
procedure XCompress_Load_DLL;
procedure DecompressXCompress_Old(Source: TStream; Dest: TStream; UncompressedSize: integer);
procedure DecompressXCompress(Source: TStream; Dest: TStream; CompressedSize, UncompressedSize: integer);
const
XMEMCOMPRESS_STREAM = $00000001;
implementation
procedure XCompress_Load_DLL;
var
ResStream: TResourceStream;
begin
if DllLib <> nil then
exit; //already loaded
//Load it from resource into memory
ResStream := TResourceStream.Create(hInstance, 'xcompressdll', RT_RCDATA);
try
ResStream.Position := 0;
if MemoryLoadLibrary(ResStream.Memory, DLLLib) < 0 then
begin
raise Exception.Create('XCompress dll load failed!');
exit;
end;
finally
ResStream.Free;
end;
{XDecompress := MemoryGetProcAddress(DllLib, PAnsiChar('LZXdecompress'));
if not Assigned (XDecompress) then
begin
raise Exception.Create('Couldnt find decompression function in DLL');
end;
LZXinit := MemoryGetProcAddress(DllLib, PAnsiChar('LZXinit'));
if not Assigned (LZXinit) then
begin
raise Exception.Create('Couldnt find LZXinit function in DLL');
end;}
XMemCreateDecompressionContext := MemoryGetProcAddress(DllLib, PAnsiChar('XMemCreateDecompressionContext'));
if not Assigned (XMemCreateDecompressionContext) then
begin
raise Exception.Create('Couldnt find XMemCreateDecompressionContext function in DLL');
end;
XMemDestroyDecompressionContext := MemoryGetProcAddress(DllLib, PAnsiChar('XMemDestroyDecompressionContext'));
if not Assigned (XMemDestroyDecompressionContext) then
begin
raise Exception.Create('Couldnt find XMemDestroyDecompressionContext function in DLL');
end;
XMemResetDecompressionContext := MemoryGetProcAddress(DllLib, PAnsiChar('XMemResetDecompressionContext'));
if not Assigned (XMemResetDecompressionContext) then
begin
raise Exception.Create('Couldnt find XMemResetDecompressionContext function in DLL');
end;
XMemDecompressStream := MemoryGetProcAddress(DllLib, PAnsiChar('XMemDecompressStream'));
if not Assigned (XMemDecompressStream) then
begin
raise Exception.Create('Couldnt find XMemDecompressStream function in DLL');
end;
end;
function ReadBlockSize(Stream: TStream): LZXBlockSize;
var
b0, b1, b2, b3, b4: Byte;
begin
Stream.Read(b0,1);
if b0 = $FF then
begin
Stream.Read(b1,1);
Stream.Read(b2,1);
Stream.Read(b3,1);
Stream.Read(b4,1);
Result.UnCompressedSize:= b2 or b1 shl 8; //(b1 shl 8)+b2;
Result.CompressedSize:= b4 or b3 shl 8; //(b3 shl 8)+b4;
end
else
begin
Stream.Read(b1,1);
Result.UnCompressedSize:= $8000;
Result.CompressedSize:= b1 or b0 shl 8; //(b0 shl 8)+b1;
end;
end;
procedure DecompressXCompress_Old(Source: TStream; Dest: TStream; UncompressedSize: integer);
var
//OutResult : integer;
Identifier: byte;
BlockSize: LZXBlockSize;
pDataIn, pDataOut: PAnsiChar;
begin
LZXinit(17);
{Source.Read(Identifier, 1);
if Identifier <> $FF then raise EXCompressDecompressionError.Create('Decompression Failed not XMemCompress compressed data'); //Always first byte FF?
Source.Seek(-1, soFromCurrent);}
while (Dest.Size <> UncompressedSize) do
begin
BlockSize:= ReadBlockSize(Source);
GetMem(pDataIn, BlockSize.CompressedSize);
try
GetMem(pDataOut, BlockSize.UnCompressedSize);
try
Source.ReadBuffer(pDataIn^,BlockSize.CompressedSize);
{OutResult :=} XDecompress(pDataIn, BlockSize.CompressedSize, pDataOut, BlockSize.UnCompressedSize);
{if OutResult <> 0 then //Unsure about this, it seems to return 0 if uncompressed ok
begin
raise EXCompressDecompressionError.Create('XMemCompress Decompression Failed. Result was ' + inttostr(OutResult));
end;}
Dest.WriteBuffer(pDataOut^,BlockSize.UnCompressedSize);
finally
FreeMem(pDataOut, BlockSize.UnCompressedSize);
end;
finally
FreeMem(pDataIn, BlockSize.CompressedSize);
end;
end;
Dest.Position := 0;
end;
procedure DecompressXCompress(Source: TStream; Dest: TStream; CompressedSize, UncompressedSize: integer);
var
Contex: Integer;
Result: HRESULT;
codec_parameters: XMEMCODEC_PARAMETERS_LZX;
pSource, pDest: Pointer;
dwInSize, dwOutSize: DWORD;
tmp: integer;
begin
Contex:=0;
Result:= XMemCreateDecompressionContext(XMEMCODEC_LZX, @codec_parameters, XMEMCOMPRESS_STREAM, @Contex);
if Succeeded(Result) then
begin
Result:= XMemResetDecompressionContext(Contex);
dwInSize := CompressedSize;
dwOutSize := UncompressedSize;
GetMem(pSource, dwInSize);
ZeroMemory(pSource, dwInSize);
Source.Read(pSource^, dwInSize);
pDest:= GetMemory(dwOutSize);
ZeroMemory(pDest, dwOutSize);
tmp:=dwOutSize;
Result:= XMemDecompressStream(Contex, pDest, @dwOutSize, pSource, @dwInSize);
if Succeeded(Result) then
begin
dwOutSize:=tmp;
Dest.Write(pDest^, dwOutSize);
FreeMemory(pDest);
FreeMemory(pSource);
end;
XMemDestroyDecompressionContext(Contex);
Dest.Position := 0;
end;
end;
Initialization
DllLib := nil;
finalization
if DllLib <> nil then
MemoryFreeLibrary(DllLib);
end.