Move some functions from Utilities to LibHac.Util.*

This commit is contained in:
Alex Barney 2020-11-19 15:39:17 -07:00
parent 7fcb0054e4
commit acce155341
25 changed files with 242 additions and 178 deletions

View File

@ -340,7 +340,7 @@ namespace LibHac.Boot
int pk11Size = Unsafe.SizeOf<Package1Pk11Header>() + GetSectionSize(Package1Section.WarmBoot) +
GetSectionSize(Package1Section.Bootloader) + GetSectionSize(Package1Section.SecureMonitor);
pk11Size = Utilities.AlignUp(pk11Size, 0x10);
pk11Size = Alignment.AlignUp(pk11Size, 0x10);
return pk11Size == Pk11Size;
}

View File

@ -5,6 +5,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using LibHac.Common;
using LibHac.Util;
namespace LibHac.Crypto.Detail
{
@ -25,7 +26,7 @@ namespace LibHac.Crypto.Detail
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
int blockCount = Utilities.DivideByRoundUp(input.Length, Aes.BlockSize);
int blockCount = BitUtil.DivideUp(input.Length, Aes.BlockSize);
int length = blockCount * Aes.BlockSize;
using var counterBuffer = new RentedArray<byte>(length);

View File

@ -59,7 +59,7 @@ namespace LibHac.Crypto
BigInteger dp = d % (p - BigInteger.One);
BigInteger dq = d % (q - BigInteger.One);
BigInteger inverseQ = Utilities.ModInverse(q, p);
BigInteger inverseQ = ModInverse(q, p);
byte[] nBytes = n.ToByteArray();
int modLen = nBytes.Length;
@ -138,7 +138,7 @@ namespace LibHac.Crypto
do
{
rng.NextBytes(rndBuf);
g = Utilities.GetBigInteger(rndBuf);
g = GetBigInteger(rndBuf);
}
while (g >= n);
@ -179,5 +179,66 @@ namespace LibHac.Crypto
return (p, q);
}
private static BigInteger GetBigInteger(this ReadOnlySpan<byte> bytes)
{
var signPadded = new byte[bytes.Length + 1];
bytes.CopyTo(signPadded.AsSpan(1));
Array.Reverse(signPadded);
return new BigInteger(signPadded);
}
private static byte[] GetBytes(this BigInteger value, int size)
{
byte[] bytes = value.ToByteArray();
if (size == -1)
{
size = bytes.Length;
}
if (bytes.Length > size + 1)
{
throw new InvalidOperationException($"Cannot squeeze value {value} to {size} bytes from {bytes.Length}.");
}
if (bytes.Length == size + 1 && bytes[bytes.Length - 1] != 0)
{
throw new InvalidOperationException($"Cannot squeeze value {value} to {size} bytes from {bytes.Length}.");
}
Array.Resize(ref bytes, size);
Array.Reverse(bytes);
return bytes;
}
private static BigInteger ModInverse(BigInteger e, BigInteger n)
{
BigInteger r = n;
BigInteger newR = e;
BigInteger t = 0;
BigInteger newT = 1;
while (newR != 0)
{
BigInteger quotient = r / newR;
BigInteger temp;
temp = t;
t = newT;
newT = temp - quotient * newT;
temp = r;
r = newR;
newR = temp - quotient * newR;
}
if (t < 0)
{
t = t + n;
}
return t;
}
}
}

View File

