{%MainUnit fileutil.pas} {------------------------------------------------------------------------------ procedure CheckIfFileIsExecutable(const AFilename: string); ------------------------------------------------------------------------------} procedure CheckIfFileIsExecutable(const AFilename: string); begin // TProcess does not report, if a program can not be executed // to get good error messages consider the OS if not FileExistsUTF8(AFilename) then begin raise Exception.Create('file "'+AFilename+'" does not exist'); end; if DirPathExists(AFilename) then begin raise Exception.Create('file "'+AFilename+'" is a directory and not an executable'); end; end; {------------------------------------------------------------------------------ procedure CheckIfFileIsSymlink(const AFilename: string); ------------------------------------------------------------------------------} procedure CheckIfFileIsSymlink(const AFilename: string); begin // to get good error messages consider the OS if not FileExistsUTF8(AFilename) then begin raise Exception.Create('file "'+AFilename+'" does not exist'); end; raise Exception.Create('"'+AFilename+'" is not symlink'); end; {------------------------------------------------------------------------------ function FileIsReadable(const AFilename: string): boolean; ------------------------------------------------------------------------------} function FileIsReadable(const AFilename: string): boolean; begin Result:=true; end; {------------------------------------------------------------------------------ FileIsWritable ------------------------------------------------------------------------------} function FileIsWritable(const AFilename: string): boolean; begin Result:=((FileGetAttrUTF8(AFilename) and faReadOnly)=0); end; {------------------------------------------------------------------------------ function FileIsExecutable(const AFilename: string): boolean; ------------------------------------------------------------------------------} function FileIsExecutable(const AFilename: string): boolean; begin Result:=FileExistsUTF8(AFilename); end; {------------------------------------------------------------------------------ function FileIsSymlink(const AFilename: string): boolean; ------------------------------------------------------------------------------} function FileIsSymlink(const AFilename: string): boolean; {$ifndef wince} const IO_REPARSE_TAG_MOUNT_POINT = $A0000003; IO_REPARSE_TAG_SYMLINK = $A000000C; var Attr: Longint; Rec: TSearchRec; {$endif} begin {$ifndef wince} Attr := FileGetAttrUTF8(AFilename); if (Attr <> -1) and (Attr and FILE_ATTRIBUTE_REPARSE_POINT <> 0) then begin FindFirstUTF8(AFilename, Attr, Rec); if Rec.FindHandle <> feInvalidHandle then begin Windows.FindClose(Rec.FindHandle); Result := (Rec.FindData.dwReserved0 = IO_REPARSE_TAG_SYMLINK) or (Rec.FindData.dwReserved0 = IO_REPARSE_TAG_MOUNT_POINT); end else Result := False; end else {$endif} Result := False; end; {------------------------------------------------------------------------------ function FileIsHardLink(const AFilename: string): boolean; ------------------------------------------------------------------------------} function FileIsHardLink(const AFilename: string): boolean; var H: THandle; FileInfo: BY_HANDLE_FILE_INFORMATION; begin Result := false; {$ifndef wince} //HardLinks are not supported in Win9x platform if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) then Exit; H := FileOpenUtf8(aFilename, fmOpenRead); if (H <> feInvalidHandle) then begin FillChar(FileInfo, SizeOf(BY_HANDLE_FILE_INFORMATION),0); if GetFileInformationByHandle(H, FileInfo) then Result := (FileInfo.nNumberOfLinks > 1); FileClose(H); end; {$endif} end; {------------------------------------------------------------------------------ GetFileDescription ------------------------------------------------------------------------------} function GetFileDescription(const AFilename: string): string; begin // date + time Result:=lrsModified; try Result:=Result+FormatDateTime('DD/MM/YYYY hh:mm', FileDateToDateTime(FileAgeUTF8(AFilename))); except Result:=Result+'?'; end; end; {------------------------------------------------------------------------------ function ReadAllLinks(const Filename: string; ExceptionOnError: boolean): string; ------------------------------------------------------------------------------} function ReadAllLinks(const Filename: string; ExceptionOnError: boolean): string; begin Result:=Filename; end; {------------------------------------------------------------------------------ function FilenameIsAbsolute(const TheFilename: string):boolean; ------------------------------------------------------------------------------} function FilenameIsAbsolute(const TheFilename: string):boolean; begin Result:=FilenameIsWinAbsolute(TheFilename); end; function NeedRTLAnsi: boolean; {$IFDEF WinCE} // CP_UTF8 is missing in the windows unit of the Windows CE RTL const CP_UTF8 = 65001; {$ENDIF} begin if FNeedRTLAnsiValid then exit(FNeedRTLAnsi); FNeedRTLAnsi:=GetACP<>CP_UTF8; FNeedRTLAnsiValid:=true; Result:=FNeedRTLAnsi; end; function ConsoleToUTF8(const s: string): string;// converts UTF8 string to console encoding (used by Write, WriteLn) var Dst: PChar; begin {$ifdef WinCE} Result := SysToUTF8(s); {$else} Dst := AllocMem((Length(s) + 1) * SizeOf(Char)); if OemToChar(PChar(s), Dst) then Result := StrPas(Dst) else Result := s; FreeMem(Dst); Result := SysToUTF8(Result); {$endif} end; function UTF8ToConsole(const s: string): string; var Dst: PChar; begin {$ifdef WinCE} Result := UTF8ToSys(s); {$else} Result := UTF8ToSys(s); Dst := AllocMem((Length(Result) + 1) * SizeOf(Char)); if CharToOEM(PChar(Result), Dst) then Result := StrPas(Dst); FreeMem(Dst); {$endif} end; {------------------------------------------------------------------------------ FileSize ------------------------------------------------------------------------------} {$ifndef WinCE} function FileSizeAnsi(const Filename: string): int64; var FindData: TWIN32FindDataA; FindHandle: THandle; Str: AnsiString; begin // Fix for the bug 14360: // Don't assign the widestring to TSearchRec.name because it is of type // string, which will generate a conversion to the system encoding Str := Utf8ToAnsi(Filename); FindHandle:=Windows.FindFirstFileA(PAnsiChar(Str), FindData); if FindHandle=Windows.Invalid_Handle_value then begin Result:=-1; exit; end; Result:=(int64(FindData.nFileSizeHigh) shl 32)+FindData.nFileSizeLow; Windows.FindClose(FindHandle); end; {$endif} function FileSizeWide(const Filename: string): int64; var FindData: TWIN32FindDataW; FindHandle: THandle; Str: WideString; begin // Fix for the bug 14360: // Don't assign the widestring to TSearchRec.name because it is of type // string, which will generate a conversion to the system encoding Str := UTF8Decode(Filename); FindHandle:=Windows.FindFirstFileW(PWideChar(Str), FindData); if FindHandle=Windows.Invalid_Handle_value then begin Result:=-1; exit; end; Result:=(int64(FindData.nFileSizeHigh) shl 32)+FindData.nFileSizeLow; Windows.FindClose(FindHandle); end; {------------------------------------------------------------------------------ FindFirstUTF8 ------------------------------------------------------------------------------} {$ifndef WinCE} function FindFirstAnsi(const Path: string; Attr: Longint; out Rslt: TSearchRec): Longint; begin Result:=SysUtils.FindFirst(UTF8ToSys(Path),Attr,Rslt); Rslt.Name:=SysToUTF8(Rslt.Name); end; {$endif} function WinToDosTime (Var Wtime : TFileTime;var DTime:longint):longbool; var lft : TFileTime; begin WinToDosTime:=FileTimeToLocalFileTime(WTime,lft) {$ifndef WinCE} and FileTimeToDosDateTime(lft,Longrec(Dtime).Hi,LongRec(DTIME).lo) {$endif} ; end; function FindMatch(var f: TSearchRec) : Longint; begin { Find file with correct attribute } While (F.FindData.dwFileAttributes and cardinal(F.ExcludeAttr))<>0 do begin if FindNextUTF8(F)<>0 then begin Result:=GetLastError; exit; end; end; { Convert some attributes back } WinToDosTime(F.FindData.ftLastWriteTime,F.Time); f.size:=F.FindData.NFileSizeLow+(qword(maxdword)+1)*F.FindData.NFileSizeHigh; f.attr:=F.FindData.dwFileAttributes; { The structures are different at this point in win32 it is the ansi structure with a utf-8 string in wince it is a wide structure } {$ifdef WinCE} f.Name:=UTF8Encode(F.FindData.cFileName); {$else} f.Name:=F.FindData.cFileName; {$endif} Result:=0; end; { This function does not really convert from wide to ansi, but from wide to a utf-8 encoded ansi version of the data structures in win32 and does nothing in wince See FindMatch also } procedure FindWideToAnsi(const wide: TWIN32FINDDATAW; var ansi: TWIN32FINDDATA); var ws: WideString; an: AnsiString; begin {$ifdef WinCE} ansi := wide; {$else} SetLength(ws, length(wide.cAlternateFileName)); Move(wide.cAlternateFileName[0], ws[1], length(ws)*2); an := AnsiString(ws); // no need to utf8 for cAlternateFileName (it's always ansi encoded) Move(an[1], ansi.cAlternateFileName, sizeof(ansi.cAlternateFileName)); ws := PWideChar(@wide.cFileName[0]); an := UTF8Encode(ws); ansi.cFileName := an; if length(an) -1 then Result:= (Attr and FILE_ATTRIBUTE_DIRECTORY) = 0 else Result:=False; end; function DirectoryExistsUTF8(const Directory: string): boolean; var Attr: Longint; begin Attr:=FileGetAttrUTF8(Directory); if Attr <> -1 then Result:= (Attr and FILE_ATTRIBUTE_DIRECTORY) > 0 else Result:=False; end; function FileOpenUTF8(Const FileName : string; Mode : Integer) : THandle; const AccessMode: array[0..2] of Cardinal = ( GENERIC_READ, GENERIC_WRITE, GENERIC_READ or GENERIC_WRITE); ShareMode: array[0..4] of Integer = ( 0, 0, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE); begin {$ifndef WinCE} if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) then Result := FileOpen(UTF8ToSys(FileName), Mode) else {$endif} Result := CreateFileW(PWideChar(UTF8Decode(FileName)), dword(AccessMode[Mode and 3]), dword(ShareMode[(Mode and $F0) shr 4]), nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); //if fail api return feInvalidHandle (INVALIDE_HANDLE=feInvalidHandle=-1) end; function FileCreateUTF8(Const FileName : string) : THandle; begin {$ifndef WinCE} if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) then Result := FileCreate(Utf8ToSys(FileName)) else {$endif} Result := CreateFileW(PWideChar(UTF8Decode(FileName)), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); end; function FileCreateUTF8(Const FileName : string; Rights: Cardinal) : THandle; begin {$ifndef WinCE} if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) then Result := FileCreate(Utf8ToSys(FileName), Rights) else {$endif} Result := CreateFileW(PWideChar(UTF8Decode(FileName)), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); end; function ExtractShortPathNameUTF8(const FileName: String): String; var lPathSize: DWORD; WideFileName, WideResult: UnicodeString; begin // WinCE doesnt have this concept {$ifdef WinCE} Result := FileName; {$else} if Win32MajorVersion >= 5 then begin WideFileName := UTF8ToUTF16(FileName); SetLength(WideResult,Max_Path); lPathSize := GetShortPathNameW(PWideChar(WideFileName), PWideChar(WideResult), Length(WideResult)); SetLength(WideResult,lPathSize); Result := UTF16ToUTF8(WideResult); end else Result:=SysToUTF8(SysUtils.ExtractShortPathName(UTF8ToSys(FileName))); {$endif} end; procedure InitFileUtils; begin {$ifndef WinCE} if Win32MajorVersion <= 4 then begin FileSize_:=@FileSizeAnsi; FileGetAttr_:=@FileGetAttrAnsi; FileSetAttr_:=@FileSetAttrAnsi; DeleteFile_:=@DeleteFileAnsi; RenameFile_:=@RenameFileAnsi; SetCurrentDir_:=@SetCurrentDirAnsi; GetCurrentDir_:=@GetCurrentDirAnsi; CreateDir_:=@CreateDirAnsi; RemoveDir_:=@RemoveDirAnsi; FindFirst_:=@FindFirstAnsi; FindNext_:=@FindNextAnsi; FindClose_:=@FindCloseAnsi; end; {$endif} end;