123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2008 by Giulio Bernardi
- Base classes for resource handling
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit resource;
- {$MODE OBJFPC} {$H+}
- interface
- uses
- Classes, Sysutils;
- const
- RT_CURSOR = 1; //Hardware-dependent cursor resource.
- RT_BITMAP = 2; //Bitmap resource.
- RT_ICON = 3; //Hardware-dependent icon resource.
- RT_MENU = 4; //Menu resource.
- RT_DIALOG = 5; //Dialog box.
- RT_STRING = 6; //String-table entry.
- RT_FONTDIR = 7; //Font directory resource.
- RT_FONT = 8; //Font resource.
- RT_ACCELERATOR = 9; //Accelerator table.
- RT_RCDATA = 10; //Application-defined resource (raw data).
- RT_MESSAGETABLE = 11; //Message-table entry.
- RT_GROUP_CURSOR = 12; //Hardware-independent cursor resource.
- RT_GROUP_ICON = 14; //Hardware-independent icon resource.
- RT_VERSION = 16; //Version resource.
- RT_DLGINCLUDE = 17; //Never present in compiled form
- RT_PLUGPLAY = 19; //Plug and Play resource.
- RT_VXD = 20; //VXD.
- RT_ANICURSOR = 21; //Animated cursor.
- RT_ANIICON = 22; //Animated icon.
- RT_HTML = 23; //HTML.
- RT_MANIFEST = 24; //Microsoft Windows XP: Side-by-Side Assembly XML Manifest.
- CREATEPROCESS_MANIFEST_RESOURCE_ID = 1;
- ISOLATIONAWARE_MANIFEST_RESOURCE_ID = 2;
- ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID = 3;
- MINIMUM_RESERVED_MANIFEST_RESOURCE_ID = 1; //inclusive
- MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID = 16; //inclusive
- const
- MF_MOVEABLE = $0010;
- MF_PURE = $0020;
- MF_PRELOAD = $0040;
- MF_DISCARDABLE = $1000;
- resourcestring
- SReaderNotFoundExt = 'Cannot find resource reader for extension ''%s''';
- SReaderNotFoundProbe = 'Cannot find a resource reader: unknown format.';
- SWriterNotFoundExt = 'Cannot find resource writer for extension ''%s''';
- SDescChangeNotAllowed = 'Cannot modify %s resource description';
- SLangIDChangeNotAllowed = 'Cannot modify %s resource language ID';
- SResDuplicate = 'Duplicate resource: Type = %s, Name = %s, Lang ID = %.4x';
- SResourceNotFound = 'Cannot find resource: Type = %s, Name = %s';
- SResourceNotFoundLang = 'Cannot find resource: Type = %s, Name = %s, Lang ID = %.4x';
- type
- TLangID = word;
- TResName = string;
- TResID = LongWord;
- TDescType = (dtName, dtID);
- type
- EResourceException = class(Exception);
- EResourceDescTypeException = class(EResourceException);
- EResourceDescChangeNotAllowedException = class(EResourceException);
- EResourceLangIDChangeNotAllowedException = class(EResourceException);
- EResourceDuplicateException = class(EResourceException);
- EResourceNotFoundException = class(EResourceException);
- ENoMoreFreeIDsException = class(EResourceException);
- EResourceReaderException = class(EResourceException);
- EResourceReaderNotFoundException = class(EResourceReaderException);
- EResourceReaderWrongFormatException = class(EResourceReaderException);
- EResourceReaderUnexpectedEndOfStreamException = class (EResourceReaderException);
- EResourceWriterException = class(EResourceException);
- EResourceWriterNotFoundException = class(EResourceWriterException);
- type
- TAbstractResource = class;
- { TResourceDesc }
- TResourceDesc = class
- private
- fName : TResName;
- fID : TResID;
- fDescType : TDescType;
- fOwner : TAbstractresource;
-
- function GetID : TResID;
- function GetName : TResName;
- procedure SetID(const aID : TResID);
- procedure SetName(const aName : TResName);
- procedure CanChangeType(newType : TDescType);
- procedure CanChangeValue;
- protected
- procedure SetOwner(aOwner : TAbstractResource);
- public
- constructor Create; overload;
- constructor Create(const aID : TResID); overload;
- constructor Create(const aName : TResName); overload;
- procedure Assign(aResourceDesc : TResourceDesc);
- function Equals(aResDesc : TResourceDesc) : boolean;
- property Name : TResName read GetName write SetName;
- property ID : TResID read GetID write SetID;
- property DescType : TDescType read fDescType;
- end;
- TResources = class;
- { TAbstractResource }
- TAbstractResource = class
- private
- fLangId : TLangID;
- fDataSize : longword;
- fHeaderSize : longword;
- fDataVersion : longword;
- fMemoryFlags : word;
- fVersion : longword;
- fCharacteristics : longword;
- fDataOffset : longword;
- fCodePage : longword;
- fRawData : TStream;
- fOwnerList : TResources;
- fOwner : TAbstractResource;
- function GetRawData : TStream;
- function GetCacheData : boolean;
- procedure SetCacheData(const aValue : boolean);
- function GetDataSize : longword;
- procedure SetLangID(aLangID : TLangID);
- protected
- procedure SetDescOwner(aDesc : TResourceDesc);
- procedure SetOwnerList(aResources : TResources); virtual;
- procedure SetChildOwner(aChild : TAbstractResource);
- function GetType : TResourceDesc; virtual; abstract;
- function GetName : TResourceDesc; virtual; abstract;
- function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; virtual; abstract;
- function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; virtual; abstract;
- procedure NotifyResourcesLoaded; virtual; abstract;
- constructor Create; virtual; overload;
- public
- constructor Create(aType,aName : TResourceDesc); virtual; abstract; overload;
- destructor Destroy; override;
- function CompareContents(aResource: TAbstractResource): boolean; virtual;
- procedure UpdateRawData; virtual; abstract;
- procedure SetCustomRawDataStream(aStream : TStream);
- property _Type : TResourceDesc read GetType;
- property Name : TResourceDesc read GetName;
- property LangID : TLangID read fLangID write SetLangID;
- property DataSize : longword read GetDataSize;
- property HeaderSize : longword read fHeaderSize;
- property DataVersion : longword read fDataVersion write fDataVersion;
- property MemoryFlags : word read fMemoryFlags write fMemoryFlags;
- property Version : longword read fVersion write fVersion;
- property Characteristics : longword read fCharacteristics write fCharacteristics;
- property DataOffset : longword read fDataOffset;
- property CodePage : longword read fCodePage write fCodePage;
- property RawData : TStream read GetRawData;
- property CacheData : boolean read GetCacheData write SetCacheData;
- property OwnerList : TResources read fOwnerList;
- property Owner : TAbstractResource read fOwner;
- end;
-
- TResourceClass = class of TAbstractResource;
-
- { TGenericResource }
- TGenericResource = class(TAbstractResource)
- private
- fType : TResourceDesc;
- fName : TResourceDesc;
- protected
- function GetType : TResourceDesc; override;
- function GetName : TResourceDesc; override;
- function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
- function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
- procedure NotifyResourcesLoaded; override;
- public
- constructor Create(aType,aName : TResourceDesc); override;
- destructor Destroy; override;
- procedure UpdateRawData; override;
- end;
- type
- TAbstractResourceReader = class;
- TAbstractResourceWriter = class;
- TResourceReaderClass = class of TAbstractResourceReader;
- TResourceWriterClass = class of TAbstractResourceWriter;
- { TResources }
- TResources = class
- private
- fList : TFPList;
- fTree : TObject;
- dummyType : TResourceDesc;
- dummyName : TResourceDesc;
- fCacheData : boolean;
- fMoveFromCount : integer;
- fRemovedCount : integer;
- function GetItem(index : integer) : TAbstractResource;
- function GetCount : longword;
- procedure SetCacheData(const aValue : boolean);
- procedure NotifyLoaded;
- // protected
- private
- fTempRStream : TStream;
- class procedure InitReaderList;
- class procedure InitWriterList;
- class procedure DisposeStreamerList(aList : TFPList);
- class procedure DisposeReaderList;
- class procedure DisposeWriterList;
- class function FindWriterClass(aExtension : string) : TResourceWriterClass;
- class procedure RegisterStreamer(aList : TFPList; aExtension : string; aClass : TClass);
- procedure SendUpdateRawData;
- procedure InternalRemove(aResource: TAbstractResource);
- procedure InternalRemove(aIndex : integer);
- procedure QuietRemove(aResource : TAbstractResource; aIndex : integer; aIndexValid : boolean);
- procedure InternalClear;
- procedure InternalAdd(aResource : TAbstractResource; prevIdx : integer; prevIdxValid : boolean);
- procedure AddNoTree(aResource : TAbstractResource);
- function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
- function InternalFind(aType, aName : TResourceDesc) : TAbstractResource; overload;
- procedure BeginMoveFrom;
- procedure EndMoveFrom;
- public
- constructor Create;
- destructor Destroy; override;
- procedure Add(aResource : TAbstractResource);
- function AddAutoID(aResource : TAbstractResource) : TResID;
- procedure Clear;
- function Find(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
- function Find(aType, aName : TResourceDesc) : TAbstractResource; overload;
- function Find(const aType : TResName; const aName : TResName; const aLangID : TLangID) : TAbstractResource; overload;
- function Find(const aType : TResName; const aName : TResID; const aLangID : TLangID) : TAbstractResource; overload;
- function Find(const aType : TResID; const aName : TResName; const aLangID : TLangID) : TAbstractResource; overload;
- function Find(const aType : TResID; const aName : TResID; const aLangID : TLangID) : TAbstractResource; overload;
- function Find(const aType : TResName; const aName : TResName) : TAbstractResource; overload;
- function Find(const aType : TResName; const aName : TResID) : TAbstractResource; overload;
- function Find(const aType : TResID; const aName : TResName) : TAbstractResource; overload;
- function Find(const aType : TResID; const aName : TResID) : TAbstractResource; overload;
- class function FindReader(aStream: TStream; aExtension: string) : TAbstractResourceReader;
- class function FindReader(aStream : TStream) : TAbstractResourceReader;
- procedure MoveFrom(aResources : TResources);
- function Remove(aType,aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
- function Remove(aType,aName : TResourceDesc) : TAbstractResource; overload;
- function Remove(aResource : TAbstractResource) : TAbstractResource; overload;
- function Remove(aIndex : integer) : TAbstractResource; overload;
- procedure LoadFromStream(aStream : TStream); overload;
- procedure LoadFromStream(aStream : TStream; aReader : TAbstractResourceReader); overload;
- procedure LoadFromFile(aFileName : string); overload;
- procedure LoadFromFile(aFileName : string; aReader : TAbstractResourceReader); overload;
- class procedure RegisterReader(const aExtension : string; aClass : TResourceReaderClass);
- class procedure RegisterWriter(const aExtension : string; aClass : TResourceWriterClass);
- procedure WriteToStream(aStream : TStream; aWriter : TAbstractResourceWriter);
- procedure WriteToFile(aFileName : string); overload;
- procedure WriteToFile(aFileName : string; aWriter : TAbstractResourceWriter); overload;
- property Count : longword read GetCount;
- property Items[Index : integer] : TAbstractResource read GetItem; default;
- property CacheData : boolean read fCacheData write SetCacheData;
- end;
- { TAbstractResourceReader }
- TAbstractResourceReader = class
- private
- protected
- procedure SetDataSize(aResource : TAbstractResource; aValue : longword);
- procedure SetHeaderSize(aResource : TAbstractResource; aValue : longword);
- procedure SetDataOffset(aResource : TAbstractResource; aValue : longword);
- procedure SetRawData(aResource : TAbstractResource; aStream : TStream);
- procedure CallSubReaderLoad(aReader: TAbstractResourceReader; aResources : TResources; aStream : TStream);
- procedure AddNoTree(aResources : TResources; aResource: TAbstractResource);
- function GetTree(aResources : TResources) : TObject;
- function GetExtensions : string; virtual; abstract;
- function GetDescription : string; virtual; abstract;
- procedure Load(aResources : TResources; aStream : TStream); virtual; abstract;
- function CheckMagic(aStream : TStream) : boolean; virtual; abstract;
- public
- constructor Create; virtual; abstract;
- property Extensions : string read GetExtensions;
- property Description : string read GetDescription;
- end;
- { TAbstractResourceWriter }
- TAbstractResourceWriter = class
- private
- protected
- function GetTree(aResources : TResources) : TObject;
- function GetExtensions : string; virtual; abstract;
- function GetDescription : string; virtual; abstract;
- procedure Write(aResources : TResources; aStream : TStream); virtual; abstract;
- public
- constructor Create; virtual; abstract;
- property Extensions : string read GetExtensions;
- property Description : string read GetDescription;
- end;
- implementation
- uses resdatastream, resourcetree, resmerger;
- type
- PRegisteredStreamerEntry = ^TRegisteredStreamerEntry;
- TRegisteredStreamerEntry = record
- ext : shortstring;
- _class : TClass;
- next : PRegisteredStreamerEntry;
- end;
- var RegisteredReaders : TFPList = nil;
- RegisteredWriters : TFPList = nil;
- { TResourceDesc }
- function TResourceDesc.GetID: TResID;
- begin
- if fDescType<>dtId then
- raise EResourceDescTypeException.Create('');
- Result:=fId;
- end;
- function TResourceDesc.GetName: TResName;
- begin
- if fDescType = dtName then
- Result:=fName
- else Result:=IntToStr(fId);
- end;
- procedure TResourceDesc.CanChangeType(newType : TDescType);
- begin
- if fOwner=nil then exit;
- if newType=fDescType then exit;
- if (fOwner.OwnerList<>nil) or (not fOwner.ChangeDescTypeAllowed(self)) then
- raise EResourceDescChangeNotAllowedException.CreateFmt(SDescChangeNotAllowed,[Name]);
- end;
- procedure TResourceDesc.CanChangeValue;
- begin
- if fOwner=nil then exit;
- if (fOwner.OwnerList<>nil) or (not fOwner.ChangeDescValueAllowed(self)) then
- raise EResourceDescChangeNotAllowedException.CreateFmt(SDescChangeNotAllowed,[Name]);
- end;
- procedure TResourceDesc.SetOwner(aOwner: TAbstractResource);
- begin
- fOwner:=aOwner;
- end;
- procedure TResourceDesc.SetID(const aID: TResID);
- begin
- CanChangeType(dtID);
- CanChangeValue;
- fDescType:=dtID;
- fId:=aID;
- end;
- procedure TResourceDesc.SetName(const aName: TResName);
- begin
- CanChangeType(dtName);
- CanChangeValue;
- fDescType:=dtName;
- fName:=UpperCase(aName);
- end;
- constructor TResourceDesc.Create;
- begin
- fName:='';
- fID:=0;
- fDescType:=dtName;
- fOwner:=nil;
- end;
- constructor TResourceDesc.Create(const aID: TResID);
- begin
- Create;
- SetID(aID);
- end;
- constructor TResourceDesc.Create(const aName: TResName);
- begin
- Create;
- SetName(aName);
- end;
- procedure TResourceDesc.Assign(aResourceDesc: TResourceDesc);
- begin
- CanChangeType(aResourceDesc.fDescType);
- CanChangeValue;
- fDescType:=aResourceDesc.fDescType;
- case fDescType of
- dtID : begin fID:=aResourceDesc.fID; fName:=''; end;
- dtName : begin fName:=aResourceDesc.fName; fID:=0; end;
- end;
- end;
- function TResourceDesc.Equals(aResDesc: TResourceDesc): boolean;
- begin
- Result:=aResDesc.DescType=fDescType;
- if not Result then exit;
- case fDescType of
- dtName : Result:=aResDesc.Name=fName;
- dtID : Result:=aResDesc.ID=fID;
- end;
- end;
- { TAbstractResource }
- function TAbstractResource.GetRawData: TStream;
- begin
- if fRawData = nil then
- fRawData:=TResourceDataStream.Create(nil,self,DataSize,TCachedResourceDataStream);
- Result:=fRawData;
- end;
- function TAbstractResource.GetCacheData: boolean;
- begin
- Result:=TResourceDataStream(RawData).Cached;
- end;
- procedure TAbstractResource.SetCacheData(const aValue: boolean);
- begin
- TResourceDataStream(RawData).Cached:=aValue;
- end;
- function TAbstractResource.GetDataSize: longword;
- begin
- if fRawData=nil then Result:=fDataSize
- else Result:=fRawData.Size;
- end;
- procedure TAbstractResource.SetLangID(aLangID: TLangID);
- begin
- if OwnerList<>nil then
- raise EResourceLangIDChangeNotAllowedException.CreateFmt(SLangIDChangeNotAllowed,[Name]);
- fLangId:=aLangID;
- end;
- procedure TAbstractResource.SetDescOwner(aDesc: TResourceDesc);
- begin
- aDesc.SetOwner(self);
- end;
- procedure TAbstractResource.SetOwnerList(aResources: TResources);
- begin
- fOwnerList:=aResources;
- end;
- procedure TAbstractResource.SetChildOwner(aChild: TAbstractResource);
- begin
- aChild.fOwner:=self;
- end;
- constructor TAbstractResource.Create;
- begin
- fLangID:=0;
-
- fDataSize:=0;
- fHeaderSize:=0;
- fDataVersion:=0;
- fMemoryFlags:=MF_MOVEABLE or MF_DISCARDABLE;
- fVersion:=0;
- fCharacteristics:=0;
- fDataOffset:=0;
- fCodePage:=0;
- fRawData:=nil;
- fOwnerList:=nil;
- fOwner:=nil;
- end;
- destructor TAbstractResource.Destroy;
- begin
- if fRawData<>nil then fRawData.Free;
- end;
- function TAbstractResource.CompareContents(aResource: TAbstractResource
- ): boolean;
- begin
- Result:=TResourceDataStream(RawData).Compare(aResource.RawData);
- end;
- procedure TAbstractResource.SetCustomRawDataStream(aStream: TStream);
- begin
- TResourceDataStream(RawData).SetCustomStream(aStream);
- end;
- { TResources }
- function TResources.GetItem(index: integer): TAbstractResource;
- begin
- Result:=TAbstractResource(fList[index]);
- end;
- function TResources.GetCount: longword;
- begin
- Result:=fList.Count;
- end;
- procedure TResources.SetCacheData(const aValue: boolean);
- var i : integer;
- begin
- if aValue=fCacheData then exit;
- fCacheData:=aValue;
- if fCacheData then exit; //single resources cache data by default
- //don't cache data: load everything and free the temporary stream.
- for i:=0 to Count-1 do
- Items[i].CacheData:=aValue;
- if fTempRStream<>nil then FreeAndNil(fTempRStream);
- end;
- procedure TResources.NotifyLoaded;
- var i : integer;
- begin
- for i:=0 to Count-1 do
- Items[i].NotifyResourcesLoaded;
- end;
- class procedure TResources.InitReaderList;
- begin
- if RegisteredReaders=nil then
- RegisteredReaders:=TFPList.Create;
- end;
- class procedure TResources.InitWriterList;
- begin
- if RegisteredWriters=nil then
- RegisteredWriters:=TFPList.Create;
- end;
- class procedure TResources.DisposeStreamerList(aList: TFPList);
- var p,p2 : PRegisteredStreamerEntry;
- i : integer;
- begin
- if aList=nil then exit;
- for i:=0 to aList.Count-1 do
- begin
- p:=PRegisteredStreamerEntry(aList[i]);
- while p<>nil do
- begin
- p2:=p^.next;
- Freemem(p);
- p:=p2;
- end;
- end;
- end;
- class procedure TResources.DisposeReaderList;
- begin
- DisposeStreamerList(RegisteredReaders);
- FreeAndNil(RegisteredReaders);
- end;
- class procedure TResources.DisposeWriterList;
- begin
- DisposeStreamerList(RegisteredWriters);
- FreeAndNil(RegisteredWriters);
- end;
- class function TResources.FindReader(aStream: TStream; aExtension: string) :
- TAbstractResourceReader;
- var i : integer;
- p : PRegisteredStreamerEntry;
- position : int64;
- found : boolean;
- begin
- Result:=nil;
- InitReaderList;
- position:=aStream.Position;
- aExtension:=lowercase(aExtension);
- for i:=0 to RegisteredReaders.Count-1 do
- begin
- p:=PRegisteredStreamerEntry(RegisteredReaders[i]);
- if p^.ext=aExtension then //try all readers registered for this extension
- begin
- while p<>nil do
- begin
- Result:=TResourceReaderClass(p^._class).Create;
- found:=Result.CheckMagic(aStream);
- aStream.Position:=position; //rewind
- if found then exit;
- FreeAndNil(Result);
- p:=p^.next;
- end;
- // There are readers for this extension, but no one seems to be able
- // to read the file.
- // So, return the first reader, and it will fail later.
- p:=PRegisteredStreamerEntry(RegisteredReaders[i]);
- Result:=TResourceReaderClass(p^._class).Create;
- exit;
- end;
- end;
- raise EResourceReaderNotFoundException.Create(Format(SReaderNotFoundExt,[aExtension]));
- end;
- class function TResources.FindReader(aStream: TStream
- ): TAbstractResourceReader;
- var i : integer;
- p : PRegisteredStreamerEntry;
- position : int64;
- found : boolean;
- begin
- Result:=nil;
- InitReaderList;
- position:=aStream.Position;
- for i:=0 to RegisteredReaders.Count-1 do
- begin
- p:=PRegisteredStreamerEntry(RegisteredReaders[i]);
- while p<>nil do
- begin
- Result:=TResourceReaderClass(p^._class).Create;
- found:=Result.CheckMagic(aStream);
- aStream.Position:=position; //rewind
- if found then exit;
- FreeAndNil(Result);
- p:=p^.next;
- end;
- end;
- raise EResourceReaderNotFoundException.Create(SReaderNotFoundProbe);
- end;
- procedure TResources.MoveFrom(aResources: TResources);
- var res : TAbstractResource;
- i : integer;
- begin
- aResources.BeginMoveFrom;
- try
- for i:=0 to aResources.Count-1 do
- begin
- res:=aResources.Items[i];
- if res=nil then continue;
- if res.Owner<>nil then //If we are adding an owned resource, add
- InternalAdd(res.Owner,0,false) //the owner resource instead (it will take
- else //care of adding its sub-resources)
- InternalAdd(res,i,true);
- end;
- finally
- aResources.EndMoveFrom;
- end;
- end;
- class function TResources.FindWriterClass(aExtension: string
- ): TResourceWriterClass;
- var i : integer;
- p : PRegisteredStreamerEntry;
- begin
- Result:=nil;
- InitWriterList;
- aExtension:=lowercase(aExtension);
- for i:=0 to RegisteredWriters.Count-1 do
- begin
- p:=PRegisteredStreamerEntry(RegisteredWriters[i]);
- if p^.ext=aExtension then
- begin
- Result:=TResourceWriterClass(p^._class);
- exit;
- end;
- end;
- raise EResourceWriterNotFoundException.Create(Format(SWriterNotFoundExt,[aExtension]));
- end;
- procedure TResources.InternalAdd(aResource : TAbstractResource; prevIdx :
- integer; prevIdxValid : boolean);
- var resold : TAbstractResource;
- begin
- resold:=InternalFind(aResource._Type,aResource.Name,aResource.LangID);
- if resold<>nil then
- begin
- if TResourceMerger.Merge(resold,aResource) then exit;
- raise EResourceDuplicateException.CreateFmt(SResDuplicate,[aResource._Type.Name,aResource.Name.Name,aResource.LangID]);
- end;
- fList.Add(aResource);
- TRootResTreeNode(fTree).Add(aResource);
- if aResource.OwnerList<>nil then
- aResource.OwnerList.QuietRemove(aResource,prevIdx,prevIdxValid);
- aResource.SetOwnerList(self);
- aResource.CacheData:=fCacheData;
- end;
- procedure TResources.AddNoTree(aResource: TAbstractResource);
- begin
- fList.Add(aResource);
- aResource.SetOwnerList(self);
- aResource.CacheData:=fCacheData;
- end;
- function TResources.InternalFind(aType, aName: TResourceDesc;
- const aLangID: TLangID): TAbstractResource;
- begin
- Result:=TRootResTreeNode(fTree).Find(aType,aName,aLangID);
- end;
- function TResources.InternalFind(aType, aName: TResourceDesc
- ): TAbstractResource;
- begin
- Result:=TRootResTreeNode(fTree).Find(aType,aName);
- end;
- procedure TResources.BeginMoveFrom;
- begin
- inc(fMoveFromCount);
- fRemovedCount:=0;
- end;
- procedure TResources.EndMoveFrom;
- begin
- dec(fMoveFromCount);
- if fMoveFromCount=0 then
- if fRemovedCount=fList.Count then //all items removed: clear the list
- fList.Clear
- else
- fList.Pack; //for some reason, not all items were removed. remove only nils
- end;
- procedure TResources.Add(aResource: TAbstractResource);
- begin
- InternalAdd(aResource,0,false);
- end;
- function TResources.AddAutoID(aResource: TAbstractResource): TResID;
- var newid : TResID;
- begin
- newid:=TRootResTreeNode(fTree).FindFreeID(aResource._Type);
- //if we reached this point, ENoMoreFreeIDsException hasn't been raised.
- if aResource.OwnerList<>nil then aResource.OwnerList.Remove(aResource);
- aResource.Name.ID:=newid;
- InternalAdd(aResource,0,false);
- Result:=newid;
- end;
- //clear without freeing fTempRStream
- procedure TResources.InternalClear;
- var i : integer;
- begin
- TRootResTreeNode(fTree).Clear;
- for i:=0 to Count-1 do
- TAbstractResource(fList[i]).Free;
- fList.Clear;
- end;
- procedure TResources.Clear;
- begin
- InternalClear;
- if fTempRStream<>nil then FreeAndNil(fTempRStream);
- end;
- function TResources.Find(aType, aName: TResourceDesc; const aLangID : TLangID):
- TAbstractResource;
- begin
- Result:=TRootResTreeNode(fTree).Find(aType,aName,aLangID);
- if Result=nil then
- raise EResourceNotFoundException.CreateFmt(SResourceNotFoundLang,[aType.Name,aName.Name,aLangID]);
- end;
- function TResources.Find(aType, aName: TResourceDesc):
- TAbstractResource;
- begin
- Result:=TRootResTreeNode(fTree).Find(aType,aName);
- if Result=nil then
- raise EResourceNotFoundException.CreateFmt(SResourceNotFound,[aType.Name,aName.Name]);
- end;
- function TResources.Find(const aType: TResName; const aName: TResName; const
- aLangID : TLangID): TAbstractResource;
- begin
- dummyType.Name:=aType;
- dummyName.Name:=aName;
- Result:=Find(dummyType,dummyName,aLangID);
- end;
- function TResources.Find(const aType: TResName; const aName: TResID; const
- aLangID : TLangID ): TAbstractResource;
- begin
- dummyType.Name:=aType;
- dummyName.ID:=aName;
- Result:=Find(dummyType,dummyName,aLangID);
- end;
- function TResources.Find(const aType: TResID; const aName: TResName; const
- aLangID : TLangID ): TAbstractResource;
- begin
- dummyType.ID:=aType;
- dummyName.Name:=aName;
- Result:=Find(dummyType,dummyName,aLangID);
- end;
- function TResources.Find(const aType: TResID; const aName: TResID; const
- aLangID : TLangID ): TAbstractResource;
- begin
- dummyType.ID:=aType;
- dummyName.ID:=aName;
- Result:=Find(dummyType,dummyName,aLangID);
- end;
- function TResources.Find(const aType: TResName; const aName: TResName
- ): TAbstractResource;
- begin
- dummyType.Name:=aType;
- dummyName.Name:=aName;
- Result:=Find(dummyType,dummyName);
- end;
- function TResources.Find(const aType: TResName; const aName: TResID
- ): TAbstractResource;
- begin
- dummyType.Name:=aType;
- dummyName.ID:=aName;
- Result:=Find(dummyType,dummyName);
- end;
- function TResources.Find(const aType: TResID; const aName: TResName
- ): TAbstractResource;
- begin
- dummyType.ID:=aType;
- dummyName.Name:=aName;
- Result:=Find(dummyType,dummyName);
- end;
- function TResources.Find(const aType: TResID; const aName: TResID
- ): TAbstractResource;
- begin
- dummyType.ID:=aType;
- dummyName.ID:=aName;
- Result:=Find(dummyType,dummyName);
- end;
- function TResources.Remove(aType,aName : TResourceDesc;
- const aLangID : TLangID) : TAbstractResource;
- begin
- Result:=TRootResTreeNode(fTree).Remove(aType,aName,aLangID);
- InternalRemove(Result);
- Result.SetOwnerList(nil);
- end;
- function TResources.Remove(aType,aName : TResourceDesc) : TAbstractResource;
- begin
- Result:=TRootResTreeNode(fTree).Remove(aType,aName);
- InternalRemove(Result);
- Result.SetOwnerList(nil);
- end;
- function TResources.Remove(aResource: TAbstractResource) : TAbstractResource;
- begin
- InternalRemove(aResource);
- Result:=TRootResTreeNode(fTree).Remove(aResource._Type,aResource.Name,aResource.LangID);
- Result.SetOwnerList(nil);
- end;
- function TResources.Remove(aIndex: integer): TAbstractResource;
- begin
- Result:=Items[aIndex];
- InternalRemove(aIndex);
- Result:=TRootResTreeNode(fTree).Remove(Result._Type,Result.Name,Result.LangID);
- Result.SetOwnerList(nil);
- end;
- procedure TResources.InternalRemove(aResource: TAbstractResource);
- var idx : integer;
- begin
- if aResource=nil then exit;
- idx:=fList.IndexOf(aResource);
- if idx=-1 then
- raise EResourceNotFoundException.CreateFmt(SResourceNotFoundLang,[
- aResource._Type.Name,aResource.Name.Name,aResource.LangID]);
- if fMoveFromCount>0 then fList[idx]:=nil
- else fList.Delete(idx);
- inc(fRemovedCount);
- end;
- procedure TResources.InternalRemove(aIndex: integer);
- begin
- if fMoveFromCount>0 then fList[aIndex]:=nil
- else fList.Delete(aIndex);
- inc(fRemovedCount);
- end;
- //removes without calling setownerlist
- procedure TResources.QuietRemove(aResource : TAbstractResource; aIndex :
- integer; aIndexValid : boolean);
- begin
- if aIndexValid then InternalRemove(aIndex)
- else InternalRemove(aResource);
- TRootResTreeNode(fTree).Remove(aResource._Type,aResource.Name,aResource.LangID);
- end;
- procedure TResources.LoadFromStream(aStream: TStream);
- var aReader : TAbstractResourceReader;
- begin
- aReader:=FindReader(aStream);
- try
- LoadFromStream(aStream,aReader);
- finally
- aReader.Free;
- end;
- end;
- procedure TResources.LoadFromStream(aStream: TStream;
- aReader: TAbstractResourceReader);
- begin
- InternalClear;
- aReader.Load(self,aStream);
- NotifyLoaded;
- end;
- procedure TResources.LoadFromFile(aFileName: string);
- var ext : string;
- aReader : TAbstractResourceReader;
- begin
- ext:=ExtractFileExt(aFileName);
- if fTempRStream<>nil then FreeAndNil(fTempRStream);
- fTempRStream:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
- aReader:=FindReader(fTempRStream,ext);
- try
- LoadFromStream(fTempRStream,aReader);
- finally
- aReader.Free;
- if not fCacheData then FreeAndNil(fTempRStream);
- end;
- end;
- procedure TResources.LoadFromFile(aFileName: string;
- aReader: TAbstractResourceReader);
- begin
- if fTempRStream<>nil then FreeAndNil(fTempRStream);
- fTempRStream:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
- try
- LoadFromStream(fTempRStream,aReader);
- finally
- if not fCacheData then FreeAndNil(fTempRStream);
- end;
- end;
- class procedure TResources.RegisterStreamer(aList : TFPList; aExtension :
- string; aClass : TClass);
- var newp,p : PRegisteredStreamerEntry;
- i : integer;
- begin
- aExtension:=lowercase(aExtension);
- newp:=GetMem(sizeof(TRegisteredStreamerEntry));
- newp^.next:=nil;
- newp^.ext:=aExtension;
- newp^._class:=aClass;
- for i:=0 to aList.Count-1 do
- begin
- p:=PRegisteredStreamerEntry(aList[i]);
- if p^.ext=aExtension then
- begin
- while p^.next<>nil do
- p:=p^.next;
- p^.next:=newp;
- exit;
- end;
- end;
- aList.Add(newp);
- end;
- procedure TResources.SendUpdateRawData;
- var i : integer;
- begin
- for i:=0 to Count-1 do
- Items[i].UpdateRawData;
- end;
- class procedure TResources.RegisterReader(const aExtension : string;
- aClass: TResourceReaderClass);
- begin
- InitReaderList;
- RegisterStreamer(RegisteredReaders,aExtension,aClass);
- end;
- class procedure TResources.RegisterWriter(const aExtension : string;
- aClass: TResourceWriterClass);
- begin
- InitWriterList;
- RegisterStreamer(RegisteredWriters,aExtension,aClass);
- end;
- procedure TResources.WriteToStream(aStream: TStream;
- aWriter: TAbstractResourceWriter);
- begin
- SendUpdateRawData;
- aWriter.Write(self,aStream);
- end;
- procedure TResources.WriteToFile(aFileName: string);
- var ext : string;
- aWriter : TAbstractResourceWriter;
- begin
- ext:=ExtractFileExt(aFileName);
- aWriter:=FindWriterClass(ext).Create;
- try
- WriteToFile(aFileName,aWriter);
- finally
- aWriter.Free;
- end;
- end;
- procedure TResources.WriteToFile(aFileName: string;
- aWriter: TAbstractResourceWriter);
- var OutStream : TFileStream;
- begin
- OutStream:=TFileStream.Create(aFileName,fmCreate or fmShareDenyWrite);
- try
- WriteToStream(OutStream,aWriter);
- finally
- OutStream.Free;
- end;
- end;
- constructor TResources.Create;
- begin
- fList:=TFPList.Create;
- fTree:=TRootResTreeNode.Create;
- dummyType:=TResourceDesc.Create;
- dummyName:=TResourceDesc.Create;
- fTempRStream:=nil;
- fCacheData:=true;
- fMoveFromCount:=0;
- fRemovedCount:=0;
- end;
- destructor TResources.Destroy;
- begin
- Clear;
- fList.Free;
- fTree.Free;
- dummyType.Free;
- dummyName.Free;
- end;
- { TAbstractResourceReader }
- procedure TAbstractResourceReader.SetDataSize(aResource: TAbstractResource;
- aValue: longword);
- begin
- aResource.fDataSize:=aValue;
- end;
- procedure TAbstractResourceReader.SetHeaderSize(aResource: TAbstractResource;
- aValue: longword);
- begin
- aResource.fHeaderSize:=aValue;
- end;
- procedure TAbstractResourceReader.SetDataOffset(aResource: TAbstractResource;
- aValue: longword);
- begin
- aResource.fDataOffset:=aValue;
- end;
- procedure TAbstractResourceReader.SetRawData(aResource: TAbstractResource;
- aStream: TStream);
- begin
- if aResource.fRawData<>nil then aResource.fRawData.Free; //should never happen!
- aResource.fRawData:=aStream;
- end;
- procedure TAbstractResourceReader.CallSubReaderLoad(
- aReader: TAbstractResourceReader; aResources: TResources; aStream: TStream);
- begin
- aReader.Load(aResources,aStream);
- end;
- procedure TAbstractResourceReader.AddNoTree(aResources: TResources;
- aResource: TAbstractResource);
- begin
- aResources.AddNoTree(aResource);
- end;
- function TAbstractResourceReader.GetTree(aResources: TResources): TObject;
- begin
- Result:=aResources.fTree;
- end;
- { TGenericResource }
- function TGenericResource.ChangeDescTypeAllowed(aDesc: TResourceDesc): boolean;
- begin
- Result:=true;
- end;
- function TGenericResource.ChangeDescValueAllowed(aDesc: TResourceDesc
- ): boolean;
- begin
- Result:=true;
- end;
- procedure TGenericResource.NotifyResourcesLoaded;
- begin
- end;
- procedure TGenericResource.UpdateRawData;
- begin
- end;
- function TGenericResource.GetType : TResourceDesc;
- begin
- Result:=fType;
- end;
- function TGenericResource.GetName : TResourceDesc;
- begin
- Result:=fName;
- end;
- constructor TGenericResource.Create(aType, aName: TResourceDesc);
- begin
- Create;
- fType:=TResourceDesc.Create;
- fType.Assign(aType);
- fName:=TResourceDesc.Create;
- fName.Assign(aName);
- SetDescOwner(fType);
- SetDescOwner(fName);
- end;
- destructor TGenericResource.Destroy;
- begin
- fName.Free;
- fType.Free;
- inherited Destroy;
- end;
- { TAbstractResourceWriter }
- function TAbstractResourceWriter.GetTree(aResources: TResources): TObject;
- begin
- Result:=aResources.fTree;
- end;
- finalization
- TResources.DisposeReaderList;
- TResources.DisposeWriterList;
- end.
|