2019-08-23 11:56:54 -07:00
|
|
|
using System.Threading;
|
|
|
|
using System.Diagnostics.Contracts;
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
|
|
namespace System.IO
|
|
|
|
{
|
|
|
|
abstract class FileStreamBase : Stream
|
|
|
|
{
|
|
|
|
protected Platform.BfpFile* mBfpFile;
|
|
|
|
|
|
|
|
public override int64 Position
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return Platform.BfpFile_Seek(mBfpFile, 0, .Relative);
|
|
|
|
}
|
|
|
|
|
|
|
|
set
|
|
|
|
{
|
|
|
|
Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int64 Length
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return Platform.BfpFile_GetFileSize(mBfpFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 05:29:50 -07:00
|
|
|
public int Handle
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (mBfpFile == null)
|
|
|
|
return 0;
|
|
|
|
return Platform.BfpFile_GetSystemHandle(mBfpFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
public ~this()
|
|
|
|
{
|
2021-04-11 07:04:17 -04:00
|
|
|
Delete();
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
|
2019-09-10 11:25:53 -07:00
|
|
|
public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, (Platform.BfpFileSeekKind)seekKind);
|
|
|
|
// Ensure position is what was requested
|
|
|
|
if ((seekKind == .Absolute) && (newPos != pos))
|
|
|
|
return .Err;
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override Result<int> TryRead(Span<uint8> data)
|
|
|
|
{
|
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
|
|
|
|
if ((result != .Ok) && (result != .PartialData))
|
|
|
|
return .Err;
|
|
|
|
return numBytesRead;
|
|
|
|
}
|
|
|
|
|
2023-04-17 15:16:19 -07:00
|
|
|
public override Result<int, FileError> TryRead(Span<uint8> data, int timeoutMS)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
|
|
|
|
if ((result != .Ok) && (result != .PartialData))
|
2021-12-31 10:26:32 -05:00
|
|
|
{
|
|
|
|
switch (result)
|
|
|
|
{
|
|
|
|
case .Timeout:
|
|
|
|
return .Err(.ReadError(.Timeout));
|
|
|
|
default:
|
|
|
|
return .Err(.ReadError(.Unknown));
|
|
|
|
}
|
|
|
|
}
|
2019-08-23 11:56:54 -07:00
|
|
|
return numBytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override Result<int> TryWrite(Span<uint8> data)
|
|
|
|
{
|
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
int numBytesWritten = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
|
|
|
|
if ((result != .Ok) && (result != .PartialData))
|
|
|
|
return .Err;
|
|
|
|
return numBytesWritten;
|
|
|
|
}
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
public override Result<void> Close()
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
if (mBfpFile != null)
|
|
|
|
Platform.BfpFile_Release(mBfpFile);
|
|
|
|
mBfpFile = null;
|
2021-04-11 07:04:17 -04:00
|
|
|
return .Ok;
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
public override Result<void> Flush()
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
if (mBfpFile != null)
|
|
|
|
Platform.BfpFile_Flush(mBfpFile);
|
2021-04-11 07:04:17 -04:00
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual void Delete()
|
|
|
|
{
|
|
|
|
Close();
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-13 07:00:11 -05:00
|
|
|
interface IFileStream
|
|
|
|
{
|
|
|
|
Result<void> Attach(Platform.BfpFile* bfpFile, FileAccess access = .ReadWrite);
|
|
|
|
}
|
|
|
|
|
|
|
|
class UnbufferedFileStream : FileStreamBase, IFileStream
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
FileAccess mFileAccess;
|
|
|
|
|
|
|
|
public this()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public this(Platform.BfpFile* handle, FileAccess access, int32 bufferSize, bool isAsync)
|
|
|
|
{
|
|
|
|
mBfpFile = handle;
|
|
|
|
mFileAccess = access;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CanRead
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mFileAccess.HasFlag(FileAccess.Read);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CanWrite
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mFileAccess.HasFlag(FileAccess.Write);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-29 07:47:44 -08:00
|
|
|
public Result<void, FileOpenError> Create(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
return Open(path, FileMode.Create, access, share, bufferSize, options, secAttrs);
|
|
|
|
}
|
|
|
|
|
2020-02-29 07:47:44 -08:00
|
|
|
public Result<void, FileOpenError> Open(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
return Open(path, FileMode.Open, access, share, bufferSize, options, secAttrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<void, FileOpenError> OpenStd(Platform.BfpFileStdKind stdKind)
|
|
|
|
{
|
|
|
|
Platform.BfpFileResult fileResult = .Ok;
|
|
|
|
mBfpFile = Platform.BfpFile_GetStd(stdKind, &fileResult);
|
2020-02-29 07:47:44 -08:00
|
|
|
mFileAccess = .ReadWrite;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
if ((mBfpFile == null) || (fileResult != .Ok))
|
|
|
|
{
|
|
|
|
switch (fileResult)
|
|
|
|
{
|
|
|
|
case .ShareError:
|
|
|
|
return .Err(.SharingViolation);
|
|
|
|
case .NotFound:
|
|
|
|
return .Err(.NotFound);
|
|
|
|
default:
|
|
|
|
return .Err(.Unknown);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
2020-02-29 07:47:44 -08:00
|
|
|
public Result<void, FileOpenError> Open(StringView path, FileMode mode, FileAccess access, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
Runtime.Assert(mBfpFile == null);
|
|
|
|
|
|
|
|
Platform.BfpFileCreateKind createKind = .CreateAlways;
|
|
|
|
Platform.BfpFileCreateFlags createFlags = .None;
|
|
|
|
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case .CreateNew:
|
|
|
|
createKind = .CreateIfNotExists;
|
|
|
|
case .Create:
|
|
|
|
createKind = .CreateAlways;
|
2021-09-15 11:18:32 -07:00
|
|
|
createFlags |= .Truncate;
|
2019-08-23 11:56:54 -07:00
|
|
|
case .Open:
|
|
|
|
createKind = .OpenExisting;
|
|
|
|
case .OpenOrCreate:
|
2021-08-01 17:30:40 -03:00
|
|
|
createKind = .OpenAlways;
|
2019-08-23 11:56:54 -07:00
|
|
|
case .Truncate:
|
2021-09-15 11:18:32 -07:00
|
|
|
createKind = .OpenExisting;
|
2019-08-23 11:56:54 -07:00
|
|
|
createFlags |= .Truncate;
|
|
|
|
case .Append:
|
|
|
|
createKind = .CreateAlways;
|
|
|
|
createFlags |= .Append;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (access.HasFlag(.Read))
|
|
|
|
createFlags |= .Read;
|
|
|
|
if (access.HasFlag(.Write))
|
|
|
|
createFlags |= .Write;
|
|
|
|
|
|
|
|
if (share.HasFlag(.Read))
|
|
|
|
createFlags |= .ShareRead;
|
|
|
|
if (share.HasFlag(.Write))
|
|
|
|
createFlags |= .ShareWrite;
|
|
|
|
if (share.HasFlag(.Delete))
|
|
|
|
createFlags |= .ShareDelete;
|
|
|
|
|
|
|
|
Platform.BfpFileAttributes fileFlags = .Normal;
|
|
|
|
|
|
|
|
Platform.BfpFileResult fileResult = .Ok;
|
|
|
|
mBfpFile = Platform.BfpFile_Create(path.ToScopeCStr!(128), createKind, createFlags, fileFlags, &fileResult);
|
|
|
|
|
|
|
|
if ((mBfpFile == null) || (fileResult != .Ok))
|
|
|
|
{
|
|
|
|
switch (fileResult)
|
|
|
|
{
|
|
|
|
case .ShareError:
|
|
|
|
return .Err(.SharingViolation);
|
|
|
|
case .NotFound:
|
|
|
|
return .Err(.NotFound);
|
|
|
|
default:
|
|
|
|
return .Err(.Unknown);
|
|
|
|
}
|
|
|
|
}
|
2020-02-29 07:47:44 -08:00
|
|
|
mFileAccess = access;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
2023-01-13 07:00:11 -05:00
|
|
|
public Result<void> Attach(Platform.BfpFile* bfpFile, FileAccess access = .ReadWrite)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
Close();
|
|
|
|
mBfpFile = bfpFile;
|
2020-02-29 07:47:44 -08:00
|
|
|
mFileAccess = access;
|
2023-01-13 07:00:11 -05:00
|
|
|
return .Ok;
|
2020-02-29 07:47:44 -08:00
|
|
|
}
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
public override Result<void> Close()
|
2020-02-29 07:47:44 -08:00
|
|
|
{
|
|
|
|
mFileAccess = default;
|
2021-04-11 07:04:17 -04:00
|
|
|
if (base.Close() case .Err)
|
|
|
|
return .Err;
|
|
|
|
return .Ok;
|
|
|
|
}
|
2021-08-01 17:38:30 -03:00
|
|
|
|
|
|
|
public override Result<void> SetLength(int64 length)
|
|
|
|
{
|
|
|
|
int64 pos = Position;
|
|
|
|
|
|
|
|
if (pos != length)
|
|
|
|
Seek(length);
|
|
|
|
|
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
Platform.BfpFile_Truncate(mBfpFile, &result);
|
|
|
|
if (result != .Ok)
|
|
|
|
{
|
|
|
|
Seek(pos);
|
|
|
|
return .Err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos != length)
|
|
|
|
{
|
|
|
|
if (pos < length)
|
|
|
|
Seek(pos);
|
|
|
|
else
|
|
|
|
Seek(0, .FromEnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
2021-04-11 07:04:17 -04:00
|
|
|
}
|
|
|
|
|
2023-01-13 07:00:11 -05:00
|
|
|
class BufferedFileStream : BufferedStream, IFileStream
|
2021-04-11 07:04:17 -04:00
|
|
|
{
|
2023-08-18 12:04:01 -07:00
|
|
|
public struct PositionRestorer : this(BufferedFileStream stream, int prevPosition), IDisposable
|
|
|
|
{
|
|
|
|
public void Dispose() => stream.Position = prevPosition;
|
|
|
|
}
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
protected Platform.BfpFile* mBfpFile;
|
|
|
|
protected int64 mBfpFilePos;
|
|
|
|
FileAccess mFileAccess;
|
|
|
|
|
2021-07-03 05:29:50 -07:00
|
|
|
public int Handle
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (mBfpFile == null)
|
|
|
|
return 0;
|
|
|
|
return Platform.BfpFile_GetSystemHandle(mBfpFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-01 17:37:37 -03:00
|
|
|
public override bool CanRead
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mFileAccess.HasFlag(FileAccess.Read);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CanWrite
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mFileAccess.HasFlag(FileAccess.Write);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-09 20:04:17 +01:00
|
|
|
public override int64 Position
|
|
|
|
{
|
|
|
|
set
|
|
|
|
{
|
|
|
|
// Matches the behavior of Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
|
|
|
|
mPos = Math.Max(value, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
public this()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public ~this()
|
|
|
|
{
|
|
|
|
Delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
public this(Platform.BfpFile* handle, FileAccess access, int32 bufferSize, bool isAsync)
|
|
|
|
{
|
|
|
|
mBfpFile = handle;
|
|
|
|
mFileAccess = access;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<void, FileOpenError> Create(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
|
|
|
|
{
|
|
|
|
return Open(path, FileMode.Create, access, share, bufferSize, options, secAttrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<void, FileOpenError> Open(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
|
|
|
|
{
|
|
|
|
return Open(path, FileMode.Open, access, share, bufferSize, options, secAttrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<void, FileOpenError> OpenStd(Platform.BfpFileStdKind stdKind)
|
|
|
|
{
|
|
|
|
Platform.BfpFileResult fileResult = .Ok;
|
|
|
|
mBfpFile = Platform.BfpFile_GetStd(stdKind, &fileResult);
|
|
|
|
mFileAccess = .ReadWrite;
|
|
|
|
|
|
|
|
if ((mBfpFile == null) || (fileResult != .Ok))
|
|
|
|
{
|
|
|
|
switch (fileResult)
|
|
|
|
{
|
|
|
|
case .ShareError:
|
|
|
|
return .Err(.SharingViolation);
|
|
|
|
case .NotFound:
|
|
|
|
return .Err(.NotFound);
|
|
|
|
default:
|
|
|
|
return .Err(.Unknown);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<void, FileOpenError> Open(StringView path, FileMode mode, FileAccess access, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
|
|
|
|
{
|
|
|
|
Runtime.Assert(mBfpFile == null);
|
|
|
|
|
|
|
|
Platform.BfpFileCreateKind createKind = .CreateAlways;
|
|
|
|
Platform.BfpFileCreateFlags createFlags = .None;
|
|
|
|
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case .CreateNew:
|
|
|
|
createKind = .CreateIfNotExists;
|
|
|
|
case .Create:
|
|
|
|
createKind = .CreateAlways;
|
|
|
|
case .Open:
|
|
|
|
createKind = .OpenExisting;
|
|
|
|
case .OpenOrCreate:
|
2021-08-01 17:30:40 -03:00
|
|
|
createKind = .OpenAlways;
|
2021-04-11 07:04:17 -04:00
|
|
|
case .Truncate:
|
|
|
|
createKind = .CreateAlways;
|
|
|
|
createFlags |= .Truncate;
|
|
|
|
case .Append:
|
|
|
|
createKind = .CreateAlways;
|
|
|
|
createFlags |= .Append;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (access.HasFlag(.Read))
|
|
|
|
createFlags |= .Read;
|
|
|
|
if (access.HasFlag(.Write))
|
|
|
|
createFlags |= .Write;
|
|
|
|
|
|
|
|
if (share.HasFlag(.Read))
|
|
|
|
createFlags |= .ShareRead;
|
|
|
|
if (share.HasFlag(.Write))
|
|
|
|
createFlags |= .ShareWrite;
|
|
|
|
if (share.HasFlag(.Delete))
|
|
|
|
createFlags |= .ShareDelete;
|
|
|
|
|
|
|
|
Platform.BfpFileAttributes fileFlags = .Normal;
|
|
|
|
|
|
|
|
Platform.BfpFileResult fileResult = .Ok;
|
|
|
|
mBfpFile = Platform.BfpFile_Create(path.ToScopeCStr!(128), createKind, createFlags, fileFlags, &fileResult);
|
|
|
|
|
|
|
|
if ((mBfpFile == null) || (fileResult != .Ok))
|
|
|
|
{
|
|
|
|
switch (fileResult)
|
|
|
|
{
|
|
|
|
case .ShareError:
|
|
|
|
return .Err(.SharingViolation);
|
|
|
|
case .NotFound:
|
|
|
|
return .Err(.NotFound);
|
|
|
|
default:
|
|
|
|
return .Err(.Unknown);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mFileAccess = access;
|
|
|
|
|
|
|
|
MakeBuffer(bufferSize);
|
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
2023-01-13 07:00:11 -05:00
|
|
|
public Result<void> Attach(Platform.BfpFile* bfpFile, FileAccess access = .ReadWrite)
|
2021-04-11 07:04:17 -04:00
|
|
|
{
|
|
|
|
Close();
|
|
|
|
mBfpFile = bfpFile;
|
|
|
|
mFileAccess = access;
|
2023-01-13 07:00:11 -05:00
|
|
|
return .Ok;
|
2021-04-11 07:04:17 -04:00
|
|
|
}
|
|
|
|
|
2023-08-18 12:04:01 -07:00
|
|
|
public PositionRestorer PushPosition(int position)
|
|
|
|
{
|
|
|
|
PositionRestorer restorer = .(this, Position);
|
|
|
|
Position = position;
|
|
|
|
return restorer;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual void Delete()
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
2021-12-09 20:04:17 +01:00
|
|
|
public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
|
|
|
|
{
|
|
|
|
int64 newPos;
|
|
|
|
switch (seekKind)
|
|
|
|
{
|
|
|
|
case .Absolute:
|
|
|
|
newPos = pos;
|
|
|
|
case .FromEnd:
|
|
|
|
newPos = Length + pos;
|
|
|
|
case .Relative:
|
|
|
|
newPos = mPos + pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Matches the behaviour of Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
|
|
|
|
mPos = Math.Max(newPos, 0);
|
|
|
|
if (seekKind == .Absolute && newPos < 0)
|
|
|
|
return .Err;
|
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
public override Result<void> Close()
|
|
|
|
{
|
2021-04-13 09:30:59 +02:00
|
|
|
let ret = base.Close();
|
2021-04-11 07:04:17 -04:00
|
|
|
if (mBfpFile != null)
|
|
|
|
Platform.BfpFile_Release(mBfpFile);
|
2021-04-13 09:30:59 +02:00
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
mBfpFile = null;
|
|
|
|
mFileAccess = default;
|
2021-04-13 09:30:59 +02:00
|
|
|
mBfpFilePos = 0;
|
|
|
|
return ret;
|
2021-04-11 07:04:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
protected override void UpdateLength()
|
|
|
|
{
|
|
|
|
mUnderlyingLength = Platform.BfpFile_GetFileSize(mBfpFile);
|
|
|
|
}
|
|
|
|
|
2021-12-31 10:26:32 -05:00
|
|
|
protected Result<void, FileError> SeekUnderlying(int64 offset, Platform.BfpFileSeekKind seekKind = .Absolute)
|
2021-08-01 17:37:37 -03:00
|
|
|
{
|
|
|
|
int64 newPos = Platform.BfpFile_Seek(mBfpFile, offset, seekKind);
|
2021-12-31 10:26:32 -05:00
|
|
|
Result<void, FileError> result = ((seekKind == .Absolute) && (newPos != offset)) ? .Err(.SeekError) : .Ok;
|
2021-08-01 17:37:37 -03:00
|
|
|
if (result case .Ok)
|
|
|
|
mBfpFilePos = newPos;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
protected override Result<int> TryReadUnderlying(int64 pos, Span<uint8> data)
|
|
|
|
{
|
|
|
|
if (mBfpFilePos != pos)
|
2021-08-01 17:37:37 -03:00
|
|
|
Try!(SeekUnderlying(pos));
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
|
|
|
|
if ((result != .Ok) && (result != .PartialData))
|
|
|
|
return .Err;
|
|
|
|
mBfpFilePos += numBytesRead;
|
|
|
|
return numBytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override Result<int> TryWriteUnderlying(int64 pos, Span<uint8> data)
|
|
|
|
{
|
|
|
|
if (mBfpFilePos != pos)
|
2021-08-01 17:37:37 -03:00
|
|
|
Try!(SeekUnderlying(pos));
|
|
|
|
|
2021-04-11 07:04:17 -04:00
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
int numBytesRead = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
|
|
|
|
if ((result != .Ok) && (result != .PartialData))
|
|
|
|
return .Err;
|
|
|
|
mBfpFilePos += numBytesRead;
|
|
|
|
return numBytesRead;
|
|
|
|
}
|
|
|
|
|
2023-04-17 15:16:19 -07:00
|
|
|
public override Result<int, FileError> TryRead(Span<uint8> data, int timeoutMS)
|
2021-04-11 07:04:17 -04:00
|
|
|
{
|
|
|
|
if (mBfpFilePos != mPos)
|
2021-08-01 17:37:37 -03:00
|
|
|
Try!(SeekUnderlying(mPos));
|
2021-04-11 07:04:17 -04:00
|
|
|
|
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
|
|
|
|
if ((result != .Ok) && (result != .PartialData))
|
2021-12-31 10:26:32 -05:00
|
|
|
{
|
|
|
|
switch (result)
|
|
|
|
{
|
|
|
|
case .Timeout:
|
|
|
|
return .Err(.ReadError(.Timeout));
|
|
|
|
default:
|
|
|
|
return .Err(.ReadError(.Unknown));
|
|
|
|
}
|
|
|
|
}
|
2021-04-11 07:04:17 -04:00
|
|
|
return numBytesRead;
|
|
|
|
}
|
2021-08-01 17:38:30 -03:00
|
|
|
|
|
|
|
public override Result<void> SetLength(int64 length)
|
|
|
|
{
|
|
|
|
Try!(Flush());
|
|
|
|
|
|
|
|
int64 pos = Position;
|
|
|
|
|
|
|
|
if (pos != length || pos != mBfpFilePos)
|
|
|
|
{
|
|
|
|
Try!(SeekUnderlying(length));
|
|
|
|
mPos = length;
|
|
|
|
}
|
|
|
|
|
|
|
|
Platform.BfpFileResult result = .Ok;
|
|
|
|
Platform.BfpFile_Truncate(mBfpFile, &result);
|
|
|
|
if (result != .Ok)
|
|
|
|
{
|
|
|
|
Try!(SeekUnderlying(pos));
|
|
|
|
return .Err;
|
|
|
|
}
|
|
|
|
|
|
|
|
mUnderlyingLength = length;
|
|
|
|
mPos = Math.Min(pos, Length);
|
|
|
|
|
|
|
|
if (pos != length)
|
|
|
|
{
|
|
|
|
if (pos < length)
|
|
|
|
Try!(SeekUnderlying(pos));
|
|
|
|
else
|
|
|
|
Try!(SeekUnderlying(0, .FromEnd));
|
|
|
|
}
|
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
2023-01-13 07:00:11 -05:00
|
|
|
|
|
|
|
public override Result<void> Flush()
|
|
|
|
{
|
|
|
|
var result = base.Flush();
|
|
|
|
if (mBfpFile != null)
|
|
|
|
Platform.BfpFile_Flush(mBfpFile);
|
|
|
|
return result;
|
|
|
|
}
|
2021-04-11 07:04:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
class FileStream : BufferedFileStream
|
|
|
|
{
|
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
}
|