This commit is contained in:
1 parent
1a5b20ca9f
commit
06baad3db6
4 files changed
+779
-52
No files matched your search
@@ -65,13 +65,16 @@ uses
|
||||
implementation
|
||||
uses
|
||||
StrUtils, KM_CommonUtils,
|
||||
KM_Defaults;
|
||||
KM_Defaults
|
||||
{$IFDEF ANDROID}, KM_FileIO_Mobile{$ENDIF};
|
||||
|
||||
|
||||
function ReadTextA(const aFilename: UnicodeString): AnsiString;
|
||||
var
|
||||
MS: TMemoryStream;
|
||||
Head: Cardinal;
|
||||
BOM: array[0..2] of Byte;
|
||||
HasBOM: Boolean;
|
||||
Remaining: Int64;
|
||||
begin
|
||||
MS := TMemoryStream.Create;
|
||||
try
|
||||
@@ -80,18 +83,23 @@ begin
|
||||
// Instead we read plain ANSI text. If there's BOM - clip it
|
||||
MS.LoadFromFile(aFileName);
|
||||
|
||||
// Read 4 bytes but check just 3, cos reading 3 bytes is a hassle
|
||||
MS.Read(Head, SizeOf(Cardinal));
|
||||
HasBOM := False;
|
||||
if MS.Size >= 3 then
|
||||
begin
|
||||
MS.Position := 0;
|
||||
MS.ReadBuffer(BOM, SizeOf(BOM));
|
||||
HasBOM := (BOM[0] = $EF) and (BOM[1] = $BB) and (BOM[2] = $BF);
|
||||
end;
|
||||
|
||||
// Trim UTF8 BOM (don't know how to deal with others yet)
|
||||
if Head and $FFFFFF = $BFBBEF then
|
||||
if HasBOM then
|
||||
MS.Position := 3
|
||||
else
|
||||
MS.Position := 0;
|
||||
|
||||
SetLength(Result, MS.Size - MS.Position);
|
||||
if MS.Size - MS.Position > 0 then
|
||||
MS.Read(Result[1], MS.Size - MS.Position);
|
||||
Remaining := MS.Size - MS.Position;
|
||||
SetLength(Result, Remaining);
|
||||
if Remaining > 0 then
|
||||
MS.ReadBuffer(Result[1], Remaining);
|
||||
finally
|
||||
MS.Free;
|
||||
end;
|
||||
@@ -107,9 +115,10 @@ var
|
||||
{$ENDIF}
|
||||
{$IFDEF FPC}
|
||||
MS: TMemoryStream;
|
||||
Head: Cardinal;
|
||||
BOM: array[0..2] of Byte;
|
||||
HasBOM: Boolean;
|
||||
TmpA: AnsiString;
|
||||
TmpA: RawByteString;
|
||||
Remaining: Int64;
|
||||
{$ENDIF}
|
||||
begin
|
||||
{$IFDEF WDC}
|
||||
@@ -129,23 +138,29 @@ begin
|
||||
MS := TMemoryStream.Create;
|
||||
try
|
||||
MS.LoadFromFile(aFileName);
|
||||
MS.Read(Head, 4);
|
||||
|
||||
//Trim UTF8 BOM (don't know how to deal with others yet)
|
||||
HasBOM := Head and $FFFFFF = $BFBBEF;
|
||||
HasBOM := False;
|
||||
if MS.Size >= 3 then
|
||||
begin
|
||||
MS.Position := 0;
|
||||
MS.ReadBuffer(BOM, SizeOf(BOM));
|
||||
HasBOM := (BOM[0] = $EF) and (BOM[1] = $BB) and (BOM[2] = $BF);
|
||||
end;
|
||||
|
||||
if HasBOM then
|
||||
MS.Position := 3
|
||||
else
|
||||
MS.Position := 0;
|
||||
|
||||
SetLength(TmpA, MS.Size - MS.Position);
|
||||
MS.Read(TmpA[1], MS.Size - MS.Position);
|
||||
Remaining := MS.Size - MS.Position;
|
||||
SetLength(TmpA, Remaining);
|
||||
if Remaining > 0 then
|
||||
MS.ReadBuffer(TmpA[1], Remaining);
|
||||
|
||||
{$IFDEF ANDROID}
|
||||
if not HasBOM then
|
||||
raise Exception.Create('KM_FileIO: ReadTextU codepage conversion is unsupported on Android');
|
||||
Result := UTF8Decode(TmpA);
|
||||
if HasBOM then
|
||||
Result := UTF8Decode(TmpA)
|
||||
else
|
||||
Result := KMFileIODecodeLegacy(TmpA, aEncoding);
|
||||
{$ELSE}
|
||||
//Non-UTF8 files must be converted from their native encoding
|
||||
if not HasBOM then
|
||||
@@ -163,7 +178,7 @@ end;
|
||||
procedure KMCopyFile(const aSrc, aDest: UnicodeString);
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMCopyFile is unsupported on Android');
|
||||
KMFileIOCopyFile(aSrc, aDest);
|
||||
{$ELSE}
|
||||
{$IFDEF FPC}
|
||||
CopyFile(pchar(aSrc), pchar(aDest), True);
|
||||
@@ -178,7 +193,9 @@ end;
|
||||
procedure KMCopyFile(const aSrc, aDest: UnicodeString; aOverwrite: Boolean);
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMCopyFile is unsupported on Android');
|
||||
if aOverwrite and FileExists(aDest) and not SysUtils.DeleteFile(aDest) then
|
||||
raise Exception.CreateFmt('KM_FileIO: unable to delete destination file: %s', [aDest]);
|
||||
KMFileIOCopyFile(aSrc, aDest);
|
||||
{$ELSE}
|
||||
if aOverwrite and FileExists(aDest) then
|
||||
DeleteFile(aDest);
|
||||
@@ -211,7 +228,7 @@ end;
|
||||
procedure KMDeleteFileToBin(const aPath: UnicodeString);
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMDeleteFileToBin is unsupported on Android');
|
||||
KMDeleteFile(aPath, True);
|
||||
{$ELSE}
|
||||
KMDeleteFile(aPath, True);
|
||||
{$ENDIF}
|
||||
@@ -242,10 +259,15 @@ begin
|
||||
SHFileOperation(ShOp);
|
||||
{$ELSE}
|
||||
{$IFDEF ANDROID}
|
||||
if not FileExists(aFilePath) then
|
||||
Exit;
|
||||
if aDeleteToBin then
|
||||
raise Exception.Create('KM_FileIO: KMDeleteFile recycle-bin mode is unsupported on Android');
|
||||
KMFileIOMoveToTrash(aFilePath, False)
|
||||
else if not SysUtils.DeleteFile(aFilePath) then
|
||||
raise Exception.CreateFmt('KM_FileIO: unable to delete file: %s', [aFilePath]);
|
||||
{$ELSE}
|
||||
DeleteFile(aFilePath);
|
||||
{$ENDIF}
|
||||
DeleteFile(aFilePath);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
@@ -253,7 +275,7 @@ end;
|
||||
procedure KMDeleteFolderToBin(const aPath: UnicodeString);
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMDeleteFolderToBin is unsupported on Android');
|
||||
KMDeleteFolder(aPath, True);
|
||||
{$ELSE}
|
||||
KMDeleteFolder(aPath, True);
|
||||
{$ENDIF}
|
||||
@@ -263,7 +285,7 @@ end;
|
||||
procedure KMDeleteFolder(const aPath: UnicodeString);
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMDeleteFolder is unsupported on Android');
|
||||
KMDeleteFolder(aPath, False);
|
||||
{$ELSE}
|
||||
KMDeleteFolder(aPath, False);
|
||||
{$ENDIF}
|
||||
@@ -320,11 +342,14 @@ const
|
||||
|
||||
{$ENDIF}
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMDeleteFolder is unsupported on Android');
|
||||
{$ELSE}
|
||||
if DirectoryExists(aPath) then
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
if aDeleteToBin then
|
||||
KMFileIOMoveToTrash(aPath, True)
|
||||
else
|
||||
KMFileIORemoveDirectoryTree(aPath);
|
||||
{$ELSE}
|
||||
{$IFDEF MSWINDOWS}
|
||||
if aDeleteToBin then
|
||||
begin
|
||||
@@ -344,8 +369,8 @@ begin
|
||||
{$ELSE}
|
||||
DeleteDefault;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
|
||||
@@ -356,7 +381,12 @@ var
|
||||
{$ENDIF}
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMDeleteFolderContent is unsupported on Android');
|
||||
if DirectoryExists(aPath) then
|
||||
begin
|
||||
KMDeleteFolder(aPath, aDeleteToBin);
|
||||
if not ForceDirectories(aPath) and not DirectoryExists(aPath) then
|
||||
raise Exception.CreateFmt('KM_FileIO: unable to recreate folder: %s', [aPath]);
|
||||
end;
|
||||
{$ELSE}
|
||||
if DirectoryExists(aPath) then
|
||||
begin
|
||||
@@ -393,7 +423,13 @@ end;
|
||||
|
||||
procedure KMRenameFolder(const aSourcePath, aDestPath: UnicodeString);
|
||||
begin
|
||||
{$IFDEF FPC} RenameFile(aSourcePath, aDestPath); {$ENDIF}
|
||||
{$IFDEF FPC}
|
||||
{$IFDEF ANDROID}
|
||||
KMFileIORenameDirectory(aSourcePath, aDestPath);
|
||||
{$ELSE}
|
||||
RenameFile(aSourcePath, aDestPath);
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
{$IFDEF WDC} TDirectory.Move(aSourcePath, aDestPath); {$ENDIF}
|
||||
end;
|
||||
|
||||
@@ -405,15 +441,19 @@ begin
|
||||
if IsFilePath(aSourcePath) then
|
||||
begin
|
||||
if FileExists(aSourcePath) then
|
||||
{$IFDEF FPC} RenameFile(aSourcePath, aDestPath); {$ENDIF}
|
||||
{$IFDEF FPC}
|
||||
{$IFDEF ANDROID}
|
||||
if not SysUtils.RenameFile(aSourcePath, aDestPath) then
|
||||
raise Exception.CreateFmt('KM_FileIO: unable to rename file from %s to %s', [aSourcePath, aDestPath]);
|
||||
{$ELSE}
|
||||
RenameFile(aSourcePath, aDestPath);
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
{$IFDEF WDC} TFile.Move(aSourcePath, aDestPath); {$ENDIF}
|
||||
end
|
||||
else
|
||||
if DirectoryExists(aSourcePath) then
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMRenamePath directory mode is unsupported on Android');
|
||||
{$ELSE}
|
||||
//Try to delete folder up to 3 times. Sometimes folder could not be deleted for some reason
|
||||
if not TryExecuteMethodProc(KMDeleteFolder, aDestPath, 'KMDeleteFolder', ErrorStr) then
|
||||
raise Exception.Create('Can''t delete folder ' + aDestPath + ': ' + ErrorStr);
|
||||
@@ -421,7 +461,6 @@ begin
|
||||
//Try to rename folder up to 3 times. Sometimes folder could not be renamed for some reason
|
||||
if not TryExecuteMethodProc(KMRenameFolder, aSourcePath, aDestPath, 'KMRenameFolder', ErrorStr) then
|
||||
raise Exception.Create(Format('Can''t rename folder from %s to %s: %s', [aSourcePath, aDestPath, ErrorStr]));
|
||||
{$ENDIF}
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -480,10 +519,6 @@ begin
|
||||
or (aSourceFolder = aDestFolder)
|
||||
or not DirectoryExists(aSourceFolder) then Exit;
|
||||
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: KMMoveFolder is unsupported on Android');
|
||||
{$ENDIF}
|
||||
|
||||
KMDeleteFolder(aDestFolder, False);
|
||||
|
||||
//Move directory to dest first
|
||||
@@ -503,6 +538,10 @@ function KMFileSize(const aFilename: String): Int64;
|
||||
var
|
||||
info: TWin32FileAttributeData;
|
||||
{$ENDIF}
|
||||
{$IFDEF ANDROID}
|
||||
var
|
||||
Stream: TFileStream;
|
||||
{$ENDIF}
|
||||
begin
|
||||
Result := -1;
|
||||
|
||||
@@ -512,6 +551,22 @@ begin
|
||||
|
||||
Result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF ANDROID}
|
||||
if not FileExists(aFilename) then
|
||||
Exit;
|
||||
|
||||
try
|
||||
Stream := TFileStream.Create(aFilename, fmOpenRead or fmShareDenyNone);
|
||||
try
|
||||
Result := Stream.Size;
|
||||
finally
|
||||
Stream.Free;
|
||||
end;
|
||||
except
|
||||
Result := -1;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
|
||||
@@ -526,10 +581,7 @@ procedure WriteText(const aText: string; aFilename: string; aEncoding: TEncoding
|
||||
var
|
||||
sl: TStringList;
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: WriteText is unsupported on Android');
|
||||
{$ELSE}
|
||||
{$IFDEF WDC}
|
||||
{$IF DEFINED(WDC) OR DEFINED(ANDROID)}
|
||||
sl := TStringList.Create;
|
||||
try
|
||||
sl.Text := aText;
|
||||
@@ -538,7 +590,6 @@ begin
|
||||
sl.Free;
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
|
||||
@@ -551,10 +602,12 @@ begin
|
||||
Stream := TFileStream.Create(aFileName, fmCreate);
|
||||
try
|
||||
BOM := TEncoding.UTF8.GetPreamble;
|
||||
Stream.WriteBuffer(BOM, Length(BOM));
|
||||
if Length(BOM) > 0 then
|
||||
Stream.WriteBuffer(BOM[0], Length(BOM));
|
||||
|
||||
Buffer := TEncoding.UTF8.GetBytes(aText);
|
||||
Stream.WriteBuffer(Buffer, Length(Buffer));
|
||||
if Length(Buffer) > 0 then
|
||||
Stream.WriteBuffer(Buffer[0], Length(Buffer));
|
||||
finally
|
||||
Stream.Free;
|
||||
end;
|
||||
@@ -569,7 +622,7 @@ var
|
||||
{$ENDIF}
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: IsDirectoryWriteable is unsupported on Android');
|
||||
Result := KMFileIOIsDirectoryWriteable(aDir);
|
||||
{$ELSE}
|
||||
{$IFDEF WDC}
|
||||
tmpFilename := IncludeTrailingPathDelimiter(aDir) + 'chk.tmp';
|
||||
@@ -594,7 +647,9 @@ end;
|
||||
function CreateAndGetDocumentsSavePath: string;
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: CreateAndGetDocumentsSavePath is unsupported on Android');
|
||||
Result := KMFileIOApplicationSavePath;
|
||||
if not IsDirectoryWriteable(Result) then
|
||||
raise Exception.CreateFmt('KM_FileIO: application save path is not writeable: %s', [Result]);
|
||||
{$ELSE}
|
||||
// Returns C:\Users\Username\My Documents\My Games\GAME_TITLE\
|
||||
// According to GDSE this is the most commonly used savegame location (https://gamedev.stackexchange.com/a/108243)
|
||||
@@ -681,7 +736,7 @@ end;
|
||||
procedure CheckFolderPermission(const aPath: string; var aRead, aWrite, aExec: Boolean);
|
||||
begin
|
||||
{$IFDEF ANDROID}
|
||||
raise Exception.Create('KM_FileIO: CheckFolderPermission is unsupported on Android');
|
||||
KMFileIOCheckFolderPermission(aPath, aRead, aWrite, aExec);
|
||||
{$ELSE}
|
||||
{$IFDEF WDC}
|
||||
aRead := (CheckFileAccess(aPath, FILE_GENERIC_READ) = FILE_GENERIC_READ);
|
||||
|
||||
Reference in new issue
Block a user