mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Add IResultLogger and IResultNameResolver
This commit is contained in:
parent
5910b9f9c2
commit
0040db1153
@ -10,8 +10,8 @@ namespace LibHac.Fs
|
||||
public static Result.Base PathAlreadyExists => new Result.Base(ModuleFs, 2);
|
||||
public static Result.Base TargetLocked => new Result.Base(ModuleFs, 7);
|
||||
public static Result.Base DirectoryNotEmpty => new Result.Base(ModuleFs, 8);
|
||||
public static Result.Base InsufficientFreeSpace => new Result.Base(ResultFs.ModuleFs, 30, 45);
|
||||
public static Result.Base InsufficientFreeSpaceBis => new Result.Base(ResultFs.ModuleFs, 34, 38);
|
||||
public static Result.Base InsufficientFreeSpace => new Result.Base(ModuleFs, 30, 45);
|
||||
public static Result.Base InsufficientFreeSpaceBis => new Result.Base(ModuleFs, 34, 38);
|
||||
public static Result.Base InsufficientFreeSpaceBisCalibration => new Result.Base(ModuleFs, 35);
|
||||
public static Result.Base InsufficientFreeSpaceBisSafe => new Result.Base(ModuleFs, 36);
|
||||
public static Result.Base InsufficientFreeSpaceBisUser => new Result.Base(ModuleFs, 37);
|
||||
@ -23,10 +23,10 @@ namespace LibHac.Fs
|
||||
public static Result.Base TargetNotFound => new Result.Base(ModuleFs, 1002);
|
||||
public static Result.Base ExternalKeyNotFound => new Result.Base(ModuleFs, 1004);
|
||||
|
||||
public static Result.Base SdCardAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 2000, 2499); }
|
||||
public static Result.Base SdCardAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2000, 2499); }
|
||||
public static Result.Base SdCardNotPresent => new Result.Base(ModuleFs, 2001);
|
||||
|
||||
public static Result.Base GameCardAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 2500, 2999); }
|
||||
public static Result.Base GameCardAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2500, 2999); }
|
||||
public static Result.Base InvalidBufferForGameCard => new Result.Base(ModuleFs, 2503);
|
||||
public static Result.Base GameCardNotInserted => new Result.Base(ModuleFs, 2520);
|
||||
|
||||
@ -41,20 +41,20 @@ namespace LibHac.Fs
|
||||
public static Result.Base SaveDataPathAlreadyExists => new Result.Base(ModuleFs, 3003);
|
||||
public static Result.Base OutOfRange => new Result.Base(ModuleFs, 3005);
|
||||
|
||||
public static Result.Base AllocationMemoryFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 3200, 3499); }
|
||||
public static Result.Base AllocationMemoryFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 3200, 3499); }
|
||||
public static Result.Base AesXtsFileFileStorageAllocationError => new Result.Base(ModuleFs, 3312);
|
||||
public static Result.Base AesXtsFileXtsStorageAllocationError => new Result.Base(ModuleFs, 3313);
|
||||
public static Result.Base AesXtsFileAlignmentStorageAllocationError => new Result.Base(ModuleFs, 3314);
|
||||
public static Result.Base AesXtsFileStorageFileAllocationError => new Result.Base(ModuleFs, 3315);
|
||||
public static Result.Base AesXtsFileSubStorageAllocationError => new Result.Base(ModuleFs, 3383);
|
||||
|
||||
public static Result.Base MmcAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 3500, 3999); }
|
||||
public static Result.Base MmcAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 3500, 3999); }
|
||||
|
||||
public static Result.Base DataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4000, 4999); }
|
||||
public static Result.Base RomCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4001, 4299); }
|
||||
public static Result.Base DataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4000, 4999); }
|
||||
public static Result.Base RomCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4001, 4299); }
|
||||
public static Result.Base InvalidIndirectStorageSource => new Result.Base(ModuleFs, 4023);
|
||||
|
||||
public static Result.Base SaveDataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4301, 4499); }
|
||||
public static Result.Base SaveDataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4301, 4499); }
|
||||
public static Result.Base Result4302 => new Result.Base(ModuleFs, 4302);
|
||||
public static Result.Base InvalidSaveDataEntryType => new Result.Base(ModuleFs, 4303);
|
||||
public static Result.Base InvalidSaveDataHeader => new Result.Base(ModuleFs, 4315);
|
||||
@ -70,34 +70,34 @@ namespace LibHac.Fs
|
||||
public static Result.Base SaveDataFileTableCorrupted => new Result.Base(ModuleFs, 4463);
|
||||
public static Result.Base AllocationTableIteratedRangeEntry => new Result.Base(ModuleFs, 4464);
|
||||
|
||||
public static Result.Base NcaCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4501, 4599); }
|
||||
public static Result.Base NcaCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4501, 4599); }
|
||||
|
||||
public static Result.Base IntegrityVerificationStorageCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4601, 4639); }
|
||||
public static Result.Base IntegrityVerificationStorageCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4601, 4639); }
|
||||
public static Result.Base Result4602 => new Result.Base(ModuleFs, 4602);
|
||||
public static Result.Base Result4603 => new Result.Base(ModuleFs, 4603);
|
||||
public static Result.Base InvalidHashInIvfc => new Result.Base(ModuleFs, 4604);
|
||||
public static Result.Base IvfcHashIsEmpty => new Result.Base(ModuleFs, 4612);
|
||||
public static Result.Base InvalidHashInIvfcTopLayer => new Result.Base(ModuleFs, 4613);
|
||||
|
||||
public static Result.Base PartitionFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4641, 4659); }
|
||||
public static Result.Base PartitionFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4641, 4659); }
|
||||
public static Result.Base InvalidPartitionFileSystemHashOffset => new Result.Base(ModuleFs, 4642);
|
||||
public static Result.Base InvalidPartitionFileSystemHash => new Result.Base(ModuleFs, 4643);
|
||||
public static Result.Base InvalidPartitionFileSystemMagic => new Result.Base(ModuleFs, 4644);
|
||||
public static Result.Base InvalidHashedPartitionFileSystemMagic => new Result.Base(ModuleFs, 4645);
|
||||
public static Result.Base InvalidPartitionFileSystemEntryNameOffset => new Result.Base(ModuleFs, 4646);
|
||||
|
||||
public static Result.Base BuiltInStorageCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4661, 4679); }
|
||||
public static Result.Base BuiltInStorageCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4661, 4679); }
|
||||
public static Result.Base Result4662 => new Result.Base(ModuleFs, 4662);
|
||||
|
||||
public static Result.Base FatFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4681, 4699); }
|
||||
public static Result.Base HostFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4701, 4719); }
|
||||
public static Result.Base FatFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4681, 4699); }
|
||||
public static Result.Base HostFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4701, 4719); }
|
||||
|
||||
public static Result.Base DatabaseCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4721, 4739); }
|
||||
public static Result.Base DatabaseCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4721, 4739); }
|
||||
public static Result.Base SaveDataAllocationTableCorruptedInternal => new Result.Base(ModuleFs, 4722);
|
||||
public static Result.Base SaveDataFileTableCorruptedInternal => new Result.Base(ModuleFs, 4723);
|
||||
public static Result.Base AllocationTableIteratedRangeEntryInternal => new Result.Base(ModuleFs, 4724);
|
||||
|
||||
public static Result.Base AesXtsFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4741, 4759); }
|
||||
public static Result.Base AesXtsFileSystemCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4741, 4759); }
|
||||
public static Result.Base AesXtsFileHeaderTooShort => new Result.Base(ModuleFs, 4742);
|
||||
public static Result.Base AesXtsFileHeaderInvalidKeys => new Result.Base(ModuleFs, 4743);
|
||||
public static Result.Base AesXtsFileHeaderInvalidMagic => new Result.Base(ModuleFs, 4744);
|
||||
@ -106,15 +106,15 @@ namespace LibHac.Fs
|
||||
public static Result.Base AesXtsFileHeaderInvalidKeysInRenameFile => new Result.Base(ModuleFs, 4747);
|
||||
public static Result.Base AesXtsFileHeaderInvalidKeysInSetSize => new Result.Base(ModuleFs, 4748);
|
||||
|
||||
public static Result.Base SaveDataTransferDataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4761, 4769); }
|
||||
public static Result.Base SignedSystemPartitionDataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4771, 4779); }
|
||||
public static Result.Base SaveDataTransferDataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4761, 4769); }
|
||||
public static Result.Base SignedSystemPartitionDataCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4771, 4779); }
|
||||
|
||||
public static Result.Base GameCardLogoDataCorrupted => new Result.Base(ModuleFs, 4781);
|
||||
|
||||
public static Result.Base Range4811To4819 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 4811, 4819); }
|
||||
public static Result.Base Range4811To4819 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4811, 4819); }
|
||||
public static Result.Base Result4812 => new Result.Base(ModuleFs, 4812);
|
||||
|
||||
public static Result.Base Unexpected { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 5000, 5999); }
|
||||
public static Result.Base Unexpected { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 5000, 5999); }
|
||||
|
||||
public static Result.Base UnexpectedErrorInHostFileFlush => new Result.Base(ModuleFs, 5307);
|
||||
public static Result.Base UnexpectedErrorInHostFileGetSize => new Result.Base(ModuleFs, 5308);
|
||||
@ -131,7 +131,7 @@ namespace LibHac.Fs
|
||||
public static Result.Base DirectoryUnobtainable => new Result.Base(ModuleFs, 6006);
|
||||
public static Result.Base NotNormalized => new Result.Base(ModuleFs, 6007);
|
||||
|
||||
public static Result.Base InvalidPathForOperation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6030, 6059); }
|
||||
public static Result.Base InvalidPathForOperation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6030, 6059); }
|
||||
public static Result.Base DirectoryNotDeletable => new Result.Base(ModuleFs, 6031);
|
||||
public static Result.Base DestinationIsSubPathOfSource => new Result.Base(ModuleFs, 6032);
|
||||
public static Result.Base PathNotFoundInSaveDataFileTable => new Result.Base(ModuleFs, 6033);
|
||||
@ -145,16 +145,16 @@ namespace LibHac.Fs
|
||||
public static Result.Base ExtensionSizeInvalid => new Result.Base(ModuleFs, 6067);
|
||||
public static Result.Base ReadOldSaveDataInfoReader => new Result.Base(ModuleFs, 6068);
|
||||
|
||||
public static Result.Base InvalidEnumValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6080, 6099); }
|
||||
public static Result.Base InvalidEnumValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6080, 6099); }
|
||||
public static Result.Base InvalidSaveDataState => new Result.Base(ModuleFs, 6081);
|
||||
public static Result.Base InvalidSaveDataSpaceId => new Result.Base(ModuleFs, 6082);
|
||||
|
||||
public static Result.Base InvalidOperationForOpenMode { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6200, 6299); }
|
||||
public static Result.Base InvalidOperationForOpenMode { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6200, 6299); }
|
||||
public static Result.Base FileExtensionWithoutOpenModeAllowAppend => new Result.Base(ModuleFs, 6201);
|
||||
public static Result.Base InvalidOpenModeForRead => new Result.Base(ModuleFs, 6202);
|
||||
public static Result.Base InvalidOpenModeForWrite => new Result.Base(ModuleFs, 6203);
|
||||
|
||||
public static Result.Base UnsupportedOperation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6300, 6399); }
|
||||
public static Result.Base UnsupportedOperation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6300, 6399); }
|
||||
public static Result.Base SubStorageNotResizable => new Result.Base(ModuleFs, 6302);
|
||||
public static Result.Base SubStorageNotResizableMiddleOfFile => new Result.Base(ModuleFs, 6303);
|
||||
public static Result.Base UnsupportedOperationInMemoryStorageSetSize => new Result.Base(ModuleFs, 6304);
|
||||
@ -176,7 +176,7 @@ namespace LibHac.Fs
|
||||
public static Result.Base UnsupportedOperationInPartitionFileSetSize => new Result.Base(ModuleFs, 6376);
|
||||
public static Result.Base UnsupportedOperationIdInPartitionFileSystem => new Result.Base(ModuleFs, 6377);
|
||||
|
||||
public static Result.Base PermissionDenied { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6400, 6449); }
|
||||
public static Result.Base PermissionDenied { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6400, 6449); }
|
||||
|
||||
public static Result.Base ExternalKeyAlreadyRegistered => new Result.Base(ModuleFs, 6452);
|
||||
public static Result.Base WriteStateUnflushed => new Result.Base(ModuleFs, 6454);
|
||||
@ -184,17 +184,17 @@ namespace LibHac.Fs
|
||||
public static Result.Base AllocatorAlignmentViolation => new Result.Base(ModuleFs, 6461);
|
||||
public static Result.Base UserNotExist => new Result.Base(ModuleFs, 6465);
|
||||
|
||||
public static Result.Base EntryNotFound { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6600, 6699); }
|
||||
public static Result.Base EntryNotFound { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6600, 6699); }
|
||||
|
||||
public static Result.Base OutOfResource { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6700, 6799); }
|
||||
public static Result.Base OutOfResource { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6700, 6799); }
|
||||
public static Result.Base MappingTableFull => new Result.Base(ModuleFs, 6706);
|
||||
public static Result.Base AllocationTableInsufficientFreeBlocks => new Result.Base(ModuleFs, 6707);
|
||||
public static Result.Base OpenCountLimit => new Result.Base(ModuleFs, 6709);
|
||||
|
||||
public static Result.Base MappingFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6800, 6899); }
|
||||
public static Result.Base MappingFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6800, 6899); }
|
||||
public static Result.Base RemapStorageMapFull => new Result.Base(ModuleFs, 6811);
|
||||
|
||||
public static Result.Base BadState { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ResultFs.ModuleFs, 6900, 6999); }
|
||||
public static Result.Base BadState { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6900, 6999); }
|
||||
public static Result.Base SubStorageNotInitialized => new Result.Base(ModuleFs, 6902);
|
||||
public static Result.Base NotMounted => new Result.Base(ModuleFs, 6905);
|
||||
public static Result.Base SaveDataIsExtending => new Result.Base(ModuleFs, 6906);
|
||||
|
@ -4,10 +4,10 @@
|
||||
{
|
||||
public const int ModuleKvdb = 20;
|
||||
|
||||
public static Result TooLargeKeyOrDbFull => new Result(ModuleKvdb, 1);
|
||||
public static Result KeyNotFound => new Result(ModuleKvdb, 2);
|
||||
public static Result AllocationFailed => new Result(ModuleKvdb, 4);
|
||||
public static Result InvalidKeyValue => new Result(ModuleKvdb, 5);
|
||||
public static Result BufferInsufficient => new Result(ModuleKvdb, 6);
|
||||
public static Result.Base TooLargeKeyOrDbFull => new Result.Base(ModuleKvdb, 1);
|
||||
public static Result.Base KeyNotFound => new Result.Base(ModuleKvdb, 2);
|
||||
public static Result.Base AllocationFailed => new Result.Base(ModuleKvdb, 4);
|
||||
public static Result.Base InvalidKeyValue => new Result.Base(ModuleKvdb, 5);
|
||||
public static Result.Base BufferInsufficient => new Result.Base(ModuleKvdb, 6);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,10 @@ namespace LibHac
|
||||
public struct Result : IEquatable<Result>
|
||||
{
|
||||
private const BaseType SuccessValue = default;
|
||||
public static Result Success => new Result(SuccessValue);
|
||||
|
||||
private static IResultLogger Logger { get; set; }
|
||||
private static IResultNameResolver NameResolver { get; set; }
|
||||
|
||||
private const int ModuleBitsOffset = 0;
|
||||
private const int ModuleBitsCount = 9;
|
||||
@ -27,8 +31,6 @@ namespace LibHac
|
||||
|
||||
private readonly BaseType _value;
|
||||
|
||||
public static Result Success => new Result(SuccessValue);
|
||||
|
||||
public Result(BaseType value)
|
||||
{
|
||||
_value = GetBitsValue(value, ModuleBitsOffset, ModuleBitsCount + DescriptionBitsCount);
|
||||
@ -53,18 +55,6 @@ namespace LibHac
|
||||
public bool IsSuccess() => _value == SuccessValue;
|
||||
public bool IsFailure() => !IsSuccess();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static BaseType GetBitsValue(BaseType value, int bitsOffset, int bitsCount)
|
||||
{
|
||||
return (value >> bitsOffset) & ~(~default(BaseType) << bitsCount);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static BaseType SetBitsValue(int value, int bitsOffset, int bitsCount)
|
||||
{
|
||||
return ((uint)value & ~(~default(BaseType) << bitsCount)) << bitsOffset;
|
||||
}
|
||||
|
||||
public void ThrowIfFailure()
|
||||
{
|
||||
if (IsFailure())
|
||||
@ -74,8 +64,10 @@ namespace LibHac
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A function that can contain code for logging or debugging returned results.
|
||||
/// Intended to be used when returning a non-zero Result:
|
||||
/// Performs no action in release mode.
|
||||
/// In debug mode, logs returned results using the <see cref="IResultLogger"/> set by <see cref="SetLogger"/>.
|
||||
/// <br/>Intended to always be used when returning a non-zero <see cref="Result"/>.
|
||||
/// <br/><br/>Example:
|
||||
/// <code>return result.Log();</code>
|
||||
/// </summary>
|
||||
/// <returns>The called <see cref="Result"/> value.</returns>
|
||||
@ -87,7 +79,7 @@ namespace LibHac
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as <see cref="Log"/>, but for when one result is converted to another.
|
||||
/// In debug mode, logs converted results using the <see cref="IResultLogger"/> set by <see cref="SetLogger"/>.
|
||||
/// </summary>
|
||||
/// <param name="originalResult">The original <see cref="Result"/> value.</param>
|
||||
/// <returns>The called <see cref="Result"/> value.</returns>
|
||||
@ -98,37 +90,17 @@ namespace LibHac
|
||||
return this;
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void LogImpl()
|
||||
{
|
||||
LogCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void LogConvertedImpl(Result originalResult)
|
||||
{
|
||||
ConvertedLogCallback?.Invoke(this, originalResult);
|
||||
}
|
||||
|
||||
public delegate void ResultLogger(Result result);
|
||||
public delegate void ConvertedResultLogger(Result result, Result originalResult);
|
||||
public delegate bool ResultNameGetter(Result result, out string name);
|
||||
|
||||
public static ResultLogger LogCallback { get; set; }
|
||||
public static ConvertedResultLogger ConvertedLogCallback { get; set; }
|
||||
public static ResultNameGetter GetResultNameHandler { get; set; }
|
||||
|
||||
public bool TryGetResultName(out string name)
|
||||
{
|
||||
ResultNameGetter func = GetResultNameHandler;
|
||||
IResultNameResolver resolver = NameResolver;
|
||||
|
||||
if (func == null)
|
||||
if (resolver == null)
|
||||
{
|
||||
name = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
return func(this, out name);
|
||||
return resolver.TryResolveName(this, out name);
|
||||
}
|
||||
|
||||
public string ToStringWithName()
|
||||
@ -150,6 +122,40 @@ namespace LibHac
|
||||
public static bool operator ==(Result left, Result right) => left.Equals(right);
|
||||
public static bool operator !=(Result left, Result right) => !left.Equals(right);
|
||||
|
||||
public static void SetLogger(IResultLogger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public static void SetNameResolver(IResultNameResolver nameResolver)
|
||||
{
|
||||
NameResolver = nameResolver;
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void LogImpl()
|
||||
{
|
||||
Logger?.LogResult(this);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void LogConvertedImpl(Result originalResult)
|
||||
{
|
||||
Logger?.LogConvertedResult(this, originalResult);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static BaseType GetBitsValue(BaseType value, int bitsOffset, int bitsCount)
|
||||
{
|
||||
return (value >> bitsOffset) & ~(~default(BaseType) << bitsCount);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static BaseType SetBitsValue(int value, int bitsOffset, int bitsCount)
|
||||
{
|
||||
return ((uint)value & ~(~default(BaseType) << bitsCount)) << bitsOffset;
|
||||
}
|
||||
|
||||
public struct Base
|
||||
{
|
||||
private const int DescriptionEndBitsOffset = ReservedBitsOffset;
|
||||
@ -175,6 +181,7 @@ namespace LibHac
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Result"/> representing the start of this result range.
|
||||
/// If returning a <see cref="Result"/> from a function, use <see cref="Log"/> instead.
|
||||
/// </summary>
|
||||
public Result Value => new Result((BaseType)_value);
|
||||
|
||||
@ -198,9 +205,11 @@ namespace LibHac
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A function that can contain code for logging or debugging returned results.
|
||||
/// Intended to be used when returning a non-zero Result:
|
||||
/// <code>return result.Log();</code>
|
||||
/// Performs no action in release mode.
|
||||
/// In debug mode, logs returned results using the <see cref="IResultLogger"/> set by <see cref="SetLogger"/>.
|
||||
/// <br/>Intended to always be used when returning a non-zero <see cref="Result"/>.
|
||||
/// <br/><br/>Example:
|
||||
/// <code>return ResultFs.PathNotFound.Log();</code>
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="Result"/> representing the start of this result range.</returns>
|
||||
public Result Log()
|
||||
@ -209,7 +218,7 @@ namespace LibHac
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as <see cref="Log"/>, but for when one result is converted to another.
|
||||
/// In debug mode, logs converted results using the <see cref="IResultLogger"/> set by <see cref="SetLogger"/>.
|
||||
/// </summary>
|
||||
/// <param name="originalResult">The original <see cref="Result"/> value.</param>
|
||||
/// <returns>The <see cref="Result"/> representing the start of this result range.</returns>
|
||||
@ -230,5 +239,16 @@ namespace LibHac
|
||||
return ((uint)value & ~(~default(ulong) << bitsCount)) << bitsOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IResultLogger
|
||||
{
|
||||
public void LogResult(Result result);
|
||||
public void LogConvertedResult(Result result, Result originalResult);
|
||||
}
|
||||
|
||||
public interface IResultNameResolver
|
||||
{
|
||||
public bool TryResolveName(Result result, out string name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using LibHac;
|
||||
@ -52,11 +52,11 @@ namespace hactoolnet
|
||||
if (ctx.Options == null) return false;
|
||||
|
||||
StreamWriter logWriter = null;
|
||||
StreamWriter resultWriter = null;
|
||||
ResultLogger resultLogger = null;
|
||||
|
||||
try
|
||||
{
|
||||
Result.GetResultNameHandler = ResultLogFunctions.TryGetResultName;
|
||||
Result.SetNameResolver(new ResultNameResolver());
|
||||
|
||||
using (var logger = new ProgressBar())
|
||||
{
|
||||
@ -76,11 +76,10 @@ namespace hactoolnet
|
||||
|
||||
if (ctx.Options.ResultLog != null)
|
||||
{
|
||||
resultWriter = new StreamWriter(ctx.Options.ResultLog);
|
||||
ResultLogFunctions.LogWriter = resultWriter;
|
||||
resultLogger = new ResultLogger(new StreamWriter(ctx.Options.ResultLog),
|
||||
printStackTrace: true, printSourceInfo: true, combineRepeats: true);
|
||||
|
||||
Result.LogCallback = ResultLogFunctions.LogResult;
|
||||
Result.ConvertedLogCallback = ResultLogFunctions.LogConvertedResult;
|
||||
Result.SetLogger(resultLogger);
|
||||
}
|
||||
|
||||
OpenKeyset(ctx);
|
||||
@ -97,9 +96,12 @@ namespace hactoolnet
|
||||
finally
|
||||
{
|
||||
logWriter?.Dispose();
|
||||
resultWriter?.Dispose();
|
||||
|
||||
ResultLogFunctions.LogWriter = null;
|
||||
if (resultLogger != null)
|
||||
{
|
||||
Result.SetLogger(null);
|
||||
resultLogger.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using LibHac;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace hactoolnet
|
||||
{
|
||||
public static class ResultLogFunctions
|
||||
{
|
||||
private static Dictionary<Result, string> ResultNames { get; } = GetResultNames();
|
||||
|
||||
public static TextWriter LogWriter { get; set; }
|
||||
|
||||
public static void LogResult(Result result)
|
||||
{
|
||||
if (LogWriter == null) return;
|
||||
|
||||
var st = new StackTrace(2, true);
|
||||
|
||||
if (st.FrameCount > 1)
|
||||
{
|
||||
MethodBase method = st.GetFrame(0).GetMethod();
|
||||
|
||||
// This result from these functions is usually noise because they
|
||||
// are frequently used to detect if a file exists
|
||||
if (ResultFs.PathNotFound.Includes(result) &&
|
||||
typeof(IFileSystem).IsAssignableFrom(method.DeclaringType) &&
|
||||
method.Name.StartsWith(nameof(IFileSystem.GetEntryType)) ||
|
||||
method.Name.StartsWith(nameof(IAttributeFileSystem.GetFileAttributes)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string methodName = $"{method.DeclaringType?.FullName}.{method.Name}";
|
||||
|
||||
LogWriter.WriteLine($"{result.ToStringWithName()} returned by {methodName}");
|
||||
LogWriter.WriteLine(st);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogConvertedResult(Result result, Result originalResult)
|
||||
{
|
||||
if (LogWriter == null) return;
|
||||
|
||||
var st = new StackTrace(2, false);
|
||||
|
||||
if (st.FrameCount > 1)
|
||||
{
|
||||
MethodBase method = st.GetFrame(0).GetMethod();
|
||||
|
||||
string methodName = $"{method.DeclaringType?.FullName}.{method.Name}";
|
||||
|
||||
LogWriter.WriteLine($"{originalResult.ToStringWithName()} was converted to {result.ToStringWithName()} by {methodName}");
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<Result, string> GetResultNames()
|
||||
{
|
||||
var dict = new Dictionary<Result, string>();
|
||||
|
||||
Assembly assembly = typeof(Result).Assembly;
|
||||
|
||||
foreach (Type type in assembly.GetTypes().Where(x => x.Name.Contains("Result")))
|
||||
{
|
||||
foreach (PropertyInfo property in type.GetProperties()
|
||||
.Where(x => x.PropertyType == typeof(Result) && x.GetMethod.IsStatic && x.SetMethod == null))
|
||||
{
|
||||
var value = (Result)property.GetValue(null, null);
|
||||
string name = $"{type.Name}{property.Name}";
|
||||
|
||||
dict.Add(value, name);
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
public static bool TryGetResultName(Result result, out string name)
|
||||
{
|
||||
return ResultNames.TryGetValue(result, out name);
|
||||
}
|
||||
}
|
||||
}
|
218
src/hactoolnet/ResultLogger.cs
Normal file
218
src/hactoolnet/ResultLogger.cs
Normal file
@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using LibHac;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace hactoolnet
|
||||
{
|
||||
internal class ResultLogger : Result.IResultLogger, IDisposable
|
||||
{
|
||||
private TextWriter Writer { get; }
|
||||
private bool PrintStackTrace { get; }
|
||||
private bool PrintSourceInfo { get; }
|
||||
private bool CombineRepeats { get; }
|
||||
|
||||
private LogEntry _pendingEntry;
|
||||
private bool LastEntryPrintedNewLine { get; set; } = true;
|
||||
|
||||
public ResultLogger(TextWriter writer, bool printStackTrace, bool printSourceInfo, bool combineRepeats)
|
||||
{
|
||||
Writer = writer ?? throw new ArgumentNullException(nameof(writer));
|
||||
PrintStackTrace = printStackTrace;
|
||||
PrintSourceInfo = printSourceInfo;
|
||||
CombineRepeats = combineRepeats;
|
||||
|
||||
bool isDebugMode = false;
|
||||
CheckIfDebugMode(ref isDebugMode);
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
if (!isDebugMode)
|
||||
{
|
||||
Writer.WriteLine("The result log is only enabled when running in debug mode.");
|
||||
}
|
||||
}
|
||||
|
||||
public void LogResult(Result result)
|
||||
{
|
||||
StackTrace st = GetStackTrace();
|
||||
MethodBase method = st.GetFrame(0).GetMethod();
|
||||
|
||||
// This result from these functions is usually noise because they
|
||||
// are frequently used to detect if a file exists
|
||||
if (ResultFs.PathNotFound.Includes(result) &&
|
||||
typeof(IFileSystem).IsAssignableFrom(method.DeclaringType) &&
|
||||
method.Name.StartsWith(nameof(IFileSystem.GetEntryType)) ||
|
||||
method.Name.StartsWith(nameof(IAttributeFileSystem.GetFileAttributes)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddLogEntry(new LogEntry(result, st));
|
||||
}
|
||||
|
||||
public void LogConvertedResult(Result result, Result originalResult)
|
||||
{
|
||||
StackTrace st = GetStackTrace();
|
||||
|
||||
AddLogEntry(new LogEntry(result, st, originalResult));
|
||||
}
|
||||
|
||||
private void AddLogEntry(LogEntry entry)
|
||||
{
|
||||
if (CombineRepeats && _pendingEntry.IsRepeat(entry, PrintStackTrace && !entry.IsConvertedResult))
|
||||
{
|
||||
_pendingEntry.TimesCalled++;
|
||||
return;
|
||||
}
|
||||
|
||||
PrintPendingEntry();
|
||||
|
||||
if (CombineRepeats)
|
||||
{
|
||||
_pendingEntry = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLogEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintPendingEntry()
|
||||
{
|
||||
if (_pendingEntry.StackTrace != null)
|
||||
{
|
||||
PrintLogEntry(_pendingEntry);
|
||||
_pendingEntry = default;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintLogEntry(LogEntry entry)
|
||||
{
|
||||
MethodBase method = entry.StackTrace.GetFrame(0).GetMethod();
|
||||
string methodName = $"{method.DeclaringType?.FullName}.{method.Name}";
|
||||
|
||||
bool printStackTrace = PrintStackTrace && !entry.IsConvertedResult;
|
||||
|
||||
// Make sure there's a new line if printing a stack trace
|
||||
// A stack trace includes a new line at the end of it, so add the new line only if needed
|
||||
string entryText = printStackTrace && !LastEntryPrintedNewLine ? Environment.NewLine : string.Empty;
|
||||
|
||||
string lineNumber = entry.LineNumber > 0 ? $":line{entry.LineNumber}" : string.Empty;
|
||||
|
||||
if (entry.IsConvertedResult)
|
||||
{
|
||||
entryText += $"{entry.OriginalResult.ToStringWithName()} was converted to {entry.Result.ToStringWithName()} by {methodName}{lineNumber}";
|
||||
}
|
||||
else
|
||||
{
|
||||
entryText += $"{entry.Result.ToStringWithName()} was returned by {methodName}{lineNumber}";
|
||||
}
|
||||
|
||||
if (entry.TimesCalled > 1)
|
||||
{
|
||||
entryText += $" {entry.TimesCalled} times";
|
||||
}
|
||||
|
||||
Writer.WriteLine(entryText);
|
||||
|
||||
if (printStackTrace)
|
||||
{
|
||||
Writer.WriteLine(entry.StackTraceText);
|
||||
}
|
||||
|
||||
LastEntryPrintedNewLine = printStackTrace;
|
||||
}
|
||||
|
||||
// Returns the stack trace starting at the method that called Log()
|
||||
private StackTrace GetStackTrace()
|
||||
{
|
||||
var st = new StackTrace();
|
||||
int framesToSkip = 0;
|
||||
|
||||
for (; framesToSkip < st.FrameCount; framesToSkip++)
|
||||
{
|
||||
Type declaringType = st.GetFrame(framesToSkip)?.GetMethod()?.DeclaringType;
|
||||
|
||||
if (declaringType == null)
|
||||
{
|
||||
framesToSkip = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (declaringType != typeof(ResultLogger) &&
|
||||
declaringType != typeof(Result) &&
|
||||
declaringType != typeof(Result.Base))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new StackTrace(framesToSkip, PrintSourceInfo);
|
||||
}
|
||||
|
||||
// You can't negate a conditional attribute, so this is a hacky workaround
|
||||
[Conditional("DEBUG")]
|
||||
// ReSharper disable once RedundantAssignment
|
||||
private void CheckIfDebugMode(ref bool isDebugMode)
|
||||
{
|
||||
isDebugMode = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PrintPendingEntry();
|
||||
Writer.Dispose();
|
||||
}
|
||||
|
||||
private struct LogEntry
|
||||
{
|
||||
public Result Result { get; }
|
||||
public Result OriginalResult { get; }
|
||||
public string CallingMethod { get; }
|
||||
public StackTrace StackTrace { get; }
|
||||
public string StackTraceText { get; }
|
||||
|
||||
// Line number will be 0 if there's no source info
|
||||
public int LineNumber { get; }
|
||||
public int TimesCalled { get; set; }
|
||||
public bool IsConvertedResult { get; }
|
||||
|
||||
public LogEntry(Result result, StackTrace stackTrace) : this(result, stackTrace, false, default) { }
|
||||
public LogEntry(Result result, StackTrace stackTrace, Result originalResult) : this(result, stackTrace, true, originalResult) { }
|
||||
|
||||
private LogEntry(Result result, StackTrace stackTrace, bool isConverted, Result originalResult)
|
||||
{
|
||||
Result = result;
|
||||
StackTrace = stackTrace;
|
||||
IsConvertedResult = isConverted;
|
||||
OriginalResult = originalResult;
|
||||
|
||||
MethodBase method = stackTrace.GetFrame(0).GetMethod();
|
||||
CallingMethod = $"{method.DeclaringType?.FullName}.{method.Name}";
|
||||
|
||||
StackTraceText = stackTrace.ToString();
|
||||
LineNumber = stackTrace.GetFrame(0).GetFileLineNumber();
|
||||
TimesCalled = 1;
|
||||
}
|
||||
|
||||
public bool IsRepeat(LogEntry other, bool compareByStackTrace)
|
||||
{
|
||||
if (Result != other.Result ||
|
||||
IsConvertedResult != other.IsConvertedResult ||
|
||||
(IsConvertedResult && OriginalResult != other.OriginalResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compareByStackTrace)
|
||||
{
|
||||
return StackTraceText == other.StackTraceText;
|
||||
}
|
||||
|
||||
return LineNumber == other.LineNumber && CallingMethod == other.CallingMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
src/hactoolnet/ResultNameResolver.cs
Normal file
37
src/hactoolnet/ResultNameResolver.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using LibHac;
|
||||
|
||||
namespace hactoolnet
|
||||
{
|
||||
internal class ResultNameResolver : Result.IResultNameResolver
|
||||
{
|
||||
private Lazy<Dictionary<Result, string>> ResultNames { get; } = new Lazy<Dictionary<Result, string>>(GetResultNames);
|
||||
|
||||
public bool TryResolveName(Result result, out string name)
|
||||
{
|
||||
return ResultNames.Value.TryGetValue(result, out name);
|
||||
}
|
||||
|
||||
private static Dictionary<Result, string> GetResultNames()
|
||||
{
|
||||
var dict = new Dictionary<Result, string>();
|
||||
|
||||
Assembly assembly = typeof(Result).Assembly;
|
||||
|
||||
foreach (TypeInfo type in assembly.DefinedTypes.Where(x => x.Name.Contains("Result")))
|
||||
foreach (PropertyInfo property in type.DeclaredProperties
|
||||
.Where(x => x.PropertyType == typeof(Result.Base) && x.GetMethod.IsStatic && x.SetMethod == null))
|
||||
{
|
||||
Result value = ((Result.Base)property.GetValue(null, null)).Value;
|
||||
string name = $"{type.Name}{property.Name}";
|
||||
|
||||
dict[value] = name;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user