Add remaining GetRightsId methods and U8StringBuilder

This commit is contained in:
Alex Barney 2019-10-03 23:23:30 -05:00
parent fdd7eebb4b
commit 9934f477d5
5 changed files with 180 additions and 6 deletions

View file

@ -0,0 +1,38 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace LibHac.Common
{
// In order for the Visual Studio debugger to accurately display a struct, every offset
// in the struct that is used for the debugger display must be part of a field.
// These padding structs make it easier to accomplish that.
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
internal struct Padding20
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding00;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding08;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding10;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding18;
}
[StructLayout(LayoutKind.Sequential, Size = 0x40)]
internal struct Padding40
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding20 Padding00;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding20 Padding20;
}
[StructLayout(LayoutKind.Sequential, Size = 0x80)]
internal struct Padding80
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding40 Padding00;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding40 Padding40;
}
[StructLayout(LayoutKind.Sequential, Size = 0x100)]
internal struct Padding100
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding80 Padding00;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding80 Padding80;
}
}

View file

@ -0,0 +1,86 @@
using System;
using System.Diagnostics;
namespace LibHac.Common
{
[DebuggerDisplay("{ToString()}")]
public ref struct U8StringBuilder
{
private const int NullTerminatorLength = 1;
private readonly Span<byte> _buffer;
private int _length;
public bool Overflowed { get; private set; }
public int Capacity => _buffer.Length - NullTerminatorLength;
public U8StringBuilder(Span<byte> buffer)
{
_buffer = buffer;
_length = 0;
Overflowed = false;
ThrowIfBufferLengthIsZero();
AddNullTerminator();
}
public U8StringBuilder Append(ReadOnlySpan<byte> value)
{
if (Overflowed) return this;
int valueLength = StringUtils.GetLength(value);
if (!HasAdditionalCapacity(valueLength))
{
Overflowed = true;
return this;
}
value.Slice(0, valueLength).CopyTo(_buffer.Slice(_length));
_length += valueLength;
AddNullTerminator();
return this;
}
public U8StringBuilder Append(byte value)
{
if (Overflowed) return this;
if (!HasAdditionalCapacity(1))
{
Overflowed = true;
return this;
}
_buffer[_length] = value;
_length++;
AddNullTerminator();
return this;
}
private bool HasCapacity(int requiredCapacity)
{
return requiredCapacity <= Capacity;
}
private bool HasAdditionalCapacity(int requiredAdditionalCapacity)
{
return HasCapacity(_length + requiredAdditionalCapacity);
}
private void AddNullTerminator()
{
_buffer[_length] = 0;
}
private void ThrowIfBufferLengthIsZero()
{
if (_buffer.Length == 0) throw new ArgumentException("Buffer length must be greater than 0.");
}
public override string ToString() => StringUtils.Utf8ZToString(_buffer);
}
}

View file

@ -1,4 +1,6 @@
using LibHac.FsService;
using LibHac.Common;
using LibHac.FsService;
using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Spl;
@ -14,6 +16,31 @@ namespace LibHac.Fs
return fsProxy.GetRightsId(out rightsId, programId, storageId);
}
public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, U8Span path)
{
rightsId = default;
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
Result rc = FsPath.FromSpan(out FsPath fsPath, path);
if (rc.IsFailure()) return rc;
return fsProxy.GetRightsIdByPath(out rightsId, ref fsPath);
}
public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, out byte keyGeneration, U8Span path)
{
rightsId = default;
keyGeneration = default;
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
Result rc = FsPath.FromSpan(out FsPath fsPath, path);
if (rc.IsFailure()) return rc;
return fsProxy.GetRightsIdAndKeyGenerationByPath(out rightsId, out keyGeneration, ref fsPath);
}
public static Result RegisterExternalKey(this FileSystemClient fs, ref RightsId rightsId, ref AccessKey key)
{
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();

View file

@ -2,18 +2,33 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem
{
[DebuggerDisplay("{ToString()}")]
[StructLayout(LayoutKind.Explicit, Size = MaxLength + 1)]
[StructLayout(LayoutKind.Sequential, Size = MaxLength + 1)]
public struct FsPath
{
internal const int MaxLength = 0x300;
[FieldOffset(0)] private byte _str;
#if DEBUG
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding000;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding100;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding200;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte Padding300;
#endif
public Span<byte> Str => SpanHelpers.CreateSpan(ref _str, MaxLength + 1);
public Span<byte> Str => SpanHelpers.AsByteSpan(ref this);
public static Result FromSpan(out FsPath fsPath, ReadOnlySpan<byte> path)
{
fsPath = new FsPath();
U8StringBuilder builder = new U8StringBuilder(fsPath.Str).Append(path);
return builder.Overflowed ? ResultFs.TooLongPath : Result.Success;
}
public static implicit operator U8Span(FsPath value) => new U8Span(value.Str);
public override string ToString() => StringUtils.Utf8ZToString(Str);

View file

@ -1,8 +1,16 @@
namespace LibHac.Ncm
using System.Diagnostics;
namespace LibHac.Ncm
{
[DebuggerDisplay("{" + nameof(Value) + "}")]
public struct TitleId
{
public ulong Value;
public readonly ulong Value;
public TitleId(ulong value)
{
Value = value;
}
public static explicit operator ulong(TitleId titleId) => titleId.Value;
}