mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add StreamFile. Make sure LocalFile closes the base file
This commit is contained in:
parent
01a3bef903
commit
3db2c81b77
9 changed files with 157 additions and 25 deletions
|
@ -44,7 +44,8 @@ namespace LibHac.IO
|
|||
|
||||
private long GetAesXtsFileSize(string path)
|
||||
{
|
||||
IFile file = BaseFileSystem.OpenFile(path, OpenMode.Read);
|
||||
using (IFile file = BaseFileSystem.OpenFile(path, OpenMode.Read))
|
||||
{
|
||||
var buffer = new byte[8];
|
||||
|
||||
file.Read(buffer, 0);
|
||||
|
@ -54,4 +55,5 @@ namespace LibHac.IO
|
|||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace LibHac.IO
|
|||
|
||||
public void CreateDirectory(string path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
BaseFileSystem.CreateDirectory(path);
|
||||
}
|
||||
|
||||
public void CreateFile(string path, long size)
|
||||
|
@ -38,12 +38,12 @@ namespace LibHac.IO
|
|||
|
||||
public void DeleteDirectory(string path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
BaseFileSystem.DeleteDirectory(path);
|
||||
}
|
||||
|
||||
public void DeleteFile(string path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
BaseFileSystem.DeleteFile(path);
|
||||
}
|
||||
|
||||
public IDirectory OpenDirectory(string path, OpenDirectoryMode mode)
|
||||
|
@ -77,17 +77,17 @@ namespace LibHac.IO
|
|||
|
||||
public bool DirectoryExists(string path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return BaseFileSystem.DirectoryExists(path);
|
||||
}
|
||||
|
||||
public bool FileExists(string path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return BaseFileSystem.FileExists(path);
|
||||
}
|
||||
|
||||
public void Commit()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
BaseFileSystem.Commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace LibHac.IO
|
|||
private IFile[] Sources { get; }
|
||||
private long SplitFileSize { get; }
|
||||
|
||||
public ConcatenationFile(IList<IFile> sources, long splitFileSize, OpenMode mode)
|
||||
internal ConcatenationFile(IList<IFile> sources, long splitFileSize, OpenMode mode)
|
||||
{
|
||||
Sources = sources.ToArray();
|
||||
SplitFileSize = splitFileSize;
|
||||
|
@ -22,6 +22,8 @@ namespace LibHac.IO
|
|||
throw new ArgumentException($"Source file must have size {splitFileSize}");
|
||||
}
|
||||
}
|
||||
|
||||
ToDispose.AddRange(Sources);
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> destination, long offset)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LibHac.IO
|
||||
{
|
||||
public abstract class FileBase : IFile
|
||||
{
|
||||
private bool _isDisposed;
|
||||
protected List<IDisposable> ToDispose { get; } = new List<IDisposable>();
|
||||
|
||||
public abstract int Read(Span<byte> destination, long offset);
|
||||
public abstract void Write(ReadOnlySpan<byte> source, long offset);
|
||||
|
@ -12,7 +14,7 @@ namespace LibHac.IO
|
|||
public abstract long GetSize();
|
||||
public abstract void SetSize(long size);
|
||||
|
||||
protected OpenMode Mode { get; set; }
|
||||
public OpenMode Mode { get; protected set; }
|
||||
|
||||
protected int ValidateReadParamsAndGetSize(ReadOnlySpan<byte> span, long offset)
|
||||
{
|
||||
|
@ -66,6 +68,11 @@ namespace LibHac.IO
|
|||
if (disposing)
|
||||
{
|
||||
Flush();
|
||||
|
||||
foreach (IDisposable item in ToDispose)
|
||||
{
|
||||
item?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
|
|
|
@ -98,8 +98,10 @@ namespace LibHac.IO
|
|||
}
|
||||
}
|
||||
|
||||
public static Stream AsStream(this IFile storage) => new NxFileStream(storage, true);
|
||||
public static Stream AsStream(this IFile storage, bool keepOpen) => new NxFileStream(storage, keepOpen);
|
||||
public static Stream AsStream(this IFile file) => new NxFileStream(file, true);
|
||||
public static Stream AsStream(this IFile file, bool keepOpen) => new NxFileStream(file, keepOpen);
|
||||
|
||||
public static IFile AsIFile(this Stream stream, OpenMode mode) => new StreamFile(stream, mode);
|
||||
|
||||
public static int GetEntryCount(this IFileSystem fs, OpenDirectoryMode mode)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace LibHac.IO
|
|||
{
|
||||
public interface IFile : IDisposable
|
||||
{
|
||||
OpenMode Mode { get; }
|
||||
int Read(Span<byte> destination, long offset);
|
||||
void Write(ReadOnlySpan<byte> source, long offset);
|
||||
void Flush();
|
||||
|
|
|
@ -6,20 +6,25 @@ namespace LibHac.IO
|
|||
public class LocalFile : FileBase
|
||||
{
|
||||
private string Path { get; }
|
||||
private StreamStorage Storage { get; }
|
||||
private FileStream Stream { get; }
|
||||
private StreamFile File { get; }
|
||||
|
||||
public LocalFile(string path, OpenMode mode)
|
||||
{
|
||||
Path = path;
|
||||
Mode = mode;
|
||||
Storage = new StreamStorage(new FileStream(Path, FileMode.Open), false);
|
||||
Stream = new FileStream(Path, FileMode.Open, GetFileAccess(mode));
|
||||
File = new StreamFile(Stream, mode);
|
||||
|
||||
ToDispose.Add(File);
|
||||
ToDispose.Add(Stream);
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> destination, long offset)
|
||||
{
|
||||
int toRead = ValidateReadParamsAndGetSize(destination, offset);
|
||||
|
||||
Storage.Read(destination.Slice(0, toRead), offset);
|
||||
File.Read(destination.Slice(0, toRead), offset);
|
||||
|
||||
return toRead;
|
||||
}
|
||||
|
@ -28,22 +33,28 @@ namespace LibHac.IO
|
|||
{
|
||||
ValidateWriteParams(source, offset);
|
||||
|
||||
Storage.Write(source, offset);
|
||||
File.Write(source, offset);
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
Storage.Flush();
|
||||
File.Flush();
|
||||
}
|
||||
|
||||
public override long GetSize()
|
||||
{
|
||||
return Storage.Length;
|
||||
return File.GetSize();
|
||||
}
|
||||
|
||||
public override void SetSize(long size)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
File.SetSize(size);
|
||||
}
|
||||
|
||||
private static FileAccess GetFileAccess(OpenMode mode)
|
||||
{
|
||||
// FileAccess and OpenMode have the same flags
|
||||
return (FileAccess)(mode & OpenMode.ReadWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,9 +60,9 @@ namespace LibHac.IO
|
|||
}
|
||||
|
||||
// todo access
|
||||
public override bool CanRead => true;
|
||||
public override bool CanRead => BaseFile.Mode.HasFlag(OpenMode.Read);
|
||||
public override bool CanSeek => true;
|
||||
public override bool CanWrite => true;
|
||||
public override bool CanWrite => BaseFile.Mode.HasFlag(OpenMode.Write);
|
||||
public override long Length { get; }
|
||||
public override long Position { get; set; }
|
||||
|
||||
|
|
107
src/LibHac/IO/StreamFile.cs
Normal file
107
src/LibHac/IO/StreamFile.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
#if !STREAM_SPAN
|
||||
using System.Buffers;
|
||||
#endif
|
||||
|
||||
namespace LibHac.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an <see cref="IFile"/> interface for interacting with a <see cref="Stream"/>
|
||||
/// </summary>
|
||||
public class StreamFile : FileBase
|
||||
{
|
||||
private Stream BaseStream { get; }
|
||||
private object Locker { get; } = new object();
|
||||
|
||||
public StreamFile(Stream baseStream, OpenMode mode)
|
||||
{
|
||||
BaseStream = baseStream;
|
||||
Mode = mode;
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> destination, long offset)
|
||||
{
|
||||
#if STREAM_SPAN
|
||||
lock (Locker)
|
||||
{
|
||||
if (BaseStream.Position != offset)
|
||||
{
|
||||
BaseStream.Position = offset;
|
||||
}
|
||||
|
||||
return BaseStream.Read(destination);
|
||||
}
|
||||
#else
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(destination.Length);
|
||||
try
|
||||
{
|
||||
int bytesRead;
|
||||
lock (Locker)
|
||||
{
|
||||
if (BaseStream.Position != offset)
|
||||
{
|
||||
BaseStream.Position = offset;
|
||||
}
|
||||
|
||||
bytesRead = BaseStream.Read(buffer, 0, destination.Length);
|
||||
}
|
||||
|
||||
new Span<byte>(buffer, 0, destination.Length).CopyTo(destination);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
finally { ArrayPool<byte>.Shared.Return(buffer); }
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> source, long offset)
|
||||
{
|
||||
#if STREAM_SPAN
|
||||
lock (Locker)
|
||||
{
|
||||
BaseStream.Position = offset;
|
||||
BaseStream.Write(source);
|
||||
}
|
||||
#else
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(source.Length);
|
||||
try
|
||||
{
|
||||
source.CopyTo(buffer);
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
BaseStream.Position = offset;
|
||||
BaseStream.Write(buffer, 0, source.Length);
|
||||
}
|
||||
}
|
||||
finally { ArrayPool<byte>.Shared.Return(buffer); }
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
BaseStream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public override long GetSize()
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
return BaseStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetSize(long size)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
BaseStream.SetLength(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue