2
// This unit is part of the GLScene Engine https://github.com/glscene
6
22/08/10 - DaStr - Removed warnings, converted comments from Unicode to ASCII
7
04/06/10 - Yar - Added to GLScene
8
(Created by Rustam Asmandiarov aka Predator)
25
SIGN = 'ZLIB'; //Signature for compressed zlib.
29
Signature: array[0..3] of AnsiChar;
35
FileName: array[0..119] of AnsiChar;
38
CbrMode: TCompressionLevel;
43
TZLibArchive=class(TGLBaseArchive)
48
function GetContentCount: integer;
49
procedure MakeContentList;
51
property ContentCount: integer Read GetContentCount;
52
destructor Destroy; override;
54
procedure LoadFromFile(const FileName: string); override;
56
procedure Clear; override;
57
function ContentExists(ContentName: string): boolean;override;
59
function GetContent(aStream: TStream; index: integer): TStream; override;
60
function GetContent(index: integer): TStream; override;
61
function GetContent(ContentName: string): TStream; override;
63
function GetContentSize(index: integer): integer; override;
64
function GetContentSize(ContentName: string): integer; override;
66
procedure AddFromStream(ContentName, Path: string; FS: TStream);override;
67
procedure AddFromFile(FileName, Path: string); override;
69
procedure RemoveContent(index: integer); overload; override;
70
procedure RemoveContent(ContentName: string); overload;override;
72
procedure Extract(index: integer; NewName: string); override;
73
procedure Extract(ContentName, NewName: string); override;
84
function TZLibArchive.GetContentCount: integer;
86
Result := FHeader.DirLength div SizeOf(TFileSection);
89
procedure TZLibArchive.MakeContentList;
93
FStream.Seek(FHeader.DirOffset, soFromBeginning);
95
for i := 0 to ContentCount - 1 do
97
FStream.ReadBuffer(Dir, SizeOf(TFileSection));
98
FContentList.Add(string(Dir.FileName));
102
destructor TZLibArchive.Destroy;
107
procedure TZLibArchive.LoadFromFile(const FileName: string);
109
FFileName := FileName;
110
FStream := TFileStream.Create(FileName, fmOpenReadWrite or fmShareDenyWrite);
111
if FStream.Size = 0 then
113
FHeader.Signature := SIGN;
114
FHeader.DirOffset := SizeOf(TZLibHeader);
115
FHeader.DirLength := 0;
117
FStream.WriteBuffer(FHeader, SizeOf(TZlibHeader));
118
FStream.Position := 0;
121
FStream.ReadBuffer(FHeader, SizeOf(TZlibHeader));
122
if FHeader.Signature <> SIGN then
125
raise Exception.Create(FileName+' - This is not ZLIB file');
128
if ContentCount <> 0 then
132
procedure TZLibArchive.Clear;
135
If FStream <> nil then FStream.Free;
138
function TZLibArchive.ContentExists(ContentName: string): boolean;
140
Result := (FContentList.IndexOf(ContentName) > -1);
143
function TZLibArchive.GetContent(aStream: TStream; index: integer): TStream;
145
tempStream: TMemoryStream;
146
decompr : TZDecompressionStream;
149
If FStream = nil then exit;
153
FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * index, soFromBeginning);
154
FStream.Read(Dir, SizeOf(TFileSection));
155
FStream.Seek(Dir.FilePos, soFromBeginning);
157
//�������� ���� �� ������ ������ �� ��������� �����
158
tempStream := TMemoryStream.Create;
159
tempStream.CopyFrom(FStream, Dir.FileLength);
160
tempStream.Position := 0;
163
decompr := TZDecompressionStream.Create(tempStream);
166
Result.CopyFrom(decompr, 0);
171
Result.Position := 0;
174
function TZLibArchive.GetContent(index: integer): TStream;
176
Result:=GetContent(TMemoryStream.Create,index);
179
function TZLibArchive.GetContent(ContentName: string): TStream;
182
if ContentExists(ContentName) then
183
Result := GetContent(FContentList.IndexOf(ContentName));
186
function TZLibArchive.GetContentSize(index: integer): integer;
189
If FStream = nil then exit;
190
FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * index, soFromBeginning);
191
FStream.Read(Dir, SizeOf(Dir));
192
Result := Dir.FileLength;
195
function TZLibArchive.GetContentSize(ContentName: string): integer;
198
if ContentExists(ContentName) then
199
Result := GetContentSize(FContentList.IndexOf(ContentName));
202
procedure TZLibArchive.AddFromStream(ContentName, Path: string; FS: TStream);
204
Temp, compressed: TMemoryStream;
205
FCompressor: TZCompressionStream;
208
If (FStream = nil) or ContentExists(ContentName) then exit;
210
FStream.Position := FHeader.DirOffset;
212
if FHeader.DirLength > 0 then
214
Temp := TMemoryStream.Create;
215
Temp.CopyFrom(FStream, FHeader.DirLength);
217
FStream.Position := FHeader.DirOffset;
221
Dir.FilePos := FHeader.DirOffset;
222
Dir.CbrMode := compressionLevel;
224
//������� ����� ��� ������������ � ����
225
compressed := TMemoryStream.Create;
227
//������������� ������ � ����
228
FCompressor := TZCompressionStream.Create(compressed,TZCompressionLevel(compressionLevel));
229
FCompressor.CopyFrom(FS, FS.Size);
233
FStream.CopyFrom(compressed, 0);
234
//���������� ������ �����
235
Dir.FileLength := compressed.Size;
239
FHeader.DirOffset := FStream.Position;
240
if FHeader.DirLength > 0 then
242
FStream.CopyFrom(Temp, 0);
245
//���������� ��� ����� � ���������
246
StrPCopy(Dir.FileName, AnsiString(Path + ExtractFileName(ContentName)));
247
//���������� ������ � �����
248
FStream.WriteBuffer(Dir, SizeOf(TFileSection));
249
//���������� ��������� � �����
250
FHeader.DirLength := FHeader.DirLength + SizeOf(TFileSection);
251
FStream.Position := 0;
252
FStream.WriteBuffer(FHeader, SizeOf(TZLibHeader));
253
FContentList.Add(string(Dir.FileName));
256
procedure TZLibArchive.AddFromFile(FileName, Path: string);
260
if not SysUtils.FileExists(FileName) then
262
FS := TFileStream.Create(FileName, fmOpenRead);
264
AddFromStream(FileName, Path, FS);
270
procedure TZLibArchive.RemoveContent(index: integer);
277
Temp := TMemoryStream.Create;
278
FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * index, soFromBeginning);
279
FStream.ReadBuffer(Dir, SizeOf(TFileSection));
280
FStream.Seek(Dir.FilePos + Dir.FileLength, soFromBeginning);
282
Temp.CopyFrom(FStream, FStream.Size - FStream.Position);
283
FStream.Position := Dir.FilePos;
284
FStream.CopyFrom(Temp, 0);
285
FHeader.DirOffset := FHeader.DirOffset - dir.FileLength;
287
for i := 0 to ContentCount - 1 do
290
FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * i, soFromBeginning);
291
FStream.ReadBuffer(f, SizeOf(TFileSection));
292
FStream.Position := FStream.Position - SizeOf(TFileSection);
293
f.FilePos := f.FilePos - dir.FileLength;
294
FStream.WriteBuffer(f, SizeOf(TFileSection));
297
i := FHeader.DirOffset + SizeOf(TFileSection) * index;
298
FStream.Position := Cardinal(i + SizeOf(TFileSection));
299
if FStream.Position < FStream.Size then
301
Temp.CopyFrom(FStream, FStream.Size - FStream.Position);
302
FStream.Position := i;
303
FStream.CopyFrom(Temp, 0);
306
FHeader.DirLength := FHeader.DirLength - SizeOf(TFileSection);
307
FStream.Position := 0;
308
FStream.WriteBuffer(FHeader, SizeOf(TZLibHeader));
309
FStream.Size := FStream.Size - dir.FileLength - SizeOf(TFileSection);
313
procedure TZLibArchive.RemoveContent(ContentName: string);
315
if ContentExists(ContentName) then
316
RemoveContent(FContentList.IndexOf(ContentName));
319
procedure TZLibArchive.Extract(index: integer; NewName: string);
321
vExtractFileStream: TFileStream;
326
if (index < 0) or (index >= ContentCount) then
328
vExtractFileStream := TFileStream.Create(NewName, fmCreate);
329
vTmpStream := GetContent(index);
330
vExtractFileStream.CopyFrom(vTmpStream, 0);
332
vExtractFileStream.Free;
335
procedure TZLibArchive.Extract(ContentName, NewName: string);
337
if ContentExists(ContentName) then
338
Extract(FContentList.IndexOf(ContentName), NewName);
342
// ���� ������������ �������� ������ zlib
343
RegisterArchiveFormat('zlib', 'GLScene file uses the zlib compression algorithm', TZLibArchive);