mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add some RomFS and IFileStorage documentation.
This commit is contained in:
parent
f8e724fe0b
commit
29d1cd110f
11 changed files with 307 additions and 18 deletions
|
@ -79,6 +79,9 @@ namespace LibHac.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies which operations are available on an <see cref="IFile"/>.
|
||||||
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum OpenMode
|
public enum OpenMode
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,13 +2,38 @@
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interface for enumerating the child entries of a directory.
|
||||||
|
/// </summary>
|
||||||
public interface IDirectory
|
public interface IDirectory
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IFileSystem"/> that contains the current <see cref="IDirectory"/>.
|
||||||
|
/// </summary>
|
||||||
IFileSystem ParentFileSystem { get; }
|
IFileSystem ParentFileSystem { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The full path of the current <see cref="IDirectory"/> in its <see cref="ParentFileSystem"/>.
|
||||||
|
/// </summary>
|
||||||
string FullPath { get; }
|
string FullPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies which types of entries will be enumerated when <see cref="Read"/> is called.
|
||||||
|
/// </summary>
|
||||||
OpenDirectoryMode Mode { get; }
|
OpenDirectoryMode Mode { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerable collection the file system entries of the types specified by
|
||||||
|
/// <see cref="Mode"/> that this directory contains. Does not search subdirectories.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerable collection of file system entries in this directory.</returns>
|
||||||
IEnumerable<DirectoryEntry> Read();
|
IEnumerable<DirectoryEntry> Read();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the number of file system entries of the types specified by
|
||||||
|
/// <see cref="Mode"/> that this directory contains. Does not search subdirectories.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The number of child entries the directory contains.</returns>
|
||||||
int GetEntryCount();
|
int GetEntryCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,13 +2,65 @@
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interface for reading and writing a sequence of bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks><see cref="IFile"/> is similar to <see cref="IStorage"/>, and has a few main differences:
|
||||||
|
///
|
||||||
|
/// - <see cref="IFile"/> allows an <see cref="OpenMode"/> to be set that controls read, write
|
||||||
|
/// and append permissions for the file.
|
||||||
|
///
|
||||||
|
/// - If the <see cref="IFile"/> cannot read or write as many bytes as requested, it will read
|
||||||
|
/// or write as many bytes as it can and return that number of bytes to the caller.
|
||||||
|
///
|
||||||
|
/// - If <see cref="Write"/> is called on an offset past the end of the <see cref="IFile"/>,
|
||||||
|
/// the <see cref="OpenMode.Append"/> mode is set and the file supports expansion,
|
||||||
|
/// the file will be expanded so that it is large enough to contain the written data.</remarks>
|
||||||
public interface IFile : IDisposable
|
public interface IFile : IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The permissions mode for the current file.
|
||||||
|
/// </summary>
|
||||||
OpenMode Mode { get; }
|
OpenMode Mode { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a sequence of bytes from the current <see cref="IFile"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination">The buffer where the read bytes will be stored.
|
||||||
|
/// The number of bytes read will be no larger than the length of the buffer.</param>
|
||||||
|
/// <param name="offset">The offset in the <see cref="IFile"/> at which to begin reading.</param>
|
||||||
|
/// <returns>The total number of bytes read into the buffer. This can be less than the
|
||||||
|
/// size of the buffer if the IFile is too short to fulfill the request.</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> is invalid.</exception>
|
||||||
|
/// <exception cref="NotSupportedException">The file's <see cref="OpenMode"/> does not allow reading.</exception>
|
||||||
int Read(Span<byte> destination, long offset);
|
int Read(Span<byte> destination, long offset);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a sequence of bytes to the current <see cref="IFile"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The buffer containing the bytes to be written.</param>
|
||||||
|
/// <param name="offset">The offset in the <see cref="IStorage"/> at which to begin writing.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> is negative.</exception>
|
||||||
|
/// <exception cref="NotSupportedException">The file's <see cref="OpenMode"/> does not allow this request.</exception>
|
||||||
void Write(ReadOnlySpan<byte> source, long offset);
|
void Write(ReadOnlySpan<byte> source, long offset);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Causes any buffered data to be written to the underlying device.
|
||||||
|
/// </summary>
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of bytes in the file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The length of the file in bytes.</returns>
|
||||||
long GetSize();
|
long GetSize();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the size of the file in bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">The desired size of the file in bytes.</param>
|
||||||
|
/// <exception cref="NotSupportedException">If increasing the file size, The file's
|
||||||
|
/// <see cref="OpenMode"/> does not allow this appending.</exception>
|
||||||
void SetSize(long size);
|
void SetSize(long size);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,23 +1,116 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interface for accessing a file system. <c>/</c> is used as the path delimiter.
|
||||||
|
/// </summary>
|
||||||
public interface IFileSystem
|
public interface IFileSystem
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates all directories and subdirectories in the specified path unless they already exist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the directory to create.</param>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while creating the directory.</exception>
|
||||||
void CreateDirectory(string path);
|
void CreateDirectory(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates or overwrites a file at the specified path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the file to create.</param>
|
||||||
|
/// <param name="size">The initial size of the created file.</param>
|
||||||
|
/// <param name="options">Flags to control how the file is created.
|
||||||
|
/// Should usually be <see cref="CreateFileOptions.None"/></param>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while creating the file.</exception>
|
||||||
void CreateFile(string path, long size, CreateFileOptions options);
|
void CreateFile(string path, long size, CreateFileOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the specified directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the directory to delete.</param>
|
||||||
|
/// <exception cref="DirectoryNotFoundException">The specified directory does not exist.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while deleting the directory.</exception>
|
||||||
void DeleteDirectory(string path);
|
void DeleteDirectory(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the specified file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the file to delete.</param>
|
||||||
|
/// <exception cref="FileNotFoundException">The specified file does not exist.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while deleting the file.</exception>
|
||||||
void DeleteFile(string path);
|
void DeleteFile(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an <see cref="IDirectory"/> instance for enumerating the specified directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The directory's full path.</param>
|
||||||
|
/// <param name="mode">Specifies which sub-entries should be enumerated.</param>
|
||||||
|
/// <returns>An <see cref="IDirectory"/> instance for the specified directory.</returns>
|
||||||
|
/// <exception cref="DirectoryNotFoundException">The specified directory does not exist.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while opening the directory.</exception>
|
||||||
IDirectory OpenDirectory(string path, OpenDirectoryMode mode);
|
IDirectory OpenDirectory(string path, OpenDirectoryMode mode);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens an <see cref="IFile"/> instance for the specified path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the file to open.</param>
|
||||||
|
/// <param name="mode">Specifies the access permissions of the created <see cref="IFile"/>.</param>
|
||||||
|
/// <returns>An <see cref="IFile"/> instance for the specified path.</returns>
|
||||||
|
/// <exception cref="FileNotFoundException">The specified file does not exist.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while deleting the file.</exception>
|
||||||
IFile OpenFile(string path, OpenMode mode);
|
IFile OpenFile(string path, OpenMode mode);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renames or moves a directory to a new location.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="srcPath">The full path of the directory to rename.</param>
|
||||||
|
/// <param name="dstPath">The new full path of the directory.</param>
|
||||||
|
/// <exception cref="DirectoryNotFoundException">The specified directory does not exist.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while deleting the directory.</exception>
|
||||||
void RenameDirectory(string srcPath, string dstPath);
|
void RenameDirectory(string srcPath, string dstPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renames or moves a file to a new location.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="srcPath">The full path of the file to rename.</param>
|
||||||
|
/// <param name="dstPath">The new full path of the file.</param>
|
||||||
|
/// <exception cref="FileNotFoundException">The specified file does not exist.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred while deleting the file.</exception>
|
||||||
void RenameFile(string srcPath, string dstPath);
|
void RenameFile(string srcPath, string dstPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified directory exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the directory to check.</param>
|
||||||
|
/// <returns><see langword="true"/> if the directory exists, otherwise <see langword="false"/>.</returns>
|
||||||
bool DirectoryExists(string path);
|
bool DirectoryExists(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified file exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the file to check.</param>
|
||||||
|
/// <returns><see langword="true"/> if the file exists, otherwise <see langword="false"/>.</returns>
|
||||||
bool FileExists(string path);
|
bool FileExists(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified path is a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path to check.</param>
|
||||||
|
/// <returns>The <see cref="DirectoryEntryType"/> of the file.</returns>
|
||||||
|
/// <exception cref="FileNotFoundException">The specified path does not exist.</exception>
|
||||||
DirectoryEntryType GetEntryType(string path);
|
DirectoryEntryType GetEntryType(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Commits any changes to a transactional file system.
|
||||||
|
/// Does nothing if called on a non-transactional file system.
|
||||||
|
/// </summary>
|
||||||
void Commit();
|
void Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies which types of entries are returned when enumerating an <see cref="IDirectory"/>.
|
||||||
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum OpenDirectoryMode
|
public enum OpenDirectoryMode
|
||||||
{
|
{
|
||||||
|
@ -26,10 +119,16 @@ namespace LibHac.IO
|
||||||
All = Directories | Files
|
All = Directories | Files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional file creation flags.
|
||||||
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum CreateFileOptions
|
public enum CreateFileOptions
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// On a <see cref="ConcatenationFileSystem"/>, creates a concatenation file.
|
||||||
|
/// </summary>
|
||||||
CreateConcatenationFile = 1 << 0
|
CreateConcatenationFile = 1 << 0
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interface for reading and writing a sequence of bytes.
|
||||||
|
/// </summary>
|
||||||
public interface IStorage : IDisposable
|
public interface IStorage : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -9,14 +12,17 @@ namespace LibHac.IO
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="destination">The buffer where the read bytes will be stored.
|
/// <param name="destination">The buffer where the read bytes will be stored.
|
||||||
/// The number of bytes read will be equal to the length of the buffer.</param>
|
/// The number of bytes read will be equal to the length of the buffer.</param>
|
||||||
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin reading from.</param>
|
/// <param name="offset">The offset in the <see cref="IStorage"/> at which to begin reading.</param>
|
||||||
|
/// <exception cref="ArgumentException">Invalid offset or the IStorage contains fewer bytes than requested. </exception>
|
||||||
void Read(Span<byte> destination, long offset);
|
void Read(Span<byte> destination, long offset);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a sequence of bytes to the current <see cref="IStorage"/>.
|
/// Writes a sequence of bytes to the current <see cref="IStorage"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">The buffer containing the bytes to be written.</param>
|
/// <param name="source">The buffer containing the bytes to be written.</param>
|
||||||
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin writing to.</param>
|
/// <param name="offset">The offset in the <see cref="IStorage"/> at which to begin writing.</param>
|
||||||
|
/// <exception cref="ArgumentException">Invalid offset or <paramref name="source"/>
|
||||||
|
/// is too large to be written to the IStorage. </exception>
|
||||||
void Write(ReadOnlySpan<byte> source, long offset);
|
void Write(ReadOnlySpan<byte> source, long offset);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System.IO;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
|
@ -145,9 +144,6 @@ namespace LibHac.IO
|
||||||
throw new FileNotFoundException(path);
|
throw new FileNotFoundException(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Commit()
|
public void Commit() { }
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ namespace LibHac.IO
|
||||||
public void DeleteFile(string path) => throw new NotSupportedException();
|
public void DeleteFile(string path) => throw new NotSupportedException();
|
||||||
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
||||||
public void RenameFile(string srcPath, string dstPath) => throw new NotSupportedException();
|
public void RenameFile(string srcPath, string dstPath) => throw new NotSupportedException();
|
||||||
public void Commit() => throw new NotSupportedException();
|
public void Commit() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PartitionFileSystemType
|
public enum PartitionFileSystemType
|
||||||
|
|
|
@ -5,11 +5,34 @@ using System.Text;
|
||||||
|
|
||||||
namespace LibHac.IO.RomFs
|
namespace LibHac.IO.RomFs
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the file table used by the RomFS format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This file table stores the structure of the file tree in a RomFS.
|
||||||
|
/// Each file or directory entry is stored in the table using its full path as a key.
|
||||||
|
/// Once added, a file or directory is assigned an ID that can also be used to retrieve it.
|
||||||
|
/// Each file entry contains the size of the file and its offset in the RomFS.
|
||||||
|
/// Each directory entry contains the IDs for its first child file and first child directory.
|
||||||
|
///
|
||||||
|
/// The table is represented by four byte arrays. Two of the arrays contain the hash buckets and
|
||||||
|
/// entries for the files, and the other two for the directories.
|
||||||
|
///
|
||||||
|
/// Once all files have been added to the table, <see cref="TrimExcess"/> should be called
|
||||||
|
/// to optimize the size of the table.
|
||||||
|
/// </remarks>
|
||||||
public class HierarchicalRomFileTable
|
public class HierarchicalRomFileTable
|
||||||
{
|
{
|
||||||
private RomFsDictionary<FileRomEntry> FileTable { get; }
|
private RomFsDictionary<FileRomEntry> FileTable { get; }
|
||||||
private RomFsDictionary<DirectoryRomEntry> DirectoryTable { get; }
|
private RomFsDictionary<DirectoryRomEntry> DirectoryTable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a <see cref="HierarchicalRomFileTable"/> from an existing table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dirHashTable"></param>
|
||||||
|
/// <param name="dirEntryTable"></param>
|
||||||
|
/// <param name="fileHashTable"></param>
|
||||||
|
/// <param name="fileEntryTable"></param>
|
||||||
public HierarchicalRomFileTable(IStorage dirHashTable, IStorage dirEntryTable, IStorage fileHashTable,
|
public HierarchicalRomFileTable(IStorage dirHashTable, IStorage dirEntryTable, IStorage fileHashTable,
|
||||||
IStorage fileEntryTable)
|
IStorage fileEntryTable)
|
||||||
{
|
{
|
||||||
|
@ -17,8 +40,18 @@ namespace LibHac.IO.RomFs
|
||||||
DirectoryTable = new RomFsDictionary<DirectoryRomEntry>(dirHashTable, dirEntryTable);
|
DirectoryTable = new RomFsDictionary<DirectoryRomEntry>(dirHashTable, dirEntryTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new <see cref="HierarchicalRomFileTable"/> that has the default initial capacity.
|
||||||
|
/// </summary>
|
||||||
public HierarchicalRomFileTable() : this(0, 0) { }
|
public HierarchicalRomFileTable() : this(0, 0) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new <see cref="HierarchicalRomFileTable"/> that has the specified initial capacity.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="directoryCapacity">The initial number of directories that the
|
||||||
|
/// <see cref="HierarchicalRomFileTable"/> can contain.</param>
|
||||||
|
/// <param name="fileCapacity">The initial number of files that the
|
||||||
|
/// <see cref="HierarchicalRomFileTable"/> can contain.</param>
|
||||||
public HierarchicalRomFileTable(int directoryCapacity, int fileCapacity)
|
public HierarchicalRomFileTable(int directoryCapacity, int fileCapacity)
|
||||||
{
|
{
|
||||||
FileTable = new RomFsDictionary<FileRomEntry>(fileCapacity);
|
FileTable = new RomFsDictionary<FileRomEntry>(fileCapacity);
|
||||||
|
@ -73,6 +106,13 @@ namespace LibHac.IO.RomFs
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens a directory for enumeration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the directory to open.</param>
|
||||||
|
/// <param name="position">The initial position of the directory enumerator.</param>
|
||||||
|
/// <returns><see langword="true"/> if the table contains a directory with the specified path;
|
||||||
|
/// otherwise, <see langword="false"/>.</returns>
|
||||||
public bool TryOpenDirectory(string path, out FindPosition position)
|
public bool TryOpenDirectory(string path, out FindPosition position)
|
||||||
{
|
{
|
||||||
FindDirectoryRecursive(GetUtf8Bytes(path), out RomEntryKey key);
|
FindDirectoryRecursive(GetUtf8Bytes(path), out RomEntryKey key);
|
||||||
|
@ -87,6 +127,13 @@ namespace LibHac.IO.RomFs
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens a directory for enumeration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="directoryId">The ID of the directory to open.</param>
|
||||||
|
/// <param name="position">When this method returns, contains the initial position of the directory enumerator.</param>
|
||||||
|
/// <returns><see langword="true"/> if the table contains a directory with the specified path;
|
||||||
|
/// otherwise, <see langword="false"/>.</returns>
|
||||||
public bool TryOpenDirectory(int directoryId, out FindPosition position)
|
public bool TryOpenDirectory(int directoryId, out FindPosition position)
|
||||||
{
|
{
|
||||||
if (DirectoryTable.TryGetValue(directoryId, out RomKeyValuePair<DirectoryRomEntry> keyValuePair))
|
if (DirectoryTable.TryGetValue(directoryId, out RomKeyValuePair<DirectoryRomEntry> keyValuePair))
|
||||||
|
@ -99,6 +146,15 @@ namespace LibHac.IO.RomFs
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the next file in a directory and updates the enumerator's position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">The current position of the directory enumerator.
|
||||||
|
/// This position will be updated when the method returns.</param>
|
||||||
|
/// <param name="info">When this method returns, contains the file's metadata.</param>
|
||||||
|
/// <param name="name">When this method returns, contains the file's name (Not the full path).</param>
|
||||||
|
/// <returns><see langword="true"/> if the next file was successfully returned.
|
||||||
|
/// <see langword="false"/> if there are no more files to enumerate.</returns>
|
||||||
public bool FindNextFile(ref FindPosition position, out RomFileInfo info, out string name)
|
public bool FindNextFile(ref FindPosition position, out RomFileInfo info, out string name)
|
||||||
{
|
{
|
||||||
if (position.NextFile == -1)
|
if (position.NextFile == -1)
|
||||||
|
@ -117,6 +173,14 @@ namespace LibHac.IO.RomFs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the next child directory in a directory and updates the enumerator's position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">The current position of the directory enumerator.
|
||||||
|
/// This position will be updated when the method returns.</param>
|
||||||
|
/// <param name="name">When this method returns, contains the directory's name (Not the full path).</param>
|
||||||
|
/// <returns><see langword="true"/> if the next directory was successfully returned.
|
||||||
|
/// <see langword="false"/> if there are no more directories to enumerate.</returns>
|
||||||
public bool FindNextDirectory(ref FindPosition position, out string name)
|
public bool FindNextDirectory(ref FindPosition position, out string name)
|
||||||
{
|
{
|
||||||
if (position.NextDirectory == -1)
|
if (position.NextDirectory == -1)
|
||||||
|
@ -132,7 +196,13 @@ namespace LibHac.IO.RomFs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, ref RomFileInfo fileInfo)
|
/// <summary>
|
||||||
|
/// Adds a file to the file table. If the file already exists
|
||||||
|
/// its <see cref="RomFileInfo"/> will be updated.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the file to be added.</param>
|
||||||
|
/// <param name="fileInfo">The file information to be stored.</param>
|
||||||
|
public void AddFile(string path, ref RomFileInfo fileInfo)
|
||||||
{
|
{
|
||||||
path = PathTools.Normalize(path);
|
path = PathTools.Normalize(path);
|
||||||
ReadOnlySpan<byte> pathBytes = GetUtf8Bytes(path);
|
ReadOnlySpan<byte> pathBytes = GetUtf8Bytes(path);
|
||||||
|
@ -140,13 +210,25 @@ namespace LibHac.IO.RomFs
|
||||||
CreateFileRecursiveInternal(pathBytes, ref fileInfo);
|
CreateFileRecursiveInternal(pathBytes, ref fileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateDirectory(string path)
|
/// <summary>
|
||||||
|
/// Adds a directory to the file table. If the directory already exists,
|
||||||
|
/// no action is performed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the directory to be added.</param>
|
||||||
|
public void AddDirectory(string path)
|
||||||
{
|
{
|
||||||
path = PathTools.Normalize(path);
|
path = PathTools.Normalize(path);
|
||||||
|
|
||||||
CreateDirectoryRecursive(GetUtf8Bytes(path));
|
CreateDirectoryRecursive(GetUtf8Bytes(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the capacity of this dictionary to what it would be if
|
||||||
|
/// it had been originally initialized with all its entries.
|
||||||
|
///
|
||||||
|
/// This method can be used to minimize the memory overhead
|
||||||
|
/// once it is known that no new elements will be added.
|
||||||
|
/// </summary>
|
||||||
public void TrimExcess()
|
public void TrimExcess()
|
||||||
{
|
{
|
||||||
DirectoryTable.TrimExcess();
|
DirectoryTable.TrimExcess();
|
||||||
|
@ -263,9 +345,9 @@ namespace LibHac.IO.RomFs
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ref FileRomEntry entry = ref FileTable.AddOrGet(ref key, out int offset, out _, out _);
|
ref FileRomEntry entry = ref FileTable.AddOrGet(ref key, out int offset, out bool alreadyExists, out _);
|
||||||
entry.NextSibling = -1;
|
|
||||||
entry.Info = fileInfo;
|
entry.Info = fileInfo;
|
||||||
|
if (alreadyExists) entry.NextSibling = -1;
|
||||||
|
|
||||||
ref DirectoryRomEntry parent = ref DirectoryTable.GetValueReference(prevOffset);
|
ref DirectoryRomEntry parent = ref DirectoryTable.GetValueReference(prevOffset);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,12 @@ using System.Linq;
|
||||||
|
|
||||||
namespace LibHac.IO.RomFs
|
namespace LibHac.IO.RomFs
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a RomFS from a collection of files.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>A <see cref="RomFsBuilder"/> produces a view of a RomFS archive.
|
||||||
|
/// When doing so, it will create an <see cref="IStorage"/> instance that will
|
||||||
|
/// provide the RomFS data when read. Random seek is supported.</remarks>
|
||||||
public class RomFsBuilder
|
public class RomFsBuilder
|
||||||
{
|
{
|
||||||
private const int FileAlignment = 0x10;
|
private const int FileAlignment = 0x10;
|
||||||
|
@ -15,8 +21,15 @@ namespace LibHac.IO.RomFs
|
||||||
private HierarchicalRomFileTable FileTable { get; } = new HierarchicalRomFileTable();
|
private HierarchicalRomFileTable FileTable { get; } = new HierarchicalRomFileTable();
|
||||||
private long CurrentOffset { get; set; }
|
private long CurrentOffset { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new, empty <see cref="RomFsBuilder"/>
|
||||||
|
/// </summary>
|
||||||
public RomFsBuilder() { }
|
public RomFsBuilder() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="RomFsBuilder"/> and populates it with all
|
||||||
|
/// the files in the specified <see cref="IFileSystem"/>.
|
||||||
|
/// </summary>
|
||||||
public RomFsBuilder(IFileSystem input)
|
public RomFsBuilder(IFileSystem input)
|
||||||
{
|
{
|
||||||
foreach (DirectoryEntry file in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
foreach (DirectoryEntry file in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
||||||
|
@ -26,6 +39,11 @@ namespace LibHac.IO.RomFs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a file to the RomFS.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path in the RomFS</param>
|
||||||
|
/// <param name="file">An <see cref="IFile"/> of the file data to add.</param>
|
||||||
public void AddFile(string path, IFile file)
|
public void AddFile(string path, IFile file)
|
||||||
{
|
{
|
||||||
var fileInfo = new RomFileInfo();
|
var fileInfo = new RomFileInfo();
|
||||||
|
@ -43,9 +61,15 @@ namespace LibHac.IO.RomFs
|
||||||
var padding = new NullStorage(CurrentOffset - newOffset);
|
var padding = new NullStorage(CurrentOffset - newOffset);
|
||||||
Sources.Add(padding);
|
Sources.Add(padding);
|
||||||
|
|
||||||
FileTable.CreateFile(path, ref fileInfo);
|
FileTable.AddFile(path, ref fileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a view of a RomFS containing all the currently added files.
|
||||||
|
/// Additional files may be added and a new view produced without
|
||||||
|
/// invalidating previously built RomFS views.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public IStorage Build()
|
public IStorage Build()
|
||||||
{
|
{
|
||||||
FileTable.TrimExcess();
|
FileTable.TrimExcess();
|
||||||
|
|
|
@ -46,10 +46,15 @@ namespace LibHac.IO.RomFs
|
||||||
public long Length;
|
public long Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the current position when enumerating a directory's contents.
|
||||||
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct FindPosition
|
public struct FindPosition
|
||||||
{
|
{
|
||||||
|
/// <summary>The ID of the next directory to be enumerated.</summary>
|
||||||
public int NextDirectory;
|
public int NextDirectory;
|
||||||
|
/// <summary>The ID of the next file to be enumerated.</summary>
|
||||||
public int NextFile;
|
public int NextFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,10 +34,7 @@ namespace LibHac.IO.RomFs
|
||||||
throw new FileNotFoundException(path);
|
throw new FileNotFoundException(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Commit()
|
public void Commit() { }
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDirectory OpenDirectory(string path, OpenDirectoryMode mode)
|
public IDirectory OpenDirectory(string path, OpenDirectoryMode mode)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue