Implement NGC service (#5681)
* Implement NGC service * Use raw byte arrays instead of string for _wordSeparators * Silence IDE0230 for _wordSeparators * Try to silence warning about _rangeValuesCount not being read on SparseSet * Make AcType enum private * Add abstract methods and one TODO that I forgot * PR feedback * More PR feedback * More PR feedback
This commit is contained in:
104
src/Ryujinx.Horizon/Sdk/Ngc/Detail/Utf8Text.cs
Normal file
104
src/Ryujinx.Horizon/Sdk/Ngc/Detail/Utf8Text.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Ngc.Detail
|
||||
{
|
||||
readonly struct Utf8Text
|
||||
{
|
||||
private readonly byte[] _text;
|
||||
private readonly int[] _charOffsets;
|
||||
|
||||
public int CharacterCount => _charOffsets.Length - 1;
|
||||
|
||||
public Utf8Text()
|
||||
{
|
||||
_text = Array.Empty<byte>();
|
||||
_charOffsets = Array.Empty<int>();
|
||||
}
|
||||
|
||||
public Utf8Text(byte[] text)
|
||||
{
|
||||
_text = text;
|
||||
|
||||
UTF8Encoding encoding = new(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
|
||||
|
||||
string str = encoding.GetString(text);
|
||||
|
||||
_charOffsets = new int[str.Length + 1];
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (int index = 0; index < str.Length; index++)
|
||||
{
|
||||
_charOffsets[index] = offset;
|
||||
offset += encoding.GetByteCount(str.AsSpan().Slice(index, 1));
|
||||
}
|
||||
|
||||
_charOffsets[str.Length] = offset;
|
||||
}
|
||||
|
||||
public Utf8Text(ReadOnlySpan<byte> text) : this(text.ToArray())
|
||||
{
|
||||
}
|
||||
|
||||
public static Utf8ParseResult Create(out Utf8Text utf8Text, ReadOnlySpan<byte> text)
|
||||
{
|
||||
try
|
||||
{
|
||||
utf8Text = new(text);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
utf8Text = default;
|
||||
|
||||
return Utf8ParseResult.InvalidCharacter;
|
||||
}
|
||||
|
||||
return Utf8ParseResult.Success;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> AsSubstring(int startCharIndex, int endCharIndex)
|
||||
{
|
||||
int startOffset = _charOffsets[startCharIndex];
|
||||
int endOffset = _charOffsets[endCharIndex];
|
||||
|
||||
return _text.AsSpan()[startOffset..endOffset];
|
||||
}
|
||||
|
||||
public Utf8Text AppendNullTerminated(ReadOnlySpan<byte> toAppend)
|
||||
{
|
||||
int length = toAppend.IndexOf((byte)0);
|
||||
if (length >= 0)
|
||||
{
|
||||
toAppend = toAppend[..length];
|
||||
}
|
||||
|
||||
return Append(toAppend);
|
||||
}
|
||||
|
||||
public Utf8Text Append(ReadOnlySpan<byte> toAppend)
|
||||
{
|
||||
byte[] combined = new byte[_text.Length + toAppend.Length];
|
||||
|
||||
_text.AsSpan().CopyTo(combined.AsSpan()[.._text.Length]);
|
||||
toAppend.CopyTo(combined.AsSpan()[_text.Length..]);
|
||||
|
||||
return new(combined);
|
||||
}
|
||||
|
||||
public void CopyTo(Span<byte> destination)
|
||||
{
|
||||
_text.CopyTo(destination[.._text.Length]);
|
||||
|
||||
if (destination.Length > _text.Length)
|
||||
{
|
||||
destination[_text.Length] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> AsSpan()
|
||||
{
|
||||
return _text;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user