From a5ac82f7b9a7431dc18ea6a779ab884359aab78d Mon Sep 17 00:00:00 2001 From: tobigun Date: Sat, 14 Mar 2009 22:55:52 +0000 Subject: UFilename.pas + UFilename.pas added for uniform filesystem access for Windows/Mac/Unix. Very experimental. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/experimental@1639 b956fd51-792f-4845-bead-9b4dfca2ff2c --- unicode/src/base/UFilename.pas | 462 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 462 insertions(+) create mode 100644 unicode/src/base/UFilename.pas (limited to 'unicode/src/base/UFilename.pas') 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. -- cgit v1.2.3