mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-15 23:46: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;
|
||||
}
|
||||
|
||||
[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(
|
||||
Nid = "Ovb2dSJOAuE",
|
||||
ExportName = "strcmp",
|
||||
@@ -243,6 +259,24 @@ public static class KernelMemoryCompatExports
|
||||
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(
|
||||
Nid = "aesyjrHVWy4",
|
||||
ExportName = "strncmp",
|
||||
@@ -262,6 +296,25 @@ public static class KernelMemoryCompatExports
|
||||
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(
|
||||
Nid = "eLdDw6l0-bU",
|
||||
ExportName = "snprintf",
|
||||
@@ -340,6 +393,29 @@ public static class KernelMemoryCompatExports
|
||||
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(
|
||||
Nid = "6sJWiWSRuqk",
|
||||
ExportName = "strncpy",
|
||||
@@ -382,6 +458,80 @@ public static class KernelMemoryCompatExports
|
||||
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(
|
||||
Nid = "Q3VBxCXhUHs",
|
||||
ExportName = "memcpy",
|
||||
@@ -2440,6 +2590,84 @@ public static class KernelMemoryCompatExports
|
||||
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)
|
||||
{
|
||||
value = string.Empty;
|
||||
@@ -2510,6 +2738,19 @@ public static class KernelMemoryCompatExports
|
||||
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)
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[sizeof(ulong)];
|
||||
|
||||
Reference in New Issue
Block a user