@ -4,6 +4,7 @@ using LibHac.Account;
using LibHac.Fs.Shim;
using LibHac.Ncm;
using LibHac.Ns;
using LibHac.Util;
namespace LibHac.Fs
{
@ -101,7 +102,7 @@ namespace LibHac.Fs
if (queryRc.IsFailure()) return queryRc;
requiredSizeSum += Utilities.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000;
requiredSizeSum += Alignment.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000;
}
}
else
@ -118,7 +119,7 @@ namespace LibHac.Fs
if (queryRc.IsFailure()) return queryRc;
requiredSizeSum += Utilities.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000;
requiredSizeSum += Alignment.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000;
}
else if (ResultFs.PathAlreadyExists.Includes(createRc))
{
@ -162,7 +163,7 @@ namespace LibHac.Fs
Result queryRc = fs.QuerySaveDataTotalSize(out long totalSize, dataSize, journalSize);
if (queryRc.IsFailure()) return queryRc;
requiredSize += Utilities.AlignUp(totalSize, 0x4000) + baseSize;
requiredSize += Alignment.AlignUp(totalSize, 0x4000) + baseSize;
}
else if (!ResultFs.PathAlreadyExists.Includes(rc))
{

View File

@ -5,6 +5,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Util;
namespace LibHac.FsSrv.Impl
{
@ -127,7 +128,7 @@ namespace LibHac.FsSrv.Impl
accessControlData.Slice(data.SaveDataOwnerInfoOffset + sizeof(int), infoCount);
// The ID list must be 4-byte aligned
int idsOffset = Utilities.AlignUp(data.SaveDataOwnerInfoOffset + sizeof(int) + infoCount, 4);
int idsOffset = Alignment.AlignUp(data.SaveDataOwnerInfoOffset + sizeof(int) + infoCount, 4);
ReadOnlySpan<ulong> ids = MemoryMarshal.Cast<byte, ulong>(
accessControlData.Slice(idsOffset, infoCount * sizeof(ulong)));

View File

@ -3,6 +3,7 @@ using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -36,7 +37,7 @@ namespace LibHac.FsSystem
public int TransformBlock(Span<byte> data)
{
int blockCount = Utilities.DivideByRoundUp(data.Length, BlockSizeBytes);
int blockCount = BitUtil.DivideUp(data.Length, BlockSizeBytes);
int length = blockCount * BlockSizeBytes;
byte[] counterXor = ArrayPool<byte>.Shared.Rent(length);

View File

@ -28,6 +28,7 @@ using System;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -83,7 +84,7 @@ namespace LibHac.FsSystem
/* get number of blocks */
int m = count >> 4;
int mo = count & 15;
int alignedCount = Utilities.AlignUp(count, BlockSizeBytes);
int alignedCount = Alignment.AlignUp(count, BlockSizeBytes);
/* for i = 0 to m-2 do */
if (mo == 0)

View File

@ -2,6 +2,7 @@
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -37,7 +38,7 @@ namespace LibHac.FsSystem
ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderInvalidKeys.Value, "NAX0 key derivation failed.");
}
if (HeaderLength + Utilities.AlignUp(Header.Size, 0x10) > fileSize)
if (HeaderLength + Alignment.AlignUp(Header.Size, 0x10) > fileSize)
{
ThrowHelper.ThrowResult(ResultFs.AesXtsFileTooShort.Value, "NAX0 key derivation failed.");
}
@ -118,7 +119,7 @@ namespace LibHac.FsSystem
Result rc = BaseFile.Write(0, Header.ToBytes(false));
if (rc.IsFailure()) return rc;
return BaseStorage.SetSize(Utilities.AlignUp(size, 0x10));
return BaseStorage.SetSize(Alignment.AlignUp(size, 0x10));
}
protected override void Dispose(bool disposing)

View File

