mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-19 17:36:15 +08:00
More HLE implements: wcs*
This commit is contained in:
@@ -225,6 +225,22 @@ public static class KernelMemoryCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "WkkeywLJcgU",
|
||||||
|
ExportName = "wcslen",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int Wcslen(CpuContext ctx)
|
||||||
|
{
|
||||||
|
if (!TryReadWideCString(ctx, ctx[CpuRegister.Rdi], 1_048_576, out var units))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = unchecked((ulong)units.Length);
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "Ovb2dSJOAuE",
|
Nid = "Ovb2dSJOAuE",
|
||||||
ExportName = "strcmp",
|
ExportName = "strcmp",
|
||||||
@@ -243,6 +259,24 @@ public static class KernelMemoryCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "pNtJdE3x49E",
|
||||||
|
ExportName = "wcscmp",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int Wcscmp(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var left = ctx[CpuRegister.Rdi];
|
||||||
|
var right = ctx[CpuRegister.Rsi];
|
||||||
|
if (!TryCompareWideStrings(ctx, left, right, limit: ulong.MaxValue, out var compare))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = unchecked((ulong)compare);
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "aesyjrHVWy4",
|
Nid = "aesyjrHVWy4",
|
||||||
ExportName = "strncmp",
|
ExportName = "strncmp",
|
||||||
@@ -262,6 +296,25 @@ public static class KernelMemoryCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "E8wCoUEbfzk",
|
||||||
|
ExportName = "wcsncmp",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int Wcsncmp(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var left = ctx[CpuRegister.Rdi];
|
||||||
|
var right = ctx[CpuRegister.Rsi];
|
||||||
|
var limit = ctx[CpuRegister.Rdx];
|
||||||
|
if (!TryCompareWideStrings(ctx, left, right, limit, out var compare))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = unchecked((ulong)compare);
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "eLdDw6l0-bU",
|
Nid = "eLdDw6l0-bU",
|
||||||
ExportName = "snprintf",
|
ExportName = "snprintf",
|
||||||
@@ -340,6 +393,29 @@ public static class KernelMemoryCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "FM5NPnLqBc8",
|
||||||
|
ExportName = "wcscpy",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int Wcscpy(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var destination = ctx[CpuRegister.Rdi];
|
||||||
|
var source = ctx[CpuRegister.Rsi];
|
||||||
|
if (!TryReadWideCString(ctx, source, 1_048_576, out var units))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryWriteCompat(ctx, destination, EncodeWideUnitsWithTerminator(units)))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = destination;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "6sJWiWSRuqk",
|
Nid = "6sJWiWSRuqk",
|
||||||
ExportName = "strncpy",
|
ExportName = "strncpy",
|
||||||
@@ -382,6 +458,80 @@ public static class KernelMemoryCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "0nV21JjYCH8",
|
||||||
|
ExportName = "wcsncpy",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int Wcsncpy(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var destination = ctx[CpuRegister.Rdi];
|
||||||
|
var source = ctx[CpuRegister.Rsi];
|
||||||
|
var count = (int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue);
|
||||||
|
if (count < 0 || count > (int.MaxValue / sizeof(ushort)))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload = new byte[count * sizeof(ushort)];
|
||||||
|
for (var copied = 0; copied < count; copied++)
|
||||||
|
{
|
||||||
|
if (!TryReadUInt16Compat(ctx, source + ((ulong)copied * sizeof(ushort)), out var unit))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryPrimitives.WriteUInt16LittleEndian(
|
||||||
|
payload.AsSpan(copied * sizeof(ushort), sizeof(ushort)),
|
||||||
|
unit);
|
||||||
|
|
||||||
|
if (unit == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryWriteCompat(ctx, destination, payload))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = destination;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "Ezzq78ZgHPs",
|
||||||
|
ExportName = "wcschr",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int Wcschr(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var address = ctx[CpuRegister.Rdi];
|
||||||
|
var needle = unchecked((ushort)ctx[CpuRegister.Rsi]);
|
||||||
|
for (ulong index = 0; index < 1_048_576; index++)
|
||||||
|
{
|
||||||
|
if (!TryReadUInt16Compat(ctx, address + (index * sizeof(ushort)), out var unit))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unit == needle)
|
||||||
|
{
|
||||||
|
ctx[CpuRegister.Rax] = address + (index * sizeof(ushort));
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unit == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = 0;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "Q3VBxCXhUHs",
|
Nid = "Q3VBxCXhUHs",
|
||||||
ExportName = "memcpy",
|
ExportName = "memcpy",
|
||||||
@@ -2440,6 +2590,84 @@ public static class KernelMemoryCompatExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TryReadWideCString(CpuContext ctx, ulong address, ulong maxLength, out ushort[] units)
|
||||||
|
{
|
||||||
|
units = Array.Empty<ushort>();
|
||||||
|
if (address == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var limit = (int)Math.Min(maxLength, 1_048_576UL);
|
||||||
|
var buffer = new List<ushort>(Math.Min(limit, 256));
|
||||||
|
for (var i = 0; i < limit; i++)
|
||||||
|
{
|
||||||
|
if (!TryReadUInt16Compat(ctx, address + ((ulong)i * sizeof(ushort)), out var unit))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unit == 0)
|
||||||
|
{
|
||||||
|
units = buffer.ToArray();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Add(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
units = buffer.ToArray();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryCompareWideStrings(CpuContext ctx, ulong left, ulong right, ulong limit, out int compare)
|
||||||
|
{
|
||||||
|
compare = 0;
|
||||||
|
if (left == 0 || right == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var max = limit == ulong.MaxValue ? 1_048_576UL : Math.Min(limit, 1_048_576UL);
|
||||||
|
for (ulong i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
if (!TryReadUInt16Compat(ctx, left + (i * sizeof(ushort)), out var leftUnit) ||
|
||||||
|
!TryReadUInt16Compat(ctx, right + (i * sizeof(ushort)), out var rightUnit))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
compare = leftUnit - rightUnit;
|
||||||
|
if (compare != 0 || leftUnit == 0 || rightUnit == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compare = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] EncodeWideUnits(ReadOnlySpan<ushort> units)
|
||||||
|
{
|
||||||
|
var bytes = new byte[units.Length * sizeof(ushort)];
|
||||||
|
for (var i = 0; i < units.Length; i++)
|
||||||
|
{
|
||||||
|
BinaryPrimitives.WriteUInt16LittleEndian(
|
||||||
|
bytes.AsSpan(i * sizeof(ushort), sizeof(ushort)),
|
||||||
|
units[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] EncodeWideUnitsWithTerminator(ReadOnlySpan<ushort> units)
|
||||||
|
{
|
||||||
|
var bytes = new byte[(units.Length + 1) * sizeof(ushort)];
|
||||||
|
EncodeWideUnits(units).CopyTo(bytes, 0);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool TryReadNullTerminatedUtf8(CpuContext ctx, ulong address, int maxLength, out string value)
|
private static bool TryReadNullTerminatedUtf8(CpuContext ctx, ulong address, int maxLength, out string value)
|
||||||
{
|
{
|
||||||
value = string.Empty;
|
value = string.Empty;
|
||||||
@@ -2510,6 +2738,19 @@ public static class KernelMemoryCompatExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TryReadUInt16Compat(CpuContext ctx, ulong address, out ushort value)
|
||||||
|
{
|
||||||
|
Span<byte> bytes = stackalloc byte[sizeof(ushort)];
|
||||||
|
if (!TryReadCompat(ctx, address, bytes))
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = BinaryPrimitives.ReadUInt16LittleEndian(bytes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt64Compat(CpuContext ctx, ulong address, out ulong value)
|
private static bool TryReadUInt64Compat(CpuContext ctx, ulong address, out ulong value)
|
||||||
{
|
{
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(ulong)];
|
Span<byte> bytes = stackalloc byte[sizeof(ulong)];
|
||||||
|
|||||||
Reference in New Issue
Block a user