aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--unicode/src/base/UFilename.pas462
-rw-r--r--unicode/src/base/UFilesystem.pas497
2 files changed, 959 insertions, 0 deletions
diff --git a/unicode/src/base/UFilename.pas b/unicode/src/base/UFilename.pas
new file mode 100644
index 00000000..0cf12cc0
--- /dev/null
+++ b/unicode/src/base/UFilename.pas
@@ -0,0 +1,462 @@
+{* UltraStar Deluxe - Karaoke Game
+ *
+ * UltraStar Deluxe is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *}
+
+unit UFilename;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+interface
+
+uses
+ {$IFDEF MSWINDOWS}
+ TntClasses,
+ {$ENDIF}
+ Classes;
+
+type
+ TPathEncoding = (
+ // pencLossless,
+ pencSystemUTF8, // use system encoding. Mac: UTF8, Linux: None, Win: UTF8
+ // Note:
+ // - On windows, this format is lossless but is not
+ // supported direclty (UTF-16 only).
+ // - This is the best format to store filenames as there is
+ // no dataloss.
+ // - Do not use with glPrint() or other display functions
+ // as the resulting string is neither guaranteed to be
+ // UTF-8 nor ANSI.
+
+ pencSystemANSI, // use system encoding. Mac: UTF8, Linux: None, Win: ANSI
+ // Note:
+ // - On windows, the ANSI format may break filenames
+ // that are not encoded in the active codepage.
+ // - Use only if there is no equivalent WideString
+ // filesystem function.
+ // - Do not use with glPrint() or other display functions
+ // as the resulting string is neither guaranteed to be
+ // UTF-8 nor ANSI.
+
+ // pencPrintable,
+ pencUTF8 // tries to present the filename as UTF-8 encoded string
+ // that can be used for printing etc.
+ // Note:
+ // - Some characters whose encodings are unknown are
+ // represented either by '?' or as the representative of
+ // a different encoding.
+ // - On linux not all filenames can be represented
+ // correclty in UTF-8 as it does not have filename
+ // encodings (though most filenames are stored in UTF-8).
+ // - Never use the result to store filenames or open files
+ // as the filenames may break due to conversion.
+ );
+
+ IPath = interface;
+
+ {$IFDEF MSWINDOWS}
+ TUniFileStream = class(TTntFileStream)
+ {$ELSE}
+ TUniFileStream = class(TFileStream)
+ {$ENDIF}
+ public
+ constructor Create(const FileName: IPath; Mode: Word);
+ end;
+
+ TUniMemoryStream = class(TMemoryStream)
+ public
+ procedure LoadFromFile(const FileName: IPath);
+ procedure SaveToFile(const FileName: IPath);
+ end;
+
+ IPath = interface
+ function ToString(Encoding: TPathEncoding = pencSystemUTF8): AnsiString;
+ function ToWideString(): WideString;
+
+ function Adjust(): boolean;
+
+ function Expand(): IPath;
+ {** File must be closed with FileClose(Handle) after usage }
+ function CreateFile(): integer;
+ function CreateDir(): boolean;
+ {** File must be closed with FileClose(Handle) after usage }
+ function Open(Mode: LongWord): integer;
+ {** Stream must be freed with TUniFileStream.Free after usage }
+ function OpenStream(Mode: Word): TUniFileStream;
+ function GetFileAge(): integer; overload;
+ function GetFileAge(out FileDateTime: TDateTime): boolean; overload;
+ function Exists(): boolean;
+ function IsFile(): boolean;
+ function IsDirectory(): boolean;
+ function GetAttr(): cardinal;
+ function SetAttr(Attr: Integer): boolean;
+ function IsReadOnly(): boolean;
+ function SetReadOnly(ReadOnly: boolean): boolean;
+ function ForceDirectories(): boolean; //-
+ function FileSearch(const DirList: IPath): IPath; //-
+ function Rename(const NewName: IPath): boolean;
+ function DeleteFile(): boolean;
+ function DeleteEmptyDir(): boolean;
+ function CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
+ end;
+
+function Path(const Name: AnsiString; Encoding: TPathEncoding = pencSystemANSI): IPath; overload;
+function Path(const Name: WideString): IPath; overload;
+function Path(PathComponents: array of const): IPath; overload;
+
+implementation
+
+uses
+ UFilesystem,
+ SysUtils;
+
+type
+ TPathImpl = class(TInterfacedObject, IPath)
+ private
+ fName: AnsiString;
+ public
+ constructor Create(const Name: string);
+ destructor Destroy(); override;
+
+ function ToString(Encoding: TPathEncoding = pencSystemANSI): AnsiString;
+ function ToWideString(): WideString;
+
+ //function Append(const IPath): IPath;
+ function Adjust(): boolean;
+ {**
+ * Removes trailing path-delimiter and replaces path-delimiters with '/'.
+ *}
+ procedure Unify();
+ function Expand(): IPath;
+
+ (*
+ function IncludeTrailingPathDelimiter(): IPath;
+ function ExcludeTrailingPathDelimiter(): IPath;
+ function ChangeFileExt(const Extension: IPath): IPath;
+ function ExtractFilePath(): IPath;
+ function ExtractFileDir(): IPath;
+ function ExtractFileDrive(): IPath;
+ function ExtractFileName(): IPath;
+ function ExtractFileExt(): IPath;
+ function ExtractRelativePath(const BaseName: IPath): IPath;
+ *)
+
+ function CreateFile(): integer;
+ function CreateDir(): boolean;
+ function Open(Mode: LongWord): integer;
+ function OpenStream(Mode: Word): TUniFileStream;
+ function GetFileAge(): integer; overload;
+ function GetFileAge(out FileDateTime: TDateTime): boolean; overload;
+ function Exists(): boolean;
+ function IsFile(): boolean;
+ function IsDirectory(): boolean;
+ function GetAttr(): cardinal;
+ function SetAttr(Attr: Integer): boolean;
+ function IsReadOnly(): boolean;
+ function SetReadOnly(ReadOnly: boolean): boolean;
+ function ForceDirectories(): boolean;
+ function FileSearch(const DirList: IPath): IPath;
+ function Rename(const NewName: IPath): boolean;
+ function DeleteFile(): boolean;
+ function DeleteEmptyDir(): boolean;
+ function CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
+ end;
+
+ IPathIterator = interface
+ function Next(): IPath;
+ end;
+
+ TPathIteratorImpl = class(TInterfacedObject, IPathIterator)
+ private
+ fPath: IPath;
+ fPos: integer;
+ public
+ constructor Create(Path: IPath);
+
+ function Next(): IPath;
+ end;
+
+function Path(const Name: AnsiString; Encoding: TPathEncoding): IPath;
+begin
+ {$IFDEF MSWINDOWS}
+ case Encoding of
+ pencUTF8:
+ // TODO: Check if UTF8
+ Result := TPathImpl.Create(Name);
+ pencSystemANSI:
+ Result := TPathImpl.Create(AnsiToUtf8(Name));
+ else
+ raise Exception.Create('Unhandled encoding');
+ end;
+ {$ELSE}
+ Result := TPathImpl.Create(Name);
+ {$ENDIF}
+end;
+
+function Path(const Name: WideString): IPath;
+begin
+ Result := TPathImpl.Create(UTF8Encode(Name));
+end;
+
+function Path(PathComponents: array of const): IPath;
+var
+ CompIndex: integer;
+ Name: string;
+begin
+ Name := '';
+ for CompIndex := 0 to High(PathComponents) do
+ begin
+ with PathComponents[CompIndex] do
+ begin
+ case (VType) of
+ vtString:
+ Name := Name + VString^;
+ vtAnsiString:
+ Name := Name + AnsiString(VAnsiString);
+ vtWideString:
+ Name := Name + UTF8Encode(WideString(VWideString));
+ vtObject:
+ raise Exception.Create('Unhandled Object type');
+ else
+ raise Exception.Create('Unhandled Path type');
+ end;
+ end;
+ Name := Name + PathDelim;
+ end;
+ Result := Path(Name);
+end;
+
+constructor TPathImpl.Create(const Name: string);
+begin
+ inherited Create();
+ fName := Name;
+ Unify();
+end;
+
+destructor TPathImpl.Destroy();
+begin
+ inherited;
+end;
+
+procedure TPathImpl.Unify();
+var
+ I: integer;
+begin
+ for I := 1 to Length(fName) do
+ begin
+ if (fName[I] in ['\', '/']) then
+ fName[I] := PathDelim;
+ end;
+ fName := ExcludeTrailingPathDelimiter(fName);
+end;
+
+function TPathImpl.ToString(Encoding: TPathEncoding): AnsiString;
+begin
+ {$IFDEF MSWINDOWS}
+ case Encoding of
+ pencUTF8:
+ Result := fName;
+ pencSystemANSI:
+ Result := Utf8ToAnsi(fName);
+ else
+ raise Exception.Create('Unhandled encoding');
+ end;
+ {$ELSE}
+ Result := fName;
+ {$ENDIF}
+end;
+
+function TPathImpl.ToWideString(): WideString;
+begin
+ Result := UTF8Decode(fName);
+end;
+
+function TPathImpl.Adjust(): boolean;
+begin
+ Result := false; //TODO
+end;
+
+
+
+function TPathImpl.Expand(): IPath;
+begin
+ Result := FileSystem.ExpandFileName(Self);
+end;
+
+function TPathImpl.CreateFile(): integer;
+begin
+ Result := FileSystem.FileCreate(Self);
+end;
+
+function TPathImpl.CreateDir(): boolean;
+begin
+ Result := FileSystem.DirectoryCreate(Self);
+end;
+
+function TPathImpl.Open(Mode: LongWord): integer;
+begin
+ Result := FileSystem.FileOpen(Self, Mode);
+end;
+
+function TPathImpl.OpenStream(Mode: Word): TUniFileStream;
+begin
+ Result := TUniFileStream.Create(Self, Mode);
+end;
+
+function TPathImpl.GetFileAge(): integer;
+begin
+ Result := FileSystem.FileAge(Self);
+end;
+
+function TPathImpl.GetFileAge(out FileDateTime: TDateTime): boolean;
+begin
+ Result := FileSystem.FileAge(Self, FileDateTime);
+end;
+
+function TPathImpl.Exists(): boolean;
+begin
+ Result := IsFile() or IsDirectory();
+end;
+
+function TPathImpl.IsFile(): boolean;
+begin
+ Result := FileSystem.FileExists(Self);
+end;
+
+function TPathImpl.IsDirectory(): boolean;
+begin
+ Result := FileSystem.DirectoryExists(Self);
+end;
+
+function TPathImpl.GetAttr(): cardinal;
+begin
+ Result := FileSystem.FileGetAttr(Self);
+end;
+
+function TPathImpl.SetAttr(Attr: Integer): boolean;
+begin
+ Result := FileSystem.FileSetAttr(Self, Attr);
+end;
+
+function TPathImpl.IsReadOnly(): boolean;
+begin
+ Result := FileSystem.FileIsReadOnly(Self);
+end;
+
+function TPathImpl.SetReadOnly(ReadOnly: boolean): boolean;
+begin
+ Result := FileSystem.FileSetReadOnly(Self, ReadOnly);
+end;
+
+function TPathImpl.ForceDirectories(): boolean;
+begin
+ Result := FileSystem.ForceDirectories(Self);
+end;
+
+function TPathImpl.FileSearch(const DirList: IPath): IPath;
+begin
+ Result := FileSystem.FileSearch(Self, DirList);
+end;
+
+function TPathImpl.Rename(const NewName: IPath): boolean;
+begin
+ Result := FileSystem.RenameFile(Self, NewName);
+end;
+
+function TPathImpl.DeleteFile(): boolean;
+begin
+ Result := FileSystem.DeleteFile(Self);
+end;
+
+function TPathImpl.DeleteEmptyDir(): boolean;
+begin
+ Result := FileSystem.RemoveDir(Self);
+end;
+
+function TPathImpl.CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
+begin
+ Result := FileSystem.CopyFile(Self, Target, FailIfExists);
+end;
+
+
+
+{ TPathIteratorImpl }
+
+constructor TPathIteratorImpl.Create(Path: IPath);
+begin
+ fPath := Path;
+ fPos := -1;
+end;
+
+function TPathIteratorImpl.Next(): IPath;
+begin
+end;
+
+
+{ TUniFileStream }
+
+{$IFDEF MSWINDOWS}
+
+constructor TUniFileStream.Create(const FileName: IPath; Mode: Word);
+begin
+ inherited Create(FileName.ToWideString(), Mode);
+end;
+
+{$ELSE}
+
+constructor TUniFileStream.Create(const FileName: IPath; Mode: Word);
+begin
+ inherited Create(FileName.ToSystemString(), Mode);
+end;
+
+{$ENDIF}
+
+{ TUniMemoryStream }
+
+procedure TUniMemoryStream.LoadFromFile(const FileName: IPath);
+var
+ Stream: TStream;
+begin
+ Stream := TUniFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TUniMemoryStream.SaveToFile(const FileName: IPath);
+var
+ Stream: TStream;
+begin
+ Stream := TUniFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+end.
diff --git a/unicode/src/base/UFilesystem.pas b/unicode/src/base/UFilesystem.pas
new file mode 100644
index 00000000..b9020391
--- /dev/null
+++ b/unicode/src/base/UFilesystem.pas
@@ -0,0 +1,497 @@
+{* UltraStar Deluxe - Karaoke Game
+ *
+ * UltraStar Deluxe is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *}
+
+unit UFilesystem;
+
+interface
+
+uses
+ {$IFDEF MSWINDOWS}
+ Windows,
+ TntSysUtils,
+ {$ENDIF}
+ UFilename,
+ SysUtils,
+ Classes;
+
+type
+ {$IFDEF MSWINDOWSe}
+ TSytemSearchRec = TSearchRecW;
+ {$ELSE}
+ TSytemSearchRec = TSearchRec;
+ {$ENDIF}
+
+ TUniSearchRec = record
+ Time: Integer;
+ Size: Int64;
+ Attr: Integer;
+ Name: IPath;
+ ExcludeAttr: Integer;
+ //FindHandle(): THandle;
+ end;
+
+ IFileFindIterator = interface
+ function HasNext(): Boolean;
+ function Next(): TUniSearchRec;
+ end;
+
+ IFileSystem = interface
+ function ExpandFileName(const FileName: IPath): IPath;
+ function FileCreate(const FileName: IPath): Integer;
+ function DirectoryCreate(const Dir: IPath): Boolean;
+ function FileOpen(const FileName: IPath; Mode: LongWord): Integer;
+ function FileAge(const FileName: IPath): Integer; overload;
+ function FileAge(const FileName: IPath; out FileDateTime: TDateTime): Boolean; overload;
+ function DirectoryExists(const Name: IPath): Boolean;
+ function FileExists(const Name: IPath): Boolean;
+ function FileGetAttr(const FileName: IPath): Cardinal;
+ function FileSetAttr(const FileName: IPath; Attr: Integer): Boolean;
+ function FileIsReadOnly(const FileName: IPath): Boolean;
+ function FileSetReadOnly(const FileName: IPath; ReadOnly: Boolean): Boolean;
+ function ForceDirectories(const Dir: IPath): Boolean;
+ function FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+ function RenameFile(const OldName, NewName: IPath): Boolean;
+ function DeleteFile(const FileName: IPath): Boolean;
+ function RemoveDir(const Dir: IPath): Boolean;
+ function CopyFile(const Source, Target: IPath; FailIfExists: Boolean): Boolean;
+
+ function FileFind(const FilePattern: IPath; Attr: Integer): IFileFindIterator;
+
+ function FindFirst(const FilePattern: IPath; Attr: Integer; var F: TSytemSearchRec): Integer;
+ function FindNext(var F: TSytemSearchRec): Integer;
+ procedure FindClose(var F: TSytemSearchRec);
+
+ function GetCurrentDir: IPath;
+ function SetCurrentDir(const Dir: IPath): Boolean;
+
+ function CreateFileStream(const FileName: IPath; Mode: Word): THandleStream;
+ end;
+
+var
+ FileSystem: IFileSystem;
+
+implementation
+
+type
+ TFileSystemImpl = class(TInterfacedObject, IFileSystem)
+ public
+ function ExpandFileName(const FileName: IPath): IPath;
+ function FileCreate(const FileName: IPath): Integer;
+ function DirectoryCreate(const Dir: IPath): Boolean;
+ function FileOpen(const FileName: IPath; Mode: LongWord): Integer;
+ function FileAge(const FileName: IPath): Integer; overload;
+ function FileAge(const FileName: IPath; out FileDateTime: TDateTime): Boolean; overload;
+ function DirectoryExists(const Name: IPath): Boolean;
+ function FileExists(const Name: IPath): Boolean;
+ function FileGetAttr(const FileName: IPath): Cardinal;
+ function FileSetAttr(const FileName: IPath; Attr: Integer): Boolean;
+ function FileIsReadOnly(const FileName: IPath): Boolean;
+ function FileSetReadOnly(const FileName: IPath; ReadOnly: Boolean): Boolean;
+ function ForceDirectories(const Dir: IPath): Boolean;
+ function FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+ function RenameFile(const OldName, NewName: IPath): Boolean;
+ function DeleteFile(const FileName: IPath): Boolean;
+ function RemoveDir(const Dir: IPath): Boolean;
+ function CopyFile(const Source, Target: IPath; FailIfExists: Boolean): Boolean;
+
+ function FileFind(const FilePattern: IPath; Attr: Integer): IFileFindIterator;
+
+ function FindFirst(const FilePattern: IPath; Attr: Integer; var F: TSytemSearchRec): Integer;
+ function FindNext(var F: TSytemSearchRec): Integer;
+ procedure FindClose(var F: TSytemSearchRec);
+
+ function GetCurrentDir: IPath;
+ function SetCurrentDir(const Dir: IPath): Boolean;
+
+ function CreateFileStream(const FileName: IPath; Mode: Word): THandleStream;
+ end;
+
+ TFileFindIterator = class(TInterfacedObject, IFileFindIterator)
+ private
+ fHasNext: Boolean;
+ fSearchRec: TSytemSearchRec;
+ public
+ constructor Create(const FilePattern: IPath; Attr: Integer);
+ destructor Destroy(); override;
+
+ function HasNext(): Boolean;
+ function Next(): TUniSearchRec;
+ end;
+
+
+function TFileSystemImpl.CreateFileStream(const FileName: IPath; Mode: Word): THandleStream;
+begin
+ Result := TUniFileStream.Create(FileName, Mode);
+end;
+
+function TFileSystemImpl.FileFind(const FilePattern: IPath; Attr: Integer): IFileFindIterator;
+begin
+ Result := TFileFindIterator.Create(FilePattern, Attr);
+end;
+
+{$IFDEF MSWINDOWSs}
+
+function TFileSystemImpl.ExpandFileName(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExpandFileName(FileName.ToWideString()));
+end;
+
+function TFileSystemImpl.FileCreate(const FileName: IPath): Integer;
+begin
+ Result := WideFileCreate(FileName.ToWideString());
+end;
+
+function TFileSystemImpl.DirectoryCreate(const Dir: IPath): Boolean;
+begin
+ Result := WideCreateDir(Dir.ToWideString());
+end;
+
+function TFileSystemImpl.FileOpen(const FileName: IPath; Mode: LongWord): Integer;
+begin
+ Result := WideFileOpen(FileName.ToWideString(), Mode);
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath): Integer;
+begin
+ Result := WideFileAge(FileName.ToWideString());
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath; out FileDateTime: TDateTime): Boolean;
+begin
+ Result := WideFileAge(FileName.ToWideString(), FileDateTime);
+end;
+
+function TFileSystemImpl.DirectoryExists(const Name: IPath): Boolean;
+begin
+ Result := WideDirectoryExists(Name.ToWideString());
+end;
+
+function TFileSystemImpl.FileExists(const Name: IPath): Boolean;
+begin
+ Result := WideFileExists(Name.ToWideString());
+end;
+
+function TFileSystemImpl.FileGetAttr(const FileName: IPath): Cardinal;
+begin
+ Result := WideFileGetAttr(FileName.ToWideString());
+end;
+
+function TFileSystemImpl.FileSetAttr(const FileName: IPath; Attr: Integer): Boolean;
+begin
+ Result := WideFileSetAttr(FileName.ToWideString(), Attr);
+end;
+
+function TFileSystemImpl.FileIsReadOnly(const FileName: IPath): Boolean;
+begin
+ Result := WideFileIsReadOnly(FileName.ToWideString());
+end;
+
+function TFileSystemImpl.FileSetReadOnly(const FileName: IPath; ReadOnly: Boolean): Boolean;
+begin
+ Result := WideFileSetReadOnly(FileName.ToWideString(), ReadOnly);
+end;
+
+function TFileSystemImpl.ForceDirectories(const Dir: IPath): Boolean;
+begin
+ Result := WideForceDirectories(Dir.ToWideString());
+end;
+
+function TFileSystemImpl.FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+var
+ I: integer;
+ DirListStr: WideString;
+begin
+ DirListStr := '';
+ for I := 0 to High(DirList) do
+ begin
+ if (I > 0) then
+ DirListStr := DirListStr + PathSep;
+ DirListStr := DirListStr + DirList[I].ToWideString();
+ end;
+ Result := Path(WideFileSearch(Name.ToWideString(), DirListStr));
+end;
+
+function TFileSystemImpl.RenameFile(const OldName, NewName: IPath): Boolean;
+begin
+ Result := WideRenameFile(OldName.ToWideString(), NewName.ToWideString());
+end;
+
+function TFileSystemImpl.DeleteFile(const FileName: IPath): Boolean;
+begin
+ Result := WideDeleteFile(FileName.ToWideString());
+end;
+
+function TFileSystemImpl.RemoveDir(const Dir: IPath): Boolean;
+begin
+ Result := WideRemoveDir(Dir.ToWideString());
+end;
+
+function TFileSystemImpl.CopyFile(const Source, Target: IPath; FailIfExists: Boolean): Boolean;
+begin
+ Result := WideCopyFile(Source.ToWideString(), Target.ToWideString(), FailIfExists);
+end;
+
+function TFileSystemImpl.FindFirst(const FilePattern: IPath; Attr: Integer; var F: TSytemSearchRec): Integer;
+begin
+ Result := WideFindFirst(FilePattern.ToWideString(), Attr, F);
+end;
+
+function TFileSystemImpl.FindNext(var F: TSytemSearchRec): Integer;
+begin
+ Result := WideFindNext(F);
+end;
+
+procedure TFileSystemImpl.FindClose(var F: TSytemSearchRec);
+begin
+ WideFindClose(F);
+end;
+
+function TFileSystemImpl.GetCurrentDir: IPath;
+begin
+ Result := Path(WideGetCurrentDir());
+end;
+
+function TFileSystemImpl.SetCurrentDir(const Dir: IPath): Boolean;
+begin
+ Result := WideSetCurrentDir(Dir.ToWideString());
+end;
+
+{$ELSE} // UNIX
+
+function TFileSystemImpl.ExpandFileName(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExpandFileName(FileName.ToString(pencSystemANSI)), pencSystemANSI);
+end;
+
+function TFileSystemImpl.FileCreate(const FileName: IPath): Integer;
+begin
+ Result := SysUtils.FileCreate(FileName.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.DirectoryCreate(const Dir: IPath): Boolean;
+begin
+ Result := SysUtils.CreateDir(Dir.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.FileOpen(const FileName: IPath; Mode: LongWord): Integer;
+begin
+ Result := SysUtils.FileOpen(FileName.ToString(pencSystemANSI), Mode);
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath): Integer;
+begin
+ Result := SysUtils.FileAge(FileName.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath; out FileDateTime: TDateTime): Boolean;
+begin
+ Result := SysUtils.FileAge(FileName.ToString(pencSystemANSI), FileDateTime);
+end;
+
+function TFileSystemImpl.DirectoryExists(const Name: IPath): Boolean;
+begin
+ Result := SysUtils.DirectoryExists(Name.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.FileExists(const Name: IPath): Boolean;
+begin
+ Result := SysUtils.FileExists(Name.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.FileGetAttr(const FileName: IPath): Cardinal;
+begin
+ Result := SysUtils.FileGetAttr(FileName.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.FileSetAttr(const FileName: IPath; Attr: Integer): Boolean;
+begin
+ Result := (SysUtils.FileSetAttr(FileName.ToString(pencSystemANSI), Attr) = 0);
+end;
+
+function TFileSystemImpl.FileIsReadOnly(const FileName: IPath): Boolean;
+begin
+ Result := SysUtils.FileIsReadOnly(FileName.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.FileSetReadOnly(const FileName: IPath; ReadOnly: Boolean): Boolean;
+begin
+ Result := SysUtils.FileSetReadOnly(FileName.ToString(pencSystemANSI), ReadOnly);
+end;
+
+function TFileSystemImpl.ForceDirectories(const Dir: IPath): Boolean;
+begin
+ Result := SysUtils.ForceDirectories(Dir.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+var
+ I: integer;
+ DirListStr: AnsiString;
+begin
+ DirListStr := '';
+ for I := 0 to High(DirList) do
+ begin
+ if (I > 0) then
+ DirListStr := DirListStr + PathSep;
+ DirListStr := DirListStr + DirList[I].ToString(pencSystemANSI);
+ end;
+ Result := Path(SysUtils.FileSearch(Name.ToString(pencSystemANSI), DirListStr), pencSystemANSI);
+end;
+
+function TFileSystemImpl.RenameFile(const OldName, NewName: IPath): Boolean;
+begin
+ Result := SysUtils.RenameFile(OldName.ToString(pencSystemANSI), NewName.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.DeleteFile(const FileName: IPath): Boolean;
+begin
+ Result := SysUtils.DeleteFile(FileName.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.RemoveDir(const Dir: IPath): Boolean;
+begin
+ Result := SysUtils.RemoveDir(Dir.ToString(pencSystemANSI));
+end;
+
+function TFileSystemImpl.CopyFile(const Source, Target: IPath; FailIfExists: Boolean): Boolean;
+const
+ COPY_BUFFER_SIZE = 4096; // a good tradeoff between speed and memory consumption
+var
+ SourceFile, TargetFile: TFileStream;
+ FileCopyBuffer: array [0..COPY_BUFFER_SIZE-1] of byte; // temporary copy-buffer.
+ NumberOfBytes: integer; // number of bytes read from SourceFile
+begin
+ Result := false;
+ SourceFile := nil;
+ TargetFile := nil;
+
+ // if overwrite is disabled return if the target file already exists
+ if (FailIfExists and FileExists(Target)) then
+ Exit;
+
+ try
+ try
+ // open source and target file (might throw an exception on error)
+ SourceFile := TFileStream.Create(Source.ToString(pencSystemANSI), fmOpenRead);
+ TargetFile := TFileStream.Create(Target.ToString(pencSystemANSI), fmCreate or fmOpenWrite);
+
+ while true do
+ begin
+ // read a block from the source file and check for errors or EOF
+ NumberOfBytes := SourceFile.Read(FileCopyBuffer, SizeOf(FileCopyBuffer));
+ if (NumberOfBytes <= 0) then
+ Break;
+ // write block to target file and check if everything was written
+ if (TargetFile.Write(FileCopyBuffer, NumberOfBytes) <> NumberOfBytes) then
+ Exit;
+ end;
+ except
+ Exit;
+ end;
+ finally
+ SourceFile.Free;
+ TargetFile.Free;
+ end;
+
+ Result := true;
+end;
+
+function TFileSystemImpl.FindFirst(const FilePattern: IPath; Attr: Integer; var F: TSytemSearchRec): Integer;
+begin
+ Result := SysUtils.FindFirst(FilePattern.ToString(pencSystemANSI), Attr, F);
+end;
+
+function TFileSystemImpl.FindNext(var F: TSytemSearchRec): Integer;
+begin
+ Result := SysUtils.FindNext(F);
+end;
+
+procedure TFileSystemImpl.FindClose(var F: TSytemSearchRec);
+begin
+ SysUtils.FindClose(F);
+end;
+
+function TFileSystemImpl.GetCurrentDir: IPath;
+begin
+ Result := Path(SysUtils.GetCurrentDir(), pencSystemANSI);
+end;
+
+function TFileSystemImpl.SetCurrentDir(const Dir: IPath): Boolean;
+begin
+ Result := SysUtils.SetCurrentDir(Dir.ToString(pencSystemANSI));
+end;
+
+{$ENDIF}
+
+
+{ TFileFindIterator }
+
+constructor TFileFindIterator.Create(const FilePattern: IPath; Attr: Integer);
+begin
+ inherited Create();
+ fHasNext := (FileSystem.FindFirst(FilePattern, Attr, fSearchRec) = 0);
+end;
+
+destructor TFileFindIterator.Destroy();
+begin
+ FileSystem.FindClose(fSearchRec);
+ inherited;
+end;
+
+function TFileFindIterator.HasNext(): Boolean;
+begin
+ Result := fHasNext;
+end;
+
+function TFileFindIterator.Next(): TUniSearchRec;
+begin
+ if (not fHasNext) then
+ begin
+ FillChar(Result, SizeOf(Result), 0);
+ Exit;
+ end;
+
+ Result.Time := fSearchRec.Time;
+ Result.Size := fSearchRec.Size;
+ Result.Attr := fSearchRec.Attr;
+ {$IFDEF MSWINDOWS}
+ Result.Name := Path(fSearchRec.Name);
+ {$ELSE}
+ Result.Name := Path(fSearchRec.Name, pencSystem);
+ {$ENDIF}
+ Result.ExcludeAttr := fSearchRec.ExcludeAttr;
+
+ // fetch next entry
+ fHasNext := (FileSystem.FindNext(fSearchRec) = 0);
+end;
+
+
+initialization
+ FileSystem := TFileSystemImpl.Create;
+
+finalization
+ FileSystem := nil;
+
+end.