@ -3,6 +3,7 @@ using System.Diagnostics;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -62,7 +63,7 @@ namespace LibHac.FsSystem
/// <param name="key">The 256-bit key containing a 128-bit data key followed by a 128-bit tweak key.</param>
public Result CreateFile(U8Span path, long size, CreateFileOptions options, byte[] key)
{
long containerSize = AesXtsFile.HeaderLength + Utilities.AlignUp(size, 0x10);
long containerSize = AesXtsFile.HeaderLength + Alignment.AlignUp(size, 0x10);
Result rc = BaseFileSystem.CreateFile(path, containerSize, options);
if (rc.IsFailure()) return rc;

View File

@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -37,7 +38,7 @@ namespace LibHac.FsSystem
Assert.AssertTrue(entrySize >= sizeof(long));
Assert.AssertTrue(nodeSize >= entrySize + Unsafe.SizeOf<NodeHeader>());
Assert.AssertTrue(NodeSizeMin <= nodeSize && nodeSize <= NodeSizeMax);
Assert.AssertTrue(Utilities.IsPowerOfTwo(nodeSize));
Assert.AssertTrue(BitUtil.IsPowerOfTwo(nodeSize));
Assert.AssertTrue(!IsInitialized());
// Ensure valid entry count.
@ -139,7 +140,7 @@ namespace LibHac.FsSystem
Assert.AssertTrue(entrySize >= sizeof(long));
Assert.AssertTrue(nodeSize >= entrySize + Unsafe.SizeOf<NodeHeader>());
Assert.AssertTrue(NodeSizeMin <= nodeSize && nodeSize <= NodeSizeMax);
Assert.AssertTrue(Utilities.IsPowerOfTwo(nodeSize));
Assert.AssertTrue(BitUtil.IsPowerOfTwo(nodeSize));
Assert.AssertTrue(entryCount >= 0);
if (entryCount <= 0)
@ -153,7 +154,7 @@ namespace LibHac.FsSystem
Assert.AssertTrue(entrySize >= sizeof(long));
Assert.AssertTrue(nodeSize >= entrySize + Unsafe.SizeOf<NodeHeader>());
Assert.AssertTrue(NodeSizeMin <= nodeSize && nodeSize <= NodeSizeMax);
Assert.AssertTrue(Utilities.IsPowerOfTwo(nodeSize));
Assert.AssertTrue(BitUtil.IsPowerOfTwo(nodeSize));
Assert.AssertTrue(entryCount >= 0);
if (entryCount <= 0)
@ -175,7 +176,7 @@ namespace LibHac.FsSystem
private static int GetEntrySetCount(long nodeSize, long entrySize, int entryCount)
{
int entryCountPerNode = GetEntryCount(nodeSize, entrySize);
return Utilities.DivideByRoundUp(entryCount, entryCountPerNode);
return BitUtil.DivideUp(entryCount, entryCountPerNode);
}
public static int GetNodeL2Count(long nodeSize, long entrySize, int entryCount)
@ -186,10 +187,10 @@ namespace LibHac.FsSystem
if (entrySetCount <= offsetCountPerNode)
return 0;
int nodeL2Count = Utilities.DivideByRoundUp(entrySetCount, offsetCountPerNode);
int nodeL2Count = BitUtil.DivideUp(entrySetCount, offsetCountPerNode);
Abort.DoAbortUnless(nodeL2Count <= offsetCountPerNode);
return Utilities.DivideByRoundUp(entrySetCount - (offsetCountPerNode - (nodeL2Count - 1)), offsetCountPerNode);
return BitUtil.DivideUp(entrySetCount - (offsetCountPerNode - (nodeL2Count - 1)), offsetCountPerNode);
}
private static long GetBucketTreeEntryOffset(long entrySetOffset, long entrySize, int entryIndex)

View File

