2
// This unit is part of the GLScene Engine https://github.com/glscene
8
04/06/10 - Yar - Added to GLScene
9
(Created by Rustam Asmandiarov aka Predator)
13
unit GLSArchiveManager;
22
GLPersistentClasses, GLApplicationFileIO;
42
//****************************************************************************
44
//Базовый класс для архиваторов
48
TGLBaseArchive= class(TGLDataFile)
51
FContentList: TStrings;
52
FCompressionLevel: TCompressionLevel;
53
Procedure SetCompressionLevel(aValue: TCompressionLevel); Virtual;
55
constructor Create(AOwner: TPersistent); override;
56
destructor Destroy; override;
58
property ContentList: TStrings read FContentList;
60
property CompressionLevel: TCompressionLevel
61
read FCompressionLevel
62
write SetCompressionLevel default clNone;
64
procedure Clear; virtual;abstract;
66
function ContentExists(ContentName: string): boolean;virtual;abstract;
68
function GetContent(Stream: TStream; index: integer): TStream; overload;virtual;abstract;
69
function GetContent(ContentName: string): TStream; overload;virtual;abstract;
70
function GetContent(index: integer): TStream; overload;virtual;abstract;
72
function GetContentSize(index: integer): integer; overload;virtual;abstract;
73
function GetContentSize(ContentName: string): integer; overload;virtual;abstract;
75
procedure AddFromStream(ContentName, Path: string; FS: TStream);virtual;abstract;
76
procedure AddFromFile(FileName, Path: string);virtual;abstract;
78
procedure RemoveContent(index: integer); overload;virtual;abstract;
79
procedure RemoveContent(ContentName: string); overload;virtual;abstract;
81
procedure Extract(index: integer; NewName: string); overload; virtual;abstract;
82
procedure Extract(ContentName, NewName: string); overload; virtual;abstract;
85
TGLBaseArchiveClass = class of TGLBaseArchive;
87
//****************************************************************************
89
//Классы регистрации архивов, для того что бы по расшырениям архива можно было
90
//использовать соответсвующий архиватор. Например: GLFilePak,GLFileZLib
93
{Запись для зарегестрированного класса}
95
TArchiveFileFormat = class
97
BaseArchiveClass: TGLBaseArchiveClass;
103
{TGLArchiveFileFormatsList}
104
{Список зарегестрированных классов}
106
TGLArchiveFileFormatsList = class(TPersistentObjectList)
109
destructor Destroy; override;
111
procedure Add(const Ext, Desc: string; DescID: Integer; AClass:
112
TGLBaseArchiveClass);
113
function FindExt(ext: string): TGLBaseArchiveClass;
114
function FindFromFileName(const fileName: string): TGLBaseArchiveClass;
115
procedure Remove(AClass: TGLBaseArchiveClass);
118
//*****************************************************************************
120
//Для одновременной работы с несколькими архивами ввел коллекции
123
{Итем для работы с одним архивом}
125
TLibArchive = class(TCollectionItem)
128
vArchive: TGLBaseArchive;
129
ArcClass: TGLBaseArchiveClass;
132
procedure SetCompressionLevel(aValue: TCompressionLevel);
133
function GetCompressionLevel: TCompressionLevel;
134
function GetContentList: TStrings;
135
procedure SetName(const val: string);
138
function GetDisplayName: string; override;
141
constructor Create(ACollection: TCollection); override;
142
destructor Destroy; override;
144
property CompressionLevel: TCompressionLevel
145
read GetCompressionLevel
146
write SetCompressionLevel default clNone;
148
procedure CreateArchive(FileName: string;
149
OverwriteExistingFile: boolean = False);
151
property ContentList: TStrings read GetContentList;
153
procedure LoadFromFile(aFileName: string); overload;
154
procedure LoadFromFile(aFileName, aAchiverType: string); overload;
158
function ContentExists(aContentName: string): boolean;
159
property FileName: string read FFileName;
161
function GetContent(aindex: integer): TStream; overload;
162
function GetContent(aContentName: string): TStream; overload;
164
function GetContentSize(aindex: integer): integer; overload;
165
function GetContentSize(aContentName: string): integer; overload;
167
procedure AddFromStream(aContentName, aPath: string; aF: TStream); overload;
168
procedure AddFromStream(aContentName: string; aF: TStream); overload;
170
procedure AddFromFile(aFileName, aPath: string); overload;
171
procedure AddFromFile(aFileName: string); overload;
173
procedure RemoveContent(aindex: integer); overload;
174
procedure RemoveContent(aContentName: string); overload;
176
procedure Extract(aindex: integer; aNewName: string); overload;
177
procedure Extract(aContentName, aNewName: string); overload;
179
property Name: string read FName write SetName;
184
TLibArchives = class(TOwnedCollection)
187
procedure SetItems(index: Integer; const val: TLibArchive);
188
function GetItems(index: Integer): TLibArchive;
191
constructor Create(AOwner: TComponent);
193
function Owner: TPersistent;
195
function IndexOf(const Item: TLibArchive) : Integer;
196
function Add: TLibArchive;
197
function FindItemID(ID: Integer) : TLibArchive;
198
property Items[index: Integer]: TLibArchive read GetItems
199
write SetItems; default;
200
//Ищем архиватор по именыи открытого архива
201
function GetArchiveByFileName(const AName: string) : TLibArchive;
202
function GetFileNameOfArchive(aValue: TLibArchive) : string;
204
function MakeUniqueName(const nameRoot: string) : string;
205
function GetLibArchiveByName(const AName: string) : TLibArchive;
206
function GetNameOfLibArchive(const Archive: TLibArchive) : string;
209
//*****************************************************************************
210
//Компонента VCL для работы с архивами.
212
{ TGLSArchiveManager }
214
TGLSArchiveManager = class(TComponent)
216
FArchives: TLibArchives;
217
Procedure SetArchives(aValue: TLibArchives);
219
constructor Create(AOwner: TComponent); override;
220
destructor Destroy; override;
221
function GetArchiveByFileName(const aName: string): TLibArchive;
222
function GetFileNameOfArchive(const aArchive: TLibArchive): string;
223
function GetContent(aContentName: string): TStream;
224
function ContentExists(aContentName: string): boolean;
225
function OpenArchive(aFileName: string): TLibArchive; overload;
226
function OpenArchive(aFileName, aAchiverType: string): TLibArchive; overload;
227
procedure CloseArchive(aArchive: TLibArchive);
229
property Archives: TLibArchives read FArchives write SetArchives;
232
//****************************************************************************
236
EInvalidArchiveFile = class(Exception);
238
//Получение класса доступных архиваторов
239
function GetArchiveFileFormats: TGLArchiveFileFormatsList;
241
//Регистрация архиватора.
242
procedure RegisterArchiveFormat(const AExtension, ADescription: string;
243
AClass: TGLBaseArchiveClass);
244
procedure UnregisterArchiveFormat(AClass: TGLBaseArchiveClass);
246
//Получение активного менеджера архивов
247
//Внимание!!! Работает только для одного Менеджера Архивов
248
function GetArchiveManager: TGLSArchiveManager;
250
// GLApplicationFileIO
251
//Эти функции служат для автоматизации загрузки
252
//Пользователь вводит LoadFromFile а через эти функции получает результат.
254
function ArcCreateFileStream(const fileName: string; mode: word): TStream;
255
function ArcFileStreamExists(const fileName: string): boolean;
257
// ------------------------------------------------------------------
258
// ------------------------------------------------------------------
259
// ------------------------------------------------------------------
261
// ------------------------------------------------------------------
262
// ------------------------------------------------------------------
263
// ------------------------------------------------------------------
268
vArchiveFileFormats: TGLArchiveFileFormatsList;
269
vArchiveManager: TGLSArchiveManager;
271
function GetArchiveFileFormats: TGLArchiveFileFormatsList;
273
if not Assigned(vArchiveFileFormats) then
274
vArchiveFileFormats := TGLArchiveFileFormatsList.Create;
275
Result := vArchiveFileFormats;
278
procedure RegisterArchiveFormat(const AExtension, ADescription: string;
279
AClass: TGLBaseArchiveClass);
281
RegisterClass(AClass);
282
GetArchiveFileFormats.Add(AExtension, ADescription, 0, AClass);
285
procedure UnregisterArchiveFormat(AClass: TGLBaseArchiveClass);
287
if Assigned(vArchiveFileFormats) then
288
vArchiveFileFormats.Remove(AClass);
291
function GetArchiveManager: TGLSArchiveManager;
293
Result := vArchiveManager;
296
function ArcCreateFileStream(const fileName: string; mode: word): TStream;
298
If GetArchiveManager <> nil then
299
with GetArchiveManager do
300
if ContentExists(fileName) then
302
Result := GetContent(fileName);
305
if SysUtils.FileExists(fileName) then begin
306
Result := TFileStream.Create(FileName, mode);
309
//Не пойму зачем создавать файловый поток когда файл не найден
312
Result := TFileStream.Create(FileName, fmCreate or fmShareDenyWrite);
319
function ArcFileStreamExists(const fileName: string): boolean;
321
If GetArchiveManager <> nil then
322
with GetArchiveManager do
323
if ContentExists(fileName) then
328
Result := SysUtils.FileExists(fileName);
331
//******************************************************************************
334
constructor TLibArchive.Create(ACollection: TCollection);
336
inherited Create(ACollection);
337
FName := TLibArchives(ACollection).MakeUniqueName('LibArchive');
340
destructor TLibArchive.Destroy;
346
procedure TLibArchive.SetCompressionLevel(aValue: TCompressionLevel);
348
if vArchive = nil then Exit;
349
vArchive.CompressionLevel := aValue;
352
function TLibArchive.GetCompressionLevel: TCompressionLevel;
355
if vArchive = nil then Exit;
356
Result := vArchive.CompressionLevel;
359
procedure TLibArchive.CreateArchive(FileName: string;
360
OverwriteExistingFile: boolean = False);
364
if OverwriteExistingFile or not SysUtils.FileExists(FileName) then
366
fFile := TFileStream.Create(FileName, fmCreate);
371
procedure TLibArchive.LoadFromFile(aFileName: string);
375
ext := LowerCase(ExtractFileExt(aFileName));
377
LoadFromFile(aFileName, ext);
380
procedure TLibArchive.LoadFromFile(aFileName, aAchiverType: string);
382
if not SysUtils.FileExists(aFileName) then
384
ArcClass := GetArchiveFileFormats.FindExt(aAchiverType);
387
raise Exception.Create(ClassName+': Unable to find module archiver to expand '+ aAchiverType);
390
vArchive := ArcClass.Create(nil);
391
vArchive .LoadFromFile(aFileName);
392
FFileName := aFileName;
395
procedure TLibArchive.Clear;
397
if vArchive=nil then Exit;
404
function TLibArchive.ContentExists(aContentName: string): boolean;
407
if vArchive=nil then Exit;
408
Result := vArchive.ContentExists(aContentName)
411
function TLibArchive.GetContent(aindex: integer): TStream;
414
if vArchive=nil then Exit;
415
Result := vArchive.GetContent(aindex)
418
function TLibArchive.GetContent(aContentName: string): TStream;
421
if vArchive=nil then Exit;
422
Result := vArchive.GetContent(aContentName)
425
function TLibArchive.GetContentSize(aindex: integer): integer;
428
if vArchive=nil then Exit;
429
Result := vArchive.GetContentSize(aindex)
432
function TLibArchive.GetContentSize(aContentName: string): integer;
435
if vArchive=nil then Exit;
436
Result := vArchive.GetContentSize(aContentName)
439
procedure TLibArchive.AddFromStream(aContentName, aPath: string; aF: TStream);
441
if vArchive=nil then Exit;
442
vArchive.AddFromStream(aContentName, aPath, aF)
445
procedure TLibArchive.AddFromStream(aContentName: string; aF: TStream);
447
if vArchive=nil then Exit;
448
vArchive.AddFromStream(aContentName, '', aF)
451
procedure TLibArchive.AddFromFile(aFileName, aPath: string);
453
if vArchive=nil then Exit;
454
vArchive.AddFromFile(aFileName, aPath)
457
procedure TLibArchive.AddFromFile(aFileName: string);
459
if vArchive=nil then Exit;
460
vArchive.AddFromFile(aFileName, '')
463
procedure TLibArchive.RemoveContent(aindex: integer);
465
if vArchive=nil then Exit;
466
vArchive.RemoveContent(aindex)
469
procedure TLibArchive.RemoveContent(aContentName: string);
471
if vArchive=nil then Exit;
472
vArchive.RemoveContent(aContentName)
475
procedure TLibArchive.Extract(aindex: integer; aNewName: string);
477
if vArchive=nil then Exit;
478
vArchive.Extract(aindex, aNewName)
481
procedure TLibArchive.Extract(aContentName, aNewName: string);
483
if vArchive=nil then Exit;
484
vArchive.Extract(aContentName, aNewName)
487
function TLibArchive.GetContentList: TStrings;
490
if vArchive=nil then Exit;
491
Result := vArchive.ContentList;
494
procedure TLibArchive.SetName(const val: string);
499
TComponent(TLibArchives(Collection).GetOwner).ComponentState) then
501
if TLibArchives(Collection).GetLibArchiveByName(val) <> Self then
502
FName := TLibArchives(Collection).MakeUniqueName(val)
511
function TLibArchive.GetDisplayName: string;
518
procedure TLibArchives.SetItems(index: Integer; const val: TLibArchive);
520
GetItems(Index).Assign(Val);
523
function TLibArchives.GetItems(index: Integer): TLibArchive;
525
Result := TLibArchive(inherited GetItem(Index));
528
constructor TLibArchives.Create(AOwner: TComponent);
530
inherited Create(AOwner, TLibArchive);
533
function TLibArchives.Owner: TPersistent;
538
function TLibArchives.IndexOf(const Item: TLibArchive): Integer;
544
for I := 0 to Count - 1 do
545
if GetItems(I) = Item then
552
function TLibArchives.Add: TLibArchive;
554
Result := (inherited Add) as TLibArchive;
557
function TLibArchives.FindItemID(ID: Integer): TLibArchive;
559
Result := (inherited FindItemID(ID)) as TLibArchive;
562
function TLibArchives.GetArchiveByFileName(const AName: string): TLibArchive;
567
for i := 0 to Count - 1 do
569
Arc := TLibArchive(inherited Items[i]);
570
if Arc.FileName = AName then
579
function TLibArchives.GetFileNameOfArchive(aValue: TLibArchive): string;
583
ArcIndex := IndexOf(aValue);
584
if ArcIndex <> -1 then
585
Result := GetItems(ArcIndex).FileName
590
function TLibArchives.MakeUniqueName(const nameRoot: string): string;
596
while GetLibArchiveByName(Result) <> nil do
598
Result := nameRoot + IntToStr(i);
603
function TLibArchives.GetLibArchiveByName(const AName: string): TLibArchive;
608
for i := 0 to Count - 1 do
610
Arc := TLibArchive(inherited Items[i]);
611
if (Arc.Name = AName) then
620
function TLibArchives.GetNameOfLibArchive(const Archive: TLibArchive): string;
624
MatIndex := IndexOf(Archive);
625
if MatIndex <> -1 then
626
Result := GetItems(MatIndex).Name
631
{ TGLArchiveFileFormatsList }
632
//******************************************************************************
634
destructor TGLArchiveFileFormatsList.Destroy;
640
procedure TGLArchiveFileFormatsList.Add(const Ext, Desc: string; DescID: Integer;
641
AClass: TGLBaseArchiveClass);
643
newRec: TArchiveFileFormat;
645
newRec := TArchiveFileFormat.Create;
648
Extension := AnsiLowerCase(Ext);
649
BaseArchiveClass := AClass;
653
inherited Add(newRec);
656
function TGLArchiveFileFormatsList.FindExt(ext: string): TGLBaseArchiveClass;
660
ext := AnsiLowerCase(ext);
661
for i := Count - 1 downto 0 do
662
with TArchiveFileFormat(Items[I]) do
664
if Extension = ext then
666
Result := BaseArchiveClass;
673
function TGLArchiveFileFormatsList.FindFromFileName(const fileName: string
674
): TGLBaseArchiveClass;
678
ext := ExtractFileExt(Filename);
679
System.Delete(ext, 1, 1);
680
Result := FindExt(ext);
681
if not Assigned(Result) then
682
raise EInvalidArchiveFile.CreateFmt(glsUnknownExtension,
683
[ext, 'GLFile' + UpperCase(ext)]);
686
procedure TGLArchiveFileFormatsList.Remove(AClass: TGLBaseArchiveClass);
690
for i := Count - 1 downto 0 do
692
if TArchiveFileFormat(Items[i]).BaseArchiveClass.InheritsFrom(AClass) then
698
//******************************************************************************
702
procedure TGLBaseArchive.SetCompressionLevel(aValue: TCompressionLevel);
704
if FCompressionLevel <> aValue then
705
FCompressionLevel := aValue;
708
constructor TGLBaseArchive.Create(AOwner: TPersistent);
710
inherited Create(AOwner);
711
FContentList := TStringList.Create;
712
FCompressionLevel := clNone;
715
destructor TGLBaseArchive.Destroy;
721
//******************************************************************************
723
{ TGLSArchiveManager }
725
constructor TGLSArchiveManager.Create(AOwner: TComponent);
727
inherited Create(AOwner);
728
FArchives := TLibArchives.Create(self);
729
vArchiveManager := Self;
730
vAFIOCreateFileStream := ArcCreateFileStream;
731
vAFIOFileStreamExists := ArcFileStreamExists;
734
destructor TGLSArchiveManager.Destroy;
736
vArchiveManager := nil;
741
procedure TGLSArchiveManager.SetArchives(aValue: TLibArchives);
743
FArchives.Assign(aValue);
746
function TGLSArchiveManager.GetArchiveByFileName(const aName: string): TLibArchive;
748
Result := FArchives.GetArchiveByFileName(AName);
751
function TGLSArchiveManager.GetFileNameOfArchive(const aArchive: TLibArchive): string;
753
Result := FArchives.GetFileNameOfArchive(aArchive)
756
function TGLSArchiveManager.GetContent(aContentName: string): TStream;
762
for i:=0 to Count-1 do
763
if Items[i].ContentExists(aContentName) then
765
Result := Items[i].GetContent(aContentName);
770
function TGLSArchiveManager.ContentExists(aContentName: string): boolean;
776
for i:=0 to Count-1 do
777
if Items[i].ContentExists(aContentName) then
779
Result := Items[i].ContentExists(aContentName);
784
function TGLSArchiveManager.OpenArchive(aFileName: string): TLibArchive;
786
Result := FArchives.Add;
787
Result.LoadFromFile(aFileName);
790
function TGLSArchiveManager.OpenArchive(aFileName, aAchiverType: string
793
Result := FArchives.Add;
794
Result.LoadFromFile(aFileName, aAchiverType);
797
procedure TGLSArchiveManager.CloseArchive(aArchive: TLibArchive);
799
FArchives.Delete(FArchives.IndexOf(aArchive));
804
RegisterClasses([TGLSArchiveManager, TLibArchives]);
808
FreeAndNil(vArchiveFileFormats);