Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
fpc-src / usr / share / fpcsrc / 3.0.0 / packages / fcl-res / src / resourcetree.pp
Size: Mime:
{
    This file is part of the Free Pascal run time library.
    Copyright (c) 2008 by Giulio Bernardi

    Implements an ordered tree of resources

    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 resourcetree;

{$MODE OBJFPC}

interface

uses
  Classes, SysUtils, resource;

type

  { TResourceTreeNode }

  TResourceTreeNode = class
  protected
    fParent : TResourceTreeNode;
    fNamedEntries : TFPList;
    fIDEntries : TFPList;
    fSubDirRVA : longword;
    fDataRVA : longword;
    fNameRva : longword;
    fDesc : TResourceDesc;
    function GetNamedCount : longword;
    function GetNamedEntry(index : integer) : TResourceTreeNode;
    function GetIDCount : longword;
    function GetIDEntry(index : integer) : TResourceTreeNode;
    function GetData : TAbstractResource; virtual;
    function InternalFind(aList : TFPList; aDesc : TResourceDesc; out index : integer) : boolean; overload;
    function InternalFind(aList : TFPList; aLangID : TLangID; out index : integer) : boolean; overload;
    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; virtual; abstract; overload;
    constructor Create; virtual; overload;
    property Parent : TResourceTreeNode read fParent;
  public
    destructor Destroy; override;
    procedure Add(aResource : TAbstractResource); virtual; abstract;
    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; virtual; abstract;
    function CreateResource : TAbstractResource; virtual;
    procedure Clear;
    function Remove(aType, aName : TResourceDesc) : TAbstractResource; overload;
    function Remove(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
    function Find(aType, aName : TResourceDesc) : TAbstractResource; overload;
    function Find(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
    function FindFreeID(aType : TResourceDesc) : TResID; virtual;
    function IsLeaf : boolean; virtual;
    property Desc : TResourceDesc read fDesc;
    property NamedCount : longword read GetNamedCount;
    property NamedEntries[index : integer] : TResourceTreeNode read GetNamedEntry;
    property IDCount : longword read GetIDCount;
    property IDEntries[index : integer] : TResourceTreeNode read GetIDEntry;
    property NameRVA : longword read fNameRVA write fNameRVA;
    property SubDirRVA : longword read fSubDirRVA write fSubDirRVA;
    property DataRVA : longword read fDataRVA write fDataRVA;
    property Data : TAbstractResource read GetData;
  end;

  { TRootResTreeNode }

  TRootResTreeNode = class (TResourceTreeNode)
  protected
    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
  public
    constructor Create; override;
    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
    procedure Add(aResource : TAbstractResource); override;
    function FindFreeID(aType : TResourceDesc) : TResID; override;
  end;

implementation

uses resfactory;

  { TTypeResTreeNode }

type
  TTypeResTreeNode = class (TResourceTreeNode)
  protected
    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
  public
    constructor Create(aType : TResourceDesc; aParent : TResourceTreeNode); overload;
    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
    procedure Add(aResource : TAbstractResource); override;
    function FindFreeID(aType : TResourceDesc) : TResID; override;
  end;

  { TNameResTreeNode }

  TNameResTreeNode = class (TResourceTreeNode)
  protected
    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
  public
    constructor Create(aName : TResourceDesc; aParent : TResourceTreeNode); overload;
    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
    procedure Add(aResource : TAbstractResource); override;
  end;

  { TLangIDResTreeNode }

  TLangIDResTreeNode = class (TResourceTreeNode)
  private
    fData : TAbstractResource;
  protected
    function GetData : TAbstractResource; override;
    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
  public
    constructor Create(aLangID : TLangID; aResource : TAbstractResource; aParent : TResourceTreeNode); overload;
    function CreateResource : TAbstractResource; override;
    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
    procedure Add(aResource : TAbstractResource); override;
    function IsLeaf : boolean; override;
  end;

function CompareDesc(desc1, desc2 : TResourceDesc) : integer;
begin
  if desc1.DescType=desc2.DescType then
  begin
    case desc1.DescType of
      dtID : Result:=desc1.ID - desc2.ID;
      dtName : Result:=CompareStr(desc1.Name,desc2.Name);
    end;
  end
  else
    case desc1.DescType of
      dtID : Result:=1;
      dtName : Result:=-1;
    end;
end;

function ResListCompare(Item1: Pointer;Item2: Pointer) : Integer;
var node1, node2 : TResourceTreeNode;
begin
  node1:=TResourceTreeNode(Item1);
  node2:=TResourceTreeNode(Item2);
  Result:=CompareDesc(node1.Desc,node2.Desc);
end;

{ TResourceTreeNode }

function TResourceTreeNode.GetIDEntry(index : integer): TResourceTreeNode;
begin
  Result:=TResourceTreeNode(fIDEntries[index]);
end;

function TResourceTreeNode.GetData: TAbstractResource;
begin
  Result:=nil;
end;

function TResourceTreeNode.InternalFind(aList: TFPList; aDesc: TResourceDesc; out index: integer
  ): boolean;
var l, r, p,res : integer;
begin
  Result:=true;
  l:=0;
  r:=aList.Count-1;

  while l<=r do
  begin
    p:=(l+r) div 2;
    res:=CompareDesc(TResourceTreeNode(aList[p]).Desc, aDesc);
    if res<0 then l:=p+1
    else if res>0 then r:=p-1
    else if res=0 then
    begin
      index:=p;
      exit;
    end;
  end;
  index:=l; //the item can be inserted here
  Result:=false;
end;

function TResourceTreeNode.InternalFind(aList: TFPList; aLangID: TLangID; out
  index: integer): boolean;
var l, r, p,res : integer;
begin
  Result:=true;
  l:=0;
  r:=aList.Count-1;

  while l<=r do
  begin
    p:=(l+r) div 2;
    if TResourceTreeNode(aList[p]).Desc.DescType=dtName then res:=-1
    else res:=TResourceTreeNode(aList[p]).Desc.ID - aLangID;
    if res<0 then l:=p+1
    else if res>0 then r:=p-1
    else if res=0 then
    begin
      index:=p;
      exit;
    end;
  end;
  index:=l; //the item can be inserted here
  Result:=false;
end;

function TResourceTreeNode.GetNamedEntry(index : integer): TResourceTreeNode;
begin
  Result:=TResourceTreeNode(fNamedEntries[index]);
end;

function TResourceTreeNode.GetNamedCount: longword;
begin
  Result:=fNamedEntries.Count;
end;

function TResourceTreeNode.GetIDCount: longword;
begin
  Result:=fIDEntries.Count;
end;

constructor TResourceTreeNode.Create;
begin
  fDesc:=TResourceDesc.Create(0);
  fNamedEntries:=TFPList.Create;
  fIDEntries:=TFPList.Create;
  fNameRVA:=0;
  fSubDirRva:=0;
  fDataRVA:=0;
  fParent:=nil;
end;

destructor TResourceTreeNode.Destroy;
begin
  fDesc.Free;
  Clear;
  fNamedEntries.Free;
  fIDEntries.Free;
end;

function TResourceTreeNode.CreateResource: TAbstractResource;
begin
  Result:=nil;
end;

procedure TResourceTreeNode.Clear;
var i : integer;
begin
  for i:=0 to fNamedEntries.Count-1 do
    TResourceTreeNode(fNamedEntries[i]).Free;
  for i:=0 to fIDEntries.Count-1 do
    TResourceTreeNode(fIDEntries[i]).Free;
  fNamedEntries.Clear;
  fIDEntries.Clear;
end;

function TResourceTreeNode.Remove(aType, aName: TResourceDesc
  ): TAbstractResource;
begin
  Result:=InternalFind(aType,aName,0,true,true);
end;

function TResourceTreeNode.Remove(aType, aName: TResourceDesc;
  const aLangID: TLangID): TAbstractResource;
begin
  Result:=InternalFind(aType,aName,aLangID,false,true);
end;

function TResourceTreeNode.Find(aType, aName: TResourceDesc
  ): TAbstractResource;
begin
  Result:=InternalFind(aType,aName,0,true,false);
end;

function TResourceTreeNode.Find(aType, aName: TResourceDesc;
  const aLangID: TLangID): TAbstractResource;
begin
  Result:=InternalFind(aType,aName,aLangID,false,false);
end;

function TResourceTreeNode.FindFreeID(aType: TResourceDesc): TResID;
begin
  Result:=0;
end;

function TResourceTreeNode.IsLeaf: boolean;
begin
  Result:=false;
end;

{ TRootResTreeNode }

constructor TRootResTreeNode.Create;
begin
  inherited Create;
end;

function TRootResTreeNode.CreateSubNode(aDesc: TResourceDesc
  ): TResourceTreeNode;
var theList : TFPList;
begin
  case aDesc.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  Result:=TTypeResTreeNode.Create(aDesc,self);
  thelist.Add(Result);
end;

procedure TRootResTreeNode.Add(aResource: TAbstractResource);
var theList : TFPList;
    idx : integer;
    subitem : TResourceTreeNode;
begin
  case aResource._Type.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  if InternalFind(theList,aResource._Type,idx) then
    subitem:=TResourceTreeNode(theList[idx])
  else
  begin
    subitem:=TTypeResTreeNode.Create(aResource._Type,self);
    theList.Insert(idx,subitem);
  end;
  subitem.Add(aResource);
end;

function TRootResTreeNode.FindFreeID(aType: TResourceDesc): TResID;
var theList : TFPList;
    idx : integer;
    subitem : TResourceTreeNode;
begin
  Result:=1;
  case aType.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  if InternalFind(theList,aType,idx) then
    subitem:=TResourceTreeNode(theList[idx])
  else exit;
  Result:=subitem.FindFreeID(aType);
end;

function TRootResTreeNode.InternalFind(aType, aName : TResourceDesc;
  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
var theList : TFPList;
    idx : integer;
    subitem : TResourceTreeNode;
begin
  Result:=nil;
  case aType.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  if InternalFind(theList,aType,idx) then
    subitem:=TResourceTreeNode(theList[idx])
  else exit;
  Result:=subitem.InternalFind(aType,aName,aLangID,noLangID,toDelete);
  if toDelete and ((subitem.IDCount+subitem.NamedCount)=0) then
  begin
    subitem.Free;
    theList.Delete(idx);
  end;
end;

{ TTypeResTreeNode }

constructor TTypeResTreeNode.Create(aType: TResourceDesc;
  aParent: TResourceTreeNode);
begin
  inherited Create;
  fDesc.Assign(aType);
  fParent:=aParent;
end;

function TTypeResTreeNode.CreateSubNode(aDesc: TResourceDesc
  ): TResourceTreeNode;
var theList : TFPList;
begin
  case aDesc.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  Result:=TNameResTreeNode.Create(aDesc,self);
  thelist.Add(Result);
end;

procedure TTypeResTreeNode.Add(aResource: TAbstractResource);
var theList : TFPList;
    idx : integer;
    subitem : TResourceTreeNode;
begin
  case aResource.Name.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  if InternalFind(theList,aResource.Name,idx) then
    subitem:=TResourceTreeNode(theList[idx])
  else
  begin
    subitem:=TNameResTreeNode.Create(aResource.Name,self);
    theList.Insert(idx,subitem);
  end;
  subitem.Add(aResource);
end;

function TTypeResTreeNode.FindFreeID(aType: TResourceDesc): TResID;
var i : integer;
begin
  Result:=1;
  if IDCount<=0 then exit; //no items, use 1
  Result:=IDEntries[IDCount-1].Desc.ID+1; //try last one+1
  if Result>$FFFF then
    if IDEntries[0].Desc.ID>1 then Result:=IDEntries[0].Desc.ID-1 //try first one-1
    else
    begin //scan the whole list to find the first free id.
      Result:=1;
      for i:=0 to IDCount-1 do
      begin
        if IDEntries[i].Desc.ID<>Result then exit;
        inc(Result);
      end;
      raise ENoMoreFreeIDsException.Create('');
    end;
end;

function TTypeResTreeNode.InternalFind(aType, aName : TResourceDesc;
  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
var theList : TFPList;
    idx : integer;
    subitem : TResourceTreeNode;
begin
  Result:=nil;
  case aName.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  if InternalFind(theList,aName,idx) then
    subitem:=TResourceTreeNode(theList[idx])
  else exit;
  Result:=subitem.InternalFind(aType,aName,aLangID,noLangID,toDelete);
  if toDelete and ((subitem.IDCount+subitem.NamedCount)=0) then
  begin
    subitem.Free;
    theList.Delete(idx);
  end;
end;

{ TNameResTreeNode }

constructor TNameResTreeNode.Create(aName: TResourceDesc;
  aParent: TResourceTreeNode);
begin
  inherited Create;
  fDesc.Assign(aName);
  fParent:=aParent;
end;

function TNameResTreeNode.CreateSubNode(aDesc: TResourceDesc
  ): TResourceTreeNode;
var theList : TFPList;
begin
  case aDesc.DescType of
    dtID : theList:=fIDEntries;
    dtName : theList:=fNamedEntries;
  end;
  Result:=TLangIDResTreeNode.Create(aDesc.ID,nil,self);
  thelist.Add(Result);
end;

procedure TNameResTreeNode.Add(aResource: TAbstractResource);
var idx : integer;
    subitem : TResourceTreeNode;
begin
  if InternalFind(fIDEntries,aResource.LangID,idx) then
    raise EResourceDuplicateException.Create('');

  subitem:=TLangIDResTreeNode.Create(aResource.LangID,aResource,self);
  fIDEntries.Insert(idx,subitem);
end;

function TNameResTreeNode.InternalFind(aType, aName : TResourceDesc;
  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
var idx : integer;
begin
  Result:=nil;
  if noLangID then
  begin
    if IDCount<=0 then exit
    else idx:=0;
  end
  else
  if not InternalFind(fIDEntries,aLangID,idx) then exit;

  Result:=IDEntries[idx].Data;
  if toDelete then
  begin
    IDEntries[idx].Free;
    fIDEntries.Delete(idx);
  end;
end;

{ TLangIDResTreeNode }

function TLangIDResTreeNode.GetData: TAbstractResource;
begin
  Result:=fData;
end;

constructor TLangIDResTreeNode.Create(aLangID: TLangID;
  aResource: TAbstractResource; aParent: TResourceTreeNode);
begin
  inherited Create;
  fDesc.ID:=aLangID;
  fData:=aResource;
  fParent:=aParent;
end;

function TLangIDResTreeNode.CreateResource: TAbstractResource;
var theType, theName : TResourceDesc;
begin
  Result:=nil;
  if fData<>nil then exit;
  theType:=Parent.Parent.Desc;
  theName:=Parent.Desc;
  fData:=TResourceFactory.CreateResource(theType,theName);
  fData.LangID:=fDesc.ID;
  Result:=fData;
end;

function TLangIDResTreeNode.CreateSubNode(aDesc: TResourceDesc
  ): TResourceTreeNode;
begin
  Result:=nil;
end;

procedure TLangIDResTreeNode.Add(aResource: TAbstractResource);
begin
  //can't add, it's a leaf node
end;

function TLangIDResTreeNode.InternalFind(aType, aName : TResourceDesc;
  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
begin
  //can't find, it's a leaf node
  Result:=nil;
end;

function TLangIDResTreeNode.IsLeaf: boolean;
begin
  Result:=true;
end;

end.