@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -44,7 +45,7 @@ namespace LibHac.FsSystem
Assert.AssertTrue(entrySize >= sizeof(long));
Assert.AssertTrue(nodeSize >= entrySize + Unsafe.SizeOf<NodeHeader>());
Assert.AssertTrue(NodeSizeMin <= nodeSize && nodeSize <= NodeSizeMax);
Assert.AssertTrue(Utilities.IsPowerOfTwo(nodeSize));
Assert.AssertTrue(BitUtil.IsPowerOfTwo(nodeSize));
if (headerStorage is null || nodeStorage is null || entryStorage is null)
return ResultFs.NullptrArgument.Log();
@ -267,7 +268,7 @@ namespace LibHac.FsSystem
if (rc.IsFailure()) return rc;
}
int l2NodeIndex = Utilities.DivideByRoundUp(CurrentL2OffsetIndex, OffsetsPerNode) - 2;
int l2NodeIndex = BitUtil.DivideUp(CurrentL2OffsetIndex, OffsetsPerNode) - 2;
int indexInL2Node = CurrentL2OffsetIndex % OffsetsPerNode;
// Finalize the current L2 node if needed
@ -291,7 +292,7 @@ namespace LibHac.FsSystem
// L1 count depends on the existence or absence of L2 nodes
if (CurrentL2OffsetIndex == 0)
{
l1NodeHeader.Count = Utilities.DivideByRoundUp(CurrentEntryIndex, EntriesPerEntrySet);
l1NodeHeader.Count = BitUtil.DivideUp(CurrentEntryIndex, EntriesPerEntrySet);
}
else
{

View File

@ -6,6 +6,7 @@ using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -227,7 +228,7 @@ namespace LibHac.FsSystem
if (size == 0) return 1;
return (int)Utilities.DivideByRoundUp(size, subFileSize);
return (int)BitUtil.DivideUp(size, subFileSize);
}
private static long QuerySubFileSize(int subFileIndex, long totalSize, long subFileSize)

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Security.Cryptography;
using System.Text;
using LibHac.Fs;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -37,7 +38,7 @@ namespace LibHac.FsSystem
var levelData = new IntegrityVerificationStorage(levelInfo[i], Levels[i - 1], integrityCheckLevel, leaveOpen);
levelData.GetSize(out long levelSize).ThrowIfFailure();
int cacheCount = Math.Min((int)Utilities.DivideByRoundUp(levelSize, levelInfo[i].BlockSize), 4);
int cacheCount = Math.Min((int)BitUtil.DivideUp(levelSize, levelInfo[i].BlockSize), 4);
Levels[i] = new CachedStorage(levelData, cacheCount, leaveOpen);
LevelValidities[i - 1] = levelData.BlockValidities;
@ -145,7 +146,7 @@ namespace LibHac.FsSystem
IntegrityVerificationStorage storage = IntegrityStorages[IntegrityStorages.Length - 1];
long blockSize = storage.SectorSize;
int blockCount = (int)Utilities.DivideByRoundUp(Length, blockSize);
int blockCount = (int)BitUtil.DivideUp(Length, blockSize);
var buffer = new byte[blockSize];
var result = Validity.Valid;

View File

@ -150,7 +150,7 @@ namespace LibHac.FsSystem.NcaUtils
BaseStorage.GetSize(out long baseSize).ThrowIfFailure();
if (!Utilities.IsSubRange(offset, size, baseSize))
if (!IsSubRange(offset, size, baseSize))
{
throw new InvalidDataException(
$"Section offset (0x{offset:x}) and length (0x{size:x}) fall outside the total NCA length (0x{baseSize:x}).");
@ -693,7 +693,7 @@ namespace LibHac.FsSystem.NcaUtils
bodyStorage.GetSize(out long baseSize).ThrowIfFailure();
if (!Utilities.IsSubRange(offset, size, baseSize))
if (!IsSubRange(offset, size, baseSize))
{
throw new InvalidDataException(
$"Section offset (0x{offset + 0x400:x}) and length (0x{size:x}) fall outside the total NCA length (0x{baseSize + 0x400:x}).");
@ -763,5 +763,11 @@ namespace LibHac.FsSystem.NcaUtils
header.CounterType = counterType;
header.CounterVersion = counterVersion;
}
private static bool IsSubRange(long startIndex, long subLength, long length)
{
bool isOutOfRange = startIndex < 0 || startIndex > length || subLength < 0 || startIndex > length - subLength;
return !isOutOfRange;
}
}
}

View File

