Messing around

This commit is contained in:
Alex Barney 2018-12-24 17:53:14 -07:00
parent bb6c73014b
commit 2bf6613165
11 changed files with 417 additions and 0 deletions

View file

@ -0,0 +1,22 @@
namespace LibHac.IO
{
public class DirectoryEntry
{
public string Name { get; }
public DirectoryEntryType Type { get; }
public long Size { get; }
public DirectoryEntry(string name, DirectoryEntryType type, long size)
{
Name = name;
Type = type;
Size = size;
}
}
public enum DirectoryEntryType
{
Directory,
File
}
}

View file

@ -0,0 +1,7 @@
namespace LibHac.IO
{
public class HierarchicalRomFileTable
{
}
}

View file

@ -0,0 +1,10 @@
namespace LibHac.IO
{
public interface IDirectory
{
IFileSystem ParentFileSystem { get; }
DirectoryEntry[] Read();
int GetEntryCount();
}
}

13
src/LibHac/IO/IFile.cs Normal file
View file

@ -0,0 +1,13 @@
using System;
namespace LibHac.IO
{
public interface IFile
{
void Read(Span<byte> destination, long offset);
void Write(ReadOnlySpan<byte> source, long offset);
void Flush();
long GetSize();
long SetSize();
}
}

View file

@ -0,0 +1,17 @@
namespace LibHac.IO
{
public interface IFileSystem
{
void Commit();
void CreateDirectory(string path);
void CreateFile(string path, long size);
void DeleteDirectory(string path);
void DeleteFile(string path);
IDirectory OpenDirectory(string path);
IFile OpenFile(string path);
void RenameDirectory(string srcPath, string dstPath);
void RenameFile(string srcPath, string dstPath);
bool DirectoryExists(string path);
bool FileExists(string path);
}
}

