123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- using System;
- using System.IO;
- using Godot;
- namespace TBL.GodotSharp.IO.File
- {
- /// <summary>
- /// Wrapper for <see cref="Godot.File"/> that allows it to be used as a <see cref="System.IO.Stream"/>.
- /// </summary>
- /// <remarks>
- /// Use this if really necessary, but prefer to use .NET's built in IO classes as they will be quite a bit faster.
- /// If you need to convert a godot path to an absolute one, use <see cref="ProjectSettings.GlobalizePath(string)"/>.
- /// </remarks>
- public class GodotFileStream : Stream
- {
- private Godot.File _file;
- private Godot.File.ModeFlags _flags;
- /// <summary>
- /// Create a new instance of the <see cref="GodotFileStream"/> class.
- /// </summary>
- /// <param name="path">The path to the file to open. This accepts Godot-style <code>user://</code> and <code>res://</code> paths.</param>
- /// <param name="flags">File flags.</param>
- /// <param name="compressionMode">If not null, this will enable compression/decompression.</param>
- public GodotFileStream(string path, Godot.File.ModeFlags flags,
- Godot.File.CompressionMode? compressionMode = null)
- {
- if (path == null)
- throw new ArgumentNullException("path");
- _file = new Godot.File();
- _flags = flags;
- Error result;
- if (compressionMode.HasValue)
- {
- result = _file.OpenCompressed(path, flags, compressionMode.Value);
- }
- else
- {
- result = _file.Open(path, flags);
- }
- if (result != Error.Ok)
- {
- throw new IOException($"Unable to open \"{path}\": {result}");
- }
- }
- public override bool CanRead => _flags == Godot.File.ModeFlags.Read ||
- _flags == Godot.File.ModeFlags.ReadWrite ||
- _flags == Godot.File.ModeFlags.WriteRead;
- public override bool CanSeek => true;
- public override bool CanWrite => _flags == Godot.File.ModeFlags.Write ||
- _flags == Godot.File.ModeFlags.ReadWrite ||
- _flags == Godot.File.ModeFlags.WriteRead;
- public override long Length => checked((long)_file.GetLen());
- public override long Position
- {
- get => checked((long)_file.GetPosition());
- set => _file.Seek(value);
- }
- public override void Flush()
- {
- _file.Flush();
- }
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (!_file.IsOpen())
- throw new ObjectDisposedException("File has been closed");
- if (!CanRead)
- throw new NotSupportedException($"Cannot Read on a GodotFileStream with flags {_flags}");
- if (count < 0)
- throw new ArgumentOutOfRangeException("count");
- if (offset < 0)
- throw new ArgumentOutOfRangeException("offset");
- if (count + offset > buffer.Length)
- throw new ArgumentException("count + offset is greater than the given buffer length");
- var data = _file.GetBuffer(count);
- if (_file.GetError() != Error.Ok)
- throw new IOException($"Error reading file: {_file.GetError()}");
- Array.Copy(data, 0, buffer, offset, data.Length);
- return data.Length;
- }
- public override long Seek(long offset, SeekOrigin origin)
- {
- if (!_file.IsOpen())
- throw new ObjectDisposedException("File has been closed");
- switch (origin)
- {
- case SeekOrigin.Begin:
- _file.Seek(offset);
- break;
- case SeekOrigin.Current:
- _file.Seek(checked((long)_file.GetPosition()) + offset);
- break;
- case SeekOrigin.End:
- _file.SeekEnd(offset);
- break;
- }
- if (_file.GetError() != Error.Ok)
- throw new IOException($"Error seeking file: {_file.GetError()}");
- return checked((long)_file.GetPosition());
- }
- public override void SetLength(long value)
- {
- throw new NotSupportedException("GodotFileStream does not support SetLength");
- }
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (!_file.IsOpen())
- throw new ObjectDisposedException("File has been closed");
- if (!CanWrite)
- throw new NotSupportedException($"Cannot Write on a GodotFileStream with flags {_flags}");
- if (count < 0)
- throw new ArgumentOutOfRangeException("count");
- if (offset < 0)
- throw new ArgumentOutOfRangeException("offset");
- if (count + offset > buffer.Length)
- throw new ArgumentException("count + offset is greater than the given buffer length");
- var data = new byte[count];
- Array.Copy(buffer, offset, data, 0, count);
- _file.StoreBuffer(data);
- if (_file.GetError() != Error.Ok)
- throw new IOException($"Error writing file: {_file.GetError()}");
- }
- protected override void Dispose(bool disposing)
- {
- _file.Close();
- }
- }
- }
|