@ -7,6 +7,7 @@ using LibHac.Common;
using LibHac.Crypto;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -121,7 +122,7 @@ namespace LibHac.FsSystem
size += entry.NameLength + 1;
}
int endOffset = Utilities.AlignUp(startOffset + size, GetMetaDataAlignment(type));
int endOffset = Alignment.AlignUpPow2(startOffset + size, GetMetaDataAlignment(type));
return endOffset - startOffset;
}
@ -135,7 +136,7 @@ namespace LibHac.FsSystem
}
}
private int GetMetaDataAlignment(PartitionFileSystemType type)
private uint GetMetaDataAlignment(PartitionFileSystemType type)
{
switch (type)
{

View File

@ -5,6 +5,7 @@ using System.Linq;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Util;
namespace LibHac.FsSystem.RomFs
{
@ -61,7 +62,7 @@ namespace LibHac.FsSystem.RomFs
Sources.Add(fileStorage);
long newOffset = CurrentOffset + fileSize;
CurrentOffset = Utilities.AlignUp(newOffset, FileAlignment);
CurrentOffset = Alignment.AlignUp(newOffset, FileAlignment);
var padding = new NullStorage(CurrentOffset - newOffset);
Sources.Add(padding);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Fs;
using LibHac.Util;
namespace LibHac.FsSystem.RomFs
{
@ -140,7 +141,7 @@ namespace LibHac.FsSystem.RomFs
private int CreateNewEntry(int nameLength)
{
int bytesNeeded = Utilities.AlignUp(_sizeOfEntry + nameLength, 4);
int bytesNeeded = Alignment.AlignUp(_sizeOfEntry + nameLength, 4);
if (_length + bytesNeeded > _capacity)
{

View File

@ -1,6 +1,7 @@
using System;
using System.IO;
using LibHac.Fs;
using LibHac.Util;
namespace LibHac.FsSystem.Save
{
@ -104,8 +105,8 @@ namespace LibHac.FsSystem.Save
protected override Result DoSetSize(long size)
{
int oldBlockCount = (int)Utilities.DivideByRoundUp(_length, BlockSize);
int newBlockCount = (int)Utilities.DivideByRoundUp(size, BlockSize);
int oldBlockCount = (int)BitUtil.DivideUp(_length, BlockSize);
int newBlockCount = (int)BitUtil.DivideUp(size, BlockSize);
if (oldBlockCount == newBlockCount) return Result.Success;

View File

@ -1,5 +1,6 @@
using System.IO;
using LibHac.Fs;
using LibHac.Util;
namespace LibHac.FsSystem.Save
{
@ -64,8 +65,8 @@ namespace LibHac.FsSystem.Save
int physicalBlockCount = virtualBlockCount + Header.JournalBlockCount;
int blockMapLength = virtualBlockCount * MapEntryLength;
int physicalBitmapLength = Utilities.AlignUp(physicalBlockCount, 32) / 8;
int virtualBitmapLength = Utilities.AlignUp(virtualBlockCount, 32) / 8;
int physicalBitmapLength = Alignment.AlignUp(physicalBlockCount, 32) / 8;
int virtualBitmapLength = Alignment.AlignUp(virtualBlockCount, 32) / 8;
MapStorage.Slice(blockMapLength).Fill(SaveDataFileSystem.TrimFillValue);
FreeBlocks.Slice(physicalBitmapLength).Fill(SaveDataFileSystem.TrimFillValue);

View File

@ -3,6 +3,7 @@ using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Util;
namespace LibHac.FsSystem.Save
{
@ -57,7 +58,7 @@ namespace LibHac.FsSystem.Save
return Result.Success;
}
int blockCount = (int)Utilities.DivideByRoundUp(size, AllocationTable.Header.BlockSize);
int blockCount = (int)BitUtil.DivideUp(size, AllocationTable.Header.BlockSize);
int startBlock = AllocationTable.Allocate(blockCount);
if (startBlock == -1)

View File

@ -1,5 +1,6 @@
using System;
using LibHac.Fs;
using LibHac.Util;
namespace LibHac.FsSystem
{
@ -20,7 +21,7 @@ namespace LibHac.FsSystem
baseStorage.GetSize(out long baseSize).ThrowIfFailure();
SectorCount = (int)Utilities.DivideByRoundUp(baseSize, SectorSize);
SectorCount = (int)BitUtil.DivideUp(baseSize, SectorSize);
Length = baseSize;
LeaveOpen = leaveOpen;
@ -57,7 +58,7 @@ namespace LibHac.FsSystem
rc = BaseStorage.GetSize(out long newSize);
if (rc.IsFailure()) return rc;
SectorCount = (int)Utilities.DivideByRoundUp(newSize, SectorSize);
SectorCount = (int)BitUtil.DivideUp(newSize, SectorSize);
Length = newSize;
return Result.Success;

View File

@ -1,6 +1,7 @@
using System;
using System.IO;
using LibHac.Common.Keys;
using LibHac.Util;
namespace LibHac
{
@ -112,7 +113,7 @@ namespace LibHac
throw new ArgumentOutOfRangeException();
}
long bodyStart = Utilities.GetNextMultiple(4 + sigLength, 0x40);
long bodyStart = Alignment.AlignUp(4 + sigLength, 0x40);
writer.Write((int)SignatureType);

View File

@ -0,0 +1,70 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Diag;
namespace LibHac.Util
{
public static class Alignment
{
// The alignment functions in this class come from C++ templates that always cast to unsigned types
public static ulong AlignUpPow2(ulong value, uint alignment)
{
Assert.AssertTrue(BitUtil.IsPowerOfTwo(alignment));
ulong invMask = alignment - 1;
return ((value + invMask) & ~invMask);
}
public static ulong AlignDownPow2(ulong value, uint alignment)
{
Assert.AssertTrue(BitUtil.IsPowerOfTwo(alignment));
ulong invMask = alignment - 1;
return (value & ~invMask);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static bool IsAlignedPow2(ulong value, uint alignment)
{
Assert.AssertTrue(BitUtil.IsPowerOfTwo(alignment));
ulong invMask = alignment - 1;
return (value & invMask) == 0;
}
public static bool IsAlignedPow2<T>(Span<T> buffer, uint alignment)
{
return IsAlignedPow2(buffer, alignment);
}
public static bool IsAlignedPow2<T>(ReadOnlySpan<T> buffer, uint alignment)
{
return IsAlignedPow2(ref MemoryMarshal.GetReference(buffer), alignment);
}
public static unsafe bool IsAlignedPow2<T>(ref T pointer, uint alignment)
{
return IsAlignedPow2((ulong)Unsafe.AsPointer(ref pointer), alignment);
}
public static int AlignUpPow2(int value, uint alignment) => (int)AlignUpPow2((ulong)value, alignment);
public static long AlignUpPow2(long value, uint alignment) => (long)AlignUpPow2((ulong)value, alignment);
public static int AlignDownPow2(int value, uint alignment) => (int)AlignDownPow2((ulong)value, alignment);
public static long AlignDownPow2(long value, uint alignment) => (long)AlignDownPow2((ulong)value, alignment);
public static bool IsAlignedPow2(int value, uint alignment) => IsAlignedPow2((ulong)value, alignment);
public static bool IsAlignedPow2(long value, uint alignment) => IsAlignedPow2((ulong)value, alignment);
public static ulong AlignUp(ulong value, uint alignment) => AlignDown(value + alignment - 1, alignment);
public static ulong AlignDown(ulong value, uint alignment) => value - value % alignment;
public static bool IsAligned(ulong value, uint alignment) => value % alignment == 0;
public static int AlignUp(int value, uint alignment) => (int)AlignUp((ulong)value, alignment);
public static long AlignUp(long value, uint alignment) => (long)AlignUp((ulong)value, alignment);
public static int AlignDown(int value, uint alignment) => (int)AlignDown((ulong)value, alignment);
public static long AlignDown(long value, uint alignment) => (long)AlignDown((ulong)value, alignment);
public static bool IsAligned(int value, uint alignment) => IsAligned((ulong)value, alignment);
public static bool IsAligned(long value, uint alignment) => IsAligned((ulong)value, alignment);
}
}

View File

@ -0,0 +1,46 @@
using System.Runtime.CompilerServices;
namespace LibHac.Util
{
public static class BitUtil
{
public static bool IsPowerOfTwo(int value)
{
return value > 0 && ResetLeastSignificantOneBit(value) == 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPowerOfTwo(long value)
{
return value > 0 && ResetLeastSignificantOneBit(value) == 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPowerOfTwo(ulong value)
{
return value > 0 && ResetLeastSignificantOneBit(value) == 0;
}
private static int ResetLeastSignificantOneBit(int value)
{
return value & (value - 1);
}
private static long ResetLeastSignificantOneBit(long value)
{
return value & (value - 1);
}
private static ulong ResetLeastSignificantOneBit(ulong value)
{
return value & (value - 1);
}
// DivideUp comes from a C++ template that always casts to unsigned types
public static uint DivideUp(uint value, uint divisor) => (value + divisor - 1) / divisor;
public static ulong DivideUp(ulong value, ulong divisor) => (value + divisor - 1) / divisor;
public static int DivideUp(int value, int divisor) => (int)DivideUp((uint)value, (uint)divisor);
public static long DivideUp(long value, long divisor) => (long)DivideUp((ulong)value, (ulong)divisor);
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
@ -11,35 +10,6 @@ namespace LibHac
{
private const int MediaSize = 0x200;
public static byte[][] CreateJaggedByteArray(int len1, int len2)
{
var array = new byte[len1][];
for (int i = 0; i < array.Length; i++)
{
array[i] = new byte[len2];
}
return array;
}
public static byte[][][] CreateJaggedByteArray(int len1, int len2, int len3)
{
var array = new byte[len1][][];
for (int i = 0; i < array.Length; i++)
{
array[i] = new byte[len2][];
for (int j = 0; j < array[i].Length; j++)
{
array[i][j] = new byte[len3];
}
}
return array;
}
public static bool ArraysEqual<T>(T[] a1, T[] a2)
{
if (a1 == null || a2 == null) return false;
@ -265,26 +235,7 @@ namespace LibHac
// Return formatted number with suffix
return readable.ToString("0.### ") + suffix;
}
public static long GetNextMultiple(long value, int multiple)
{
if (multiple <= 0)
return value;
if (value % multiple == 0)
return value;
return value + multiple - value % multiple;
}
public static int DivideByRoundUp(int value, int divisor) => (value + divisor - 1) / divisor;
public static long DivideByRoundUp(long value, long divisor) => (value + divisor - 1) / divisor;
public static int AlignUp(int value, int multiple) => AlignDown(value + multiple - 1, multiple);
public static long AlignUp(long value, long multiple) => AlignDown(value + multiple - 1, multiple);
public static int AlignDown(int value, int multiple) => value - value % multiple;
public static long AlignDown(long value, long multiple) => value - value % multiple;
public static void IncrementByteArray(byte[] array)
{
for (int i = array.Length - 1; i >= 0; i--)
@ -341,100 +292,11 @@ namespace LibHac
_ => "Unknown"
};
public static bool IsSubRange(long startIndex, long subLength, long length)
{
bool isOutOfRange = startIndex < 0 || startIndex > length || subLength < 0 || startIndex > length - subLength;
return !isOutOfRange;
}
public static int GetMasterKeyRevision(int keyGeneration)
{
if (keyGeneration == 0) return 0;
return keyGeneration - 1;
}
public static bool IsPowerOfTwo(int value)
{
return value > 0 && ResetLeastSignificantOneBit(value) == 0;
}
public static bool IsPowerOfTwo(long value)
{
return value > 0 && ResetLeastSignificantOneBit(value) == 0;
}
public static BigInteger GetBigInteger(this ReadOnlySpan<byte> bytes)
{
var signPadded = new byte[bytes.Length + 1];
bytes.CopyTo(signPadded.AsSpan(1));
Array.Reverse(signPadded);
return new BigInteger(signPadded);
}
public static byte[] GetBytes(this BigInteger value, int size)
{
byte[] bytes = value.ToByteArray();
if (size == -1)
{
size = bytes.Length;
}
if (bytes.Length > size + 1)
{
throw new InvalidOperationException($"Cannot squeeze value {value} to {size} bytes from {bytes.Length}.");
}
if (bytes.Length == size + 1 && bytes[bytes.Length - 1] != 0)
{
throw new InvalidOperationException($"Cannot squeeze value {value} to {size} bytes from {bytes.Length}.");
}
Array.Resize(ref bytes, size);
Array.Reverse(bytes);
return bytes;
}
public static BigInteger ModInverse(BigInteger e, BigInteger n)
{
BigInteger r = n;
BigInteger newR = e;
BigInteger t = 0;
BigInteger newT = 1;
while (newR != 0)
{
BigInteger quotient = r / newR;
BigInteger temp;
temp = t;
t = newT;
newT = temp - quotient * newT;
temp = r;
r = newR;
newR = temp - quotient * newR;
}
if (t < 0)
{
t = t + n;
}
return t;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int ResetLeastSignificantOneBit(int value)
{
return value & (value - 1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long ResetLeastSignificantOneBit(long value)
{
return value & (value - 1);
}
}
}