mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-29 09:57:09 +02:00
Move solution and projects to src
This commit is contained in:
parent
cd124bda58
commit
cee7121058
3466 changed files with 55 additions and 55 deletions
60
src/Ryujinx.Common/Utilities/BitUtils.cs
Normal file
60
src/Ryujinx.Common/Utilities/BitUtils.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class BitUtils
|
||||
{
|
||||
public static T AlignUp<T>(T value, T size)
|
||||
where T : IBinaryInteger<T>
|
||||
{
|
||||
return (value + (size - T.One)) & -size;
|
||||
}
|
||||
|
||||
public static T AlignDown<T>(T value, T size)
|
||||
where T : IBinaryInteger<T>
|
||||
{
|
||||
return value & -size;
|
||||
}
|
||||
|
||||
public static T DivRoundUp<T>(T value, T dividend)
|
||||
where T : IBinaryInteger<T>
|
||||
{
|
||||
return (value + (dividend - T.One)) / dividend;
|
||||
}
|
||||
|
||||
public static int Pow2RoundUp(int value)
|
||||
{
|
||||
value--;
|
||||
|
||||
value |= (value >> 1);
|
||||
value |= (value >> 2);
|
||||
value |= (value >> 4);
|
||||
value |= (value >> 8);
|
||||
value |= (value >> 16);
|
||||
|
||||
return ++value;
|
||||
}
|
||||
|
||||
public static int Pow2RoundDown(int value)
|
||||
{
|
||||
return BitOperations.IsPow2(value) ? value : Pow2RoundUp(value) >> 1;
|
||||
}
|
||||
|
||||
public static long ReverseBits64(long value)
|
||||
{
|
||||
return (long)ReverseBits64((ulong)value);
|
||||
}
|
||||
|
||||
private static ulong ReverseBits64(ulong value)
|
||||
{
|
||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1 ) | ((value & 0x5555555555555555) << 1 );
|
||||
value = ((value & 0xcccccccccccccccc) >> 2 ) | ((value & 0x3333333333333333) << 2 );
|
||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4 ) | ((value & 0x0f0f0f0f0f0f0f0f) << 4 );
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8 ) | ((value & 0x00ff00ff00ff00ff) << 8 );
|
||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
return (value >> 32) | (value << 32);
|
||||
}
|
||||
}
|
||||
}
|
57
src/Ryujinx.Common/Utilities/BitfieldExtensions.cs
Normal file
57
src/Ryujinx.Common/Utilities/BitfieldExtensions.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class BitfieldExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Extract<T>(this T value, int lsb) where T : IBinaryInteger<T>
|
||||
{
|
||||
int bitSize = Unsafe.SizeOf<T>() * 8;
|
||||
lsb &= bitSize - 1;
|
||||
|
||||
return !T.IsZero((value >>> lsb) & T.One);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Extract<T>(this T value, int lsb, int length) where T : IBinaryInteger<T>
|
||||
{
|
||||
int bitSize = Unsafe.SizeOf<T>() * 8;
|
||||
lsb &= bitSize - 1;
|
||||
|
||||
return (value >>> lsb) & (~T.Zero >>> (bitSize - length));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ExtractSx<T>(this T value, int lsb, int length) where T : IBinaryInteger<T>
|
||||
{
|
||||
int bitSize = Unsafe.SizeOf<T>() * 8;
|
||||
int shift = lsb & (bitSize - 1);
|
||||
|
||||
return (value << (bitSize - (shift + length))) >> (bitSize - length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Insert<T>(this T value, int lsb, bool toInsert) where T : IBinaryInteger<T>
|
||||
{
|
||||
int bitSize = Unsafe.SizeOf<T>() * 8;
|
||||
lsb &= bitSize - 1;
|
||||
|
||||
T mask = T.One << lsb;
|
||||
|
||||
return (value & ~mask) | (toInsert ? mask : T.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Insert<T>(this T value, int lsb, int length, T toInsert) where T : IBinaryInteger<T>
|
||||
{
|
||||
int bitSize = Unsafe.SizeOf<T>() * 8;
|
||||
lsb &= bitSize - 1;
|
||||
|
||||
T mask = (~T.Zero >>> (bitSize - length)) << lsb;
|
||||
|
||||
return (value & ~mask) | ((toInsert << lsb) & mask);
|
||||
}
|
||||
}
|
||||
}
|
59
src/Ryujinx.Common/Utilities/Buffers.cs
Normal file
59
src/Ryujinx.Common/Utilities/Buffers.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
public struct Buffer16
|
||||
{
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
|
||||
|
||||
public byte this[int i]
|
||||
{
|
||||
get => Bytes[i];
|
||||
set => Bytes[i] = value;
|
||||
}
|
||||
|
||||
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
|
||||
|
||||
// Prevent a defensive copy by changing the read-only in reference to a reference with Unsafe.AsRef()
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator Span<byte>(in Buffer16 value)
|
||||
{
|
||||
return SpanHelpers.AsByteSpan(ref Unsafe.AsRef(in value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ReadOnlySpan<byte>(in Buffer16 value)
|
||||
{
|
||||
return SpanHelpers.AsReadOnlyByteSpan(ref Unsafe.AsRef(in value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref T As<T>() where T : unmanaged
|
||||
{
|
||||
if (Unsafe.SizeOf<T>() > (uint)Unsafe.SizeOf<Buffer16>())
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
return ref MemoryMarshal.GetReference(AsSpan<T>());
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Span<T> AsSpan<T>() where T : unmanaged
|
||||
{
|
||||
return SpanHelpers.AsSpan<Buffer16, T>(ref this);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly ReadOnlySpan<T> AsReadOnlySpan<T>() where T : unmanaged
|
||||
{
|
||||
return SpanHelpers.AsReadOnlySpan<Buffer16, T>(ref Unsafe.AsRef(in this));
|
||||
}
|
||||
}
|
||||
}
|
11
src/Ryujinx.Common/Utilities/CommonJsonContext.cs
Normal file
11
src/Ryujinx.Common/Utilities/CommonJsonContext.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
[JsonSerializable(typeof(string[]), TypeInfoPropertyName = "StringArray")]
|
||||
[JsonSerializable(typeof(Dictionary<string, string>), TypeInfoPropertyName = "StringDictionary")]
|
||||
public partial class CommonJsonContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
}
|
148
src/Ryujinx.Common/Utilities/EmbeddedResources.cs
Normal file
148
src/Ryujinx.Common/Utilities/EmbeddedResources.cs
Normal file
|
@ -0,0 +1,148 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class EmbeddedResources
|
||||
{
|
||||
private readonly static Assembly ResourceAssembly;
|
||||
|
||||
static EmbeddedResources()
|
||||
{
|
||||
ResourceAssembly = Assembly.GetAssembly(typeof(EmbeddedResources));
|
||||
}
|
||||
|
||||
public static byte[] Read(string filename)
|
||||
{
|
||||
var (assembly, path) = ResolveManifestPath(filename);
|
||||
|
||||
return Read(assembly, path);
|
||||
}
|
||||
|
||||
public static Task<byte[]> ReadAsync(string filename)
|
||||
{
|
||||
var (assembly, path) = ResolveManifestPath(filename);
|
||||
|
||||
return ReadAsync(assembly, path);
|
||||
}
|
||||
|
||||
public static byte[] Read(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return StreamUtils.StreamToBytes(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public async static Task<byte[]> ReadAsync(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return await StreamUtils.StreamToBytesAsync(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadAllText(string filename)
|
||||
{
|
||||
var (assembly, path) = ResolveManifestPath(filename);
|
||||
|
||||
return ReadAllText(assembly, path);
|
||||
}
|
||||
|
||||
public static Task<string> ReadAllTextAsync(string filename)
|
||||
{
|
||||
var (assembly, path) = ResolveManifestPath(filename);
|
||||
|
||||
return ReadAllTextAsync(assembly, path);
|
||||
}
|
||||
|
||||
public static string ReadAllText(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async static Task<string> ReadAllTextAsync(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream GetStream(string filename)
|
||||
{
|
||||
var (assembly, path) = ResolveManifestPath(filename);
|
||||
|
||||
return GetStream(assembly, path);
|
||||
}
|
||||
|
||||
public static Stream GetStream(Assembly assembly, string filename)
|
||||
{
|
||||
var namespace_ = assembly.GetName().Name;
|
||||
var manifestUri = namespace_ + "." + filename.Replace('/', '.');
|
||||
|
||||
var stream = assembly.GetManifestResourceStream(manifestUri);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static string[] GetAllAvailableResources(string path, string ext = "")
|
||||
{
|
||||
return ResolveManifestPath(path).Item1.GetManifestResourceNames()
|
||||
.Where(r => r.EndsWith(ext))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static (Assembly, string) ResolveManifestPath(string filename)
|
||||
{
|
||||
var segments = filename.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (segments.Length >= 2)
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
if (assembly.GetName().Name == segments[0])
|
||||
{
|
||||
return (assembly, segments[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ResourceAssembly, filename);
|
||||
}
|
||||
}
|
||||
}
|
90
src/Ryujinx.Common/Utilities/HexUtils.cs
Normal file
90
src/Ryujinx.Common/Utilities/HexUtils.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class HexUtils
|
||||
{
|
||||
private static readonly char[] HexChars = "0123456789ABCDEF".ToCharArray();
|
||||
|
||||
private const int HexTableColumnWidth = 8;
|
||||
private const int HexTableColumnSpace = 3;
|
||||
|
||||
// Modified for Ryujinx
|
||||
// Original by Pascal Ganaye - CPOL License
|
||||
// https://www.codeproject.com/Articles/36747/Quick-and-Dirty-HexDump-of-a-Byte-Array
|
||||
public static string HexTable(byte[] bytes, int bytesPerLine = 16)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
return "<null>";
|
||||
}
|
||||
|
||||
int bytesLength = bytes.Length;
|
||||
|
||||
int firstHexColumn =
|
||||
HexTableColumnWidth
|
||||
+ HexTableColumnSpace;
|
||||
|
||||
int firstCharColumn = firstHexColumn
|
||||
+ bytesPerLine * HexTableColumnSpace
|
||||
+ (bytesPerLine - 1) / HexTableColumnWidth
|
||||
+ 2;
|
||||
|
||||
int lineLength = firstCharColumn
|
||||
+ bytesPerLine
|
||||
+ Environment.NewLine.Length;
|
||||
|
||||
char[] line = (new String(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray();
|
||||
|
||||
int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
|
||||
|
||||
StringBuilder result = new StringBuilder(expectedLines * lineLength);
|
||||
|
||||
for (int i = 0; i < bytesLength; i += bytesPerLine)
|
||||
{
|
||||
line[0] = HexChars[(i >> 28) & 0xF];
|
||||
line[1] = HexChars[(i >> 24) & 0xF];
|
||||
line[2] = HexChars[(i >> 20) & 0xF];
|
||||
line[3] = HexChars[(i >> 16) & 0xF];
|
||||
line[4] = HexChars[(i >> 12) & 0xF];
|
||||
line[5] = HexChars[(i >> 8) & 0xF];
|
||||
line[6] = HexChars[(i >> 4) & 0xF];
|
||||
line[7] = HexChars[(i >> 0) & 0xF];
|
||||
|
||||
int hexColumn = firstHexColumn;
|
||||
int charColumn = firstCharColumn;
|
||||
|
||||
for (int j = 0; j < bytesPerLine; j++)
|
||||
{
|
||||
if (j > 0 && (j & 7) == 0)
|
||||
{
|
||||
hexColumn++;
|
||||
}
|
||||
|
||||
if (i + j >= bytesLength)
|
||||
{
|
||||
line[hexColumn] = ' ';
|
||||
line[hexColumn + 1] = ' ';
|
||||
line[charColumn] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
byte b = bytes[i + j];
|
||||
|
||||
line[hexColumn] = HexChars[(b >> 4) & 0xF];
|
||||
line[hexColumn + 1] = HexChars[b & 0xF];
|
||||
line[charColumn] = (b < 32 ? '·' : (char)b);
|
||||
}
|
||||
|
||||
hexColumn += 3;
|
||||
charColumn++;
|
||||
}
|
||||
|
||||
result.Append(line);
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
}
|
98
src/Ryujinx.Common/Utilities/JsonHelper.cs
Normal file
98
src/Ryujinx.Common/Utilities/JsonHelper.cs
Normal file
|
@ -0,0 +1,98 @@
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public class JsonHelper
|
||||
{
|
||||
private static readonly JsonNamingPolicy SnakeCasePolicy = new SnakeCaseNamingPolicy();
|
||||
private const int DefaultFileWriteBufferSize = 4096;
|
||||
|
||||
/// <summary>
|
||||
/// Creates new serializer options with default settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is REQUIRED for you to save returned options statically or as a part of static serializer context
|
||||
/// in order to avoid performance issues. You can safely modify returned options for your case before storing.
|
||||
/// </remarks>
|
||||
public static JsonSerializerOptions GetDefaultSerializerOptions(bool indented = true)
|
||||
{
|
||||
JsonSerializerOptions options = new()
|
||||
{
|
||||
DictionaryKeyPolicy = SnakeCasePolicy,
|
||||
PropertyNamingPolicy = SnakeCasePolicy,
|
||||
WriteIndented = indented,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo)
|
||||
{
|
||||
return JsonSerializer.Serialize(value, typeInfo);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo)
|
||||
{
|
||||
return JsonSerializer.Deserialize(value, typeInfo);
|
||||
}
|
||||
|
||||
public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo)
|
||||
{
|
||||
using FileStream file = File.Create(filePath, DefaultFileWriteBufferSize, FileOptions.WriteThrough);
|
||||
JsonSerializer.Serialize(file, value, typeInfo);
|
||||
}
|
||||
|
||||
public static T DeserializeFromFile<T>(string filePath, JsonTypeInfo<T> typeInfo)
|
||||
{
|
||||
using FileStream file = File.OpenRead(filePath);
|
||||
return JsonSerializer.Deserialize(file, typeInfo);
|
||||
}
|
||||
|
||||
public static void SerializeToStream<T>(Stream stream, T value, JsonTypeInfo<T> typeInfo)
|
||||
{
|
||||
JsonSerializer.Serialize(stream, value, typeInfo);
|
||||
}
|
||||
|
||||
private class SnakeCaseNamingPolicy : JsonNamingPolicy
|
||||
{
|
||||
public override string ConvertName(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
StringBuilder builder = new();
|
||||
|
||||
for (int i = 0; i < name.Length; i++)
|
||||
{
|
||||
char c = name[i];
|
||||
|
||||
if (char.IsUpper(c))
|
||||
{
|
||||
if (i == 0 || char.IsUpper(name[i - 1]))
|
||||
{
|
||||
builder.Append(char.ToLowerInvariant(c));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append('_');
|
||||
builder.Append(char.ToLowerInvariant(c));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
302
src/Ryujinx.Common/Utilities/MessagePackObjectFormatter.cs
Normal file
302
src/Ryujinx.Common/Utilities/MessagePackObjectFormatter.cs
Normal file
|
@ -0,0 +1,302 @@
|
|||
using MsgPack;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class MessagePackObjectFormatter
|
||||
{
|
||||
public static string ToString(this MessagePackObject obj, bool pretty)
|
||||
{
|
||||
if (pretty)
|
||||
{
|
||||
return Format(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return obj.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static string Format(MessagePackObject obj)
|
||||
{
|
||||
var builder = new IndentedStringBuilder();
|
||||
|
||||
FormatMsgPackObj(obj, builder);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static void FormatMsgPackObj(MessagePackObject obj, IndentedStringBuilder builder)
|
||||
{
|
||||
if (obj.IsMap || obj.IsDictionary)
|
||||
{
|
||||
FormatMsgPackMap(obj, builder);
|
||||
}
|
||||
else if (obj.IsArray || obj.IsList)
|
||||
{
|
||||
FormatMsgPackArray(obj, builder);
|
||||
}
|
||||
else if (obj.IsNil)
|
||||
{
|
||||
builder.Append("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
var literal = obj.ToObject();
|
||||
|
||||
if (literal is String)
|
||||
{
|
||||
builder.AppendQuotedString(obj.AsStringUtf16());
|
||||
}
|
||||
else if (literal is byte[] byteArray)
|
||||
{
|
||||
FormatByteArray(byteArray, builder);
|
||||
}
|
||||
else if (literal is MessagePackExtendedTypeObject extObject)
|
||||
{
|
||||
builder.Append('{');
|
||||
|
||||
// Indent
|
||||
builder.IncreaseIndent()
|
||||
.AppendLine();
|
||||
|
||||
// Print TypeCode field
|
||||
builder.AppendQuotedString("TypeCode")
|
||||
.Append(": ")
|
||||
.Append(extObject.TypeCode)
|
||||
.AppendLine(",");
|
||||
|
||||
// Print Value field
|
||||
builder.AppendQuotedString("Value")
|
||||
.Append(": ");
|
||||
|
||||
FormatByteArrayAsString(extObject.GetBody(), builder, true);
|
||||
|
||||
// Unindent
|
||||
builder.DecreaseIndent()
|
||||
.AppendLine();
|
||||
|
||||
builder.Append('}');
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(literal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void FormatByteArray(byte[] arr, IndentedStringBuilder builder)
|
||||
{
|
||||
builder.Append("[ ");
|
||||
|
||||
foreach (var b in arr)
|
||||
{
|
||||
builder.Append("0x");
|
||||
builder.Append(ToHexChar(b >> 4));
|
||||
builder.Append(ToHexChar(b & 0xF));
|
||||
builder.Append(", ");
|
||||
}
|
||||
|
||||
// Remove trailing comma
|
||||
builder.Remove(builder.Length - 2, 2);
|
||||
|
||||
builder.Append(" ]");
|
||||
}
|
||||
|
||||
private static void FormatByteArrayAsString(byte[] arr, IndentedStringBuilder builder, bool withPrefix)
|
||||
{
|
||||
builder.Append('"');
|
||||
|
||||
if (withPrefix)
|
||||
{
|
||||
builder.Append("0x");
|
||||
}
|
||||
|
||||
foreach (var b in arr)
|
||||
{
|
||||
builder.Append(ToHexChar(b >> 4));
|
||||
builder.Append(ToHexChar(b & 0xF));
|
||||
}
|
||||
|
||||
builder.Append('"');
|
||||
}
|
||||
|
||||
private static void FormatMsgPackMap(MessagePackObject obj, IndentedStringBuilder builder)
|
||||
{
|
||||
var map = obj.AsDictionary();
|
||||
|
||||
builder.Append('{');
|
||||
|
||||
// Indent
|
||||
builder.IncreaseIndent()
|
||||
.AppendLine();
|
||||
|
||||
foreach (var item in map)
|
||||
{
|
||||
FormatMsgPackObj(item.Key, builder);
|
||||
|
||||
builder.Append(": ");
|
||||
|
||||
FormatMsgPackObj(item.Value, builder);
|
||||
|
||||
builder.AppendLine(",");
|
||||
}
|
||||
|
||||
// Remove the trailing new line and comma
|
||||
builder.TrimLastLine()
|
||||
.Remove(builder.Length - 1, 1);
|
||||
|
||||
// Unindent
|
||||
builder.DecreaseIndent()
|
||||
.AppendLine();
|
||||
|
||||
builder.Append('}');
|
||||
}
|
||||
|
||||
private static void FormatMsgPackArray(MessagePackObject obj, IndentedStringBuilder builder)
|
||||
{
|
||||
var arr = obj.AsList();
|
||||
|
||||
builder.Append("[ ");
|
||||
|
||||
foreach (var item in arr)
|
||||
{
|
||||
FormatMsgPackObj(item, builder);
|
||||
|
||||
builder.Append(", ");
|
||||
}
|
||||
|
||||
// Remove trailing comma
|
||||
builder.Remove(builder.Length - 2, 2);
|
||||
|
||||
builder.Append(" ]");
|
||||
}
|
||||
|
||||
private static char ToHexChar(int b)
|
||||
{
|
||||
if (b < 10)
|
||||
{
|
||||
return unchecked((char)('0' + b));
|
||||
}
|
||||
else
|
||||
{
|
||||
return unchecked((char)('A' + (b - 10)));
|
||||
}
|
||||
}
|
||||
|
||||
internal class IndentedStringBuilder
|
||||
{
|
||||
const string DefaultIndent = " ";
|
||||
|
||||
private int _indentCount = 0;
|
||||
private int _newLineIndex = 0;
|
||||
private StringBuilder _builder;
|
||||
|
||||
public string IndentString { get; set; } = DefaultIndent;
|
||||
|
||||
public IndentedStringBuilder(StringBuilder builder)
|
||||
{
|
||||
_builder = builder;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder()
|
||||
: this(new StringBuilder())
|
||||
{ }
|
||||
|
||||
public IndentedStringBuilder(string str)
|
||||
: this(new StringBuilder(str))
|
||||
{ }
|
||||
|
||||
public IndentedStringBuilder(int length)
|
||||
: this(new StringBuilder(length))
|
||||
{ }
|
||||
|
||||
public int Length { get => _builder.Length; }
|
||||
|
||||
public IndentedStringBuilder IncreaseIndent()
|
||||
{
|
||||
_indentCount++;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder DecreaseIndent()
|
||||
{
|
||||
_indentCount--;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder Append(char value)
|
||||
{
|
||||
_builder.Append(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder Append(string value)
|
||||
{
|
||||
_builder.Append(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder Append(object value)
|
||||
{
|
||||
this.Append(value.ToString());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder AppendQuotedString(string value)
|
||||
{
|
||||
_builder.Append('"');
|
||||
_builder.Append(value);
|
||||
_builder.Append('"');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder AppendLine()
|
||||
{
|
||||
_newLineIndex = _builder.Length;
|
||||
|
||||
_builder.AppendLine();
|
||||
|
||||
for (int i = 0; i < _indentCount; i++)
|
||||
_builder.Append(IndentString);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder AppendLine(string value)
|
||||
{
|
||||
_builder.Append(value);
|
||||
|
||||
this.AppendLine();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder TrimLastLine()
|
||||
{
|
||||
_builder.Remove(_newLineIndex, _builder.Length - _newLineIndex);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndentedStringBuilder Remove(int startIndex, int length)
|
||||
{
|
||||
_builder.Remove(startIndex, length);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
src/Ryujinx.Common/Utilities/NetworkHelpers.cs
Normal file
66
src/Ryujinx.Common/Utilities/NetworkHelpers.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class NetworkHelpers
|
||||
{
|
||||
private static (IPInterfaceProperties, UnicastIPAddressInformation) GetLocalInterface(NetworkInterface adapter, bool isPreferred)
|
||||
{
|
||||
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||||
|
||||
if (isPreferred || (properties.GatewayAddresses.Count > 0 && properties.DnsAddresses.Count > 0))
|
||||
{
|
||||
foreach (UnicastIPAddressInformation info in properties.UnicastAddresses)
|
||||
{
|
||||
// Only accept an IPv4 address
|
||||
if (info.Address.GetAddressBytes().Length == 4)
|
||||
{
|
||||
return (properties, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
public static (IPInterfaceProperties, UnicastIPAddressInformation) GetLocalInterface(string lanInterfaceId = "0")
|
||||
{
|
||||
if (!NetworkInterface.GetIsNetworkAvailable())
|
||||
{
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
IPInterfaceProperties targetProperties = null;
|
||||
UnicastIPAddressInformation targetAddressInfo = null;
|
||||
|
||||
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
|
||||
string guid = lanInterfaceId;
|
||||
bool hasPreference = guid != "0";
|
||||
|
||||
foreach (NetworkInterface adapter in interfaces)
|
||||
{
|
||||
bool isPreferred = adapter.Id == guid;
|
||||
|
||||
// Ignore loopback and non IPv4 capable interface.
|
||||
if (isPreferred || (targetProperties == null && adapter.NetworkInterfaceType != NetworkInterfaceType.Loopback && adapter.Supports(NetworkInterfaceComponent.IPv4)))
|
||||
{
|
||||
(IPInterfaceProperties properties, UnicastIPAddressInformation info) = GetLocalInterface(adapter, isPreferred);
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
targetProperties = properties;
|
||||
targetAddressInfo = info;
|
||||
|
||||
if (isPreferred || !hasPreference)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (targetProperties, targetAddressInfo);
|
||||
}
|
||||
}
|
||||
}
|
61
src/Ryujinx.Common/Utilities/SpanHelpers.cs
Normal file
61
src/Ryujinx.Common/Utilities/SpanHelpers.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class SpanHelpers
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Span<T> CreateSpan<T>(scoped ref T reference, int length)
|
||||
{
|
||||
return MemoryMarshal.CreateSpan(ref reference, length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Span<T> AsSpan<T>(scoped ref T reference) where T : unmanaged
|
||||
{
|
||||
return CreateSpan(ref reference, 1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Span<TSpan> AsSpan<TStruct, TSpan>(scoped ref TStruct reference)
|
||||
where TStruct : unmanaged where TSpan : unmanaged
|
||||
{
|
||||
return CreateSpan(ref Unsafe.As<TStruct, TSpan>(ref reference),
|
||||
Unsafe.SizeOf<TStruct>() / Unsafe.SizeOf<TSpan>());
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Span<byte> AsByteSpan<T>(scoped ref T reference) where T : unmanaged
|
||||
{
|
||||
return CreateSpan(ref Unsafe.As<T, byte>(ref reference), Unsafe.SizeOf<T>());
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length)
|
||||
{
|
||||
return MemoryMarshal.CreateReadOnlySpan(ref reference, length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ReadOnlySpan<T> AsReadOnlySpan<T>(scoped ref T reference) where T : unmanaged
|
||||
{
|
||||
return CreateReadOnlySpan(ref reference, 1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ReadOnlySpan<TSpan> AsReadOnlySpan<TStruct, TSpan>(scoped ref TStruct reference)
|
||||
where TStruct : unmanaged where TSpan : unmanaged
|
||||
{
|
||||
return CreateReadOnlySpan(ref Unsafe.As<TStruct, TSpan>(ref reference),
|
||||
Unsafe.SizeOf<TStruct>() / Unsafe.SizeOf<TSpan>());
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ReadOnlySpan<byte> AsReadOnlyByteSpan<T>(scoped ref T reference) where T : unmanaged
|
||||
{
|
||||
return CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref reference), Unsafe.SizeOf<T>());
|
||||
}
|
||||
}
|
||||
}
|
31
src/Ryujinx.Common/Utilities/StreamUtils.cs
Normal file
31
src/Ryujinx.Common/Utilities/StreamUtils.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class StreamUtils
|
||||
{
|
||||
public static byte[] StreamToBytes(Stream input)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
input.CopyTo(stream);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<byte[]> StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
await input.CopyToAsync(stream, cancellationToken);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
src/Ryujinx.Common/Utilities/TypedStringEnumConverter.cs
Normal file
34
src/Ryujinx.Common/Utilities/TypedStringEnumConverter.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies that value of <see cref="TEnum"/> will be serialized as string in JSONs
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Trimming friendly alternative to <see cref="JsonStringEnumConverter"/>.
|
||||
/// Get rid of this converter if dotnet supports similar functionality out of the box.
|
||||
/// </remarks>
|
||||
/// <typeparam name="TEnum">Type of enum to serialize</typeparam>
|
||||
public sealed class TypedStringEnumConverter<TEnum> : JsonConverter<TEnum> where TEnum : struct, Enum
|
||||
{
|
||||
public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var enumValue = reader.GetString();
|
||||
if (string.IsNullOrEmpty(enumValue))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return Enum.Parse<TEnum>(enumValue);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
18
src/Ryujinx.Common/Utilities/UInt128Utils.cs
Normal file
18
src/Ryujinx.Common/Utilities/UInt128Utils.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class UInt128Utils
|
||||
{
|
||||
public static UInt128 FromHex(string hex)
|
||||
{
|
||||
return new UInt128(ulong.Parse(hex.AsSpan(0, 16), NumberStyles.HexNumber), ulong.Parse(hex.AsSpan(16), NumberStyles.HexNumber));
|
||||
}
|
||||
|
||||
public static UInt128 CreateRandom()
|
||||
{
|
||||
return new UInt128((ulong)Random.Shared.NextInt64(), (ulong)Random.Shared.NextInt64());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue