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,14 +44,16 @@ namespace LibHac.IO
|
||||||
|
|
||||||
private long GetAesXtsFileSize(string path)
|
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];
|
{
|
||||||
|
var buffer = new byte[8];
|
||||||
|
|
||||||
file.Read(buffer, 0);
|
file.Read(buffer, 0);
|
||||||
if (BitConverter.ToUInt32(buffer, 0) != 0x3058414E) return 0;
|
if (BitConverter.ToUInt32(buffer, 0) != 0x3058414E) return 0;
|
||||||
|
|
||||||
file.Read(buffer, 0x48);
|
file.Read(buffer, 0x48);
|
||||||
return BitConverter.ToInt32(buffer, 0);
|
return BitConverter.ToInt32(buffer, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace LibHac.IO
|
||||||
|
|
||||||
public void CreateDirectory(string path)
|
public void CreateDirectory(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
BaseFileSystem.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size)
|
||||||
|
@ -38,12 +38,12 @@ namespace LibHac.IO
|
||||||
|
|
||||||
public void DeleteDirectory(string path)
|
public void DeleteDirectory(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
BaseFileSystem.DeleteDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteFile(string path)
|
public void DeleteFile(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
BaseFileSystem.DeleteFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDirectory OpenDirectory(string path, OpenDirectoryMode mode)
|
public IDirectory OpenDirectory(string path, OpenDirectoryMode mode)
|
||||||
|
@ -77,17 +77,17 @@ namespace LibHac.IO
|
||||||
|
|
||||||
public bool DirectoryExists(string path)
|
public bool DirectoryExists(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return BaseFileSystem.DirectoryExists(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool FileExists(string path)
|
public bool FileExists(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return BaseFileSystem.FileExists(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Commit()
|
public void Commit()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
BaseFileSystem.Commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace LibHac.IO
|
||||||
private IFile[] Sources { get; }
|
private IFile[] Sources { get; }
|
||||||
private long SplitFileSize { 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();
|
Sources = sources.ToArray();
|
||||||
SplitFileSize = splitFileSize;
|
SplitFileSize = splitFileSize;
|
||||||
|
@ -22,6 +22,8 @@ namespace LibHac.IO
|
||||||
throw new ArgumentException($"Source file must have size {splitFileSize}");
|
throw new ArgumentException($"Source file must have size {splitFileSize}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToDispose.AddRange(Sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Read(Span<byte> destination, long offset)
|
public override int Read(Span<byte> destination, long offset)
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public abstract class FileBase : IFile
|
public abstract class FileBase : IFile
|
||||||
{
|
{
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
|
protected List<IDisposable> ToDispose { get; } = new List<IDisposable>();
|
||||||
|
|
||||||
public abstract int Read(Span<byte> destination, long offset);
|
public abstract int Read(Span<byte> destination, long offset);
|
||||||
public abstract void Write(ReadOnlySpan<byte> source, long offset);
|
public abstract void Write(ReadOnlySpan<byte> source, long offset);
|
||||||
|
@ -12,7 +14,7 @@ namespace LibHac.IO
|
||||||
public abstract long GetSize();
|
public abstract long GetSize();
|
||||||
public abstract void SetSize(long size);
|
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)
|
protected int ValidateReadParamsAndGetSize(ReadOnlySpan<byte> span, long offset)
|
||||||
{
|
{
|
||||||
|
@ -66,6 +68,11 @@ namespace LibHac.IO
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
|
foreach (IDisposable item in ToDispose)
|
||||||
|
{
|
||||||
|
item?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isDisposed = true;
|
_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 file) => new NxFileStream(file, true);
|
||||||
public static Stream AsStream(this IFile storage, bool keepOpen) => new NxFileStream(storage, keepOpen);
|
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)
|
public static int GetEntryCount(this IFileSystem fs, OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public interface IFile : IDisposable
|
public interface IFile : IDisposable
|
||||||
{
|
{
|
||||||
|
OpenMode Mode { get; }
|
||||||
int Read(Span<byte> destination, long offset);
|
int Read(Span<byte> destination, long offset);
|
||||||
void Write(ReadOnlySpan<byte> source, long offset);
|
void Write(ReadOnlySpan<byte> source, long offset);
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
|
@ -6,20 +6,25 @@ namespace LibHac.IO
|
||||||
public class LocalFile : FileBase
|
public class LocalFile : FileBase
|
||||||
{
|
{
|
||||||
private string Path { get; }
|
private string Path { get; }
|
||||||
private StreamStorage Storage { get; }
|
private FileStream Stream { get; }
|
||||||
|
private StreamFile File { get; }
|
||||||
|
|
||||||
public LocalFile(string path, OpenMode mode)
|
public LocalFile(string path, OpenMode mode)
|
||||||
{
|
{
|
||||||
Path = path;
|
Path = path;
|
||||||
Mode = mode;
|
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)
|
public override int Read(Span<byte> destination, long offset)
|
||||||
{
|
{
|
||||||
int toRead = ValidateReadParamsAndGetSize(destination, offset);
|
int toRead = ValidateReadParamsAndGetSize(destination, offset);
|
||||||
|
|
||||||
Storage.Read(destination.Slice(0, toRead), offset);
|
File.Read(destination.Slice(0, toRead), offset);
|
||||||
|
|
||||||
return toRead;
|
return toRead;
|
||||||
}
|
}
|
||||||
|
@ -28,22 +33,28 @@ namespace LibHac.IO
|
||||||
{
|
{
|
||||||
ValidateWriteParams(source, offset);
|
ValidateWriteParams(source, offset);
|
||||||
|
|
||||||
Storage.Write(source, offset);
|
File.Write(source, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
{
|
{
|
||||||
Storage.Flush();
|
File.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override long GetSize()
|
public override long GetSize()
|
||||||
{
|
{
|
||||||
return Storage.Length;
|
return File.GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetSize(long size)
|
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
|
// todo access
|
||||||
public override bool CanRead => true;
|
public override bool CanRead => BaseFile.Mode.HasFlag(OpenMode.Read);
|
||||||
public override bool CanSeek => true;
|
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 Length { get; }
|
||||||
public override long Position { get; set; }
|
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