mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add ConcatenationFile resizing
This commit is contained in:
parent
1ee3841125
commit
f570c56122
3 changed files with 105 additions and 39 deletions
|
@ -1,25 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibHac.IO
|
||||
{
|
||||
public class ConcatenationFile : FileBase
|
||||
{
|
||||
private IFile[] Sources { get; }
|
||||
private long SplitFileSize { get; }
|
||||
private IFileSystem BaseFileSystem { get; }
|
||||
private string FilePath { get; }
|
||||
private List<IFile> Sources { get; }
|
||||
private long SubFileSize { get; }
|
||||
|
||||
internal ConcatenationFile(IList<IFile> sources, long splitFileSize, OpenMode mode)
|
||||
internal ConcatenationFile(IFileSystem baseFileSystem, string path, IEnumerable<IFile> sources, long subFileSize, OpenMode mode)
|
||||
{
|
||||
Sources = sources.ToArray();
|
||||
SplitFileSize = splitFileSize;
|
||||
BaseFileSystem = baseFileSystem;
|
||||
FilePath = path;
|
||||
Sources = sources.ToList();
|
||||
SubFileSize = subFileSize;
|
||||
Mode = mode;
|
||||
|
||||
for (int i = 0; i < Sources.Length - 1; i++)
|
||||
for (int i = 0; i < Sources.Count - 1; i++)
|
||||
{
|
||||
if (Sources[i].GetSize() != SplitFileSize)
|
||||
if (Sources[i].GetSize() != SubFileSize)
|
||||
{
|
||||
throw new ArgumentException($"Source file must have size {splitFileSize}");
|
||||
throw new ArgumentException($"Source file must have size {subFileSize}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,11 +39,11 @@ namespace LibHac.IO
|
|||
|
||||
while (remaining > 0)
|
||||
{
|
||||
int fileIndex = GetFileIndexFromOffset(offset);
|
||||
int fileIndex = GetSubFileIndexFromOffset(offset);
|
||||
IFile file = Sources[fileIndex];
|
||||
long fileOffset = offset - fileIndex * SplitFileSize;
|
||||
long fileOffset = offset - fileIndex * SubFileSize;
|
||||
|
||||
long fileEndOffset = Math.Min((fileIndex + 1) * SplitFileSize, GetSize());
|
||||
long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, GetSize());
|
||||
int bytesToRead = (int)Math.Min(fileEndOffset - inPos, remaining);
|
||||
int bytesRead = file.Read(destination.Slice(outPos, bytesToRead), fileOffset);
|
||||
|
||||
|
@ -56,19 +61,19 @@ namespace LibHac.IO
|
|||
{
|
||||
ValidateWriteParams(source, offset);
|
||||
|
||||
long inPos = offset;
|
||||
int outPos = 0;
|
||||
int inPos = 0;
|
||||
long outPos = offset;
|
||||
int remaining = source.Length;
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
int fileIndex = GetFileIndexFromOffset(offset);
|
||||
int fileIndex = GetSubFileIndexFromOffset(outPos);
|
||||
IFile file = Sources[fileIndex];
|
||||
long fileOffset = offset - fileIndex * SplitFileSize;
|
||||
long fileOffset = outPos - fileIndex * SubFileSize;
|
||||
|
||||
long fileEndOffset = Math.Min((fileIndex + 1) * SplitFileSize, GetSize());
|
||||
int bytesToWrite = (int)Math.Min(fileEndOffset - inPos, remaining);
|
||||
file.Write(source.Slice(outPos, bytesToWrite), fileOffset);
|
||||
long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, GetSize());
|
||||
int bytesToWrite = (int)Math.Min(fileEndOffset - outPos, remaining);
|
||||
file.Write(source.Slice(inPos, bytesToWrite), fileOffset);
|
||||
|
||||
outPos += bytesToWrite;
|
||||
inPos += bytesToWrite;
|
||||
|
@ -98,12 +103,73 @@ namespace LibHac.IO
|
|||
|
||||
public override void SetSize(long size)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
long currentSize = GetSize();
|
||||
|
||||
if (currentSize == size) return;
|
||||
|
||||
int currentSubFileCount = QuerySubFileCount(currentSize, SubFileSize);
|
||||
int newSubFileCount = QuerySubFileCount(size, SubFileSize);
|
||||
|
||||
if (size > currentSize)
|
||||
{
|
||||
IFile currentLastSubFile = Sources[currentSubFileCount - 1];
|
||||
long newSubFileSize = QuerySubFileSize(currentSubFileCount - 1, size, SubFileSize);
|
||||
|
||||
currentLastSubFile.SetSize(newSubFileSize);
|
||||
|
||||
for (int i = currentSubFileCount; i < newSubFileCount; i++)
|
||||
{
|
||||
string newSubFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i);
|
||||
newSubFileSize = QuerySubFileSize(i, size, SubFileSize);
|
||||
|
||||
BaseFileSystem.CreateFile(newSubFilePath, newSubFileSize, CreateFileOptions.None);
|
||||
Sources.Add(BaseFileSystem.OpenFile(newSubFilePath, Mode));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = currentSubFileCount - 1; i > newSubFileCount - 1; i--)
|
||||
{
|
||||
Sources[i].Dispose();
|
||||
Sources.RemoveAt(i);
|
||||
|
||||
string subFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i);
|
||||
BaseFileSystem.DeleteFile(subFilePath);
|
||||
}
|
||||
|
||||
long newLastFileSize = QuerySubFileSize(newSubFileCount - 1, size, SubFileSize);
|
||||
Sources[newSubFileCount - 1].SetSize(newLastFileSize);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetFileIndexFromOffset(long offset)
|
||||
private int GetSubFileIndexFromOffset(long offset)
|
||||
{
|
||||
return (int)(offset / SplitFileSize);
|
||||
return (int)(offset / SubFileSize);
|
||||
}
|
||||
|
||||
private static int QuerySubFileCount(long size, long subFileSize)
|
||||
{
|
||||
Debug.Assert(size >= 0);
|
||||
Debug.Assert(subFileSize > 0);
|
||||
|
||||
if (size == 0) return 1;
|
||||
|
||||
return (int)Util.DivideByRoundUp(size, subFileSize);
|
||||
}
|
||||
|
||||
private static long QuerySubFileSize(int subFileIndex, long totalSize, long subFileSize)
|
||||
{
|
||||
int subFileCount = QuerySubFileCount(totalSize, subFileSize);
|
||||
|
||||
Debug.Assert(subFileIndex < subFileCount);
|
||||
|
||||
if (subFileIndex + 1 == subFileCount)
|
||||
{
|
||||
long remainder = totalSize % subFileSize;
|
||||
return remainder == 0 ? subFileSize : remainder;
|
||||
}
|
||||
|
||||
return subFileSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,16 @@ namespace LibHac.IO
|
|||
{
|
||||
public class ConcatenationFileSystem : IFileSystem
|
||||
{
|
||||
private const long DefaultSplitFileSize = 0xFFFF0000; // Hard-coded value used by FS
|
||||
private const long DefaultSubFileSize = 0xFFFF0000; // Hard-coded value used by FS
|
||||
private IAttributeFileSystem BaseFileSystem { get; }
|
||||
private long SplitFileSize { get; }
|
||||
private long SubFileSize { get; }
|
||||
|
||||
public ConcatenationFileSystem(IAttributeFileSystem baseFileSystem) : this(baseFileSystem, DefaultSplitFileSize) { }
|
||||
public ConcatenationFileSystem(IAttributeFileSystem baseFileSystem) : this(baseFileSystem, DefaultSubFileSize) { }
|
||||
|
||||
public ConcatenationFileSystem(IAttributeFileSystem baseFileSystem, long splitFileSize)
|
||||
public ConcatenationFileSystem(IAttributeFileSystem baseFileSystem, long subFileSize)
|
||||
{
|
||||
BaseFileSystem = baseFileSystem;
|
||||
SplitFileSize = splitFileSize;
|
||||
SubFileSize = subFileSize;
|
||||
}
|
||||
|
||||
internal bool IsConcatenationFile(string path)
|
||||
|
@ -64,8 +64,8 @@ namespace LibHac.IO
|
|||
|
||||
for (int i = 0; remaining > 0; i++)
|
||||
{
|
||||
long fileSize = Math.Min(SplitFileSize, remaining);
|
||||
string fileName = GetSplitFilePath(path, i);
|
||||
long fileSize = Math.Min(SubFileSize, remaining);
|
||||
string fileName = GetSubFilePath(path, i);
|
||||
|
||||
BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None);
|
||||
|
||||
|
@ -94,11 +94,11 @@ namespace LibHac.IO
|
|||
BaseFileSystem.DeleteFile(path);
|
||||
}
|
||||
|
||||
int count = GetSplitFileCount(path);
|
||||
int count = GetSubFileCount(path);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BaseFileSystem.DeleteFile(GetSplitFilePath(path, i));
|
||||
BaseFileSystem.DeleteFile(GetSubFilePath(path, i));
|
||||
}
|
||||
|
||||
BaseFileSystem.DeleteDirectory(path);
|
||||
|
@ -127,18 +127,18 @@ namespace LibHac.IO
|
|||
return BaseFileSystem.OpenFile(path, mode);
|
||||
}
|
||||
|
||||
int fileCount = GetSplitFileCount(path);
|
||||
int fileCount = GetSubFileCount(path);
|
||||
|
||||
var files = new List<IFile>();
|
||||
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
string filePath = GetSplitFilePath(path, i);
|
||||
string filePath = GetSubFilePath(path, i);
|
||||
IFile file = BaseFileSystem.OpenFile(filePath, mode);
|
||||
files.Add(file);
|
||||
}
|
||||
|
||||
return new ConcatenationFile(files, SplitFileSize, mode);
|
||||
return new ConcatenationFile(BaseFileSystem, path, files, SubFileSize, mode);
|
||||
}
|
||||
|
||||
public void RenameDirectory(string srcPath, string dstPath)
|
||||
|
@ -197,11 +197,11 @@ namespace LibHac.IO
|
|||
BaseFileSystem.Commit();
|
||||
}
|
||||
|
||||
private int GetSplitFileCount(string dirPath)
|
||||
private int GetSubFileCount(string dirPath)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while (BaseFileSystem.FileExists(GetSplitFilePath(dirPath, count)))
|
||||
while (BaseFileSystem.FileExists(GetSubFilePath(dirPath, count)))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
@ -209,19 +209,19 @@ namespace LibHac.IO
|
|||
return count;
|
||||
}
|
||||
|
||||
private static string GetSplitFilePath(string dirPath, int index)
|
||||
internal static string GetSubFilePath(string dirPath, int index)
|
||||
{
|
||||
return $"{dirPath}/{index:D2}";
|
||||
}
|
||||
|
||||
internal long GetConcatenationFileSize(string path)
|
||||
{
|
||||
int fileCount = GetSplitFileCount(path);
|
||||
int fileCount = GetSubFileCount(path);
|
||||
long size = 0;
|
||||
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
size += BaseFileSystem.GetFileSize(GetSplitFilePath(path, i));
|
||||
size += BaseFileSystem.GetFileSize(GetSubFilePath(path, i));
|
||||
}
|
||||
|
||||
return size;
|
||||
|
|
|
@ -174,7 +174,7 @@ namespace LibHac.IO
|
|||
|
||||
public static FileAttributes ApplyNxAttributes(this FileAttributes attributes, NxFileAttributes nxAttributes)
|
||||
{
|
||||
var nxAttributeBits = (FileAttributes)(((int)attributes & 3) << 4);
|
||||
var nxAttributeBits = (FileAttributes)(((int)nxAttributes & 3) << 4);
|
||||
return attributes | nxAttributeBits;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue