diff --git a/src/LibHac/Common/StringUtils.cs b/src/LibHac/Common/StringUtils.cs index 9579b5e6..bfd8e8fe 100644 --- a/src/LibHac/Common/StringUtils.cs +++ b/src/LibHac/Common/StringUtils.cs @@ -47,17 +47,29 @@ namespace LibHac.Common public static int Compare(ReadOnlySpan s1, ReadOnlySpan s2) { - int maxLen = Math.Min(s1.Length, s2.Length); + int i = 0; - return Compare(s1, s2, maxLen); + while (true) + { + int c1 = ((uint)i < (uint)s1.Length ? s1[i] : 0); + int c2 = ((uint)i < (uint)s2.Length ? s2[i] : 0); + + if (c1 != c2) + return c1 - c2; + + if (c1 == 0) + return 0; + + i++; + } } public static int Compare(ReadOnlySpan s1, ReadOnlySpan s2, int maxLen) { for (int i = 0; i < maxLen; i++) { - byte c1 = s1[i]; - byte c2 = s2[i]; + int c1 = ((uint)i < (uint)s1.Length ? s1[i] : 0); + int c2 = ((uint)i < (uint)s2.Length ? s2[i] : 0); if (c1 != c2) return c1 - c2; @@ -69,6 +81,51 @@ namespace LibHac.Common return 0; } + public static int CompareCaseInsensitive(ReadOnlySpan s1, ReadOnlySpan s2) + { + int i = 0; + + while (true) + { + int c1 = ((uint)i < (uint)s1.Length ? ToLowerAsciiInvariant(s1[i]) : 0); + int c2 = ((uint)i < (uint)s2.Length ? ToLowerAsciiInvariant(s2[i]) : 0); + + if (c1 != c2) + return c1 - c2; + + if (c1 == 0) + return 0; + + i++; + } + } + + public static int CompareCaseInsensitive(ReadOnlySpan s1, ReadOnlySpan s2, int maxLen) + { + for (int i = 0; i < maxLen; i++) + { + int c1 = ((uint)i < (uint)s1.Length ? ToLowerAsciiInvariant(s1[i]) : 0); + int c2 = ((uint)i < (uint)s2.Length ? ToLowerAsciiInvariant(s2[i]) : 0); + + if (c1 != c2) + return c1 - c2; + + if (c1 == 0) + return 0; + } + + return 0; + } + + private static byte ToLowerAsciiInvariant(byte c) + { + if ((uint)(c - 'A') <= 'Z' - 'A') + { + c = (byte)(c | 0x20); + } + return c; + } + /// /// Concatenates 2 byte strings. /// diff --git a/src/LibHac/Common/U8Span.cs b/src/LibHac/Common/U8Span.cs index c504d556..e36ad0c4 100644 --- a/src/LibHac/Common/U8Span.cs +++ b/src/LibHac/Common/U8Span.cs @@ -44,7 +44,7 @@ namespace LibHac.Common public override string ToString() { - return StringUtils.Utf8ToString(_buffer); + return StringUtils.Utf8ZToString(_buffer); } public bool IsNull() => _buffer == default; diff --git a/src/LibHac/Common/U8String.cs b/src/LibHac/Common/U8String.cs index e7d27a99..e7c1552f 100644 --- a/src/LibHac/Common/U8String.cs +++ b/src/LibHac/Common/U8String.cs @@ -43,7 +43,7 @@ namespace LibHac.Common public override string ToString() { - return StringUtils.Utf8ToString(_buffer); + return StringUtils.Utf8ZToString(_buffer); } public bool IsNull() => _buffer == null; diff --git a/src/LibHac/Fs/FileStorageBasedFileSystem.cs b/src/LibHac/Fs/FileStorageBasedFileSystem.cs index 2ee32426..a76888a7 100644 --- a/src/LibHac/Fs/FileStorageBasedFileSystem.cs +++ b/src/LibHac/Fs/FileStorageBasedFileSystem.cs @@ -1,13 +1,17 @@ -namespace LibHac.Fs +using LibHac.Common; + +namespace LibHac.Fs { public class FileStorageBasedFileSystem : FileStorage2 { + // ReSharper disable once UnusedAutoPropertyAccessor.Local + // FS keeps a shared pointer to the base filesystem private IFileSystem BaseFileSystem { get; set; } private IFile BaseFile { get; set; } - private FileStorageBasedFileSystem() : base() { } + private FileStorageBasedFileSystem() { } - public static Result CreateNew(out FileStorageBasedFileSystem created, IFileSystem baseFileSystem, string path, + public static Result CreateNew(out FileStorageBasedFileSystem created, IFileSystem baseFileSystem, U8Span path, OpenMode mode) { var obj = new FileStorageBasedFileSystem(); @@ -24,9 +28,9 @@ return rc; } - private Result Initialize(IFileSystem baseFileSystem, string path, OpenMode mode) + private Result Initialize(IFileSystem baseFileSystem, U8Span path, OpenMode mode) { - Result rc = baseFileSystem.OpenFile(out IFile file, path, mode); + Result rc = baseFileSystem.OpenFile(out IFile file, path.ToString(), mode); if (rc.IsFailure()) return rc; SetFile(file); diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index c751a9c9..6244ac3a 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -79,6 +79,8 @@ public static Result UnexpectedErrorInHostFileGetSize => new Result(ModuleFs, 5308); public static Result UnknownHostFileSystemError => new Result(ModuleFs, 5309); + public static Result InvalidNcaMountPoint => new Result(ModuleFs, 5320); + public static Result PreconditionViolation => new Result(ModuleFs, 6000); public static Result InvalidArgument => new Result(ModuleFs, 6001); public static Result InvalidPath => new Result(ModuleFs, 6002); diff --git a/src/LibHac/Fs/Shim/Application.cs b/src/LibHac/Fs/Shim/Application.cs new file mode 100644 index 00000000..eca12665 --- /dev/null +++ b/src/LibHac/Fs/Shim/Application.cs @@ -0,0 +1,52 @@ +using System; +using LibHac.Common; +using LibHac.FsService; +using LibHac.FsSystem; + +namespace LibHac.Fs.Shim +{ + public static class Application + { + public static Result MountApplicationPackage(this FileSystemClient fs, U8Span mountName, U8Span path) + { + Result rc; + + if (fs.IsEnabledAccessLog(AccessLogTarget.System)) + { + TimeSpan startTime = fs.Time.GetCurrent(); + rc = Run(fs, mountName, path); + TimeSpan endTime = fs.Time.GetCurrent(); + + fs.OutputAccessLog(rc, startTime, endTime, ""); + } + else + { + rc = Run(fs, mountName, path); + } + + if (rc.IsFailure()) return rc; + + if (fs.IsEnabledAccessLog(AccessLogTarget.System)) + { + fs.EnableFileSystemAccessorAccessLog(mountName); + } + + return Result.Success; + + static Result Run(FileSystemClient fs, U8Span mountName, U8Span path) + { + Result rc = MountHelpers.CheckMountName(mountName); + if (rc.IsFailure()) return rc; + + FsPath.FromSpan(out FsPath fsPath, path); + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + rc = fsProxy.OpenFileSystemWithId(out IFileSystem fileSystem, ref fsPath, default, FileSystemProxyType.ApplicationPackage); + if (rc.IsFailure()) return rc; + + return fs.Register(mountName, fileSystem); + } + } + } +} diff --git a/src/LibHac/FsService/Creators/PartitionFileSystemCreator.cs b/src/LibHac/FsService/Creators/PartitionFileSystemCreator.cs new file mode 100644 index 00000000..c05b77b0 --- /dev/null +++ b/src/LibHac/FsService/Creators/PartitionFileSystemCreator.cs @@ -0,0 +1,13 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class PartitionFileSystemCreator : IPartitionFileSystemCreator + { + public Result Create(out IFileSystem fileSystem, IStorage pFsStorage) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/Creators/RomFileSystemCreator.cs b/src/LibHac/FsService/Creators/RomFileSystemCreator.cs new file mode 100644 index 00000000..8994e8e4 --- /dev/null +++ b/src/LibHac/FsService/Creators/RomFileSystemCreator.cs @@ -0,0 +1,13 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class RomFileSystemCreator : IRomFileSystemCreator + { + public Result Create(out IFileSystem fileSystem, IStorage romFsStorage) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/Creators/StorageOnNcaCreator.cs b/src/LibHac/FsService/Creators/StorageOnNcaCreator.cs new file mode 100644 index 00000000..e651289b --- /dev/null +++ b/src/LibHac/FsService/Creators/StorageOnNcaCreator.cs @@ -0,0 +1,29 @@ +using System; +using LibHac.Fs; +using LibHac.FsSystem.NcaUtils; + +namespace LibHac.FsService.Creators +{ + public class StorageOnNcaCreator : IStorageOnNcaCreator + { + public Result Create(out IStorage storage, out NcaFsHeader fsHeader, Nca nca, int fsIndex, bool isCodeFs) + { + throw new NotImplementedException(); + } + + public Result CreateWithPatch(out IStorage storage, out NcaFsHeader fsHeader, Nca baseNca, Nca patchNca, int fsIndex, bool isCodeFs) + { + throw new NotImplementedException(); + } + + public Result OpenNca(out Nca nca, IStorage ncaStorage) + { + throw new NotImplementedException(); + } + + public Result VerifyAcidSignature(IFileSystem codeFileSystem, Nca nca) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/Creators/TargetManagerFileSystemCreator.cs b/src/LibHac/FsService/Creators/TargetManagerFileSystemCreator.cs new file mode 100644 index 00000000..c20d5884 --- /dev/null +++ b/src/LibHac/FsService/Creators/TargetManagerFileSystemCreator.cs @@ -0,0 +1,18 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class TargetManagerFileSystemCreator : ITargetManagerFileSystemCreator + { + public Result Create(out IFileSystem fileSystem, bool openCaseSensitive) + { + throw new NotImplementedException(); + } + + public Result GetCaseSensitivePath(out bool isSuccess, ref string path) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/DefaultFsServerObjects.cs b/src/LibHac/FsService/DefaultFsServerObjects.cs index 469757cf..57fb3538 100644 --- a/src/LibHac/FsService/DefaultFsServerObjects.cs +++ b/src/LibHac/FsService/DefaultFsServerObjects.cs @@ -16,6 +16,10 @@ namespace LibHac.FsService var gcStorageCreator = new EmulatedGameCardStorageCreator(gameCard); + creators.RomFileSystemCreator = new RomFileSystemCreator(); + creators.PartitionFileSystemCreator = new PartitionFileSystemCreator(); + creators.StorageOnNcaCreator = new StorageOnNcaCreator(); + creators.TargetManagerFileSystemCreator = new TargetManagerFileSystemCreator(); creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset); creators.GameCardStorageCreator = gcStorageCreator;