mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
1055 lines
28 KiB
ObjectPascal
1055 lines
28 KiB
ObjectPascal
unit uFile;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
uFileProperty,
|
|
DCBasicTypes;
|
|
|
|
type
|
|
|
|
{ TFile }
|
|
|
|
TFile = class
|
|
|
|
private
|
|
// Cached values for extension and name.
|
|
// Automatically set when name changes.
|
|
FExtension: String; //<en Extension.
|
|
FNameNoExt: String; //<en Name without extension.
|
|
FPath: String; //<en Path to the file. Always includes trailing path delimiter.
|
|
FProperties: TFileProperties;
|
|
FVariantProperties: TFileVariantProperties;
|
|
FSupportedProperties: TFilePropertiesTypes;
|
|
|
|
procedure SplitIntoNameAndExtension(const FileName: string;
|
|
var aFileNameOnly: string;
|
|
var aExtension: string);
|
|
procedure UpdateNameAndExtension(const FileName: string);
|
|
|
|
protected
|
|
function GetProperty(PropType: TFilePropertyType): TFileProperty;
|
|
procedure SetProperty(PropType: TFilePropertyType; NewValue: TFileProperty);
|
|
function GetFullPath: String;
|
|
procedure SetFullPath(const NewFullPath: String);
|
|
procedure SetPath(const NewPath: String);
|
|
function GetName: String;
|
|
procedure SetName(NewName: String);
|
|
function GetExtension: String;
|
|
{en
|
|
Retrieves name without extension.
|
|
}
|
|
function GetNameNoExt: String;
|
|
|
|
// Values.
|
|
function GetAttributes: TFileAttrs;
|
|
procedure SetAttributes(NewAttributes: TFileAttrs);
|
|
function GetSize: Int64;
|
|
procedure SetSize(NewSize: Int64);
|
|
function GetCompressedSize: Int64;
|
|
procedure SetCompressedSize(NewCompressedSize: Int64);
|
|
function GetModificationTime: TDateTime;
|
|
procedure SetModificationTime(NewTime: TDateTime);
|
|
function GetCreationTime: TDateTime;
|
|
procedure SetCreationTime(NewTime: TDateTime);
|
|
function GetLastAccessTime: TDateTime;
|
|
procedure SetLastAccessTime(NewTime: TDateTime);
|
|
function GetChangeTime: TDateTime;
|
|
procedure SetChangeTime(AValue: TDateTime);
|
|
function GetIsLinkToDirectory: Boolean;
|
|
procedure SetIsLinkToDirectory(NewValue: Boolean);
|
|
function GetType: String;
|
|
procedure SetType(NewValue: String);
|
|
|
|
// Properties.
|
|
function GetNameProperty: TFileNameProperty;
|
|
procedure SetNameProperty(NewValue: TFileNameProperty);
|
|
function GetSizeProperty: TFileSizeProperty;
|
|
procedure SetSizeProperty(NewValue: TFileSizeProperty);
|
|
function GetCompressedSizeProperty: TFileCompressedSizeProperty;
|
|
procedure SetCompressedSizeProperty(NewValue: TFileCompressedSizeProperty);
|
|
function GetAttributesProperty: TFileAttributesProperty;
|
|
procedure SetAttributesProperty(NewValue: TFileAttributesProperty);
|
|
function GetModificationTimeProperty: TFileModificationDateTimeProperty;
|
|
procedure SetModificationTimeProperty(NewValue: TFileModificationDateTimeProperty);
|
|
function GetCreationTimeProperty: TFileCreationDateTimeProperty;
|
|
procedure SetCreationTimeProperty(NewValue: TFileCreationDateTimeProperty);
|
|
function GetLastAccessTimeProperty: TFileLastAccessDateTimeProperty;
|
|
procedure SetLastAccessTimeProperty(NewValue: TFileLastAccessDateTimeProperty);
|
|
function GetChangeTimeProperty: TFileChangeDateTimeProperty;
|
|
procedure SetChangeTimeProperty(AValue: TFileChangeDateTimeProperty);
|
|
function GetLinkProperty: TFileLinkProperty;
|
|
procedure SetLinkProperty(NewValue: TFileLinkProperty);
|
|
function GetOwnerProperty: TFileOwnerProperty;
|
|
procedure SetOwnerProperty(NewValue: TFileOwnerProperty);
|
|
function GetTypeProperty: TFileTypeProperty;
|
|
procedure SetTypeProperty(NewValue: TFileTypeProperty);
|
|
function GetCommentProperty: TFileCommentProperty;
|
|
procedure SetCommentProperty(NewValue: TFileCommentProperty);
|
|
public
|
|
constructor Create(const APath: String);
|
|
constructor CreateForCloning;
|
|
destructor Destroy; override;
|
|
|
|
{en
|
|
Creates an identical copy of the object (as far as object data is concerned).
|
|
}
|
|
function Clone: TFile;
|
|
procedure CloneTo(AFile: TFile);
|
|
|
|
{en
|
|
Frees all properties except for Name (which is always required).
|
|
}
|
|
procedure ClearProperties;
|
|
procedure ClearVariantProperties;
|
|
function ReleaseProperty(PropType: TFilePropertyType): TFileProperty;
|
|
|
|
{en
|
|
Returns True if name is not '..'.
|
|
May be extended to include other conditions.
|
|
}
|
|
function IsNameValid: Boolean;
|
|
|
|
{en
|
|
This list only contains pointers to TFileProperty objects.
|
|
Never free element from this list!
|
|
|
|
Choices for implementing retrieval of file properties:
|
|
|
|
1. array [TFilePropertyType] of TFileProperty (current implementation)
|
|
|
|
Upside: it should be the fastest method.
|
|
Downside: uses more memory as the array size includes properties
|
|
not supported by the given file type
|
|
|
|
2. hash table indexed by TFilePropertyType key.
|
|
|
|
It _may_ be a bit slower than the table.
|
|
It _may_ use less memory though.
|
|
|
|
3. a simple list
|
|
|
|
Slowest, but the least memory usage.
|
|
}
|
|
//property Properties[Index: Integer];
|
|
//property Properties[Name: String];
|
|
//property Properties[Type: TFilePropertiesType]
|
|
property VariantProperties: TFileVariantProperties read FVariantProperties;
|
|
property Properties[PropType: TFilePropertyType]: TFileProperty read GetProperty write SetProperty;
|
|
|
|
{en
|
|
All supported properties should have an assigned Properties[propertyType].
|
|
}
|
|
property SupportedProperties: TFilePropertiesTypes read FSupportedProperties;
|
|
property AssignedProperties: TFilePropertiesTypes read FSupportedProperties;
|
|
|
|
{ Accessors to each property. }
|
|
|
|
property NameProperty: TFileNameProperty read GetNameProperty write SetNameProperty;
|
|
property SizeProperty: TFileSizeProperty read GetSizeProperty write SetSizeProperty;
|
|
property CompressedSizeProperty: TFileCompressedSizeProperty read GetCompressedSizeProperty write SetCompressedSizeProperty;
|
|
property AttributesProperty: TFileAttributesProperty read GetAttributesProperty write SetAttributesProperty;
|
|
property ModificationTimeProperty: TFileModificationDateTimeProperty read GetModificationTimeProperty write SetModificationTimeProperty;
|
|
property CreationTimeProperty: TFileCreationDateTimeProperty read GetCreationTimeProperty write SetCreationTimeProperty;
|
|
property LastAccessTimeProperty: TFileLastAccessDateTimeProperty read GetLastAccessTimeProperty write SetLastAccessTimeProperty;
|
|
property ChangeTimeProperty: TFileChangeDateTimeProperty read GetChangeTimeProperty write SetChangeTimeProperty;
|
|
property LinkProperty: TFileLinkProperty read GetLinkProperty write SetLinkProperty;
|
|
property OwnerProperty: TFileOwnerProperty read GetOwnerProperty write SetOwnerProperty;
|
|
property TypeProperty: TFileTypeProperty read GetTypeProperty write SetTypeProperty;
|
|
property CommentProperty: TFileCommentProperty read GetCommentProperty write SetCommentProperty;
|
|
|
|
{ Accessors to each property's value. }
|
|
|
|
{en
|
|
Sets/gets absolute path to file.
|
|
On get returns Path + Name.
|
|
On set sets Path and Name accordingly.
|
|
}
|
|
property FullPath: String read GetFullPath write SetFullPath;
|
|
property Path: String read FPath write SetPath;
|
|
property Name: String read GetName write SetName;
|
|
property NameNoExt: String read GetNameNoExt;
|
|
property Extension: String read GetExtension;
|
|
property Size: Int64 read GetSize write SetSize;
|
|
property CompressedSize: Int64 read GetCompressedSize write SetCompressedSize;
|
|
property Attributes: TFileAttrs read GetAttributes write SetAttributes;
|
|
property ModificationTime: TDateTime read GetModificationTime write SetModificationTime;
|
|
property CreationTime: TDateTime read GetCreationTime write SetCreationTime;
|
|
property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime;
|
|
property ChangeTime: TDateTime read GetChangeTime write SetChangeTime;
|
|
property FileType: String read GetType write SetType;
|
|
|
|
// Convenience functions.
|
|
// We assume here that when the file has no attributes
|
|
// the result is false for all these functions.
|
|
// These functions should probably be moved from here and should not be methods.
|
|
function IsDirectory: Boolean;
|
|
function IsSysFile: Boolean;
|
|
function IsHidden: Boolean;
|
|
function IsLink: Boolean;
|
|
property IsLinkToDirectory: Boolean read GetIsLinkToDirectory write SetIsLinkToDirectory;
|
|
function IsExecutable: Boolean; // for ShellExecute
|
|
end;
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
{ TFiles }
|
|
|
|
TFiles = class { A list of TFile }
|
|
|
|
private
|
|
FList: TFPList;
|
|
FFlat: Boolean;
|
|
FOwnsObjects: Boolean;
|
|
FPath: String; //<en path of all files
|
|
|
|
protected
|
|
function GetCount: Integer;
|
|
procedure SetCount(Count: Integer);
|
|
|
|
function Get(Index: Integer): TFile;
|
|
procedure Put(Index: Integer; AFile: TFile);
|
|
|
|
procedure SetPath(const NewPath: String);
|
|
|
|
public
|
|
constructor Create(const APath: String);
|
|
destructor Destroy; override;
|
|
|
|
{en
|
|
Create a list with cloned files.
|
|
}
|
|
function Clone: TFiles;
|
|
procedure CloneTo(Files: TFiles);
|
|
|
|
function Add(AFile: TFile): Integer;
|
|
procedure Insert(AFile: TFile; AtIndex: Integer);
|
|
procedure Delete(AtIndex: Integer);
|
|
procedure Clear;
|
|
|
|
property Count: Integer read GetCount write SetCount;
|
|
property Items[Index: Integer]: TFile read Get write Put; default;
|
|
property List: TFPList read FList;
|
|
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
|
|
property Path: String read FPath write SetPath;
|
|
property Flat: Boolean read FFlat write FFlat;
|
|
|
|
end;
|
|
|
|
{en
|
|
Tree structure representing directories/files hierarchy.
|
|
}
|
|
TFileTreeNode = class
|
|
private
|
|
{en
|
|
File object associated with this node.
|
|
}
|
|
FFile: TFile;
|
|
{en
|
|
Subnodes - usually files within a directory.
|
|
This is a list of TFileTreeNode.
|
|
}
|
|
FSubNodes: TFPList;
|
|
{en
|
|
Additional data stored in the node.
|
|
If assigned, it is automatically freed when node is destroyed.
|
|
}
|
|
FData: TObject;
|
|
|
|
protected
|
|
function Get(Index: Integer): TFileTreeNode;
|
|
|
|
function GetCount: Integer;
|
|
procedure SetCount(Count: Integer);
|
|
|
|
procedure SetData(NewData: TObject);
|
|
|
|
public
|
|
constructor Create; overload;
|
|
constructor Create(aFile: TFile); overload;
|
|
constructor Create(aFile: TFile; DataClass: TClass); overload;
|
|
destructor Destroy; override;
|
|
|
|
function AddSubNode(aFile: TFile): Integer;
|
|
procedure RemoveSubNode(Index: Integer);
|
|
|
|
property SubNodesCount: Integer read GetCount write SetCount;
|
|
property SubNodes[Index: Integer]: TFileTreeNode read Get;
|
|
property TheFile: TFile read FFile;
|
|
property Data: TObject read FData write SetData;
|
|
end;
|
|
|
|
TFileTree = TFileTreeNode; // alias
|
|
|
|
implementation
|
|
|
|
{$IFDEF UNIX}
|
|
uses
|
|
DCFileAttributes;
|
|
{$ENDIF}
|
|
|
|
constructor TFile.Create(const APath: String);
|
|
begin
|
|
inherited Create;
|
|
|
|
// Name property always present.
|
|
NameProperty := TFileNameProperty.Create;
|
|
|
|
Path := APath;
|
|
end;
|
|
|
|
constructor TFile.CreateForCloning;
|
|
begin
|
|
// Create empty object.
|
|
inherited Create;
|
|
end;
|
|
|
|
destructor TFile.Destroy;
|
|
var
|
|
AIndex: Integer;
|
|
PropertyType: TFilePropertyType;
|
|
begin
|
|
inherited Destroy;
|
|
|
|
for PropertyType := Low(FProperties) to High(FProperties) do
|
|
FProperties[PropertyType].Free;
|
|
|
|
for AIndex:= Low(FVariantProperties) to High(FVariantProperties) do
|
|
FVariantProperties[AIndex].Free;
|
|
end;
|
|
|
|
function TFile.Clone: TFile;
|
|
begin
|
|
Result := TFile.CreateForCloning;
|
|
CloneTo(Result);
|
|
end;
|
|
|
|
procedure TFile.CloneTo(AFile: TFile);
|
|
var
|
|
AIndex: Integer;
|
|
PropertyType: TFilePropertyType;
|
|
begin
|
|
if Assigned(AFile) then
|
|
begin
|
|
AFile.FExtension := FExtension;
|
|
AFile.FNameNoExt := FNameNoExt;
|
|
AFile.FPath := FPath;
|
|
AFile.FSupportedProperties := FSupportedProperties;
|
|
|
|
for PropertyType := Low(FProperties) to High(FProperties) do
|
|
begin
|
|
if Assigned(Self.FProperties[PropertyType]) then
|
|
begin
|
|
AFile.FProperties[PropertyType] := Self.FProperties[PropertyType].Clone;
|
|
end;
|
|
end;
|
|
|
|
SetLength(AFile.FVariantProperties, Length(FVariantProperties));
|
|
for AIndex:= Low(FVariantProperties) to High(FVariantProperties) do
|
|
begin
|
|
if Assigned(Self.FVariantProperties[AIndex]) then
|
|
begin
|
|
AFile.FVariantProperties[AIndex] := Self.FVariantProperties[AIndex].Clone;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFile.ClearProperties;
|
|
var
|
|
PropertyType: TFilePropertyType;
|
|
begin
|
|
ClearVariantProperties;
|
|
for PropertyType := TFilePropertyType(Ord(fpName) + 1) to High(FProperties) do
|
|
FreeAndNil(FProperties[PropertyType]);
|
|
FSupportedProperties := [fpName];
|
|
end;
|
|
|
|
procedure TFile.ClearVariantProperties;
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
for AIndex:= Low(FVariantProperties) to High(FVariantProperties) do
|
|
FreeAndNil(FVariantProperties[AIndex]);
|
|
FSupportedProperties := FSupportedProperties * fpAll;
|
|
end;
|
|
|
|
function TFile.ReleaseProperty(PropType: TFilePropertyType): TFileProperty;
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
if PropType in fpVariantAll then
|
|
begin
|
|
AIndex := Ord(PropType) - Ord(fpVariant);
|
|
if (AIndex >= 0) and (AIndex <= High(FVariantProperties)) then
|
|
begin
|
|
Result := FVariantProperties[AIndex];
|
|
FVariantProperties[AIndex] := nil;
|
|
end;
|
|
end
|
|
else begin
|
|
Result := FProperties[PropType];
|
|
FProperties[PropType] := nil;
|
|
end;
|
|
Exclude(FSupportedProperties, PropType);
|
|
end;
|
|
|
|
function TFile.GetExtension: String;
|
|
begin
|
|
Result := FExtension;
|
|
end;
|
|
|
|
function TFile.GetNameNoExt: String;
|
|
begin
|
|
Result := FNameNoExt;
|
|
end;
|
|
|
|
function TFile.GetName: String;
|
|
begin
|
|
Result := TFileNameProperty(FProperties[fpName]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetName(NewName: String);
|
|
begin
|
|
TFileNameProperty(FProperties[fpName]).Value := NewName;
|
|
UpdateNameAndExtension(NewName);
|
|
end;
|
|
|
|
function TFile.GetProperty(PropType: TFilePropertyType): TFileProperty;
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
if PropType < fpInvalid then
|
|
Result := FProperties[PropType]
|
|
else begin
|
|
AIndex := Ord(PropType) - Ord(fpVariant);
|
|
if (AIndex >= 0) and (AIndex <= High(FVariantProperties)) then
|
|
Result := FVariantProperties[AIndex]
|
|
else begin
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFile.SetProperty(PropType: TFilePropertyType; NewValue: TFileProperty);
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
if PropType < fpInvalid then
|
|
FProperties[PropType] := NewValue
|
|
else begin
|
|
AIndex := Ord(PropType) - Ord(fpVariant);
|
|
if AIndex > High(FVariantProperties) then
|
|
SetLength(FVariantProperties, AIndex + 4);
|
|
FVariantProperties[AIndex]:= NewValue;
|
|
end;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, PropType)
|
|
else
|
|
Exclude(FSupportedProperties, PropType);
|
|
end;
|
|
|
|
function TFile.GetFullPath: String;
|
|
begin
|
|
Result := Path + TFileNameProperty(FProperties[fpName]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetFullPath(const NewFullPath: String);
|
|
var
|
|
aExtractedName: String;
|
|
begin
|
|
if NewFullPath <> '' then
|
|
begin
|
|
if NewFullPath[Length(NewFullPath)] = PathDelim then
|
|
begin
|
|
// Only path passed.
|
|
SetPath(NewFullPath);
|
|
SetName('');
|
|
end
|
|
else
|
|
begin
|
|
aExtractedName := ExtractFileName(NewFullPath);
|
|
SetPath(Copy(NewFullPath, 1, Length(NewFullPath) - Length(aExtractedName)));
|
|
SetName(aExtractedName);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFile.SetPath(const NewPath: String);
|
|
begin
|
|
if NewPath = '' then
|
|
FPath := ''
|
|
else
|
|
FPath := IncludeTrailingPathDelimiter(NewPath);
|
|
end;
|
|
|
|
function TFile.GetAttributes: TFileAttrs;
|
|
begin
|
|
Result := TFileAttributesProperty(FProperties[fpAttributes]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetAttributes(NewAttributes: TFileAttrs);
|
|
begin
|
|
TFileAttributesProperty(FProperties[fpAttributes]).Value := NewAttributes;
|
|
UpdateNameAndExtension(Name);
|
|
end;
|
|
|
|
function TFile.GetSize: Int64;
|
|
begin
|
|
Result := TFileSizeProperty(FProperties[fpSize]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetSize(NewSize: Int64);
|
|
begin
|
|
TFileSizeProperty(FProperties[fpSize]).Value := NewSize;
|
|
end;
|
|
|
|
function TFile.GetCompressedSize: Int64;
|
|
begin
|
|
Result := TFileCompressedSizeProperty(FProperties[fpCompressedSize]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetCompressedSize(NewCompressedSize: Int64);
|
|
begin
|
|
TFileCompressedSizeProperty(FProperties[fpCompressedSize]).Value := NewCompressedSize;
|
|
end;
|
|
|
|
function TFile.GetModificationTime: TDateTime;
|
|
begin
|
|
Result := TFileModificationDateTimeProperty(FProperties[fpModificationTime]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetModificationTime(NewTime: TDateTime);
|
|
begin
|
|
TFileModificationDateTimeProperty(FProperties[fpModificationTime]).Value := NewTime;
|
|
end;
|
|
|
|
function TFile.GetCreationTime: TDateTime;
|
|
begin
|
|
Result := TFileCreationDateTimeProperty(FProperties[fpCreationTime]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetCreationTime(NewTime: TDateTime);
|
|
begin
|
|
TFileCreationDateTimeProperty(FProperties[fpCreationTime]).Value := NewTime;
|
|
end;
|
|
|
|
function TFile.GetLastAccessTime: TDateTime;
|
|
begin
|
|
Result := TFileLastAccessDateTimeProperty(FProperties[fpLastAccessTime]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetLastAccessTime(NewTime: TDateTime);
|
|
begin
|
|
TFileLastAccessDateTimeProperty(FProperties[fpLastAccessTime]).Value := NewTime;
|
|
end;
|
|
|
|
function TFile.GetIsLinkToDirectory: Boolean;
|
|
begin
|
|
if fpLink in SupportedProperties then
|
|
Result := TFileLinkProperty(FProperties[fpLink]).IsLinkToDirectory
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TFile.SetIsLinkToDirectory(NewValue: Boolean);
|
|
begin
|
|
TFileLinkProperty(FProperties[fpLink]).IsLinkToDirectory := NewValue;
|
|
end;
|
|
|
|
function TFile.GetType: String;
|
|
begin
|
|
Result := TFileTypeProperty(FProperties[fpType]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetType(NewValue: String);
|
|
begin
|
|
TFileTypeProperty(FProperties[fpType]).Value := NewValue;
|
|
end;
|
|
|
|
function TFile.GetNameProperty: TFileNameProperty;
|
|
begin
|
|
Result := TFileNameProperty(FProperties[fpName]);
|
|
end;
|
|
|
|
procedure TFile.SetNameProperty(NewValue: TFileNameProperty);
|
|
begin
|
|
FProperties[fpName] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpName)
|
|
else
|
|
Exclude(FSupportedProperties, fpName);
|
|
end;
|
|
|
|
function TFile.GetAttributesProperty: TFileAttributesProperty;
|
|
begin
|
|
Result := TFileAttributesProperty(FProperties[fpAttributes]);
|
|
end;
|
|
|
|
procedure TFile.SetAttributesProperty(NewValue: TFileAttributesProperty);
|
|
begin
|
|
FProperties[fpAttributes] := NewValue;
|
|
if Assigned(NewValue) then
|
|
begin
|
|
Include(FSupportedProperties, fpAttributes);
|
|
UpdateNameAndExtension(Name);
|
|
end
|
|
else
|
|
Exclude(FSupportedProperties, fpAttributes);
|
|
end;
|
|
|
|
function TFile.GetSizeProperty: TFileSizeProperty;
|
|
begin
|
|
Result := TFileSizeProperty(FProperties[fpSize]);
|
|
end;
|
|
|
|
procedure TFile.SetSizeProperty(NewValue: TFileSizeProperty);
|
|
begin
|
|
FProperties[fpSize] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpSize)
|
|
else
|
|
Exclude(FSupportedProperties, fpSize);
|
|
end;
|
|
|
|
function TFile.GetCompressedSizeProperty: TFileCompressedSizeProperty;
|
|
begin
|
|
Result := TFileCompressedSizeProperty(FProperties[fpCompressedSize]);
|
|
end;
|
|
|
|
procedure TFile.SetCompressedSizeProperty(NewValue: TFileCompressedSizeProperty);
|
|
begin
|
|
FProperties[fpCompressedSize] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpCompressedSize)
|
|
else
|
|
Exclude(FSupportedProperties, fpCompressedSize);
|
|
end;
|
|
|
|
function TFile.GetModificationTimeProperty: TFileModificationDateTimeProperty;
|
|
begin
|
|
Result := TFileModificationDateTimeProperty(FProperties[fpModificationTime]);
|
|
end;
|
|
|
|
procedure TFile.SetModificationTimeProperty(NewValue: TFileModificationDateTimeProperty);
|
|
begin
|
|
FProperties[fpModificationTime] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpModificationTime)
|
|
else
|
|
Exclude(FSupportedProperties, fpModificationTime);
|
|
end;
|
|
|
|
function TFile.GetCreationTimeProperty: TFileCreationDateTimeProperty;
|
|
begin
|
|
Result := TFileCreationDateTimeProperty(FProperties[fpCreationTime]);
|
|
end;
|
|
|
|
procedure TFile.SetCreationTimeProperty(NewValue: TFileCreationDateTimeProperty);
|
|
begin
|
|
FProperties[fpCreationTime] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpCreationTime)
|
|
else
|
|
Exclude(FSupportedProperties, fpCreationTime);
|
|
end;
|
|
|
|
function TFile.GetLastAccessTimeProperty: TFileLastAccessDateTimeProperty;
|
|
begin
|
|
Result := TFileLastAccessDateTimeProperty(FProperties[fpLastAccessTime]);
|
|
end;
|
|
|
|
procedure TFile.SetLastAccessTimeProperty(NewValue: TFileLastAccessDateTimeProperty);
|
|
begin
|
|
FProperties[fpLastAccessTime] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpLastAccessTime)
|
|
else
|
|
Exclude(FSupportedProperties, fpLastAccessTime);
|
|
end;
|
|
|
|
function TFile.GetChangeTime: TDateTime;
|
|
begin
|
|
Result := TFileChangeDateTimeProperty(FProperties[fpChangeTime]).Value;
|
|
end;
|
|
|
|
procedure TFile.SetChangeTime(AValue: TDateTime);
|
|
begin
|
|
TFileChangeDateTimeProperty(FProperties[fpChangeTime]).Value := AValue;
|
|
end;
|
|
|
|
function TFile.GetChangeTimeProperty: TFileChangeDateTimeProperty;
|
|
begin
|
|
Result := TFileChangeDateTimeProperty(FProperties[fpChangeTime]);
|
|
end;
|
|
|
|
procedure TFile.SetChangeTimeProperty(AValue: TFileChangeDateTimeProperty);
|
|
begin
|
|
FProperties[fpChangeTime] := AValue;
|
|
if Assigned(AValue) then
|
|
Include(FSupportedProperties, fpChangeTime)
|
|
else
|
|
Exclude(FSupportedProperties, fpChangeTime);
|
|
end;
|
|
|
|
function TFile.GetLinkProperty: TFileLinkProperty;
|
|
begin
|
|
Result := TFileLinkProperty(FProperties[fpLink]);
|
|
end;
|
|
|
|
procedure TFile.SetLinkProperty(NewValue: TFileLinkProperty);
|
|
begin
|
|
FProperties[fpLink] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpLink)
|
|
else
|
|
Exclude(FSupportedProperties, fpLink);
|
|
end;
|
|
|
|
function TFile.GetOwnerProperty: TFileOwnerProperty;
|
|
begin
|
|
Result := TFileOwnerProperty(FProperties[fpOwner]);
|
|
end;
|
|
|
|
procedure TFile.SetOwnerProperty(NewValue: TFileOwnerProperty);
|
|
begin
|
|
FProperties[fpOwner] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpOwner)
|
|
else
|
|
Exclude(FSupportedProperties, fpOwner);
|
|
end;
|
|
|
|
function TFile.GetTypeProperty: TFileTypeProperty;
|
|
begin
|
|
Result := TFileTypeProperty(FProperties[fpType]);
|
|
end;
|
|
|
|
procedure TFile.SetTypeProperty(NewValue: TFileTypeProperty);
|
|
begin
|
|
FProperties[fpType] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpType)
|
|
else
|
|
Exclude(FSupportedProperties, fpType);
|
|
end;
|
|
|
|
function TFile.GetCommentProperty: TFileCommentProperty;
|
|
begin
|
|
Result := TFileCommentProperty(FProperties[fpComment]);
|
|
end;
|
|
|
|
procedure TFile.SetCommentProperty(NewValue: TFileCommentProperty);
|
|
begin
|
|
FProperties[fpComment] := NewValue;
|
|
if Assigned(NewValue) then
|
|
Include(FSupportedProperties, fpComment)
|
|
else
|
|
Exclude(FSupportedProperties, fpComment);
|
|
end;
|
|
|
|
function TFile.IsNameValid: Boolean;
|
|
begin
|
|
if Name <> '..' then
|
|
Result := True
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TFile.IsDirectory: Boolean;
|
|
begin
|
|
if fpAttributes in SupportedProperties then
|
|
Result := TFileAttributesProperty(FProperties[fpAttributes]).IsDirectory
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TFile.IsLink: Boolean;
|
|
begin
|
|
if fpAttributes in SupportedProperties then
|
|
Result := TFileAttributesProperty(FProperties[fpAttributes]).IsLink
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TFile.IsExecutable: Boolean;
|
|
var
|
|
FileAttributes: TFileAttributesProperty;
|
|
begin
|
|
if fpAttributes in SupportedProperties then
|
|
begin
|
|
FileAttributes := TFileAttributesProperty(FProperties[fpAttributes]);
|
|
{$IF DEFINED(MSWINDOWS)}
|
|
Result := not FileAttributes.IsDirectory;
|
|
{$ELSEIF DEFINED(UNIX)}
|
|
Result := (not FileAttributes.IsDirectory) and
|
|
(FileAttributes.Value AND (S_IXUSR OR S_IXGRP OR S_IXOTH)>0);
|
|
{$ELSE}
|
|
Result := False;
|
|
{$ENDIF}
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TFile.IsSysFile: Boolean;
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
if fpAttributes in SupportedProperties then
|
|
Result := TFileAttributesProperty(Properties[fpAttributes]).IsSysFile
|
|
else
|
|
Result := False;
|
|
{$ELSE}
|
|
// Files beginning with '.' are treated as system/hidden files on Unix.
|
|
Result := (Length(Name) > 1) and (Name[1] = '.') and (Name <> '..');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TFile.IsHidden: Boolean;
|
|
begin
|
|
if not (fpAttributes in SupportedProperties) then
|
|
Result := False
|
|
else begin
|
|
if Properties[fpAttributes] is TNtfsFileAttributesProperty then
|
|
Result := TNtfsFileAttributesProperty(Properties[fpAttributes]).IsHidden
|
|
else begin
|
|
// Files beginning with '.' are treated as system/hidden files on Unix.
|
|
Result := (Length(Name) > 1) and (Name[1] = '.') and (Name <> '..');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFile.SplitIntoNameAndExtension(const FileName: string;
|
|
var aFileNameOnly: string;
|
|
var aExtension: string);
|
|
var
|
|
i : longint;
|
|
begin
|
|
I := Length(FileName);
|
|
while (I > 0) and (FileName[I] <> ExtensionSeparator) do
|
|
Dec(I);
|
|
if I > 1 then
|
|
begin
|
|
aFileNameOnly := Copy(FileName, 1, I - 1);
|
|
aExtension := Copy(FileName, I + 1, MaxInt);
|
|
end
|
|
else
|
|
begin
|
|
// For files that does not have '.' or that have only
|
|
// one '.' and beginning with '.' there is no extension.
|
|
aFileNameOnly := FileName;
|
|
aExtension := '';
|
|
end;
|
|
end;
|
|
|
|
procedure TFile.UpdateNameAndExtension(const FileName: string);
|
|
begin
|
|
// Cache Extension and NameNoExt.
|
|
|
|
if (FileName = '') or IsDirectory or IsLinkToDirectory
|
|
then
|
|
begin
|
|
// For directories there is no extension.
|
|
FExtension := '';
|
|
FNameNoExt := FileName;
|
|
end
|
|
else
|
|
begin
|
|
SplitIntoNameAndExtension(FileName, FNameNoExt, FExtension);
|
|
end;
|
|
end;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
constructor TFiles.Create(const APath: String);
|
|
begin
|
|
inherited Create;
|
|
FList := TFPList.Create;
|
|
FOwnsObjects := True;
|
|
Path := APath;
|
|
end;
|
|
|
|
destructor TFiles.Destroy;
|
|
begin
|
|
Clear;
|
|
FreeAndNil(FList);
|
|
inherited;
|
|
end;
|
|
|
|
function TFiles.Clone: TFiles;
|
|
begin
|
|
Result := TFiles.Create(Path);
|
|
CloneTo(Result);
|
|
end;
|
|
|
|
procedure TFiles.CloneTo(Files: TFiles);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to FList.Count - 1 do
|
|
begin
|
|
Files.Add(Get(i).Clone);
|
|
end;
|
|
end;
|
|
|
|
function TFiles.GetCount: Integer;
|
|
begin
|
|
Result := FList.Count;
|
|
end;
|
|
|
|
procedure TFiles.SetCount(Count: Integer);
|
|
begin
|
|
FList.Count := Count;
|
|
end;
|
|
|
|
function TFiles.Add(AFile: TFile): Integer;
|
|
begin
|
|
Result := FList.Add(AFile);
|
|
end;
|
|
|
|
procedure TFiles.Insert(AFile: TFile; AtIndex: Integer);
|
|
begin
|
|
FList.Insert(AtIndex, AFile);
|
|
end;
|
|
|
|
procedure TFiles.Delete(AtIndex: Integer);
|
|
var
|
|
p: Pointer;
|
|
begin
|
|
p := FList.Items[AtIndex];
|
|
TFile(p).Free;
|
|
FList.Delete(AtIndex);
|
|
end;
|
|
|
|
procedure TFiles.Clear;
|
|
var
|
|
i: Integer;
|
|
p: Pointer;
|
|
begin
|
|
if OwnsObjects then
|
|
begin
|
|
for i := 0 to FList.Count - 1 do
|
|
begin
|
|
p := FList.Items[i];
|
|
TFile(p).Free;
|
|
end;
|
|
end;
|
|
|
|
FList.Clear;
|
|
end;
|
|
|
|
function TFiles.Get(Index: Integer): TFile;
|
|
begin
|
|
Result := TFile(FList.Items[Index]);
|
|
end;
|
|
|
|
procedure TFiles.Put(Index: Integer; AFile: TFile);
|
|
begin
|
|
FList.Items[Index] := AFile;
|
|
end;
|
|
|
|
procedure TFiles.SetPath(const NewPath: String);
|
|
begin
|
|
if NewPath = '' then
|
|
FPath := ''
|
|
else
|
|
FPath := IncludeTrailingPathDelimiter(NewPath);
|
|
end;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
constructor TFileTreeNode.Create;
|
|
begin
|
|
Create(nil);
|
|
end;
|
|
|
|
constructor TFileTreeNode.Create(aFile: TFile);
|
|
begin
|
|
FSubNodes := nil;
|
|
FFile := aFile;
|
|
FData := nil;
|
|
inherited Create;
|
|
end;
|
|
|
|
constructor TFileTreeNode.Create(aFile: TFile; DataClass: TClass);
|
|
begin
|
|
Create(aFile);
|
|
FData := DataClass.Create;
|
|
end;
|
|
|
|
destructor TFileTreeNode.Destroy;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited Destroy;
|
|
|
|
FreeAndNil(FFile);
|
|
|
|
if Assigned(FSubNodes) then
|
|
begin
|
|
for i := 0 to FSubNodes.Count - 1 do
|
|
TFileTreeNode(FSubNodes.Items[i]).Free;
|
|
FreeAndNil(FSubNodes);
|
|
end;
|
|
|
|
FreeAndNil(FData);
|
|
end;
|
|
|
|
function TFileTreeNode.AddSubNode(aFile: TFile): Integer;
|
|
var
|
|
aNode: TFileTreeNode;
|
|
begin
|
|
if not Assigned(FSubNodes) then
|
|
FSubNodes := TFPList.Create;
|
|
aNode := TFileTreeNode.Create(aFile);
|
|
Result := FSubNodes.Add(aNode);
|
|
end;
|
|
|
|
procedure TFileTreeNode.RemoveSubNode(Index: Integer);
|
|
begin
|
|
if (Index >= 0) and (Index < FSubNodes.Count) then
|
|
begin
|
|
TFileTreeNode(FSubNodes.Items[Index]).Free;
|
|
FSubNodes.Delete(Index);
|
|
end;
|
|
end;
|
|
|
|
function TFileTreeNode.Get(Index: Integer): TFileTreeNode;
|
|
begin
|
|
Result := TFileTreeNode(FSubNodes.Items[Index]);
|
|
end;
|
|
|
|
function TFileTreeNode.GetCount: Integer;
|
|
begin
|
|
if Assigned(FSubNodes) then
|
|
Result := FSubNodes.Count
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TFileTreeNode.SetCount(Count: Integer);
|
|
begin
|
|
if not Assigned(FSubNodes) then
|
|
FSubNodes := TFPList.Create;
|
|
FSubNodes.Count := Count;
|
|
end;
|
|
|
|
procedure TFileTreeNode.SetData(NewData: TObject);
|
|
var
|
|
TmpData: TObject;
|
|
begin
|
|
if Assigned(FData) then
|
|
begin
|
|
TmpData := FData;
|
|
FData := NewData;
|
|
TmpData.Free;
|
|
end
|
|
else
|
|
FData := NewData;
|
|
end;
|
|
|
|
end.
|
|
|