3969 lines
125 KiB
ObjectPascal
3969 lines
125 KiB
ObjectPascal
{******************************************************************************}
|
|
{ }
|
|
{ Library: Fundamentals 5.00 }
|
|
{ File name: flcFileUtils.pas }
|
|
{ File version: 5.18 }
|
|
{ Description: File name and file system functions }
|
|
{ }
|
|
{ Copyright: Copyright (c) 2002-2020, David J Butler }
|
|
{ All rights reserved. }
|
|
{ Redistribution and use in source and binary forms, with }
|
|
{ or without modification, are permitted provided that }
|
|
{ the following conditions are met: }
|
|
{ Redistributions of source code must retain the above }
|
|
{ copyright notice, this list of conditions and the }
|
|
{ following disclaimer. }
|
|
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
|
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
|
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
|
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
|
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
|
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
|
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
|
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
|
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
|
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
|
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
|
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
|
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
|
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
|
{ POSSIBILITY OF SUCH DAMAGE. }
|
|
{ }
|
|
{ Github: https://github.com/fundamentalslib }
|
|
{ E-mail: fundamentals.library at gmail.com }
|
|
{ }
|
|
{ Revision history: }
|
|
{ }
|
|
{ 2002/06/01 3.01 Created cFileUtils from cSysUtils. }
|
|
{ 2002/12/12 3.02 Revision. }
|
|
{ 2005/07/22 4.03 Compilable with FreePascal 2 Win32 i386. }
|
|
{ 2005/08/21 4.04 Compilable with FreePascal 2 Linux i386. }
|
|
{ 2005/09/20 4.05 Improved error handling. }
|
|
{ 2005/09/21 4.06 Revised for Fundamentals 4. }
|
|
{ 2008/12/30 4.07 Revision. }
|
|
{ 2009/06/05 4.08 File access functions. }
|
|
{ 2009/07/30 4.09 File access functions. }
|
|
{ 2010/06/27 4.10 Compilable with FreePascal 2.4.0 OSX x86-64 }
|
|
{ 2012/03/26 4.11 Unicode update. }
|
|
{ 2013/11/15 4.12 Unicode update. }
|
|
{ 2015/03/13 4.13 RawByteString functions. }
|
|
{ 2016/01/09 5.14 Revised for Fundamentals 5. }
|
|
{ 2016/02/01 5.15 Unicode update. }
|
|
{ 2016/04/10 5.16 Change to FileOpenWait. }
|
|
{ 2018/08/13 5.17 String type changes. }
|
|
{ 2019/07/29 5.18 DriveSizeA function. }
|
|
{ }
|
|
{ Supported compilers: }
|
|
{ }
|
|
{ Delphi 7 Win32 5.17 2019/02/24 }
|
|
{ Delphi XE2 Win32 5.17 2019/03/02 }
|
|
{ Delphi XE2 Win64 5.17 2019/03/02 }
|
|
{ Delphi XE3 Win32 5.17 2019/03/02 }
|
|
{ Delphi XE3 Win64 5.17 2019/03/02 }
|
|
{ Delphi XE6 Win32 5.17 2019/03/02 }
|
|
{ Delphi XE6 Win64 5.17 2019/03/02 }
|
|
{ Delphi XE7 Win32 5.17 2019/03/02 }
|
|
{ Delphi XE7 Win64 5.17 2019/03/02 }
|
|
{ Delphi 10 Win32 5.14 2016/01/09 }
|
|
{ Delphi 10 Win64 5.14 2016/01/09 }
|
|
{ Delphi 10.2 Linux64 5.17 2019/04/02 }
|
|
{ FreePascal 3.0.4 Win32 5.17 2019/02/24 }
|
|
{ FreePascal 3.0.4 Linux 5.18 2019/07/29 }
|
|
{ }
|
|
{ Todo: }
|
|
{ - IFDef win certain functions }
|
|
{******************************************************************************}
|
|
|
|
{$INCLUDE ..\flcInclude.inc}
|
|
|
|
{$IFDEF FREEPASCAL}
|
|
{$WARNINGS OFF}{$HINTS OFF}
|
|
{$ENDIF}
|
|
{$IFDEF DELPHI6_UP}
|
|
{$WARN SYMBOL_PLATFORM OFF}
|
|
{$ENDIF}
|
|
|
|
unit flcFileUtils;
|
|
|
|
interface
|
|
|
|
uses
|
|
{ System }
|
|
{$IFDEF MSWIN}
|
|
Windows,
|
|
{$ENDIF}
|
|
SysUtils,
|
|
|
|
{ Fundamentals }
|
|
flcStdTypes;
|
|
|
|
|
|
|
|
{ }
|
|
{ Path functions }
|
|
{ }
|
|
const
|
|
PosixPathSeparator = '/';
|
|
WinPathSeparator = '\';
|
|
PathSeparator = {$IFDEF POSIX} PosixPathSeparator {$ENDIF}
|
|
{$IFDEF MSWIN} WinPathSeparator {$ENDIF};
|
|
|
|
function WinPathHasDriveLetterB(const Path: RawByteString): Boolean;
|
|
function WinPathHasDriveLetterU(const Path: UnicodeString): Boolean;
|
|
function WinPathHasDriveLetter(const Path: String): Boolean;
|
|
|
|
function WinPathIsDriveLetterB(const Path: RawByteString): Boolean;
|
|
function WinPathIsDriveLetterU(const Path: UnicodeString): Boolean;
|
|
function WinPathIsDriveLetter(const Path: String): Boolean;
|
|
|
|
function WinPathIsDriveRootB(const Path: RawByteString): Boolean;
|
|
function WinPathIsDriveRootU(const Path: UnicodeString): Boolean;
|
|
function WinPathIsDriveRoot(const Path: String): Boolean;
|
|
|
|
function PathIsRootB(const Path: RawByteString): Boolean;
|
|
function PathIsRootU(const Path: UnicodeString): Boolean;
|
|
function PathIsRoot(const Path: String): Boolean;
|
|
|
|
function PathIsUNCPathB(const Path: RawByteString): Boolean;
|
|
function PathIsUNCPathU(const Path: UnicodeString): Boolean;
|
|
function PathIsUNCPath(const Path: String): Boolean;
|
|
|
|
function PathIsAbsoluteB(const Path: RawByteString): Boolean;
|
|
function PathIsAbsoluteU(const Path: UnicodeString): Boolean;
|
|
function PathIsAbsolute(const Path: String): Boolean;
|
|
|
|
function PathIsDirectoryB(const Path: RawByteString): Boolean;
|
|
function PathIsDirectoryU(const Path: UnicodeString): Boolean;
|
|
function PathIsDirectory(const Path: String): Boolean;
|
|
|
|
function PathInclSuffixB(const Path: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathInclSuffixU(const Path: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathInclSuffix(const Path: String;
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function PathExclSuffixB(const Path: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathExclSuffixU(const Path: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathExclSuffix(const Path: String;
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
procedure PathEnsureSuffixB(var Path: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator);
|
|
procedure PathEnsureSuffixU(var Path: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator);
|
|
procedure PathEnsureSuffix(var Path: String;
|
|
const PathSep: Char = PathSeparator);
|
|
|
|
procedure PathEnsureNoSuffixB(var Path: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator);
|
|
procedure PathEnsureNoSuffixU(var Path: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator);
|
|
procedure PathEnsureNoSuffix(var Path: String;
|
|
const PathSep: Char = PathSeparator);
|
|
|
|
function PathCanonicalB(const Path: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathCanonicalU(const Path: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathCanonical(const Path: String;
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function PathExpandB(const Path: RawByteString; const BasePath: RawByteString = '';
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathExpandU(const Path: UnicodeString; const BasePath: UnicodeString = '';
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathExpand(const Path: String; const BasePath: String = '';
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function PathLeftElementB(const Path: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathLeftElementU(const Path: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathLeftElement(const Path: String;
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
procedure PathSplitLeftElementB(const Path: RawByteString;
|
|
var LeftElement, RightPath: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator);
|
|
procedure PathSplitLeftElementU(const Path: UnicodeString;
|
|
var LeftElement, RightPath: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator);
|
|
procedure PathSplitLeftElement(const Path: String;
|
|
var LeftElement, RightPath: String;
|
|
const PathSep: Char = PathSeparator);
|
|
|
|
procedure DecodeFilePathB(const FilePath: RawByteString;
|
|
var Path, FileName: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator);
|
|
procedure DecodeFilePathU(const FilePath: UnicodeString;
|
|
var Path, FileName: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator);
|
|
procedure DecodeFilePath(const FilePath: String;
|
|
var Path, FileName: String;
|
|
const PathSep: Char = PathSeparator);
|
|
|
|
function PathExtractFilePathB(const FilePath: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathExtractFilePathU(const FilePath: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathExtractFilePath(const FilePath: String;
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function PathExtractFileNameB(const FilePath: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathExtractFileNameU(const FilePath: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathExtractFileName(const FilePath: String;
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function PathExtractFileExtB(const FilePath: RawByteString;
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function PathExtractFileExtU(const FilePath: UnicodeString;
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function PathExtractFileExt(const FilePath: String;
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function FileNameCleanB(const FileName: RawByteString): RawByteString;
|
|
function FileNameCleanU(const FileName: UnicodeString): UnicodeString;
|
|
function FileNameClean(const FileName: String): String;
|
|
|
|
function FilePathB(const FileName, Path: RawByteString; const BasePath: RawByteString = '';
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function FilePathU(const FileName, Path: UnicodeString; const BasePath: UnicodeString = '';
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function FilePath(const FileName, Path: String; const BasePath: String = '';
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function DirectoryExpandB(const Path: RawByteString; const BasePath: RawByteString = '';
|
|
const PathSep: ByteChar = PathSeparator): RawByteString;
|
|
function DirectoryExpandU(const Path: UnicodeString; const BasePath: UnicodeString = '';
|
|
const PathSep: WideChar = PathSeparator): UnicodeString;
|
|
function DirectoryExpand(const Path: String; const BasePath: String = '';
|
|
const PathSep: Char = PathSeparator): String;
|
|
|
|
function UnixPathToSafeWinPathB(const Path: RawByteString): RawByteString;
|
|
|
|
function WinPathToSafeUnixPathB(const Path: RawByteString): RawByteString;
|
|
|
|
|
|
|
|
{ }
|
|
{ File errors }
|
|
{ }
|
|
type
|
|
TFileError = (
|
|
feNone {$IFDEF SupportEnumValue} = $00 {$ENDIF},
|
|
feInvalidParameter {$IFDEF SupportEnumValue} = $01 {$ENDIF},
|
|
|
|
feFileError {$IFDEF SupportEnumValue} = $10 {$ENDIF},
|
|
feFileOpenError {$IFDEF SupportEnumValue} = $11 {$ENDIF},
|
|
feFileCreateError {$IFDEF SupportEnumValue} = $12 {$ENDIF},
|
|
feFileSharingError {$IFDEF SupportEnumValue} = $13 {$ENDIF},
|
|
feFileSeekError {$IFDEF SupportEnumValue} = $14 {$ENDIF},
|
|
feFileReadError {$IFDEF SupportEnumValue} = $15 {$ENDIF},
|
|
feFileWriteError {$IFDEF SupportEnumValue} = $16 {$ENDIF},
|
|
feFileSizeError {$IFDEF SupportEnumValue} = $17 {$ENDIF},
|
|
feFileExists {$IFDEF SupportEnumValue} = $18 {$ENDIF},
|
|
feFileDoesNotExist {$IFDEF SupportEnumValue} = $19 {$ENDIF},
|
|
feFileMoveError {$IFDEF SupportEnumValue} = $1A {$ENDIF},
|
|
feFileDeleteError {$IFDEF SupportEnumValue} = $1B {$ENDIF},
|
|
feDirectoryCreateError {$IFDEF SupportEnumValue} = $1C {$ENDIF},
|
|
|
|
feOutOfSpace {$IFDEF SupportEnumValue} = $20 {$ENDIF},
|
|
feOutOfResources {$IFDEF SupportEnumValue} = $21 {$ENDIF},
|
|
feInvalidFilePath {$IFDEF SupportEnumValue} = $22 {$ENDIF},
|
|
feInvalidFileName {$IFDEF SupportEnumValue} = $23 {$ENDIF},
|
|
feAccessDenied {$IFDEF SupportEnumValue} = $24 {$ENDIF},
|
|
feDeviceFailure {$IFDEF SupportEnumValue} = $25 {$ENDIF}
|
|
);
|
|
|
|
EFileError = class(Exception)
|
|
private
|
|
FFileError : TFileError;
|
|
|
|
public
|
|
constructor Create(const FileError: TFileError; const Msg: string);
|
|
constructor CreateFmt(const FileError: TFileError; const Msg: string; const Args: array of const);
|
|
|
|
property FileError: TFileError read FFileError;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ File operations }
|
|
{ }
|
|
type
|
|
TFileHandle = Integer;
|
|
|
|
TFileAccess = (
|
|
faRead,
|
|
faWrite,
|
|
faReadWrite);
|
|
|
|
TFileSharing = (
|
|
fsDenyNone,
|
|
fsDenyRead,
|
|
fsDenyWrite,
|
|
fsDenyReadWrite,
|
|
fsExclusive);
|
|
|
|
TFileOpenFlags = set of (
|
|
foDeleteOnClose,
|
|
foNoBuffering,
|
|
foWriteThrough,
|
|
foRandomAccessHint,
|
|
foSequentialScanHint,
|
|
foSeekToEndOfFile);
|
|
|
|
TFileCreationMode = (
|
|
fcCreateNew,
|
|
fcCreateAlways,
|
|
fcOpenExisting,
|
|
fcOpenAlways,
|
|
fcTruncateExisting);
|
|
|
|
TFileSeekPosition = (
|
|
fpOffsetFromStart,
|
|
fpOffsetFromCurrent,
|
|
fpOffsetFromEnd);
|
|
|
|
PFileOpenWait = ^TFileOpenWait;
|
|
TFileOpenWaitProcedure = procedure (const FileOpenWait: PFileOpenWait);
|
|
TFileOpenWait = packed record
|
|
Wait : Boolean;
|
|
UserData : LongWord;
|
|
Timeout : Integer; // Total time to wait (ms) for operation to succeed (including retries)
|
|
RetryInterval : Integer; // Interval to wait (ms) before a retry
|
|
RetryRandomise : Boolean; // Randomize RetryInterval
|
|
Callback : TFileOpenWaitProcedure;
|
|
Aborted : Boolean;
|
|
{$IFDEF MSWIN}
|
|
Signal : THandle;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
var
|
|
FileOpenWaitNone : TFileOpenWait = (
|
|
Wait : False;
|
|
UserData : 0;
|
|
Timeout : 0;
|
|
RetryInterval : 0;
|
|
RetryRandomise : False;
|
|
Callback : nil;
|
|
Aborted : False;
|
|
{$IFDEF MSWIN}
|
|
Signal : 0;
|
|
{$ENDIF}
|
|
);
|
|
|
|
FileOpenWaitFewSec : TFileOpenWait = (
|
|
Wait : True;
|
|
UserData : 0;
|
|
Timeout : 2500;
|
|
RetryInterval : 250;
|
|
RetryRandomise : True;
|
|
Callback : nil;
|
|
Aborted : False;
|
|
{$IFDEF MSWIN}
|
|
Signal : 0;
|
|
{$ENDIF}
|
|
);
|
|
|
|
function FileOpenExB(
|
|
const FileName: RawByteString;
|
|
const FileAccess: TFileAccess = faRead;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileOpenFlags: TFileOpenFlags = [];
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): TFileHandle;
|
|
function FileOpenExU(
|
|
const FileName: UnicodeString;
|
|
const FileAccess: TFileAccess;
|
|
const FileSharing: TFileSharing;
|
|
const FileOpenFlags: TFileOpenFlags;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): TFileHandle;
|
|
function FileOpenEx(
|
|
const FileName: String;
|
|
const FileAccess: TFileAccess;
|
|
const FileSharing: TFileSharing;
|
|
const FileOpenFlags: TFileOpenFlags = [];
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): TFileHandle;
|
|
|
|
function FileSeekEx(
|
|
const FileHandle: TFileHandle;
|
|
const FileOffset: Int64;
|
|
const FilePosition: TFileSeekPosition = fpOffsetFromStart): Int64;
|
|
|
|
function FileReadEx(
|
|
const FileHandle: TFileHandle;
|
|
var Buf; const BufSize: Integer): Integer;
|
|
|
|
function FileWriteEx(
|
|
const FileHandle: TFileHandle;
|
|
const Buf; const BufSize: Integer): Integer;
|
|
|
|
procedure FileCloseEx(
|
|
const FileHandle: TFileHandle);
|
|
|
|
function FindFirstB(const Path: RawByteString; Attr: Integer; var F: TSearchRec): Integer;
|
|
function FindFirstU(const Path: UnicodeString; Attr: Integer; var F: TSearchRec): Integer;
|
|
|
|
function FileExistsB(const FileName: RawByteString): Boolean;
|
|
function FileExistsU(const FileName: UnicodeString): Boolean;
|
|
function FileExists(const FileName: String): Boolean;
|
|
|
|
function FileGetSizeB(const FileName: RawByteString): Int64;
|
|
function FileGetSizeU(const FileName: UnicodeString): Int64;
|
|
function FileGetSize(const FileName: String): Int64;
|
|
|
|
function FileGetDateTimeB(const FileName: RawByteString): TDateTime;
|
|
function FileGetDateTime(const FileName: String): TDateTime;
|
|
|
|
function FileGetDateTime2(const FileName: String): TDateTime;
|
|
|
|
function FileIsReadOnly(const FileName: String): Boolean;
|
|
|
|
procedure FileDeleteEx(const FileName: String);
|
|
|
|
procedure FileRenameEx(const OldFileName, NewFileName: String);
|
|
|
|
function ReadFileBufB(
|
|
const FileName: RawByteString;
|
|
var Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): Integer;
|
|
function ReadFileBufU(
|
|
const FileName: UnicodeString;
|
|
var Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): Integer;
|
|
function ReadFileBuf(
|
|
const FileName: String;
|
|
var Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): Integer;
|
|
|
|
function ReadFileRawStrB(
|
|
const FileName: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): RawByteString;
|
|
function ReadFileRawStrU(
|
|
const FileName: UnicodeString;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): RawByteString;
|
|
function ReadFileRawStr(
|
|
const FileName: String;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): RawByteString;
|
|
|
|
function ReadFileBytesB(
|
|
const FileName: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): TBytes;
|
|
function ReadFileBytesU(
|
|
const FileName: UnicodeString;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): TBytes;
|
|
function ReadFileBytes(
|
|
const FileName: String;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): TBytes;
|
|
|
|
procedure WriteFileBufB(
|
|
const FileName: RawByteString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure WriteFileBufU(
|
|
const FileName: UnicodeString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure WriteFileBuf(
|
|
const FileName: String;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
|
|
procedure WriteFileRawStrB(
|
|
const FileName: RawByteString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure WriteFileRawStrU(
|
|
const FileName: UnicodeString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure WriteFileRawStr(
|
|
const FileName: String;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
|
|
procedure WriteFileBytesB(
|
|
const FileName: RawByteString;
|
|
const Buf: TBytes;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure WriteFileBytesU(
|
|
const FileName: UnicodeString;
|
|
const Buf: TBytes;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure WriteFileBytes(
|
|
const FileName: String;
|
|
const Buf: TBytes;
|
|
const FileSharing: TFileSharing = fsDenyReadWrite;
|
|
const FileCreationMode: TFileCreationMode = fcCreateAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
|
|
procedure AppendFileB(
|
|
const FileName: RawByteString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyWrite;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure AppendFileU(
|
|
const FileName: UnicodeString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyWrite;
|
|
const FileCreationMode: TFileCreationMode = fcOpenAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure AppendFile(
|
|
const FileName: String;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyWrite;
|
|
const FileCreationMode: TFileCreationMode = fcOpenAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
|
|
procedure AppendFileRawStrB(
|
|
const FileName: RawByteString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyWrite;
|
|
const FileCreationMode: TFileCreationMode = fcOpenAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure AppendFileRawStrU(
|
|
const FileName: UnicodeString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyWrite;
|
|
const FileCreationMode: TFileCreationMode = fcOpenAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
procedure AppendFileRawStr(
|
|
const FileName: String;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing = fsDenyWrite;
|
|
const FileCreationMode: TFileCreationMode = fcOpenAlways;
|
|
const FileOpenWait: PFileOpenWait = nil);
|
|
|
|
|
|
|
|
{ }
|
|
{ Directory entries }
|
|
{ }
|
|
function DirectoryEntryExistsB(const Name: RawByteString): Boolean;
|
|
function DirectoryEntryExistsU(const Name: UnicodeString): Boolean;
|
|
function DirectoryEntryExists(const Name: String): Boolean;
|
|
|
|
function DirectoryEntrySizeB(const Name: RawByteString): Int64;
|
|
function DirectoryEntrySizeU(const Name: UnicodeString): Int64;
|
|
function DirectoryEntrySize(const Name: String): Int64;
|
|
|
|
function DirectoryExistsB(const DirectoryName: RawByteString): Boolean;
|
|
function DirectoryExistsU(const DirectoryName: UnicodeString): Boolean;
|
|
function DirectoryExists(const DirectoryName: String): Boolean;
|
|
|
|
function DirectoryGetDateTimeB(const DirectoryName: RawByteString): TDateTime;
|
|
function DirectoryGetDateTimeU(const DirectoryName: UnicodeString): TDateTime;
|
|
function DirectoryGetDateTime(const DirectoryName: String): TDateTime;
|
|
|
|
function GetFirstFileNameMatchingB(const FileMask: RawByteString): RawByteString;
|
|
function GetFirstFileNameMatchingU(const FileMask: UnicodeString): UnicodeString;
|
|
function GetFirstFileNameMatching(const FileMask: String): String;
|
|
|
|
function DirEntryGetAttrB(const FileName: RawByteString): Integer;
|
|
function DirEntryGetAttrU(const FileName: UnicodeString): Integer;
|
|
function DirEntryGetAttr(const FileName: String): Integer;
|
|
|
|
function DirEntryIsDirectoryB(const FileName: RawByteString): Boolean;
|
|
function DirEntryIsDirectoryU(const FileName: UnicodeString): Boolean;
|
|
function DirEntryIsDirectory(const FileName: String): Boolean;
|
|
|
|
function FileHasAttr(const FileName: String; const Attr: Word): Boolean;
|
|
function FileHasAttrB(const FileName: RawByteString; const Attr: Word): Boolean;
|
|
function FileHasAttrU(const FileName: UnicodeString; const Attr: Word): Boolean;
|
|
|
|
procedure DirectoryCreateB(const DirectoryName: RawByteString);
|
|
procedure DirectoryCreateU(const DirectoryName: UnicodeString);
|
|
procedure DirectoryCreate(const DirectoryName: String);
|
|
|
|
|
|
|
|
{ }
|
|
{ File operations }
|
|
{ MoveFile first attempts a rename, then a copy and delete. }
|
|
{ }
|
|
procedure CopyFile(const FileName, DestName: String);
|
|
procedure MoveFile(const FileName, DestName: String);
|
|
function DeleteFiles(const FileMask: String): Boolean;
|
|
|
|
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
{ }
|
|
{ Logical Drive functions }
|
|
{ }
|
|
type
|
|
TLogicalDriveType = (
|
|
DriveRemovable,
|
|
DriveFixed,
|
|
DriveRemote,
|
|
DriveCDRom,
|
|
DriveRamDisk,
|
|
DriveTypeUnknown);
|
|
|
|
function DriveIsValidA(const Drive: ByteChar): Boolean;
|
|
function DriveIsValidW(const Drive: WideChar): Boolean;
|
|
|
|
function DriveGetTypeA(const Path: AnsiString): TLogicalDriveType;
|
|
|
|
function DriveFreeSpaceA(const Path: AnsiString): Int64;
|
|
function DriveSizeA(const Path: AnsiString): Int64;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
{ }
|
|
{ Test cases }
|
|
{ }
|
|
{$IFDEF DEBUG}
|
|
{$IFDEF TEST}
|
|
procedure Test;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
{ System }
|
|
{$IFDEF DELPHI}{$IFDEF POSIX}
|
|
Posix.Unistd,
|
|
Posix.Stdio,
|
|
{$ENDIF}{$ENDIF}
|
|
{$IFDEF FREEPASCAL}{$IFDEF UNIX}
|
|
BaseUnix,
|
|
Unix,
|
|
{$ENDIF}{$ENDIF}
|
|
|
|
{ Fundamentals }
|
|
flcDynArrays,
|
|
flcUtils,
|
|
flcStrings,
|
|
flcSysUtils;
|
|
|
|
|
|
|
|
{$IFDEF DELPHI6_UP}
|
|
{$WARN SYMBOL_DEPRECATED OFF}
|
|
{$ENDIF}
|
|
|
|
|
|
resourcestring
|
|
SCannotOpenFile = 'Cannot open file: %s: %s';
|
|
SCannotCreateFile = 'Cannot create file: %s: %s';
|
|
SCannotMoveFile = 'Cannot move file: %s: %s';
|
|
SFileSizeError = 'File size error: %s';
|
|
SFileReadError = 'File read error: %s';
|
|
SFileWriteError = 'File write error: %s: %s';
|
|
SInvalidFileCreationMode = 'Invalid file creation mode';
|
|
SFileExists = 'File exists: %s';
|
|
SFileDoesNotExist = 'File does not exist: %s';
|
|
SInvalidFileHandle = 'Invalid file handle';
|
|
SInvalidFilePosition = 'Invalid file position';
|
|
SFileSeekError = 'File seek error: %s';
|
|
SInvalidFileName = 'Invalid file name';
|
|
SInvalidPath = 'Invalid path';
|
|
SFileDeleteError = 'File delete error: %s';
|
|
SInvalidFileAccess = 'Invalid file access';
|
|
SInvalidFileSharing = 'Invalid file sharing';
|
|
SCannotCreateDirectory = 'Cannot create directory: %s: %s';
|
|
|
|
|
|
|
|
{ }
|
|
{ Path functions }
|
|
{ }
|
|
function WinPathHasDriveLetterB(const Path: RawByteString): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Length(Path) < 2 then
|
|
exit;
|
|
case Path[1] of
|
|
'A'..'Z', 'a'..'z' : ;
|
|
else
|
|
exit;
|
|
end;
|
|
if Path[2] <> ':' then
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function WinPathHasDriveLetterU(const Path: UnicodeString): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Length(Path) < 2 then
|
|
exit;
|
|
case Path[1] of
|
|
'A'..'Z', 'a'..'z' : ;
|
|
else
|
|
exit;
|
|
end;
|
|
if Path[2] <> ':' then
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function WinPathHasDriveLetter(const Path: String): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Length(Path) < 2 then
|
|
exit;
|
|
case Path[1] of
|
|
'A'..'Z', 'a'..'z' : ;
|
|
else
|
|
exit;
|
|
end;
|
|
if Path[2] <> ':' then
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function WinPathIsDriveLetterB(const Path: RawByteString): Boolean;
|
|
begin
|
|
Result := (Length(Path) = 2) and WinPathHasDriveLetterB(Path);
|
|
end;
|
|
|
|
function WinPathIsDriveLetterU(const Path: UnicodeString): Boolean;
|
|
begin
|
|
Result := (Length(Path) = 2) and WinPathHasDriveLetterU(Path);
|
|
end;
|
|
|
|
function WinPathIsDriveLetter(const Path: String): Boolean;
|
|
begin
|
|
Result := (Length(Path) = 2) and WinPathHasDriveLetter(Path);
|
|
end;
|
|
|
|
function WinPathIsDriveRootB(const Path: RawByteString): Boolean;
|
|
begin
|
|
Result := (Length(Path) = 3) and WinPathHasDriveLetterB(Path) and
|
|
(Path[3] = '\');
|
|
end;
|
|
|
|
function WinPathIsDriveRootU(const Path: UnicodeString): Boolean;
|
|
begin
|
|
Result := (Length(Path) = 3) and WinPathHasDriveLetterU(Path) and
|
|
(Path[3] = '\');
|
|
end;
|
|
|
|
function WinPathIsDriveRoot(const Path: String): Boolean;
|
|
begin
|
|
Result := (Length(Path) = 3) and WinPathHasDriveLetter(Path) and
|
|
(Path[3] = '\');
|
|
end;
|
|
|
|
function PathIsRootB(const Path: RawByteString): Boolean;
|
|
begin
|
|
Result := ((Length(Path) = 1) and (Path[1] in csSlash)) or
|
|
WinPathIsDriveRootB(Path);
|
|
end;
|
|
|
|
function PathIsRootU(const Path: UnicodeString): Boolean;
|
|
begin
|
|
Result := WinPathIsDriveRootU(Path);
|
|
if Result then
|
|
exit;
|
|
if Length(Path) = 1 then
|
|
case Path[1] of
|
|
'/', '\' : Result := True;
|
|
end;
|
|
end;
|
|
|
|
function PathIsRoot(const Path: String): Boolean;
|
|
begin
|
|
Result := WinPathIsDriveRoot(Path);
|
|
if Result then
|
|
exit;
|
|
if Length(Path) = 1 then
|
|
case Path[1] of
|
|
'/', '\' : Result := True;
|
|
end;
|
|
end;
|
|
|
|
function PathIsUNCPathB(const Path: RawByteString): Boolean;
|
|
var P: PByteChar;
|
|
begin
|
|
Result := False;
|
|
if Length(Path) < 2 then
|
|
exit;
|
|
P := Pointer(Path);
|
|
if P^ <> '\' then
|
|
exit;
|
|
Inc(P);
|
|
if P^ <> '\' then
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function PathIsUNCPathU(const Path: UnicodeString): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Length(Path) < 2 then
|
|
exit;
|
|
if Path[1] <> '\' then
|
|
exit;
|
|
if Path[2] <> '\' then
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function PathIsUNCPath(const Path: String): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Length(Path) < 2 then
|
|
exit;
|
|
if Path[1] <> '\' then
|
|
exit;
|
|
if Path[2] <> '\' then
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function PathIsAbsoluteB(const Path: RawByteString): Boolean;
|
|
begin
|
|
if Path = '' then
|
|
Result := False else
|
|
if WinPathHasDriveLetterB(Path) then
|
|
Result := True else
|
|
if PByteChar(Pointer(Path))^ in ['\', '/'] then
|
|
Result := True
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function PathIsAbsoluteU(const Path: UnicodeString): Boolean;
|
|
begin
|
|
if Path = '' then
|
|
Result := False else
|
|
if WinPathHasDriveLetterU(Path) then
|
|
Result := True
|
|
else
|
|
case Path[1] of
|
|
'\', '/' : Result := True;
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function PathIsAbsolute(const Path: String): Boolean;
|
|
begin
|
|
if Path = '' then
|
|
Result := False else
|
|
if WinPathHasDriveLetter(Path) then
|
|
Result := True
|
|
else
|
|
case Path[1] of
|
|
'\', '/' : Result := True;
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function PathIsDirectoryB(const Path: RawByteString): Boolean;
|
|
var L: Integer;
|
|
P: PByteChar;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := False else
|
|
if (L = 2) and WinPathHasDriveLetterB(Path) then
|
|
Result := True else
|
|
begin
|
|
P := Pointer(Path);
|
|
Inc(P, L - 1);
|
|
Result := P^ in csSlash;
|
|
end;
|
|
end;
|
|
|
|
function PathIsDirectoryU(const Path: UnicodeString): Boolean;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := False else
|
|
if (L = 2) and WinPathHasDriveLetterU(Path) then
|
|
Result := True
|
|
else
|
|
case Path[L] of
|
|
'/', '\' : Result := True;
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function PathIsDirectory(const Path: String): Boolean;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := False else
|
|
if (L = 2) and WinPathHasDriveLetter(Path) then
|
|
Result := True
|
|
else
|
|
case Path[L] of
|
|
'/', '\' : Result := True;
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function PathInclSuffixB(const Path: RawByteString; const PathSep: ByteChar): RawByteString;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := ''
|
|
else
|
|
begin
|
|
if Path[L] = PathSep then
|
|
Result := Path
|
|
else
|
|
Result := Path + PathSep;
|
|
end;
|
|
end;
|
|
|
|
function PathInclSuffixU(const Path: UnicodeString; const PathSep: WideChar): UnicodeString;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := ''
|
|
else
|
|
begin
|
|
if Path[L] = PathSep then
|
|
Result := Path
|
|
else
|
|
Result := Path + PathSep;
|
|
end;
|
|
end;
|
|
|
|
function PathInclSuffix(const Path: String; const PathSep: Char): String;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := ''
|
|
else
|
|
begin
|
|
if Path[L] = PathSep then
|
|
Result := Path
|
|
else
|
|
Result := Path + PathSep;
|
|
end;
|
|
end;
|
|
|
|
procedure PathEnsureSuffixB(var Path: RawByteString; const PathSep: ByteChar);
|
|
begin
|
|
Path := PathInclSuffixB(Path, PathSep);
|
|
end;
|
|
|
|
procedure PathEnsureSuffixU(var Path: UnicodeString; const PathSep: WideChar);
|
|
begin
|
|
Path := PathInclSuffixU(Path, PathSep);
|
|
end;
|
|
|
|
procedure PathEnsureSuffix(var Path: String; const PathSep: Char);
|
|
begin
|
|
Path := PathInclSuffix(Path, PathSep);
|
|
end;
|
|
|
|
procedure PathEnsureNoSuffixB(var Path: RawByteString; const PathSep: ByteChar);
|
|
begin
|
|
Path := PathExclSuffixB(Path, PathSep);
|
|
end;
|
|
|
|
procedure PathEnsureNoSuffixU(var Path: UnicodeString; const PathSep: WideChar);
|
|
begin
|
|
Path := PathExclSuffixU(Path, PathSep);
|
|
end;
|
|
|
|
procedure PathEnsureNoSuffix(var Path: String; const PathSep: Char);
|
|
begin
|
|
Path := PathExclSuffix(Path, PathSep);
|
|
end;
|
|
|
|
function PathExclSuffixB(const Path: RawByteString; const PathSep: ByteChar): RawByteString;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := '' else
|
|
begin
|
|
if Path[L] = PathSep then
|
|
Result := Copy(Path, 1, L - 1)
|
|
else
|
|
Result := Path;
|
|
end;
|
|
end;
|
|
|
|
function PathExclSuffixU(const Path: UnicodeString; const PathSep: WideChar): UnicodeString;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := '' else
|
|
begin
|
|
if Path[L] = PathSep then
|
|
Result := Copy(Path, 1, L - 1)
|
|
else
|
|
Result := Path;
|
|
end;
|
|
end;
|
|
|
|
function PathExclSuffix(const Path: String; const PathSep: Char): String;
|
|
var L: Integer;
|
|
begin
|
|
L := Length(Path);
|
|
if L = 0 then
|
|
Result := '' else
|
|
begin
|
|
if Path[L] = PathSep then
|
|
Result := Copy(Path, 1, L - 1)
|
|
else
|
|
Result := Path;
|
|
end;
|
|
end;
|
|
|
|
function PathCanonicalB(const Path: RawByteString; const PathSep: ByteChar): RawByteString;
|
|
var L, M : Integer;
|
|
I, J : Integer;
|
|
P : RawByteStringArray;
|
|
Q : PByteChar;
|
|
begin
|
|
Result := Path;
|
|
// \.\ references
|
|
M := Length(Result);
|
|
repeat
|
|
L := M;
|
|
if L = 0 then
|
|
exit;
|
|
Result := StrReplaceB('\.\', '\', Result);
|
|
Result := StrReplaceB('/./', '/', Result);
|
|
M := Length(Result);
|
|
until L = M;
|
|
// .\ prefix
|
|
StrEnsureNoPrefixB(Result, '.\');
|
|
StrEnsureNoPrefixB(Result, './');
|
|
// \. suffix
|
|
StrEnsureNoSuffixB(Result, '\.');
|
|
StrEnsureNoSuffixB(Result, '/.');
|
|
// ..
|
|
if PosStrB('..', Result) > 0 then
|
|
begin
|
|
P := StrSplitCharB(Result, PathSep);
|
|
repeat
|
|
J := -1;
|
|
For I := Length(P) - 1 downto 0 do
|
|
if P[I] = '..' then
|
|
begin
|
|
J := I;
|
|
break;
|
|
end;
|
|
if J = -1 then
|
|
break;
|
|
M := -1;
|
|
For I := J - 1 downto 0 do
|
|
if (P[I] = '') or ((I = 0) and WinPathHasDriveLetterB(P[I])) then
|
|
break else
|
|
if P[I] <> '..' then
|
|
begin
|
|
M := I;
|
|
break;
|
|
end;
|
|
if M = -1 then
|
|
break;
|
|
DynArrayRemoveB(P, J, 1);
|
|
DynArrayRemoveB(P, M, 1);
|
|
until False;
|
|
Result := StrJoinCharB(P, PathSep);
|
|
end;
|
|
// \..\ prefix
|
|
while StrMatchLeftB(Result, '\..\') do
|
|
Delete(Result, 1, 3);
|
|
while StrMatchLeftB(Result, '/../') do
|
|
Delete(Result, 1, 3);
|
|
if (Result = '\..') or (Result = '/..') then
|
|
Result := '';
|
|
L := Length(Result);
|
|
if L = 0 then
|
|
exit;
|
|
// X:\..\ prefix
|
|
Q := Pointer(Result);
|
|
if Q^ in ['A'..'Z', 'a'..'z'] then
|
|
begin
|
|
if StrMatchB(Result, ':\..\', 2) then
|
|
Delete(Result, 4, 3) else
|
|
if (L = 5) and StrMatchB(Result, ':\..', 2) then
|
|
begin
|
|
SetLength(Result, 2);
|
|
exit;
|
|
end;
|
|
L := Length(Result);
|
|
end;
|
|
// single dot
|
|
Q := Pointer(Result);
|
|
if L = 1 then
|
|
begin
|
|
if Q^ = '.' then
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
// final dot
|
|
Inc(Q, L - 2);
|
|
if not (Q^ in ['.', '\', '/', ':']) then
|
|
begin
|
|
Inc(Q);
|
|
if Q^ = '.' then
|
|
Delete(Result, L, 1);
|
|
end;
|
|
end;
|
|
|
|
function PathCanonicalU(const Path: UnicodeString; const PathSep: WideChar): UnicodeString;
|
|
var L, M : Integer;
|
|
I, J : Integer;
|
|
P : UnicodeStringArray;
|
|
Q : PWideChar;
|
|
C : WideChar;
|
|
begin
|
|
Result := Path;
|
|
// \.\ references
|
|
M := Length(Result);
|
|
repeat
|
|
L := M;
|
|
if L = 0 then
|
|
exit;
|
|
Result := StrReplaceU('\.\', '\', Result);
|
|
Result := StrReplaceU('/./', '/', Result);
|
|
M := Length(Result);
|
|
until L = M;
|
|
// .\ prefix
|
|
StrEnsureNoPrefixU(Result, '.\');
|
|
StrEnsureNoPrefixU(Result, './');
|
|
// \. suffix
|
|
StrEnsureNoSuffixU(Result, '\.');
|
|
StrEnsureNoSuffixU(Result, '/.');
|
|
// ..
|
|
if PosStrU('..', Result) > 0 then
|
|
begin
|
|
P := StrSplitCharU(Result, PathSep);
|
|
repeat
|
|
J := -1;
|
|
For I := Length(P) - 1 downto 0 do
|
|
if P[I] = '..' then
|
|
begin
|
|
J := I;
|
|
break;
|
|
end;
|
|
if J = -1 then
|
|
break;
|
|
M := -1;
|
|
For I := J - 1 downto 0 do
|
|
if (P[I] = '') or ((I = 0) and WinPathHasDriveLetterU(P[I])) then
|
|
break else
|
|
if P[I] <> '..' then
|
|
begin
|
|
M := I;
|
|
break;
|
|
end;
|
|
if M = -1 then
|
|
break;
|
|
DynArrayRemoveU(P, J, 1);
|
|
DynArrayRemoveU(P, M, 1);
|
|
until False;
|
|
Result := StrJoinCharU(P, PathSep);
|
|
end;
|
|
// \..\ prefix
|
|
while StrMatchLeftU(Result, '\..\') do
|
|
Delete(Result, 1, 3);
|
|
while StrMatchLeftU(Result, '/../') do
|
|
Delete(Result, 1, 3);
|
|
if (Result = '\..') or (Result = '/..') then
|
|
Result := '';
|
|
L := Length(Result);
|
|
if L = 0 then
|
|
exit;
|
|
// X:\..\ prefix
|
|
Q := Pointer(Result);
|
|
case Q^ of
|
|
'A'..'Z',
|
|
'a'..'z' :
|
|
begin
|
|
if StrMatchU(Result, ':\..\', 2) then
|
|
Delete(Result, 4, 3) else
|
|
if (L = 5) and StrMatchU(Result, ':\..', 2) then
|
|
begin
|
|
SetLength(Result, 2);
|
|
exit;
|
|
end;
|
|
L := Length(Result);
|
|
end;
|
|
end;
|
|
// single dot
|
|
Q := Pointer(Result);
|
|
if L = 1 then
|
|
begin
|
|
if Q^ = '.' then
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
// final dot
|
|
Inc(Q, L - 2);
|
|
C := Q^;
|
|
if not ((C = '.') or (C = '\') or (C = '/') or (C = ':')) then
|
|
begin
|
|
Inc(Q);
|
|
if Q^ = '.' then
|
|
Delete(Result, L, 1);
|
|
end;
|
|
end;
|
|
|
|
function PathCanonical(const Path: String; const PathSep: Char): String;
|
|
var L, M : Integer;
|
|
I, J : Integer;
|
|
P : StringArray;
|
|
Q : PChar;
|
|
C : Char;
|
|
begin
|
|
Result := Path;
|
|
// \.\ references
|
|
M := Length(Result);
|
|
repeat
|
|
L := M;
|
|
if L = 0 then
|
|
exit;
|
|
Result := StrReplace('\.\', '\', Result);
|
|
Result := StrReplace('/./', '/', Result);
|
|
M := Length(Result);
|
|
until L = M;
|
|
// .\ prefix
|
|
StrEnsureNoPrefix(Result, '.\');
|
|
StrEnsureNoPrefix(Result, './');
|
|
// \. suffix
|
|
StrEnsureNoSuffix(Result, '\.');
|
|
StrEnsureNoSuffix(Result, '/.');
|
|
// ..
|
|
if PosStr('..', Result) > 0 then
|
|
begin
|
|
P := StrSplitChar(Result, PathSep);
|
|
repeat
|
|
J := -1;
|
|
For I := Length(P) - 1 downto 0 do
|
|
if P[I] = '..' then
|
|
begin
|
|
J := I;
|
|
break;
|
|
end;
|
|
if J = -1 then
|
|
break;
|
|
M := -1;
|
|
For I := J - 1 downto 0 do
|
|
if (P[I] = '') or ((I = 0) and WinPathHasDriveLetter(P[I])) then
|
|
break else
|
|
if P[I] <> '..' then
|
|
begin
|
|
M := I;
|
|
break;
|
|
end;
|
|
if M = -1 then
|
|
break;
|
|
DynArrayRemove(P, J, 1);
|
|
DynArrayRemove(P, M, 1);
|
|
until False;
|
|
Result := StrJoinChar(P, PathSep);
|
|
end;
|
|
// \..\ prefix
|
|
while StrMatchLeft(Result, '\..\') do
|
|
Delete(Result, 1, 3);
|
|
while StrMatchLeft(Result, '/../') do
|
|
Delete(Result, 1, 3);
|
|
if (Result = '\..') or (Result = '/..') then
|
|
Result := '';
|
|
L := Length(Result);
|
|
if L = 0 then
|
|
exit;
|
|
// X:\..\ prefix
|
|
Q := Pointer(Result);
|
|
C := Q^;
|
|
if ((C >= 'A') and (C <= 'Z')) or
|
|
((C >= 'a') and (C <= 'z')) then
|
|
begin
|
|
if StrMatch(Result, ':\..\', 2) then
|
|
Delete(Result, 4, 3) else
|
|
if (L = 5) and StrMatch(Result, ':\..', 2) then
|
|
begin
|
|
SetLength(Result, 2);
|
|
exit;
|
|
end;
|
|
L := Length(Result);
|
|
end;
|
|
// single dot
|
|
Q := Pointer(Result);
|
|
if L = 1 then
|
|
begin
|
|
if Q^ = '.' then
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
// final dot
|
|
Inc(Q, L - 2);
|
|
C := Q^;
|
|
if not ((C = '.') or (C = '\') or (C = '/') or (C = ':')) then
|
|
begin
|
|
Inc(Q);
|
|
if Q^ = '.' then
|
|
Delete(Result, L, 1);
|
|
end;
|
|
end;
|
|
|
|
function PathExpandB(const Path: RawByteString; const BasePath: RawByteString;
|
|
const PathSep: ByteChar): RawByteString;
|
|
begin
|
|
if Path = '' then
|
|
Result := BasePath else
|
|
if PathIsAbsoluteB(Path) then
|
|
Result := Path else
|
|
Result := PathInclSuffixB(BasePath, PathSep) + Path;
|
|
Result := PathCanonicalB(Result, PathSep);
|
|
end;
|
|
|
|
function PathExpandU(const Path: UnicodeString; const BasePath: UnicodeString;
|
|
const PathSep: WideChar): UnicodeString;
|
|
begin
|
|
if Path = '' then
|
|
Result := BasePath else
|
|
if PathIsAbsoluteU(Path) then
|
|
Result := Path else
|
|
Result := PathInclSuffixU(BasePath, PathSep) + Path;
|
|
Result := PathCanonicalU(Result, PathSep);
|
|
end;
|
|
|
|
function PathExpand(const Path: String; const BasePath: String;
|
|
const PathSep: Char): String;
|
|
begin
|
|
if Path = '' then
|
|
Result := BasePath else
|
|
if PathIsAbsolute(Path) then
|
|
Result := Path else
|
|
Result := PathInclSuffix(BasePath, PathSep) + Path;
|
|
Result := PathCanonical(Result, PathSep);
|
|
end;
|
|
|
|
function PathLeftElementB(const Path: RawByteString; const PathSep: ByteChar): RawByteString;
|
|
var I: Integer;
|
|
begin
|
|
I := PosCharB(PathSep, Path);
|
|
if I <= 0 then
|
|
Result := Path
|
|
else
|
|
Result := Copy(Path, 1, I - 1);
|
|
end;
|
|
|
|
function PathLeftElementU(const Path: UnicodeString; const PathSep: WideChar): UnicodeString;
|
|
var I: Integer;
|
|
begin
|
|
I := PosCharU(PathSep, Path);
|
|
if I <= 0 then
|
|
Result := Path
|
|
else
|
|
Result := Copy(Path, 1, I - 1);
|
|
end;
|
|
|
|
function PathLeftElement(const Path: String; const PathSep: Char): String;
|
|
var I: Integer;
|
|
begin
|
|
I := PosChar(PathSep, Path);
|
|
if I <= 0 then
|
|
Result := Path
|
|
else
|
|
Result := Copy(Path, 1, I - 1);
|
|
end;
|
|
|
|
procedure PathSplitLeftElementB(const Path: RawByteString;
|
|
var LeftElement, RightPath: RawByteString; const PathSep: ByteChar);
|
|
var I: Integer;
|
|
begin
|
|
I := PosCharB(PathSep, Path);
|
|
if I <= 0 then
|
|
begin
|
|
LeftElement := Path;
|
|
RightPath := '';
|
|
end
|
|
else
|
|
begin
|
|
LeftElement := Copy(Path, 1, I - 1);
|
|
RightPath := CopyFromB(Path, I + 1);
|
|
end;
|
|
end;
|
|
|
|
procedure PathSplitLeftElementU(const Path: UnicodeString;
|
|
var LeftElement, RightPath: UnicodeString; const PathSep: WideChar);
|
|
var I: Integer;
|
|
begin
|
|
I := PosCharU(PathSep, Path);
|
|
if I <= 0 then
|
|
begin
|
|
LeftElement := Path;
|
|
RightPath := '';
|
|
end
|
|
else
|
|
begin
|
|
LeftElement := Copy(Path, 1, I - 1);
|
|
RightPath := CopyFromU(Path, I + 1);
|
|
end;
|
|
end;
|
|
|
|
procedure PathSplitLeftElement(const Path: String;
|
|
var LeftElement, RightPath: String; const PathSep: Char);
|
|
var I: Integer;
|
|
begin
|
|
I := PosChar(PathSep, Path);
|
|
if I <= 0 then
|
|
begin
|
|
LeftElement := Path;
|
|
RightPath := '';
|
|
end
|
|
else
|
|
begin
|
|
LeftElement := Copy(Path, 1, I - 1);
|
|
RightPath := CopyFrom(Path, I + 1);
|
|
end;
|
|
end;
|
|
|
|
procedure DecodeFilePathB(const FilePath: RawByteString; var Path, FileName: RawByteString;
|
|
const PathSep: ByteChar);
|
|
var I: Integer;
|
|
begin
|
|
I := PosCharRevB(PathSep, FilePath);
|
|
if I <= 0 then
|
|
begin
|
|
Path := '';
|
|
FileName := FilePath;
|
|
end
|
|
else
|
|
begin
|
|
Path := Copy(FilePath, 1, I);
|
|
FileName := CopyFromB(FilePath, I + 1);
|
|
end;
|
|
end;
|
|
|
|
procedure DecodeFilePathU(const FilePath: UnicodeString; var Path, FileName: UnicodeString;
|
|
const PathSep: WideChar);
|
|
var I: Integer;
|
|
begin
|
|
I := PosCharRevU(PathSep, FilePath);
|
|
if I <= 0 then
|
|
begin
|
|
Path := '';
|
|
FileName := FilePath;
|
|
end
|
|
else
|
|
begin
|
|
Path := Copy(FilePath, 1, I);
|
|
FileName := CopyFromU(FilePath, I + 1);
|
|
end;
|
|
end;
|
|
|
|
procedure DecodeFilePath(const FilePath: String; var Path, FileName: String;
|
|
const PathSep: Char);
|
|
var I: Integer;
|
|
begin
|
|
I := PosCharRev(PathSep, FilePath);
|
|
if I <= 0 then
|
|
begin
|
|
Path := '';
|
|
FileName := FilePath;
|
|
end
|
|
else
|
|
begin
|
|
Path := Copy(FilePath, 1, I);
|
|
FileName := CopyFrom(FilePath, I + 1);
|
|
end;
|
|
end;
|
|
|
|
function PathExtractFilePathB(const FilePath: RawByteString;
|
|
const PathSep: ByteChar): RawByteString;
|
|
var FileName : RawByteString;
|
|
begin
|
|
DecodeFilePathB(FilePath, Result, FileName, PathSep);
|
|
end;
|
|
|
|
function PathExtractFilePathU(const FilePath: UnicodeString;
|
|
const PathSep: WideChar): UnicodeString;
|
|
var FileName : UnicodeString;
|
|
begin
|
|
DecodeFilePathU(FilePath, Result, FileName, PathSep);
|
|
end;
|
|
|
|
function PathExtractFilePath(const FilePath: String;
|
|
const PathSep: Char): String;
|
|
var FileName : String;
|
|
begin
|
|
DecodeFilePath(FilePath, Result, FileName, PathSep);
|
|
end;
|
|
|
|
function PathExtractFileNameB(const FilePath: RawByteString;
|
|
const PathSep: ByteChar): RawByteString;
|
|
var Path : RawByteString;
|
|
begin
|
|
DecodeFilePathB(FilePath, Path, Result, PathSep);
|
|
end;
|
|
|
|
function PathExtractFileNameU(const FilePath: UnicodeString;
|
|
const PathSep: WideChar): UnicodeString;
|
|
var Path : UnicodeString;
|
|
begin
|
|
DecodeFilePathU(FilePath, Path, Result, PathSep);
|
|
end;
|
|
|
|
function PathExtractFileName(const FilePath: String;
|
|
const PathSep: Char): String;
|
|
var Path : String;
|
|
begin
|
|
DecodeFilePath(FilePath, Path, Result, PathSep);
|
|
end;
|
|
|
|
function PathExtractFileExtB(const FilePath: RawByteString;
|
|
const PathSep: ByteChar): RawByteString;
|
|
var FileName : RawByteString;
|
|
I : Integer;
|
|
begin
|
|
FileName := PathExtractFileNameB(FilePath, PathSep);
|
|
I := PosCharRevB('.', FileName);
|
|
if I <= 0 then
|
|
begin
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
Result := CopyFromB(FileName, I);
|
|
end;
|
|
|
|
function PathExtractFileExtU(const FilePath: UnicodeString;
|
|
const PathSep: WideChar): UnicodeString;
|
|
var FileName : UnicodeString;
|
|
I : Integer;
|
|
begin
|
|
FileName := PathExtractFileNameU(FilePath, PathSep);
|
|
I := PosCharRevU('.', FileName);
|
|
if I <= 0 then
|
|
begin
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
Result := CopyFromU(FileName, I);
|
|
end;
|
|
|
|
function PathExtractFileExt(const FilePath: String;
|
|
const PathSep: Char): String;
|
|
var FileName : String;
|
|
I : Integer;
|
|
begin
|
|
FileName := PathExtractFileName(FilePath, PathSep);
|
|
I := PosCharRev('.', FileName);
|
|
if I <= 0 then
|
|
begin
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
Result := CopyFrom(FileName, I);
|
|
end;
|
|
|
|
function FileNameCleanB(const FileName: RawByteString): RawByteString;
|
|
begin
|
|
Result := StrReplaceCharB(['\', '/', ':', '>', '<', '*', '?'], '_', FileName);
|
|
if Result = '.' then
|
|
Result := '_' else
|
|
if Result = '..' then
|
|
Result := '__';
|
|
end;
|
|
|
|
function FileNameCleanU(const FileName: UnicodeString): UnicodeString;
|
|
begin
|
|
Result := StrReplaceCharU(['\', '/', ':', '>', '<', '*', '?'], WideChar('_'), FileName);
|
|
if Result = '.' then
|
|
Result := '_' else
|
|
if Result = '..' then
|
|
Result := '__';
|
|
end;
|
|
|
|
function FileNameClean(const FileName: String): String;
|
|
begin
|
|
Result := StrReplaceChar(['\', '/', ':', '>', '<', '*', '?'], '_', FileName);
|
|
if Result = '.' then
|
|
Result := '_' else
|
|
if Result = '..' then
|
|
Result := '__';
|
|
end;
|
|
|
|
function FilePathB(const FileName, Path: RawByteString; const BasePath: RawByteString;
|
|
const PathSep: ByteChar): RawByteString;
|
|
var P, F: RawByteString;
|
|
begin
|
|
F := FileNameCleanB(FileName);
|
|
if F = '' then
|
|
begin
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
P := PathExpandB(Path, BasePath, PathSep);
|
|
if P = '' then
|
|
Result := F
|
|
else
|
|
Result := PathInclSuffixB(P, PathSep) + F;
|
|
end;
|
|
|
|
function FilePathU(const FileName, Path: UnicodeString; const BasePath: UnicodeString;
|
|
const PathSep: WideChar): UnicodeString;
|
|
var P, F: UnicodeString;
|
|
begin
|
|
F := FileNameCleanU(FileName);
|
|
if F = '' then
|
|
begin
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
P := PathExpandU(Path, BasePath, PathSep);
|
|
if P = '' then
|
|
Result := F
|
|
else
|
|
Result := PathInclSuffixU(P, PathSep) + F;
|
|
end;
|
|
|
|
function FilePath(const FileName, Path: String; const BasePath: String;
|
|
const PathSep: Char): String;
|
|
var P, F: String;
|
|
begin
|
|
F := FileNameClean(FileName);
|
|
if F = '' then
|
|
begin
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
P := PathExpand(Path, BasePath, PathSep);
|
|
if P = '' then
|
|
Result := F
|
|
else
|
|
Result := PathInclSuffix(P, PathSep) + F;
|
|
end;
|
|
|
|
function DirectoryExpandB(const Path: RawByteString; const BasePath: RawByteString;
|
|
const PathSep: ByteChar): RawByteString;
|
|
begin
|
|
Result := PathExpandB(PathInclSuffixB(Path, PathSep),
|
|
PathInclSuffixB(BasePath, PathSep), PathSep);
|
|
end;
|
|
|
|
function DirectoryExpandU(const Path: UnicodeString; const BasePath: UnicodeString;
|
|
const PathSep: WideChar): UnicodeString;
|
|
begin
|
|
Result := PathExpandU(PathInclSuffixU(Path, PathSep),
|
|
PathInclSuffixU(BasePath, PathSep), PathSep);
|
|
end;
|
|
|
|
function DirectoryExpand(const Path: String; const BasePath: String;
|
|
const PathSep: Char): String;
|
|
begin
|
|
Result := PathExpand(PathInclSuffix(Path, PathSep),
|
|
PathInclSuffix(BasePath, PathSep), PathSep);
|
|
end;
|
|
|
|
function UnixPathToSafeWinPathB(const Path: RawByteString): RawByteString;
|
|
begin
|
|
Result := StrReplaceCharB('/', '\',
|
|
StrReplaceCharB(['\', ':', '<', '>', '|', '?', '*'], '_', Path));
|
|
end;
|
|
|
|
function WinPathToSafeUnixPathB(const Path: RawByteString): RawByteString;
|
|
begin
|
|
Result := Path;
|
|
if WinPathHasDriveLetterB(Path) then
|
|
begin
|
|
// X: -> \X
|
|
Result[2] := Result[1];
|
|
Result[1] := '\';
|
|
end
|
|
else
|
|
if StrMatchLeftB(Path, '\\.\') then
|
|
// \\.\ -> \
|
|
Delete(Result, 1, 3)
|
|
else
|
|
if PathIsUNCPathB(Path) then
|
|
// \\ -> \
|
|
Delete(Result, 1, 1);
|
|
Result := StrReplaceCharB('\', '/',
|
|
StrReplaceCharB(['/', ':', '<', '>', '|', '?', '*'], '_', Result));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ System helper functions }
|
|
{ }
|
|
{$IFDEF WindowsPlatform}
|
|
function GetTick: LongWord;
|
|
begin
|
|
Result := GetTickCount;
|
|
end;
|
|
{$ELSE}{$IFDEF UNIX}
|
|
function GetTick: LongWord;
|
|
begin
|
|
Result := LongWord(DateTimeToTimeStamp(Now).Time);
|
|
end;
|
|
{$ENDIF}{$ENDIF}
|
|
|
|
|
|
|
|
{ }
|
|
{ File errors }
|
|
{ }
|
|
constructor EFileError.Create(const FileError: TFileError; const Msg: string);
|
|
begin
|
|
FFileError := FileError;
|
|
inherited Create(Msg);
|
|
end;
|
|
|
|
constructor EFileError.CreateFmt(const FileError: TFileError; const Msg: string; const Args: array of const);
|
|
begin
|
|
FFileError := FileError;
|
|
inherited CreateFmt(Msg, Args);
|
|
end;
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
function WinErrorCodeToFileError(const ErrorCode: LongWord): TFileError;
|
|
begin
|
|
case ErrorCode of
|
|
0 : Result := feNone;
|
|
ERROR_INVALID_HANDLE : Result := feInvalidParameter;
|
|
ERROR_FILE_NOT_FOUND,
|
|
ERROR_PATH_NOT_FOUND : Result := feFileDoesNotExist;
|
|
ERROR_ALREADY_EXISTS,
|
|
ERROR_FILE_EXISTS : Result := feFileExists;
|
|
ERROR_WRITE_PROTECT,
|
|
ERROR_OPEN_FAILED : Result := feFileOpenError;
|
|
ERROR_CANNOT_MAKE : Result := feFileCreateError;
|
|
ERROR_NEGATIVE_SEEK : Result := feFileSeekError;
|
|
ERROR_ACCESS_DENIED,
|
|
ERROR_NETWORK_ACCESS_DENIED : Result := feAccessDenied;
|
|
ERROR_SHARING_VIOLATION,
|
|
ERROR_LOCK_VIOLATION,
|
|
ERROR_SHARING_PAUSED,
|
|
ERROR_LOCK_FAILED : Result := feFileSharingError;
|
|
ERROR_HANDLE_DISK_FULL,
|
|
ERROR_DISK_FULL : Result := feOutOfSpace;
|
|
ERROR_BAD_NETPATH,
|
|
ERROR_DIRECTORY,
|
|
ERROR_INVALID_DRIVE : Result := feInvalidFilePath;
|
|
ERROR_INVALID_NAME,
|
|
ERROR_FILENAME_EXCED_RANGE,
|
|
ERROR_BAD_NET_NAME,
|
|
ERROR_BUFFER_OVERFLOW : Result := feInvalidFileName;
|
|
ERROR_OUTOFMEMORY,
|
|
ERROR_NOT_ENOUGH_MEMORY,
|
|
ERROR_TOO_MANY_OPEN_FILES,
|
|
ERROR_SHARING_BUFFER_EXCEEDED : Result := feOutOfResources;
|
|
ERROR_SEEK,
|
|
ERROR_READ_FAULT,
|
|
ERROR_WRITE_FAULT,
|
|
ERROR_GEN_FAILURE,
|
|
ERROR_CRC,
|
|
ERROR_NETWORK_BUSY,
|
|
ERROR_NET_WRITE_FAULT,
|
|
ERROR_REM_NOT_LIST,
|
|
ERROR_DEV_NOT_EXIST,
|
|
ERROR_NETNAME_DELETED : Result := feDeviceFailure;
|
|
else
|
|
Result := feFileError;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
{ }
|
|
{ File operations }
|
|
{ }
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
function FileOpenFlagsToWinFileFlags(const FileOpenFlags: TFileOpenFlags): LongWord;
|
|
var
|
|
FileFlags : LongWord;
|
|
begin
|
|
FileFlags := 0;
|
|
if foDeleteOnClose in FileOpenFlags then
|
|
FileFlags := FileFlags or FILE_FLAG_DELETE_ON_CLOSE;
|
|
if foNoBuffering in FileOpenFlags then
|
|
FileFlags := FileFlags or FILE_FLAG_NO_BUFFERING;
|
|
if foWriteThrough in FileOpenFlags then
|
|
FileFlags := FileFlags or FILE_FLAG_WRITE_THROUGH;
|
|
if foRandomAccessHint in FileOpenFlags then
|
|
FileFlags := FileFlags or FILE_FLAG_RANDOM_ACCESS;
|
|
if foSequentialScanHint in FileOpenFlags then
|
|
FileFlags := FileFlags or FILE_FLAG_SEQUENTIAL_SCAN;
|
|
Result := FileFlags;
|
|
end;
|
|
|
|
function FileCreationModeToWinFileCreateDisp(const FileCreationMode: TFileCreationMode): LongWord;
|
|
var
|
|
FileCreateDisp : LongWord;
|
|
begin
|
|
case FileCreationMode of
|
|
fcCreateNew : FileCreateDisp := CREATE_NEW;
|
|
fcCreateAlways : FileCreateDisp := CREATE_ALWAYS;
|
|
fcOpenExisting : FileCreateDisp := OPEN_EXISTING;
|
|
fcOpenAlways : FileCreateDisp := OPEN_ALWAYS;
|
|
fcTruncateExisting : FileCreateDisp := TRUNCATE_EXISTING;
|
|
else
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileCreationMode);
|
|
end;
|
|
Result := FileCreateDisp;
|
|
end;
|
|
|
|
function FileSharingToWinFileShareMode(const FileSharing: TFileSharing): LongWord;
|
|
var
|
|
FileShareMode : LongWord;
|
|
begin
|
|
case FileSharing of
|
|
fsDenyNone : FileShareMode := FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE;
|
|
fsDenyRead : FileShareMode := FILE_SHARE_WRITE;
|
|
fsDenyWrite : FileShareMode := FILE_SHARE_READ;
|
|
fsDenyReadWrite : FileShareMode := 0;
|
|
fsExclusive : FileShareMode := 0;
|
|
else
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileSharing);
|
|
end;
|
|
Result := FileShareMode;
|
|
end;
|
|
|
|
function FileAccessToWinFileOpenAccess(const FileAccess: TFileAccess): LongWord;
|
|
var
|
|
FileOpenAccess : LongWord;
|
|
begin
|
|
case FileAccess of
|
|
faRead : FileOpenAccess := GENERIC_READ;
|
|
faWrite : FileOpenAccess := GENERIC_WRITE;
|
|
faReadWrite : FileOpenAccess := GENERIC_READ or GENERIC_WRITE;
|
|
else
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileAccess);
|
|
end;
|
|
Result := FileOpenAccess;
|
|
end;
|
|
{$ELSE}
|
|
function FileOpenShareMode(
|
|
const FileAccess: TFileAccess;
|
|
const FileSharing: TFileSharing): LongWord;
|
|
var FileShareMode : LongWord;
|
|
begin
|
|
case FileAccess of
|
|
faRead : FileShareMode := fmOpenRead;
|
|
faWrite : FileShareMode := fmOpenWrite;
|
|
faReadWrite : FileShareMode := fmOpenReadWrite;
|
|
else
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileAccess);
|
|
end;
|
|
case FileSharing of
|
|
fsDenyNone : FileShareMode := FileShareMode or fmShareDenyNone;
|
|
fsDenyRead : FileShareMode := FileShareMode{$IFDEF MSWINDOWS} or fmShareDenyRead{$ENDIF};
|
|
fsDenyWrite : FileShareMode := FileShareMode or fmShareDenyWrite;
|
|
fsDenyReadWrite : FileShareMode := FileShareMode{$IFDEF MSWINDOWS} or fmShareDenyRead{$ENDIF} or fmShareDenyWrite;
|
|
fsExclusive : FileShareMode := FileShareMode or fmShareExclusive;
|
|
else
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileSharing);
|
|
end;
|
|
Result := FileShareMode;
|
|
end;
|
|
|
|
function FileCreateWithShareMode(
|
|
const FileName: String;
|
|
const FileShareMode: LongWord): Integer;
|
|
var FileHandle : Integer;
|
|
begin
|
|
FileHandle := FileCreate(FileName);
|
|
if FileHandle < 0 then
|
|
begin
|
|
Result := -1;
|
|
exit;
|
|
end;
|
|
FileClose(FileHandle);
|
|
FileHandle := FileOpen(FileName, FileShareMode);
|
|
Result := FileHandle;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
procedure DoFileOpenWait(const FileOpenWait: PFileOpenWait; const WaitStart: LongWord; var Retry: Boolean);
|
|
|
|
function GetRandomRetryWait: Integer;
|
|
var Seed : Integer;
|
|
ExtraWaitTime : Integer;
|
|
begin
|
|
if not FileOpenWait^.RetryRandomise then
|
|
ExtraWaitTime := 0
|
|
else
|
|
if FileOpenWait^.RetryInterval < 0 then
|
|
ExtraWaitTime := 0
|
|
else
|
|
begin
|
|
ExtraWaitTime := FileOpenWait^.RetryInterval div 8;
|
|
Seed := Integer(GetTick) xor Integer(FileOpenWait);
|
|
ExtraWaitTime := Seed mod ExtraWaitTime;
|
|
end;
|
|
Result := ExtraWaitTime;
|
|
end;
|
|
|
|
var
|
|
WaitTime : LongWord;
|
|
WaitResult : LongInt;
|
|
begin
|
|
Assert(Assigned(FileOpenWait));
|
|
|
|
Retry := False;
|
|
if FileOpenWait^.Signal <> 0 then
|
|
begin
|
|
if FileOpenWait^.RetryInterval < 0 then
|
|
WaitTime := INFINITE
|
|
else
|
|
WaitTime := FileOpenWait^.RetryInterval + GetRandomRetryWait;
|
|
WaitResult := WaitForSingleObject(FileOpenWait^.Signal, WaitTime);
|
|
if WaitResult = WAIT_TIMEOUT then
|
|
Retry := True;
|
|
end
|
|
else
|
|
if Assigned(FileOpenWait^.Callback) then
|
|
begin
|
|
FileOpenWait^.Aborted := False;
|
|
FileOpenWait^.Callback(FileOpenWait);
|
|
if not FileOpenWait^.Aborted then
|
|
Retry := True;
|
|
end
|
|
else
|
|
begin
|
|
Sleep(MaxInt(0, FileOpenWait^.RetryInterval) + GetRandomRetryWait);
|
|
Retry := True;
|
|
end;
|
|
if Retry then
|
|
if LongInt(Int64(GetTick) - Int64(WaitStart)) >= FileOpenWait^.Timeout then
|
|
Retry := False;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function FileOpenExB(
|
|
const FileName: RawByteString;
|
|
const FileAccess: TFileAccess;
|
|
const FileSharing: TFileSharing;
|
|
const FileOpenFlags: TFileOpenFlags;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): TFileHandle;
|
|
var FileHandle : Integer;
|
|
FileShareMode : LongWord;
|
|
{$IFDEF MSWINDOWS}
|
|
FileOpenAccess : LongWord;
|
|
FileFlags : LongWord;
|
|
FileCreateDisp : LongWord;
|
|
ErrorCode : LongWord;
|
|
ErrorSharing : Boolean;
|
|
Retry : Boolean;
|
|
WaitStart : LongWord;
|
|
WaitOpen : Boolean;
|
|
{$ELSE}
|
|
FileNameStr : String;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
FileFlags := FileOpenFlagsToWinFileFlags(FileOpenFlags);
|
|
FileCreateDisp := FileCreationModeToWinFileCreateDisp(FileCreationMode);
|
|
FileShareMode := FileSharingToWinFileShareMode(FileSharing);
|
|
FileOpenAccess := FileAccessToWinFileOpenAccess(FileAccess);
|
|
WaitOpen := False;
|
|
WaitStart := 0;
|
|
if Assigned(FileOpenWait) then
|
|
if FileOpenWait^.Wait and (FileOpenWait^.Timeout > 0) then
|
|
begin
|
|
WaitOpen := True;
|
|
WaitStart := GetTick;
|
|
if Assigned(FileOpenWait^.Callback) then
|
|
FileOpenWait^.Aborted := False;
|
|
end;
|
|
Retry := False;
|
|
repeat
|
|
FileHandle := Integer(Windows.CreateFileA(
|
|
PAnsiChar(FileName),
|
|
FileOpenAccess,
|
|
FileShareMode,
|
|
nil,
|
|
FileCreateDisp,
|
|
FileFlags,
|
|
0));
|
|
if FileHandle < 0 then
|
|
begin
|
|
ErrorCode := GetLastError;
|
|
ErrorSharing :=
|
|
(ErrorCode = ERROR_SHARING_VIOLATION) or
|
|
(ErrorCode = ERROR_LOCK_VIOLATION);
|
|
end
|
|
else
|
|
begin
|
|
ErrorCode := 0;
|
|
ErrorSharing := False;
|
|
end;
|
|
if WaitOpen and ErrorSharing then
|
|
DoFileOpenWait(FileOpenWait, WaitStart, Retry);
|
|
until not Retry;
|
|
if FileHandle < 0 then
|
|
raise EFileError.CreateFmt(WinErrorCodeToFileError(ErrorCode), SCannotOpenFile,
|
|
[GetLastOSErrorMessage, FileName]);
|
|
{$ELSE}
|
|
FileNameStr := ToStringB(FileName);
|
|
FileShareMode := FileOpenShareMode(FileAccess, FileSharing);
|
|
case FileCreationMode of
|
|
fcCreateNew :
|
|
if FileExists(FileNameStr) then
|
|
raise EFileError.CreateFmt(feFileExists, SFileExists, [FileNameStr])
|
|
else
|
|
FileHandle := FileCreateWithShareMode(FileNameStr, FileShareMode);
|
|
fcCreateAlways :
|
|
FileHandle := FileCreateWithShareMode(FileNameStr, FileShareMode);
|
|
fcOpenExisting :
|
|
FileHandle := FileOpen(FileNameStr, FileShareMode);
|
|
fcOpenAlways :
|
|
if not FileExists(FileNameStr) then
|
|
FileHandle := FileCreateWithShareMode(FileNameStr, FileShareMode)
|
|
else
|
|
FileHandle := FileOpen(FileNameStr, FileShareMode);
|
|
fcTruncateExisting :
|
|
if not FileExists(FileNameStr) then
|
|
raise EFileError.CreateFmt(feFileDoesNotExist, SFileDoesNotExist, [FileNameStr])
|
|
else
|
|
FileHandle := FileCreateWithShareMode(FileNameStr, FileShareMode)
|
|
else
|
|
raise EFileError.CreateFmt(feInvalidParameter, SInvalidFileCreationMode, []);
|
|
end;
|
|
if FileHandle < 0 then
|
|
raise EFileError.CreateFmt(feFileOpenError, SCannotOpenFile, [GetLastOSErrorMessage, FileNameStr]);
|
|
{$ENDIF}
|
|
if foSeekToEndOfFile in FileOpenFlags then
|
|
FileSeekEx(FileHandle, 0, fpOffsetFromEnd);
|
|
Result := FileHandle;
|
|
end;
|
|
|
|
function FileOpenExU(
|
|
const FileName: UnicodeString;
|
|
const FileAccess: TFileAccess;
|
|
const FileSharing: TFileSharing;
|
|
const FileOpenFlags: TFileOpenFlags;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): TFileHandle;
|
|
var FileHandle : Integer;
|
|
FileShareMode : LongWord;
|
|
{$IFDEF MSWINDOWS}
|
|
FileOpenAccess : LongWord;
|
|
FileFlags : LongWord;
|
|
FileCreateDisp : LongWord;
|
|
ErrorCode : LongWord;
|
|
ErrorSharing : Boolean;
|
|
Retry : Boolean;
|
|
WaitStart : LongWord;
|
|
WaitOpen : Boolean;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
FileFlags := FileOpenFlagsToWinFileFlags(FileOpenFlags);
|
|
FileCreateDisp := FileCreationModeToWinFileCreateDisp(FileCreationMode);
|
|
FileShareMode := FileSharingToWinFileShareMode(FileSharing);
|
|
FileOpenAccess := FileAccessToWinFileOpenAccess(FileAccess);
|
|
WaitOpen := False;
|
|
WaitStart := 0;
|
|
if Assigned(FileOpenWait) then
|
|
if FileOpenWait^.Wait and (FileOpenWait^.Timeout > 0) then
|
|
begin
|
|
WaitOpen := True;
|
|
WaitStart := GetTick;
|
|
if Assigned(FileOpenWait^.Callback) then
|
|
FileOpenWait^.Aborted := False;
|
|
end;
|
|
Retry := False;
|
|
repeat
|
|
FileHandle := Integer(Windows.CreateFileW(
|
|
PWideChar(FileName),
|
|
FileOpenAccess,
|
|
FileShareMode,
|
|
nil,
|
|
FileCreateDisp,
|
|
FileFlags,
|
|
0));
|
|
if FileHandle < 0 then
|
|
begin
|
|
ErrorCode := GetLastError;
|
|
ErrorSharing :=
|
|
(ErrorCode = ERROR_SHARING_VIOLATION) or
|
|
(ErrorCode = ERROR_LOCK_VIOLATION);
|
|
end
|
|
else
|
|
begin
|
|
ErrorCode := 0;
|
|
ErrorSharing := False;
|
|
end;
|
|
if WaitOpen and ErrorSharing then
|
|
DoFileOpenWait(FileOpenWait, WaitStart, Retry);
|
|
until not Retry;
|
|
if FileHandle < 0 then
|
|
raise EFileError.CreateFmt(WinErrorCodeToFileError(ErrorCode), SCannotOpenFile,
|
|
[GetLastOSErrorMessage, FileName]);
|
|
{$ELSE}
|
|
FileShareMode := FileOpenShareMode(FileAccess, FileSharing);
|
|
case FileCreationMode of
|
|
fcCreateNew :
|
|
if FileExists(FileName) then
|
|
raise EFileError.CreateFmt(feFileExists, SFileExists, [FileName])
|
|
else
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode);
|
|
fcCreateAlways :
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode);
|
|
fcOpenExisting :
|
|
FileHandle := FileOpen(FileName, FileShareMode);
|
|
fcOpenAlways :
|
|
if not FileExists(FileName) then
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode)
|
|
else
|
|
FileHandle := FileOpen(FileName, FileShareMode);
|
|
fcTruncateExisting :
|
|
if not FileExists(FileName) then
|
|
raise EFileError.CreateFmt(feFileDoesNotExist, SFileDoesNotExist, [FileName])
|
|
else
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode)
|
|
else
|
|
raise EFileError.CreateFmt(feInvalidParameter, SInvalidFileCreationMode, []);
|
|
end;
|
|
if FileHandle < 0 then
|
|
raise EFileError.CreateFmt(feFileOpenError, SCannotOpenFile, [GetLastOSErrorMessage, FileName]);
|
|
{$ENDIF}
|
|
if foSeekToEndOfFile in FileOpenFlags then
|
|
FileSeekEx(FileHandle, 0, fpOffsetFromEnd);
|
|
Result := FileHandle;
|
|
end;
|
|
|
|
function FileOpenEx(
|
|
const FileName: String;
|
|
const FileAccess: TFileAccess;
|
|
const FileSharing: TFileSharing;
|
|
const FileOpenFlags: TFileOpenFlags;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): TFileHandle;
|
|
var FileHandle : Integer;
|
|
FileShareMode : LongWord;
|
|
{$IFDEF MSWINDOWS}
|
|
FileOpenAccess : LongWord;
|
|
FileFlags : LongWord;
|
|
FileCreateDisp : LongWord;
|
|
ErrorCode : LongWord;
|
|
ErrorSharing : Boolean;
|
|
Retry : Boolean;
|
|
WaitStart : LongWord;
|
|
WaitOpen : Boolean;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
FileFlags := FileOpenFlagsToWinFileFlags(FileOpenFlags);
|
|
FileCreateDisp := FileCreationModeToWinFileCreateDisp(FileCreationMode);
|
|
FileShareMode := FileSharingToWinFileShareMode(FileSharing);
|
|
FileOpenAccess := FileAccessToWinFileOpenAccess(FileAccess);
|
|
WaitOpen := False;
|
|
WaitStart := 0;
|
|
if Assigned(FileOpenWait) then
|
|
if FileOpenWait^.Wait and (FileOpenWait^.Timeout > 0) then
|
|
begin
|
|
WaitOpen := True;
|
|
WaitStart := GetTick;
|
|
if Assigned(FileOpenWait^.Callback) then
|
|
FileOpenWait^.Aborted := False;
|
|
end;
|
|
Retry := False;
|
|
repeat
|
|
{$IFDEF CharIsWide}
|
|
FileHandle := Integer(Windows.CreateFileW(
|
|
PWideChar(FileName),
|
|
FileOpenAccess,
|
|
FileShareMode,
|
|
nil,
|
|
FileCreateDisp,
|
|
FileFlags,
|
|
0));
|
|
{$ELSE}
|
|
FileHandle := Integer(Windows.CreateFileA(
|
|
PAnsiChar(FileName),
|
|
FileOpenAccess,
|
|
FileShareMode,
|
|
nil,
|
|
FileCreateDisp,
|
|
FileFlags,
|
|
0));
|
|
{$ENDIF}
|
|
if FileHandle < 0 then
|
|
begin
|
|
ErrorCode := GetLastError;
|
|
ErrorSharing :=
|
|
(ErrorCode = ERROR_SHARING_VIOLATION) or
|
|
(ErrorCode = ERROR_LOCK_VIOLATION);
|
|
end
|
|
else
|
|
begin
|
|
ErrorCode := 0;
|
|
ErrorSharing := False;
|
|
end;
|
|
if WaitOpen and ErrorSharing then
|
|
DoFileOpenWait(FileOpenWait, WaitStart, Retry);
|
|
until not Retry;
|
|
if FileHandle < 0 then
|
|
raise EFileError.CreateFmt(WinErrorCodeToFileError(ErrorCode), SCannotOpenFile,
|
|
[GetLastOSErrorMessage, FileName]);
|
|
{$ELSE}
|
|
FileShareMode := FileOpenShareMode(FileAccess, FileSharing);
|
|
case FileCreationMode of
|
|
fcCreateNew :
|
|
if FileExists(FileName) then
|
|
raise EFileError.CreateFmt(feFileExists, SFileExists, [FileName])
|
|
else
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode);
|
|
fcCreateAlways :
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode);
|
|
fcOpenExisting :
|
|
FileHandle := FileOpen(FileName, FileShareMode);
|
|
fcOpenAlways :
|
|
if not FileExists(FileName) then
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode)
|
|
else
|
|
FileHandle := FileOpen(FileName, FileShareMode);
|
|
fcTruncateExisting :
|
|
if not FileExists(FileName) then
|
|
raise EFileError.CreateFmt(feFileDoesNotExist, SFileDoesNotExist, [FileName])
|
|
else
|
|
FileHandle := FileCreateWithShareMode(FileName, FileShareMode)
|
|
else
|
|
raise EFileError.CreateFmt(feInvalidParameter, SInvalidFileCreationMode, []);
|
|
end;
|
|
if FileHandle < 0 then
|
|
raise EFileError.CreateFmt(feFileOpenError, SCannotOpenFile, [GetLastOSErrorMessage, FileName]);
|
|
{$ENDIF}
|
|
if foSeekToEndOfFile in FileOpenFlags then
|
|
FileSeekEx(FileHandle, 0, fpOffsetFromEnd);
|
|
Result := FileHandle;
|
|
end;
|
|
|
|
function FileSeekEx(
|
|
const FileHandle: TFileHandle;
|
|
const FileOffset: Int64;
|
|
const FilePosition: TFileSeekPosition): Int64;
|
|
begin
|
|
if FileHandle = 0 then
|
|
raise EFileError.CreateFmt(feInvalidParameter, SInvalidFileHandle, []);
|
|
case FilePosition of
|
|
fpOffsetFromStart : Result := FileSeek(FileHandle, FileOffset, 0);
|
|
fpOffsetFromCurrent : Result := FileSeek(FileHandle, FileOffset, 1);
|
|
fpOffsetFromEnd : Result := FileSeek(FileHandle, FileOffset, 2);
|
|
else
|
|
raise EFileError.CreateFmt(feInvalidParameter, SInvalidFilePosition, []);
|
|
end;
|
|
if Result < 0 then
|
|
raise EFileError.CreateFmt(feFileSeekError, SFileSeekError, [GetLastOSErrorMessage]);
|
|
end;
|
|
|
|
function FileReadEx(
|
|
const FileHandle: TFileHandle;
|
|
var Buf; const BufSize: Integer): Integer;
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
if not ReadFile(FileHandle, Buf, BufSize, LongWord(Result), nil) then
|
|
raise EFileError.CreateFmt(feFileReadError, SFileReadError, [GetLastOSErrorMessage]);
|
|
{$ELSE}
|
|
Result := FileRead(FileHandle, Buf, BufSize);
|
|
if Result < 0 then
|
|
raise EFileError.Create(feFileReadError, SFileReadError);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function FileWriteEx(
|
|
const FileHandle: TFileHandle;
|
|
const Buf; const BufSize: Integer): Integer;
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
if not WriteFile(FileHandle, Buf, BufSize, LongWord(Result), nil) then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, IntToStr(Ord(FileHandle))]);
|
|
{$ELSE}
|
|
Result := FileWrite(FileHandle, Buf, BufSize);
|
|
if Result < 0 then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, IntToStr(Ord(FileHandle))]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure FileCloseEx(const FileHandle: TFileHandle);
|
|
begin
|
|
FileClose(FileHandle);
|
|
end;
|
|
|
|
function FindFirstB(const Path: RawByteString; Attr: Integer; var F: TSearchRec): Integer;
|
|
begin
|
|
Result := FindFirst(ToStringB(Path), Attr, F);
|
|
end;
|
|
|
|
function FindFirstU(const Path: UnicodeString; Attr: Integer; var F: TSearchRec): Integer;
|
|
begin
|
|
Result := FindFirst(ToStringU(Path), Attr, F);
|
|
end;
|
|
|
|
function FileExistsB(const FileName: RawByteString): Boolean;
|
|
{$IFDEF MSWINDOWS}
|
|
var Attr : LongWord;
|
|
{$ELSE}
|
|
var SRec : TSearchRec;
|
|
{$ENDIF}
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
{$IFDEF MSWINDOWS}
|
|
Attr := GetFileAttributesA(PAnsiChar(FileName));
|
|
if Attr = $FFFFFFFF then
|
|
Result := False
|
|
else
|
|
Result := Attr and FILE_ATTRIBUTE_DIRECTORY = 0;
|
|
{$ELSE}
|
|
if FindFirstB(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := SRec.Attr and faDirectory = 0;
|
|
FindClose(SRec);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function FileExistsU(const FileName: UnicodeString): Boolean;
|
|
{$IFDEF MSWINDOWS}
|
|
var Attr : LongWord;
|
|
{$ELSE}
|
|
var SRec : TSearchRec;
|
|
{$ENDIF}
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
{$IFDEF MSWINDOWS}
|
|
Attr := GetFileAttributesW(PWideChar(FileName));
|
|
if Attr = $FFFFFFFF then
|
|
Result := False
|
|
else
|
|
Result := Attr and FILE_ATTRIBUTE_DIRECTORY = 0;
|
|
{$ELSE}
|
|
if FindFirstU(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := SRec.Attr and faDirectory = 0;
|
|
FindClose(SRec);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function FileExists(const FileName: String): Boolean;
|
|
{$IFDEF MSWINDOWS}
|
|
var Attr : LongWord;
|
|
{$ELSE}
|
|
var SRec : TSearchRec;
|
|
{$ENDIF}
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
{$IFDEF MSWINDOWS}
|
|
{$IFDEF StringIsUnicode}
|
|
Attr := GetFileAttributesW(PWideChar(FileName));
|
|
{$ELSE}
|
|
Attr := GetFileAttributesA(PAnsiChar(FileName));
|
|
{$ENDIF}
|
|
if Attr = $FFFFFFFF then
|
|
Result := False
|
|
else
|
|
Result := Attr and FILE_ATTRIBUTE_DIRECTORY = 0;
|
|
{$ELSE}
|
|
if FindFirst(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := SRec.Attr and faDirectory = 0;
|
|
FindClose(SRec);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function FileGetSizeB(const FileName: RawByteString): Int64;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
if FindFirstB(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
Int64Rec(Result).Lo := SRec.FindData.nFileSizeLow;
|
|
Int64Rec(Result).Hi := SRec.FindData.nFileSizeHigh;
|
|
{$ELSE}
|
|
Result := SRec.Size;
|
|
{$ENDIF}
|
|
end;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function FileGetSizeU(const FileName: UnicodeString): Int64;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
if FindFirstU(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
Int64Rec(Result).Lo := SRec.FindData.nFileSizeLow;
|
|
Int64Rec(Result).Hi := SRec.FindData.nFileSizeHigh;
|
|
{$ELSE}
|
|
Result := SRec.Size;
|
|
{$ENDIF}
|
|
end;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function FileGetSize(const FileName: String): Int64;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
if FindFirst(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
Int64Rec(Result).Lo := SRec.FindData.nFileSizeLow;
|
|
Int64Rec(Result).Hi := SRec.FindData.nFileSizeHigh;
|
|
{$ELSE}
|
|
Result := SRec.Size;
|
|
{$ENDIF}
|
|
end;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function FileGetDateTimeB(const FileName: RawByteString): TDateTime;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
if FindFirstB(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := 0.0
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := 0.0
|
|
else
|
|
Result := FileDateToDateTime(SRec.Time);
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function FileGetDateTime(const FileName: String): TDateTime;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
if FindFirst(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := 0.0
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := 0.0
|
|
else
|
|
Result := FileDateToDateTime(SRec.Time);
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function FileGetDateTime2(const FileName: String): TDateTime;
|
|
var Age : LongInt;
|
|
begin
|
|
Age := FileAge(FileName);
|
|
if Age = -1 then
|
|
Result := 0.0
|
|
else
|
|
Result := FileDateToDateTime(Age);
|
|
end;
|
|
|
|
function FileIsReadOnly(const FileName: String): Boolean;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
if FindFirst(FileName, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := SRec.Attr and (faReadOnly or faDirectory) = faReadOnly;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
procedure FileDeleteEx(const FileName: String);
|
|
begin
|
|
if FileName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidFileName);
|
|
if not DeleteFile(FileName) then
|
|
raise EFileError.CreateFmt(feFileDeleteError, SFileDeleteError, [GetLastOSErrorMessage]);
|
|
end;
|
|
|
|
procedure FileRenameEx(const OldFileName, NewFileName: String);
|
|
begin
|
|
RenameFile(OldFileName, NewFileName);
|
|
end;
|
|
|
|
{ ReadFileBuf }
|
|
|
|
function ReadFileBufB(
|
|
const FileName: RawByteString;
|
|
var Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): Integer;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
begin
|
|
Result := 0;
|
|
FileHandle := FileOpenExB(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSize(ToStringB(FileName));
|
|
if FileSize = 0 then
|
|
exit;
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > BufSize then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
Result := FileReadEx(FileHandle, Buf, FileSize);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
function ReadFileBufU(
|
|
const FileName: UnicodeString;
|
|
var Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): Integer;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
begin
|
|
Result := 0;
|
|
FileHandle := FileOpenExU(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSizeU(FileName);
|
|
if FileSize = 0 then
|
|
exit;
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > BufSize then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
Result := FileReadEx(FileHandle, Buf, FileSize);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
function ReadFileBuf(
|
|
const FileName: String;
|
|
var Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing = fsDenyNone;
|
|
const FileCreationMode: TFileCreationMode = fcOpenExisting;
|
|
const FileOpenWait: PFileOpenWait = nil): Integer;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
begin
|
|
Result := 0;
|
|
FileHandle := FileOpenEx(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSize(FileName);
|
|
if FileSize = 0 then
|
|
exit;
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > BufSize then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
Result := FileReadEx(FileHandle, Buf, FileSize);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
{ ReadFileStr }
|
|
|
|
function ReadFileRawStrB(
|
|
const FileName: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): RawByteString;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
ReadBytes : Integer;
|
|
begin
|
|
FileHandle := FileOpenExB(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSize(ToStringB(FileName));
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
SetLength(Result, FileSize);
|
|
if FileSize = 0 then
|
|
exit;
|
|
ReadBytes := FileReadEx(FileHandle, Result[1], FileSize);
|
|
if ReadBytes < FileSize then
|
|
SetLength(Result, ReadBytes);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
function ReadFileRawStrU(
|
|
const FileName: UnicodeString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): RawByteString;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
ReadBytes : Integer;
|
|
begin
|
|
FileHandle := FileOpenExU(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSizeU(FileName);
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
SetLength(Result, FileSize);
|
|
if FileSize = 0 then
|
|
exit;
|
|
ReadBytes := FileReadEx(FileHandle, Result[1], FileSize);
|
|
if ReadBytes < FileSize then
|
|
SetLength(Result, ReadBytes);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
function ReadFileRawStr(
|
|
const FileName: String;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): RawByteString;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
ReadBytes : Integer;
|
|
begin
|
|
FileHandle := FileOpenEx(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSize(FileName);
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
SetLength(Result, FileSize);
|
|
if FileSize = 0 then
|
|
exit;
|
|
ReadBytes := FileReadEx(FileHandle, Result[1], FileSize);
|
|
if ReadBytes < FileSize then
|
|
SetLength(Result, ReadBytes);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
{ ReadFileBytes }
|
|
|
|
function ReadFileBytesB(
|
|
const FileName: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): TBytes;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
ReadBytes : Integer;
|
|
begin
|
|
FileHandle := FileOpenExB(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSize(ToStringB(FileName));
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
SetLength(Result, FileSize);
|
|
if FileSize = 0 then
|
|
exit;
|
|
ReadBytes := FileReadEx(FileHandle, Result[0], FileSize);
|
|
if ReadBytes < FileSize then
|
|
SetLength(Result, ReadBytes);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
function ReadFileBytesU(
|
|
const FileName: UnicodeString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): TBytes;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
ReadBytes : Integer;
|
|
begin
|
|
FileHandle := FileOpenExU(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSizeU(FileName);
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
SetLength(Result, FileSize);
|
|
if FileSize = 0 then
|
|
exit;
|
|
ReadBytes := FileReadEx(FileHandle, Result[0], FileSize);
|
|
if ReadBytes < FileSize then
|
|
SetLength(Result, ReadBytes);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
function ReadFileBytes(
|
|
const FileName: String;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait): TBytes;
|
|
var FileHandle : Integer;
|
|
FileSize : Int64;
|
|
ReadBytes : Integer;
|
|
begin
|
|
FileHandle := FileOpenEx(FileName, faRead, FileSharing,
|
|
[foSequentialScanHint], FileCreationMode, FileOpenWait);
|
|
try
|
|
FileSize := FileGetSize(FileName);
|
|
if FileSize < 0 then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
if FileSize > MaxInteger then
|
|
raise EFileError.CreateFmt(feFileSizeError, SFileSizeError, [FileName]);
|
|
SetLength(Result, FileSize);
|
|
if FileSize = 0 then
|
|
exit;
|
|
ReadBytes := FileReadEx(FileHandle, Result[0], FileSize);
|
|
if ReadBytes < FileSize then
|
|
SetLength(Result, ReadBytes);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
{ WtiteFileBuf }
|
|
|
|
procedure WriteFileBufB(
|
|
const FileName: RawByteString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var FileHandle : Integer;
|
|
begin
|
|
if BufSize <= 0 then
|
|
exit;
|
|
FileHandle := FileOpenExB(FileName, faWrite, FileSharing, [],
|
|
FileCreationMode, FileOpenWait);
|
|
try
|
|
if FileWriteEx(FileHandle, Buf, BufSize) <> BufSize then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, FileName]);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
procedure WriteFileBufU(
|
|
const FileName: UnicodeString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var FileHandle : Integer;
|
|
begin
|
|
if BufSize <= 0 then
|
|
exit;
|
|
FileHandle := FileOpenExU(FileName, faWrite, FileSharing, [],
|
|
FileCreationMode, FileOpenWait);
|
|
try
|
|
if FileWriteEx(FileHandle, Buf, BufSize) <> BufSize then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, FileName]);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
procedure WriteFileBuf(
|
|
const FileName: String;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var FileHandle : Integer;
|
|
begin
|
|
if BufSize <= 0 then
|
|
exit;
|
|
FileHandle := FileOpenEx(FileName, faWrite, FileSharing, [],
|
|
FileCreationMode, FileOpenWait);
|
|
try
|
|
if FileWriteEx(FileHandle, Buf, BufSize) <> BufSize then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, FileName]);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
{ WriteFileStr }
|
|
|
|
procedure WriteFileRawStrB(
|
|
const FileName: RawByteString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
WriteFileBufB(FileName, Buf[1], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
procedure WriteFileRawStrU(
|
|
const FileName: UnicodeString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
WriteFileBufU(FileName, Buf[1], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
procedure WriteFileRawStr(
|
|
const FileName: String;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
WriteFileBuf(FileName, Buf[1], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
{ WriteFileBytes }
|
|
|
|
procedure WriteFileBytesB(
|
|
const FileName: RawByteString;
|
|
const Buf: TBytes;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
WriteFileBufB(FileName, Buf[0], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
procedure WriteFileBytesU(
|
|
const FileName: UnicodeString;
|
|
const Buf: TBytes;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
WriteFileBufU(FileName, Buf[0], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
procedure WriteFileBytes(
|
|
const FileName: String;
|
|
const Buf: TBytes;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
WriteFileBuf(FileName, Buf[0], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
{ AppendFile }
|
|
|
|
procedure AppendFileB(
|
|
const FileName: RawByteString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var FileHandle : Integer;
|
|
begin
|
|
if BufSize <= 0 then
|
|
exit;
|
|
FileHandle := FileOpenExB(FileName, faWrite, FileSharing, [foSeekToEndOfFile],
|
|
FileCreationMode, FileOpenWait);
|
|
try
|
|
if FileWriteEx(FileHandle, Buf, BufSize) <> BufSize then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, FileName]);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
procedure AppendFileU(
|
|
const FileName: UnicodeString;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var FileHandle : Integer;
|
|
begin
|
|
if BufSize <= 0 then
|
|
exit;
|
|
FileHandle := FileOpenExU(FileName, faWrite, FileSharing, [foSeekToEndOfFile],
|
|
FileCreationMode, FileOpenWait);
|
|
try
|
|
if FileWriteEx(FileHandle, Buf, BufSize) <> BufSize then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, FileName]);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
procedure AppendFile(
|
|
const FileName: String;
|
|
const Buf; const BufSize: Integer;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var FileHandle : Integer;
|
|
begin
|
|
if BufSize <= 0 then
|
|
exit;
|
|
FileHandle := FileOpenEx(FileName, faWrite, FileSharing, [foSeekToEndOfFile],
|
|
FileCreationMode, FileOpenWait);
|
|
try
|
|
if FileWriteEx(FileHandle, Buf, BufSize) <> BufSize then
|
|
raise EFileError.CreateFmt(feFileWriteError, SFileWriteError, [GetLastOSErrorMessage, FileName]);
|
|
finally
|
|
FileClose(FileHandle);
|
|
end;
|
|
end;
|
|
|
|
{ AppendFileStr }
|
|
|
|
procedure AppendFileRawStrB(
|
|
const FileName: RawByteString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
AppendFileB(FileName, Buf[1], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
procedure AppendFileRawStrU(
|
|
const FileName: UnicodeString;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
AppendFileU(FileName, Buf[1], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
procedure AppendFileRawStr(
|
|
const FileName: String;
|
|
const Buf: RawByteString;
|
|
const FileSharing: TFileSharing;
|
|
const FileCreationMode: TFileCreationMode;
|
|
const FileOpenWait: PFileOpenWait);
|
|
var BufSize : Integer;
|
|
begin
|
|
BufSize := Length(Buf);
|
|
if BufSize <= 0 then
|
|
exit;
|
|
AppendFile(FileName, Buf[1], BufSize, FileSharing, FileCreationMode, FileOpenWait);
|
|
end;
|
|
|
|
function DirectoryEntryExistsB(const Name: RawByteString): Boolean;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FindFirstB(Name, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := True;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryEntryExistsU(const Name: UnicodeString): Boolean;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FindFirstU(Name, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := True;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryEntryExists(const Name: String): Boolean;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FindFirst(Name, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := True;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryEntrySizeB(const Name: RawByteString): Int64;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FindFirstB(Name, faAnyFile, SRec) <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := 0
|
|
else
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
{$WARNINGS OFF}
|
|
Int64Rec(Result).Lo := SRec.FindData.nFileSizeLow;
|
|
Int64Rec(Result).Hi := SRec.FindData.nFileSizeHigh;
|
|
{$IFDEF DEBUG}{$IFNDEF FREEPASCAL}{$WARNINGS ON}{$ENDIF}{$ENDIF}
|
|
{$ELSE}
|
|
Result := SRec.Size;
|
|
{$ENDIF}
|
|
end;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryEntrySizeU(const Name: UnicodeString): Int64;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FindFirstU(Name, faAnyFile, SRec) <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := 0
|
|
else
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
{$WARNINGS OFF}
|
|
Int64Rec(Result).Lo := SRec.FindData.nFileSizeLow;
|
|
Int64Rec(Result).Hi := SRec.FindData.nFileSizeHigh;
|
|
{$IFDEF DEBUG}{$IFNDEF FREEPASCAL}{$WARNINGS ON}{$ENDIF}{$ENDIF}
|
|
{$ELSE}
|
|
Result := SRec.Size;
|
|
{$ENDIF}
|
|
end;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryEntrySize(const Name: String): Int64;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if FindFirst(Name, faAnyFile, SRec) <> 0 then
|
|
Result := -1
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory <> 0 then
|
|
Result := 0
|
|
else
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
{$WARNINGS OFF}
|
|
Int64Rec(Result).Lo := SRec.FindData.nFileSizeLow;
|
|
Int64Rec(Result).Hi := SRec.FindData.nFileSizeHigh;
|
|
{$IFDEF DEBUG}{$IFNDEF FREEPASCAL}{$WARNINGS ON}{$ENDIF}{$ENDIF}
|
|
{$ELSE}
|
|
Result := SRec.Size;
|
|
{$ENDIF}
|
|
end;
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryExistsB(const DirectoryName: RawByteString): Boolean;
|
|
{$IFDEF MSWINDOWS}
|
|
var Attr : LongWord;
|
|
{$ELSE}
|
|
var SRec : TSearchRec;
|
|
{$ENDIF}
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
{$IFDEF MSWINDOWS}
|
|
Attr := GetFileAttributesA(PAnsiChar(DirectoryName));
|
|
if Attr = $FFFFFFFF then
|
|
Result := False
|
|
else
|
|
Result := Attr and FILE_ATTRIBUTE_DIRECTORY <> 0;
|
|
{$ELSE}
|
|
if FindFirstB(DirectoryName, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := SRec.Attr and faDirectory <> 0;
|
|
FindClose(SRec);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function DirectoryExistsU(const DirectoryName: UnicodeString): Boolean;
|
|
{$IFDEF MSWINDOWS}
|
|
var Attr : LongWord;
|
|
{$ELSE}
|
|
var SRec : TSearchRec;
|
|
{$ENDIF}
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
{$IFDEF MSWINDOWS}
|
|
Attr := GetFileAttributesW(PWideChar(DirectoryName));
|
|
if Attr = $FFFFFFFF then
|
|
Result := False
|
|
else
|
|
Result := Attr and FILE_ATTRIBUTE_DIRECTORY <> 0;
|
|
{$ELSE}
|
|
if FindFirstU(DirectoryName, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := SRec.Attr and faDirectory <> 0;
|
|
FindClose(SRec);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function DirectoryExists(const DirectoryName: String): Boolean;
|
|
{$IFDEF MSWINDOWS}
|
|
var Attr : LongWord;
|
|
{$ELSE}
|
|
var SRec : TSearchRec;
|
|
{$ENDIF}
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
{$IFDEF MSWINDOWS}
|
|
{$IFDEF StringIsUnicode}
|
|
Attr := GetFileAttributesW(PWideChar(DirectoryName));
|
|
{$ELSE}
|
|
Attr := GetFileAttributesA(PAnsiChar(DirectoryName));
|
|
{$ENDIF}
|
|
if Attr = $FFFFFFFF then
|
|
Result := False
|
|
else
|
|
Result := Attr and FILE_ATTRIBUTE_DIRECTORY <> 0;
|
|
{$ELSE}
|
|
if FindFirst(DirectoryName, faAnyFile, SRec) <> 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := SRec.Attr and faDirectory <> 0;
|
|
FindClose(SRec);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function DirectoryGetDateTimeB(const DirectoryName: RawByteString): TDateTime;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
if FindFirstB(DirectoryName, faAnyFile, SRec) <> 0 then
|
|
Result := 0.0
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory = 0 then
|
|
Result := 0.0
|
|
else
|
|
Result := FileDateToDateTime(SRec.Time);
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryGetDateTimeU(const DirectoryName: UnicodeString): TDateTime;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
if FindFirstU(DirectoryName, faAnyFile, SRec) <> 0 then
|
|
Result := 0.0
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory = 0 then
|
|
Result := 0.0
|
|
else
|
|
Result := FileDateToDateTime(SRec.Time);
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirectoryGetDateTime(const DirectoryName: String): TDateTime;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
if FindFirst(DirectoryName, faAnyFile, SRec) <> 0 then
|
|
Result := 0.0
|
|
else
|
|
begin
|
|
if SRec.Attr and faDirectory = 0 then
|
|
Result := 0.0
|
|
else
|
|
Result := FileDateToDateTime(SRec.Time);
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ File operations }
|
|
{ }
|
|
function GetFirstFileNameMatchingB(const FileMask: RawByteString): RawByteString;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
Result := '';
|
|
if FindFirstB(FileMask, faAnyFile, SRec) = 0 then
|
|
try
|
|
repeat
|
|
if SRec.Attr and faDirectory = 0 then
|
|
begin
|
|
Result := PathExtractFilePathB(FileMask) + ToRawByteString(SRec.Name);
|
|
exit;
|
|
end;
|
|
until FindNext(SRec) <> 0;
|
|
finally
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function GetFirstFileNameMatchingU(const FileMask: UnicodeString): UnicodeString;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
Result := '';
|
|
if FindFirstU(FileMask, faAnyFile, SRec) = 0 then
|
|
try
|
|
repeat
|
|
if SRec.Attr and faDirectory = 0 then
|
|
begin
|
|
Result := PathExtractFilePathU(FileMask) + SRec.Name;
|
|
exit;
|
|
end;
|
|
until FindNext(SRec) <> 0;
|
|
finally
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function GetFirstFileNameMatching(const FileMask: String): String;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
Result := '';
|
|
if FindFirst(FileMask, faAnyFile, SRec) = 0 then
|
|
try
|
|
repeat
|
|
if SRec.Attr and faDirectory = 0 then
|
|
begin
|
|
Result := PathExtractFilePath(FileMask) + SRec.Name;
|
|
exit;
|
|
end;
|
|
until FindNext(SRec) <> 0;
|
|
finally
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
|
|
function DirEntryGetAttrB(const FileName: RawByteString): Integer;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if (FileName = '') or WinPathIsDriveLetterB(FileName) then
|
|
Result := -1
|
|
else
|
|
if PathIsRootB(FileName) then
|
|
Result := faDirectory
|
|
else
|
|
if FindFirstB(PathExclSuffixB(FileName), faAnyFile, SRec) = 0 then
|
|
begin
|
|
Result := SRec.Attr;
|
|
FindClose(SRec);
|
|
end
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function DirEntryGetAttrU(const FileName: UnicodeString): Integer;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if (FileName = '') or WinPathIsDriveLetterU(FileName) then
|
|
Result := -1
|
|
else
|
|
if PathIsRootU(FileName) then
|
|
Result := faDirectory
|
|
else
|
|
if FindFirstU(PathExclSuffixU(FileName), faAnyFile, SRec) = 0 then
|
|
begin
|
|
Result := SRec.Attr;
|
|
FindClose(SRec);
|
|
end
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function DirEntryGetAttr(const FileName: String): Integer;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if (FileName = '') or WinPathIsDriveLetter(FileName) then
|
|
Result := -1
|
|
else
|
|
if PathIsRoot(FileName) then
|
|
Result := faDirectory
|
|
else
|
|
if FindFirst(PathExclSuffix(FileName), faAnyFile, SRec) = 0 then
|
|
begin
|
|
Result := SRec.Attr;
|
|
FindClose(SRec);
|
|
end
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function DirEntryIsDirectoryB(const FileName: RawByteString): Boolean;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if (FileName = '') or WinPathIsDriveLetterB(FileName) then
|
|
Result := False
|
|
else
|
|
if PathIsRootB(FileName) then
|
|
Result := True
|
|
else
|
|
if FindFirstB(PathExclSuffixB(FileName), faDirectory, SRec) = 0 then
|
|
begin
|
|
Result := SRec.Attr and faDirectory <> 0;
|
|
FindClose(SRec);
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function DirEntryIsDirectoryU(const FileName: UnicodeString): Boolean;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if (FileName = '') or WinPathIsDriveLetterU(FileName) then
|
|
Result := False
|
|
else
|
|
if PathIsRootU(FileName) then
|
|
Result := True
|
|
else
|
|
if FindFirstU(PathExclSuffixU(FileName), faDirectory, SRec) = 0 then
|
|
begin
|
|
Result := SRec.Attr and faDirectory <> 0;
|
|
FindClose(SRec);
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function DirEntryIsDirectory(const FileName: String): Boolean;
|
|
var SRec : TSearchRec;
|
|
begin
|
|
if (FileName = '') or WinPathIsDriveLetter(FileName) then
|
|
Result := False
|
|
else
|
|
if PathIsRoot(FileName) then
|
|
Result := True
|
|
else
|
|
if FindFirst(PathExclSuffix(FileName), faDirectory, SRec) = 0 then
|
|
begin
|
|
Result := SRec.Attr and faDirectory <> 0;
|
|
FindClose(SRec);
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
{$IFDEF DELPHI6_UP}{$WARN SYMBOL_PLATFORM OFF}{$ENDIF}
|
|
function FileHasAttr(const FileName: String; const Attr: Word): Boolean;
|
|
var A : Integer;
|
|
begin
|
|
A := FileGetAttr(FileName);
|
|
Result := (A >= 0) and (A and Attr <> 0);
|
|
end;
|
|
|
|
function FileHasAttrB(const FileName: RawByteString; const Attr: Word): Boolean;
|
|
var A : Integer;
|
|
begin
|
|
A := FileGetAttr(ToStringB(FileName));
|
|
Result := (A >= 0) and (A and Attr <> 0);
|
|
end;
|
|
|
|
function FileHasAttrU(const FileName: UnicodeString; const Attr: Word): Boolean;
|
|
var A : Integer;
|
|
begin
|
|
A := FileGetAttr(ToStringU(FileName));
|
|
Result := (A >= 0) and (A and Attr <> 0);
|
|
end;
|
|
|
|
procedure DirectoryCreateB(const DirectoryName: RawByteString);
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
if not CreateDir(ToStringB(DirectoryName)) then
|
|
raise EFileError.CreateFmt(feDirectoryCreateError, SCannotCreateDirectory,
|
|
[GetLastOSErrorMessage, DirectoryName]);
|
|
end;
|
|
|
|
procedure DirectoryCreateU(const DirectoryName: UnicodeString);
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
if not CreateDir(ToStringU(DirectoryName)) then
|
|
raise EFileError.CreateFmt(feDirectoryCreateError, SCannotCreateDirectory,
|
|
[GetLastOSErrorMessage, DirectoryName]);
|
|
end;
|
|
|
|
procedure DirectoryCreate(const DirectoryName: String);
|
|
begin
|
|
if DirectoryName = '' then
|
|
raise EFileError.Create(feInvalidParameter, SInvalidPath);
|
|
if not CreateDir(DirectoryName) then
|
|
raise EFileError.CreateFmt(feDirectoryCreateError, SCannotCreateDirectory,
|
|
[GetLastOSErrorMessage, DirectoryName]);
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ File operations }
|
|
{ }
|
|
procedure CopyFile(const FileName, DestName: String);
|
|
const
|
|
BufferSize = 65536;
|
|
var DestFileName : String;
|
|
SourceHandle : Integer;
|
|
DestHandle : Integer;
|
|
Buffer : array[0..BufferSize - 1] of Byte;
|
|
BufferUsed : Integer;
|
|
begin
|
|
DestFileName := ExpandFileName(DestName);
|
|
if FileHasAttr(DestFileName, faDirectory) then // if destination is a directory, append file name
|
|
DestFileName := DestFileName + '\' + ExtractFileName(FileName);
|
|
SourceHandle := FileOpen(FileName, fmShareDenyWrite);
|
|
if SourceHandle < 0 then
|
|
raise EFileError.CreateFmt(feFileOpenError, SCannotOpenFile, [GetLastOSErrorMessage,
|
|
FileName]);
|
|
try
|
|
DestHandle := FileCreate(DestFileName);
|
|
if DestHandle < 0 then
|
|
raise EFileError.CreateFmt(feFileCreateError, SCannotCreateFile, [GetLastOSErrorMessage,
|
|
DestFileName]);
|
|
try
|
|
repeat
|
|
BufferUsed := FileRead(SourceHandle, Buffer[0], BufferSize);
|
|
if BufferUsed > 0 then
|
|
FileWrite(DestHandle, Buffer[0], BufferUsed);
|
|
until BufferUsed < BufferSize;
|
|
finally
|
|
FileClose(DestHandle);
|
|
end;
|
|
finally
|
|
FileClose(SourceHandle);
|
|
end;
|
|
end;
|
|
|
|
procedure MoveFile(const FileName, DestName: String);
|
|
var Destination : String;
|
|
Attr : Integer;
|
|
begin
|
|
Destination := ExpandFileName(DestName);
|
|
if not RenameFile(FileName, Destination) then
|
|
begin
|
|
Attr := FileGetAttr(FileName);
|
|
if (Attr < 0) or (Attr and faReadOnly <> 0) then
|
|
raise EFileError.CreateFmt(feFileMoveError, SCannotMoveFile,
|
|
[GetLastOSErrorMessage, FileName]);
|
|
CopyFile(FileName, Destination);
|
|
DeleteFile(FileName);
|
|
end;
|
|
end;
|
|
|
|
function DeleteFiles(const FileMask: String): Boolean;
|
|
var SRec : TSearchRec;
|
|
Path : String;
|
|
begin
|
|
Result := FindFirst(FileMask, faAnyFile, SRec) = 0;
|
|
if not Result then
|
|
exit;
|
|
try
|
|
Path := ExtractFilePath(FileMask);
|
|
repeat
|
|
if (SRec.Name <> '') and (SRec.Name <> '.') and (SRec.Name <> '..') and
|
|
(SRec.Attr and (faVolumeID + faDirectory) = 0) then
|
|
begin
|
|
Result := DeleteFile(Path + SRec.Name);
|
|
if not Result then
|
|
break;
|
|
end;
|
|
until FindNext(SRec) <> 0;
|
|
finally
|
|
FindClose(SRec);
|
|
end;
|
|
end;
|
|
{$IFDEF DELPHI6_UP}{$WARN SYMBOL_PLATFORM ON}{$ENDIF}
|
|
|
|
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
{ }
|
|
{ Logical Drive functions }
|
|
{ }
|
|
function Word32IsBitSet(const A: Word32; const B: Integer): Boolean;
|
|
begin
|
|
if (B < 0) or (B > 31) then
|
|
Result := False
|
|
else
|
|
Result := (A and (1 shl B) <> 0);
|
|
end;
|
|
|
|
function DriveIsValidA(const Drive: ByteChar): Boolean;
|
|
var D : ByteChar;
|
|
begin
|
|
D := UpCase(Drive);
|
|
Result := D in ['A'..'Z'];
|
|
if not Result then
|
|
exit;
|
|
Result := Word32IsBitSet(GetLogicalDrives, Ord(D) - Ord('A'));
|
|
end;
|
|
|
|
function DriveIsValidW(const Drive: WideChar): Boolean;
|
|
begin
|
|
if (Ord(Drive) < Ord('A')) or
|
|
(Ord(Drive) > Ord('z')) then
|
|
Result := False
|
|
else
|
|
Result := DriveIsValidA(ByteChar(Drive));
|
|
end;
|
|
|
|
function DriveGetTypeA(const Path: AnsiString): TLogicalDriveType;
|
|
begin
|
|
case GetDriveTypeA(PAnsiChar(Path)) of
|
|
DRIVE_REMOVABLE : Result := DriveRemovable;
|
|
DRIVE_FIXED : Result := DriveFixed;
|
|
DRIVE_REMOTE : Result := DriveRemote;
|
|
DRIVE_CDROM : Result := DriveCDRom;
|
|
DRIVE_RAMDISK : Result := DriveRamDisk;
|
|
else
|
|
Result := DriveTypeUnknown;
|
|
end;
|
|
end;
|
|
|
|
function DriveFreeSpaceA(const Path: AnsiString): Int64;
|
|
var D: Byte;
|
|
begin
|
|
if WinPathHasDriveLetterB(Path) then
|
|
D := Ord(UpCase(PAnsiChar(Path)^)) - Ord('A') + 1
|
|
else
|
|
if PathIsUNCPathB(Path) then
|
|
begin
|
|
Result := -1;
|
|
exit;
|
|
end
|
|
else
|
|
D := 0;
|
|
Result := DiskFree(D);
|
|
end;
|
|
|
|
function DriveSizeA(const Path: AnsiString): Int64;
|
|
var D: Byte;
|
|
begin
|
|
if WinPathHasDriveLetterB(Path) then
|
|
D := Ord(UpCase(PAnsiChar(Path)^)) - Ord('A') + 1
|
|
else
|
|
if PathIsUNCPathB(Path) then
|
|
begin
|
|
Result := -1;
|
|
exit;
|
|
end
|
|
else
|
|
D := 0;
|
|
Result := DiskSize(D);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
{ }
|
|
{ Test cases }
|
|
{ }
|
|
{$IFDEF DEBUG}
|
|
{$IFDEF TEST}
|
|
{$ASSERTIONS ON}
|
|
procedure Test;
|
|
{$IFDEF MSWINDOWS}
|
|
const
|
|
TempPath = 'c:\temp';
|
|
TempFilename = 'c:\temp\cFileUtilsTest.txt';
|
|
{$ENDIF}
|
|
{$IFDEF POSIX}
|
|
const
|
|
TempPath = './temp';
|
|
TempFilename = './temp/cFileUtilsTest.txt';
|
|
{$ENDIF}
|
|
begin
|
|
// PathHasDriveLetter
|
|
Assert(WinPathHasDriveLetterB('A:'), 'PathHasDriveLetter');
|
|
Assert(WinPathHasDriveLetterB('a:'), 'PathHasDriveLetter');
|
|
Assert(WinPathHasDriveLetterB('A:\'), 'PathHasDriveLetter');
|
|
Assert(not WinPathHasDriveLetterB('a\'), 'PathHasDriveLetter');
|
|
Assert(not WinPathHasDriveLetterB('\a\'), 'PathHasDriveLetter');
|
|
Assert(not WinPathHasDriveLetterB('::'), 'PathHasDriveLetter');
|
|
|
|
Assert(WinPathHasDriveLetter('A:'), 'PathHasDriveLetter');
|
|
Assert(WinPathHasDriveLetter('a:'), 'PathHasDriveLetter');
|
|
Assert(WinPathHasDriveLetter('A:\'), 'PathHasDriveLetter');
|
|
Assert(not WinPathHasDriveLetter('a\'), 'PathHasDriveLetter');
|
|
Assert(not WinPathHasDriveLetter('\a\'), 'PathHasDriveLetter');
|
|
Assert(not WinPathHasDriveLetter('::'), 'PathHasDriveLetter');
|
|
|
|
// PathIsDriveLetter
|
|
Assert(WinPathIsDriveLetterB('B:'), 'PathIsDriveLetter');
|
|
Assert(not WinPathIsDriveLetterB('B:\'), 'PathIsDriveLetter');
|
|
|
|
Assert(WinPathIsDriveLetter('B:'), 'PathIsDriveLetter');
|
|
Assert(not WinPathIsDriveLetter('B:\'), 'PathIsDriveLetter');
|
|
|
|
// PathIsDriveRoot
|
|
Assert(WinPathIsDriveRootB('C:\'), 'PathIsDriveRoot');
|
|
Assert(not WinPathIsDriveRootB('C:'), 'PathIsDriveRoot');
|
|
Assert(not WinPathIsDriveRootB('C:\A'), 'PathIsDriveRoot');
|
|
|
|
Assert(WinPathIsDriveRoot('C:\'), 'PathIsDriveRoot');
|
|
Assert(not WinPathIsDriveRoot('C:'), 'PathIsDriveRoot');
|
|
Assert(not WinPathIsDriveRoot('C:\A'), 'PathIsDriveRoot');
|
|
|
|
// PathIsAbsolute
|
|
Assert(PathIsAbsoluteB('\'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsoluteB('\C'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsoluteB('\C\'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsoluteB('C:\'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsoluteB('C:'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsoluteB('\C\..\'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsoluteB(''), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsoluteB('C'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsoluteB('C\'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsoluteB('C\D'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsoluteB('C\D\'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsoluteB('..\'), 'PathIsAbsolute');
|
|
|
|
Assert(PathIsAbsolute('\'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsolute('\C'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsolute('\C\'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsolute('C:\'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsolute('C:'), 'PathIsAbsolute');
|
|
Assert(PathIsAbsolute('\C\..\'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsolute(''), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsolute('C'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsolute('C\'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsolute('C\D'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsolute('C\D\'), 'PathIsAbsolute');
|
|
Assert(not PathIsAbsolute('..\'), 'PathIsAbsolute');
|
|
|
|
// PathIsDirectory
|
|
Assert(PathIsDirectoryB('\'), 'PathIsDirectory');
|
|
Assert(PathIsDirectoryB('\C\'), 'PathIsDirectory');
|
|
Assert(PathIsDirectoryB('C:'), 'PathIsDirectory');
|
|
Assert(PathIsDirectoryB('C:\'), 'PathIsDirectory');
|
|
Assert(PathIsDirectoryB('C:\D\'), 'PathIsDirectory');
|
|
Assert(not PathIsDirectoryB(''), 'PathIsDirectory');
|
|
Assert(not PathIsDirectoryB('D'), 'PathIsDirectory');
|
|
Assert(not PathIsDirectoryB('C\D'), 'PathIsDirectory');
|
|
|
|
Assert(PathIsDirectory('\'), 'PathIsDirectory');
|
|
Assert(PathIsDirectory('\C\'), 'PathIsDirectory');
|
|
Assert(PathIsDirectory('C:'), 'PathIsDirectory');
|
|
Assert(PathIsDirectory('C:\'), 'PathIsDirectory');
|
|
Assert(PathIsDirectory('C:\D\'), 'PathIsDirectory');
|
|
Assert(not PathIsDirectory(''), 'PathIsDirectory');
|
|
Assert(not PathIsDirectory('D'), 'PathIsDirectory');
|
|
Assert(not PathIsDirectory('C\D'), 'PathIsDirectory');
|
|
|
|
// PathInclSuffix
|
|
Assert(PathInclSuffixB('', '\') = '', 'PathInclSuffix');
|
|
Assert(PathInclSuffixB('C', '\') = 'C\', 'PathInclSuffix');
|
|
Assert(PathInclSuffixB('C\', '\') = 'C\', 'PathInclSuffix');
|
|
Assert(PathInclSuffixB('C\D', '\') = 'C\D\', 'PathInclSuffix');
|
|
Assert(PathInclSuffixB('C\D\', '\') = 'C\D\', 'PathInclSuffix');
|
|
Assert(PathInclSuffixB('C:', '\') = 'C:\', 'PathInclSuffix');
|
|
Assert(PathInclSuffixB('C:\', '\') = 'C:\', 'PathInclSuffix');
|
|
|
|
Assert(PathInclSuffix('', '\') = '', 'PathInclSuffix');
|
|
Assert(PathInclSuffix('C', '\') = 'C\', 'PathInclSuffix');
|
|
Assert(PathInclSuffix('C\', '\') = 'C\', 'PathInclSuffix');
|
|
Assert(PathInclSuffix('C\D', '\') = 'C\D\', 'PathInclSuffix');
|
|
Assert(PathInclSuffix('C\D\', '\') = 'C\D\', 'PathInclSuffix');
|
|
Assert(PathInclSuffix('C:', '\') = 'C:\', 'PathInclSuffix');
|
|
Assert(PathInclSuffix('C:\', '\') = 'C:\', 'PathInclSuffix');
|
|
|
|
// PathExclSuffix
|
|
Assert(PathExclSuffixB('', '\') = '', 'PathExclSuffix');
|
|
Assert(PathExclSuffixB('C', '\') = 'C', 'PathExclSuffix');
|
|
Assert(PathExclSuffixB('C\', '\') = 'C', 'PathExclSuffix');
|
|
Assert(PathExclSuffixB('C\D', '\') = 'C\D', 'PathExclSuffix');
|
|
Assert(PathExclSuffixB('C\D\', '\') = 'C\D', 'PathExclSuffix');
|
|
Assert(PathExclSuffixB('C:', '\') = 'C:', 'PathExclSuffix');
|
|
Assert(PathExclSuffixB('C:\', '\') = 'C:', 'PathExclSuffix');
|
|
|
|
Assert(PathExclSuffix('', '\') = '', 'PathExclSuffix');
|
|
Assert(PathExclSuffix('C', '\') = 'C', 'PathExclSuffix');
|
|
Assert(PathExclSuffix('C\', '\') = 'C', 'PathExclSuffix');
|
|
Assert(PathExclSuffix('C\D', '\') = 'C\D', 'PathExclSuffix');
|
|
Assert(PathExclSuffix('C\D\', '\') = 'C\D', 'PathExclSuffix');
|
|
Assert(PathExclSuffix('C:', '\') = 'C:', 'PathExclSuffix');
|
|
Assert(PathExclSuffix('C:\', '\') = 'C:', 'PathExclSuffix');
|
|
|
|
// PathCanonical
|
|
Assert(PathCanonicalB('', '\') = '', 'PathCanonical');
|
|
Assert(PathCanonicalB('.', '\') = '', 'PathCanonical');
|
|
Assert(PathCanonicalB('.\', '\') = '', 'PathCanonical');
|
|
Assert(PathCanonicalB('..\', '\') = '..\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\..\', '\') = '\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X\..\..\', '\') = '\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\..', '\') = '', 'PathCanonical');
|
|
Assert(PathCanonicalB('X', '\') = 'X', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X', '\') = '\X', 'PathCanonical');
|
|
Assert(PathCanonicalB('X.', '\') = 'X', 'PathCanonical');
|
|
Assert(PathCanonicalB('.', '\') = '', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X.', '\') = '\X', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X.Y', '\') = '\X.Y', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X.Y\', '\') = '\X.Y\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\X..Y\', '\') = '\A\X..Y\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\.Y\', '\') = '\A\.Y\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\..Y\', '\') = '\A\..Y\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\Y..\', '\') = '\A\Y..\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\Y..', '\') = '\A\Y..', 'PathCanonical');
|
|
Assert(PathCanonicalB('X', '\') = 'X', 'PathCanonical');
|
|
Assert(PathCanonicalB('X\', '\') = 'X\', 'PathCanonical');
|
|
Assert(PathCanonicalB('X\Y\..', '\') = 'X', 'PathCanonical');
|
|
Assert(PathCanonicalB('X\Y\..\', '\') = 'X\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X\Y\..', '\') = '\X', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X\Y\..\', '\') = '\X\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X\Y\..\..', '\') = '', 'PathCanonical');
|
|
Assert(PathCanonicalB('\X\Y\..\..\', '\') = '\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\.\.\X\.\Y\..\.\..\.\', '\') = '\A\', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:', '\') = 'C:', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:\', '\') = 'C:\', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:\A\..', '\') = 'C:', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:\A\..\', '\') = 'C:\', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:\..\', '\') = 'C:\', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:\..', '\') = 'C:', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:\A\..\..', '\') = 'C:', 'PathCanonical');
|
|
Assert(PathCanonicalB('C:\A\..\..\', '\') = 'C:\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\B\..\C\D\..\', '\') = '\A\C\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\B\..\C\D\..\..\', '\') = '\A\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\B\..\C\D\..\..\..\', '\') = '\', 'PathCanonical');
|
|
Assert(PathCanonicalB('\A\B\..\C\D\..\..\..\..\', '\') = '\', 'PathCanonical');
|
|
|
|
Assert(PathExpandB('', '', '\') = '', 'PathExpand');
|
|
Assert(PathExpandB('', '\', '\') = '\', 'PathExpand');
|
|
Assert(PathExpandB('', '\C', '\') = '\C', 'PathExpand');
|
|
Assert(PathExpandB('', '\C\', '\') = '\C\', 'PathExpand');
|
|
Assert(PathExpandB('..\', '\C\', '\') = '\', 'PathExpand');
|
|
Assert(PathExpandB('..', '\C\', '\') = '', 'PathExpand');
|
|
Assert(PathExpandB('\..', '\C\', '\') = '', 'PathExpand');
|
|
Assert(PathExpandB('\..\', '\C\', '\') = '\', 'PathExpand');
|
|
Assert(PathExpandB('A', '..\', '\') = '..\A', 'PathExpand');
|
|
Assert(PathExpandB('..\', '..\', '\') = '..\..\', 'PathExpand');
|
|
Assert(PathExpandB('\', '', '\') = '\', 'PathExpand');
|
|
Assert(PathExpandB('\', '\C', '\') = '\', 'PathExpand');
|
|
Assert(PathExpandB('\A', '\C\', '\') = '\A', 'PathExpand');
|
|
Assert(PathExpandB('\A\', '\C\', '\') = '\A\', 'PathExpand');
|
|
Assert(PathExpandB('\A\B', '\C', '\') = '\A\B', 'PathExpand');
|
|
Assert(PathExpandB('A\B', '\C', '\') = '\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('A\B', '\C', '\') = '\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('A\B', '\C\', '\') = '\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('A\B', '\C\', '\') = '\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('A\B', 'C\D', '\') = 'C\D\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\A\B', 'C\D', '\') = 'C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\A\B', '\C\D', '\') = '\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\..\A\B', 'C\D', '\') = 'A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\..\A\B', '\C\D', '\') = '\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\..\..\A\B', '\C\D', '\') = '\A\B', 'PathExpand');
|
|
Assert(PathExpandB('\..\A\B', '\C\D', '\') = '\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\A\B', '\..\C\D', '\') = '\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\A\B', '..\C\D', '\') = '..\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\A\B', 'C:\C\D', '\') = 'C:\C\A\B', 'PathExpand');
|
|
Assert(PathExpandB('..\A\B\', 'C:\C\D', '\') = 'C:\C\A\B\', 'PathExpand');
|
|
|
|
Assert(FilePathB('C', '..\X\Y', 'A\B', '\') = 'A\X\Y\C', 'FilePath');
|
|
Assert(FilePathB('C', '\X\Y', 'A\B', '\') = '\X\Y\C', 'FilePath');
|
|
Assert(FilePathB('C', '', 'A\B', '\') = 'A\B\C', 'FilePath');
|
|
Assert(FilePathB('', '\X\Y', 'A\B', '\') = '', 'FilePath');
|
|
Assert(FilePathB('C', 'X\Y', 'A\B', '\') = 'A\B\X\Y\C', 'FilePath');
|
|
Assert(FilePathB('C', 'X\Y', '', '\') = 'X\Y\C', 'FilePath');
|
|
|
|
Assert(FilePath('C', '..\X\Y', 'A\B', '\') = 'A\X\Y\C', 'FilePath');
|
|
Assert(FilePath('C', '\X\Y', 'A\B', '\') = '\X\Y\C', 'FilePath');
|
|
Assert(FilePath('C', '', 'A\B', '\') = 'A\B\C', 'FilePath');
|
|
Assert(FilePath('', '\X\Y', 'A\B', '\') = '', 'FilePath');
|
|
Assert(FilePath('C', 'X\Y', 'A\B', '\') = 'A\B\X\Y\C', 'FilePath');
|
|
Assert(FilePath('C', 'X\Y', '', '\') = 'X\Y\C', 'FilePath');
|
|
Assert(DirectoryExpandB('', '', '\') = '', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('', '\X', '\') = '\X\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('\', '\X', '\') = '\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('\A', '\X', '\') = '\A\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('\A\', '\X', '\') = '\A\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('\A\B', '\X', '\') = '\A\B\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('A', '\X', '\') = '\X\A\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('A\', '\X', '\') = '\X\A\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('C:', '\X', '\') = 'C:\', 'DirectoryExpand');
|
|
Assert(DirectoryExpandB('C:\', '\X', '\') = 'C:\', 'DirectoryExpand');
|
|
|
|
Assert(UnixPathToSafeWinPathB('/c/d.f') = '\c\d.f', 'UnixPathToWinPath');
|
|
Assert(WinPathToSafeUnixPathB('\c\d.f') = '/c/d.f', 'WinPathToUnixPath');
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
Assert(PathExtractFileNameB('c:\test\abc\file.txt') = 'file.txt');
|
|
Assert(PathExtractFileNameU('c:\test\abc\file.txt') = 'file.txt');
|
|
{$ENDIF}
|
|
|
|
if not DirectoryExists(TempPath) then
|
|
DirectoryCreate(TempPath);
|
|
Assert(DirectoryExists(TempPath));
|
|
|
|
WriteFileRawStr(TempFilename, 'FileUtilsTest', fsExclusive, fcCreateAlways, nil);
|
|
Assert(FileExists(TempFilename));
|
|
Assert(FileGetSize(TempFilename) = 13);
|
|
Assert(ReadFileRawStr(TempFilename, fsDenyNone, fcOpenExisting, nil) = 'FileUtilsTest');
|
|
|
|
AppendFileRawStr(TempFilename, '123', fsExclusive, fcOpenExisting, nil);
|
|
Assert(FileGetSize(TempFilename) = 16);
|
|
Assert(ReadFileRawStr(TempFilename, fsDenyNone, fcOpenExisting, nil) = 'FileUtilsTest123');
|
|
|
|
FileDeleteEx(TempFilename);
|
|
Assert(not FileExists(TempFilename));
|
|
end;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
end.
|
|
|