ILuaFileSystem.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. using Lua.Internal;
  2. namespace Lua.IO;
  3. public interface ILuaFileSystem
  4. {
  5. public bool IsReadable(string path);
  6. public ValueTask<LuaFileContent> ReadFileContentAsync(string path, CancellationToken cancellationToken);
  7. public ILuaIOStream? Open(string path, LuaFileOpenMode mode, bool throwError);
  8. public void Rename(string oldName, string newName);
  9. public void Remove(string path);
  10. public string DirectorySeparator { get; }
  11. public string GetTempFileName();
  12. }
  13. public interface ILuaIOStream : IDisposable
  14. {
  15. public ValueTask<string?> ReadLineAsync(CancellationToken cancellationToken);
  16. public ValueTask<string> ReadToEndAsync(CancellationToken cancellationToken);
  17. public ValueTask<string?> ReadStringAsync(int count, CancellationToken cancellationToken);
  18. public ValueTask WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken);
  19. public ValueTask FlushAsync(CancellationToken cancellationToken);
  20. public void SetVBuf(string mode, int size);
  21. public long Seek(long offset, SeekOrigin origin);
  22. public void SetLength(long value);
  23. public bool CanRead { get; }
  24. public bool CanSeek { get; }
  25. public bool CanWrite { get; }
  26. public long Length { get; }
  27. public long Position { get; set; }
  28. }
  29. public sealed class FileSystem : ILuaFileSystem
  30. {
  31. public static readonly FileSystem Instance = new();
  32. public static (FileMode, FileAccess access) GetFileMode(LuaFileOpenMode luaFileOpenMode)
  33. {
  34. return luaFileOpenMode switch
  35. {
  36. LuaFileOpenMode.Read => (FileMode.Open, FileAccess.Read),
  37. LuaFileOpenMode.Write => (FileMode.Create, FileAccess.Write),
  38. LuaFileOpenMode.Append => (FileMode.Append, FileAccess.Write),
  39. LuaFileOpenMode.ReadWriteOpen => (FileMode.Open, FileAccess.ReadWrite),
  40. LuaFileOpenMode.ReadWriteCreate => (FileMode.Create, FileAccess.ReadWrite),
  41. LuaFileOpenMode.ReadAppend => (FileMode.Append, FileAccess.ReadWrite),
  42. _ => throw new ArgumentOutOfRangeException(nameof(luaFileOpenMode), luaFileOpenMode, null)
  43. };
  44. }
  45. public bool IsReadable(string path)
  46. {
  47. if (!File.Exists(path)) return false;
  48. try
  49. {
  50. File.Open(path, FileMode.Open, FileAccess.Read).Dispose();
  51. return true;
  52. }
  53. catch (Exception)
  54. {
  55. return false;
  56. }
  57. }
  58. public ValueTask<LuaFileContent> ReadFileContentAsync(string path, CancellationToken cancellationToken)
  59. {
  60. var bytes = File.ReadAllBytes(path);
  61. return new(new LuaFileContent(bytes));
  62. }
  63. public ILuaIOStream? Open(string path, LuaFileOpenMode luaMode, bool throwError)
  64. {
  65. var (mode, access) = GetFileMode(luaMode);
  66. try
  67. {
  68. return new LuaIOStreamWrapper(File.Open(path, mode, access));
  69. }
  70. catch (Exception)
  71. {
  72. if (throwError)
  73. {
  74. throw;
  75. }
  76. return null;
  77. }
  78. }
  79. public void Rename(string oldName, string newName)
  80. {
  81. if (oldName == newName) return;
  82. File.Move(oldName, newName);
  83. File.Delete(oldName);
  84. }
  85. public void Remove(string path)
  86. {
  87. File.Delete(path);
  88. }
  89. static readonly string directorySeparator = Path.DirectorySeparatorChar.ToString();
  90. public string DirectorySeparator => directorySeparator;
  91. public string GetTempFileName()
  92. {
  93. return Path.GetTempFileName();
  94. }
  95. }
  96. public sealed class LuaIOStreamWrapper(Stream innerStream) : ILuaIOStream
  97. {
  98. StreamReader? reader;
  99. StreamWriter? writer;
  100. public ValueTask<string?> ReadLineAsync(CancellationToken cancellationToken)
  101. {
  102. reader ??= new(innerStream);
  103. return new(reader.ReadLine());
  104. }
  105. public ValueTask<string> ReadToEndAsync(CancellationToken cancellationToken)
  106. {
  107. reader ??= new(innerStream);
  108. return new(reader.ReadToEnd());
  109. }
  110. public ValueTask<string?> ReadStringAsync(int count, CancellationToken cancellationToken)
  111. {
  112. reader ??= new(innerStream);
  113. using var byteBuffer = new PooledArray<char>(count);
  114. var span = byteBuffer.AsSpan();
  115. var ret = reader.Read(span);
  116. if (ret != span.Length)
  117. {
  118. return new(default(string));
  119. }
  120. return new(span.ToString());
  121. }
  122. public ValueTask WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken)
  123. {
  124. writer ??= new(innerStream);
  125. writer.Write(buffer.Span);
  126. return new();
  127. }
  128. public ValueTask FlushAsync(CancellationToken cancellationToken)
  129. {
  130. innerStream.Flush();
  131. return new();
  132. }
  133. public void SetVBuf(string mode, int size)
  134. {
  135. writer ??= new(innerStream);
  136. // Ignore size parameter
  137. writer.AutoFlush = mode is "no" or "line";
  138. }
  139. public long Seek(long offset, SeekOrigin origin) => innerStream.Seek(offset, origin);
  140. public void SetLength(long value) => innerStream.SetLength(value);
  141. public bool CanRead => innerStream.CanRead;
  142. public bool CanSeek => innerStream.CanSeek;
  143. public bool CanWrite => innerStream.CanWrite;
  144. public long Length => innerStream.Length;
  145. public long Position
  146. {
  147. get => innerStream.Position;
  148. set => innerStream.Position = value;
  149. }
  150. public void Dispose() => innerStream.Dispose();
  151. }