View file

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace LibHac.IO
{
public static class IFileSystemExtensions
{
public static void Extract(this IFileSystem fs, string outDir)
{
var root = fs.OpenDirectory("/");
foreach (var filename in root.EnumerateFiles())
{
//Console.WriteLine(filename);
IFile file = fs.OpenFile(filename);
string outPath = Path.Combine(outDir, filename.TrimStart('/'));
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
using (var outFile = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
{
file.CopyTo(outFile);
}
}
}
public static IEnumerable<string> EnumerateFiles(this IDirectory directory)
{
var entries = directory.Read();
foreach (var entry in entries)
{
if (entry.Type == DirectoryEntryType.Directory)
{
foreach(string a in EnumerateFiles(directory.ParentFileSystem.OpenDirectory(entry.Name)))
{
yield return a;
}
}
if (entry.Type == DirectoryEntryType.File)
{
yield return entry.Name;
}
}
}
public static void CopyTo(this IFile file, Stream output)
{
const int bufferSize = 0x8000;
long remaining = file.GetSize();
long inOffset = 0;
var buffer = new byte[bufferSize];
while (remaining > 0)
{
int toWrite = (int)Math.Min(buffer.Length, remaining);
file.Read(buffer.AsSpan(0, toWrite), inOffset);
output.Write(buffer, 0, toWrite);
remaining -= toWrite;
inOffset += toWrite;
}
}
}
}

View file

@ -0,0 +1,72 @@
using System.IO;
namespace LibHac.IO
{
public class RomFsDirectory : IDirectory
{
public IFileSystem ParentFileSystem { get; }
private RomfsDir Directory { get; }
public RomFsDirectory(RomFsFileSystem fs, string path)
{
if (!fs.DirectoryDict.TryGetValue(path, out RomfsDir dir))
{
throw new DirectoryNotFoundException(path);
}
ParentFileSystem = fs;
Directory = dir;
}
public DirectoryEntry[] Read()
{
int count = GetEntryCount();
var entries = new DirectoryEntry[count];
int index = 0;
var dirEntry = Directory.FirstChild;
while (dirEntry != null)
{
entries[index] = new DirectoryEntry(dirEntry.FullPath, DirectoryEntryType.Directory, 0);
dirEntry = dirEntry.NextSibling;
index++;
}
RomfsFile fileEntry = Directory.FirstFile;
while (fileEntry != null)
{
entries[index] = new DirectoryEntry(fileEntry.FullPath, DirectoryEntryType.File, fileEntry.DataLength);
fileEntry = fileEntry.NextSibling;
index++;
}
return entries;
}
public int GetEntryCount()
{
int count = 0;
RomfsDir dirEntry = Directory.FirstChild;
while (dirEntry != null)
{
count++;
dirEntry = dirEntry.NextSibling;
}
RomfsFile fileEntry = Directory.FirstFile;
while (fileEntry != null)
{
count++;
fileEntry = fileEntry.NextSibling;
}
return count;
}
}
}

View file

@ -0,0 +1,45 @@
using System;
namespace LibHac.IO
{
public class RomFsFile : IFile
{
private IStorage BaseStorage { get; }
private long Offset { get; }
private long Size { get; }
public RomFsFile(IStorage baseStorage, long offset, long size)
{
BaseStorage = baseStorage;
Offset = offset;
Size = size;
}
public void Read(Span<byte> destination, long offset)
{
long storageOffset = Offset + offset;
BaseStorage.Read(destination, storageOffset);
}
public void Write(ReadOnlySpan<byte> source, long offset)
{
throw new NotImplementedException();
}
public void Flush()
{
throw new NotImplementedException();
}
public long GetSize()
{
return Size;
}
public long SetSize()
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace LibHac.IO
{
public class RomFsFileSystem : IFileSystem
{
public RomfsHeader Header { get; }
public List<RomfsDir> Directories { get; } = new List<RomfsDir>();
public List<RomfsFile> Files { get; } = new List<RomfsFile>();
public RomfsDir RootDir { get; }
public Dictionary<string, RomfsFile> FileDict { get; }
public Dictionary<string, RomfsDir> DirectoryDict { get; }
private IStorage BaseStorage { get; }
public RomFsFileSystem(IStorage storage)
{
BaseStorage = storage;
byte[] dirMetaTable;
byte[] fileMetaTable;
using (var reader = new BinaryReader(BaseStorage.AsStream(), Encoding.Default, true))
{
Header = new RomfsHeader(reader);
reader.BaseStream.Position = Header.DirMetaTableOffset;
dirMetaTable = reader.ReadBytes((int)Header.DirMetaTableSize);
reader.BaseStream.Position = Header.FileMetaTableOffset;
fileMetaTable = reader.ReadBytes((int)Header.FileMetaTableSize);
}
using (var reader = new BinaryReader(new MemoryStream(dirMetaTable)))
{
int position = 0;
while (position + 20 < Header.DirMetaTableSize)
{
var dir = new RomfsDir(reader) { Offset = position };
Directories.Add(dir);
if (dir.ParentDirOffset == position) RootDir = dir;
position = (int)reader.BaseStream.Position;
}
}
using (var reader = new BinaryReader(new MemoryStream(fileMetaTable)))
{
int position = 0;
while (position + 20 < Header.FileMetaTableSize)
{
var file = new RomfsFile(reader) { Offset = position };
Files.Add(file);
position = (int)reader.BaseStream.Position;
}
}
SetReferences();
RomfsEntry.ResolveFilenames(Files);
RomfsEntry.ResolveFilenames(Directories);
FileDict = Files.ToDictionary(x => x.FullPath, x => x);
DirectoryDict = Directories.ToDictionary(x => x.FullPath, x => x);
}
private void SetReferences()
{
Dictionary<int, RomfsDir> dirDict = Directories.ToDictionary(x => x.Offset, x => x);
Dictionary<int, RomfsFile> fileDict = Files.ToDictionary(x => x.Offset, x => x);
foreach (RomfsDir dir in Directories)
{
if (dir.ParentDirOffset >= 0 && dir.ParentDirOffset != dir.Offset) dir.ParentDir = dirDict[dir.ParentDirOffset];
if (dir.NextSiblingOffset >= 0) dir.NextSibling = dirDict[dir.NextSiblingOffset];
if (dir.FirstChildOffset >= 0) dir.FirstChild = dirDict[dir.FirstChildOffset];
if (dir.FirstFileOffset >= 0) dir.FirstFile = fileDict[dir.FirstFileOffset];
if (dir.NextDirHashOffset >= 0) dir.NextDirHash = dirDict[dir.NextDirHashOffset];
}
foreach (RomfsFile file in Files)
{
if (file.ParentDirOffset >= 0) file.ParentDir = dirDict[file.ParentDirOffset];
if (file.NextSiblingOffset >= 0) file.NextSibling = fileDict[file.NextSiblingOffset];
if (file.NextFileHashOffset >= 0) file.NextFileHash = fileDict[file.NextFileHashOffset];
}
}
public void Commit()
{
throw new NotImplementedException();
}
public void CreateDirectory(string path)
{
throw new NotImplementedException();
}
public void CreateFile(string path, long size)
{
throw new NotImplementedException();
}
public void DeleteDirectory(string path)
{
throw new NotImplementedException();
}
public void DeleteFile(string path)
{
throw new NotImplementedException();
}
public IDirectory OpenDirectory(string path)
{
return new RomFsDirectory(this, path);
}
public IFile OpenFile(string path)
{
if (!FileDict.TryGetValue(path, out RomfsFile file))
{
throw new FileNotFoundException();
}
return OpenFile(file);
}
public IFile OpenFile(RomfsFile file)
{
return new RomFsFile(BaseStorage, Header.DataOffset + file.DataOffset, file.DataLength);
}
public void RenameDirectory(string srcPath, string dstPath)
{
throw new NotImplementedException();
}
public void RenameFile(string srcPath, string dstPath)
{
throw new NotImplementedException();
}
public bool DirectoryExists(string path)
{
throw new NotImplementedException();
}
public bool FileExists(string path)
{
return FileDict.ContainsKey(path);
}
}
}

View file

@ -255,6 +255,15 @@ namespace LibHac
return new HierarchicalIntegrityVerificationStorage(initInfo, integrityCheckLevel, leaveOpen); return new HierarchicalIntegrityVerificationStorage(initInfo, integrityCheckLevel, leaveOpen);
} }
public IFileSystem OpenSectionFileSystem(int index)
{
IStorage storage = OpenSection(index, false, IntegrityCheckLevel.ErrorOnInvalid, true);
var fs = new RomFsFileSystem(storage);
return fs;
}
/// <summary> /// <summary>
/// Sets a base <see cref="Nca"/> to use when reading patches. /// Sets a base <see cref="Nca"/> to use when reading patches.
/// </summary> /// </summary>

View file

@ -31,6 +31,9 @@ namespace LibHac
dir = dir.ParentDir; dir = dir.ParentDir;
} }
//todo
if (list.Count == 1) list.Add("/");
for (int i = list.Count - 1; i >= 0; i--) for (int i = list.Count - 1; i >= 0; i--)
{ {
sb.Append(list[i]); sb.Append(list[i]);