mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-10 11:38:41 +08:00
5864328e35
* [media] merge bink into shared ffmpeg bridge * [avplayer] decode in process and fix stream info size * [font] add glyph and teardown exports * [build] bump ffmpeg runtime to 3b502d4 * [font] add glyph and teardown exports * [build] bump ffmpeg runtime to 3b502d4 * [avplayer] decode in process * [font] add glyph and teardown exports * [build] bump ffmpeg runtime to 3b502d4
555 lines
19 KiB
C#
555 lines
19 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using System.Buffers.Binary;
|
|
using SharpEmu.HLE;
|
|
|
|
namespace SharpEmu.Libs.Font;
|
|
|
|
public static class FontExports
|
|
{
|
|
private const ushort GlyphMagic = 0x0F03;
|
|
private const int GlyphSize = 0x100;
|
|
private const int GlyphMetricsSize = 8 * sizeof(float);
|
|
private const int RenderOutputSize = 0x40;
|
|
|
|
private static readonly object AllocationGate = new();
|
|
private static readonly Stack<ulong> FreeGlyphs = new();
|
|
private static ulong _librarySelectionAddress;
|
|
private static ulong _rendererSelectionAddress;
|
|
|
|
[SysAbiExport(
|
|
Nid = "whrS4oksXc4",
|
|
ExportName = "sceFontMemoryInit",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int MemoryInit(CpuContext ctx)
|
|
{
|
|
var descriptorAddress = ctx[CpuRegister.Rdi];
|
|
var regionAddress = ctx[CpuRegister.Rsi];
|
|
var regionSize = (uint)ctx[CpuRegister.Rdx];
|
|
var interfaceAddress = ctx[CpuRegister.Rcx];
|
|
var mspaceAddress = ctx[CpuRegister.R8];
|
|
var destroyCallback = ctx[CpuRegister.R9];
|
|
if (descriptorAddress == 0 ||
|
|
!TryWriteUInt32(ctx, descriptorAddress, 0x00000F00) ||
|
|
!TryWriteUInt32(ctx, descriptorAddress + 0x04, regionSize) ||
|
|
!ctx.TryWriteUInt64(descriptorAddress + 0x08, regionAddress) ||
|
|
!ctx.TryWriteUInt64(descriptorAddress + 0x10, mspaceAddress) ||
|
|
!ctx.TryWriteUInt64(descriptorAddress + 0x18, interfaceAddress) ||
|
|
!ctx.TryWriteUInt64(descriptorAddress + 0x20, destroyCallback) ||
|
|
!ctx.TryWriteUInt64(descriptorAddress + 0x28, 0) ||
|
|
!ctx.TryWriteUInt64(descriptorAddress + 0x30, 0) ||
|
|
!ctx.TryWriteUInt64(descriptorAddress + 0x38, mspaceAddress))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "oM+XCzVG3oM",
|
|
ExportName = "sceFontSelectLibraryFt",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFontFt")]
|
|
public static int SelectLibraryFt(CpuContext ctx) =>
|
|
ReturnSelection(ctx, ref _librarySelectionAddress, 0x38);
|
|
|
|
[SysAbiExport(
|
|
Nid = "Xx974EW-QFY",
|
|
ExportName = "sceFontSelectRendererFt",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFontFt")]
|
|
public static int SelectRendererFt(CpuContext ctx) =>
|
|
ReturnSelection(ctx, ref _rendererSelectionAddress, 0x100);
|
|
|
|
[SysAbiExport(
|
|
Nid = "n590hj5Oe-k",
|
|
ExportName = "sceFontCreateLibraryWithEdition",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int CreateLibraryWithEdition(CpuContext ctx) =>
|
|
CreateOpaqueHandle(ctx, ctx[CpuRegister.Rcx], 0x100, magic: 0x0F01);
|
|
|
|
[SysAbiExport(
|
|
Nid = "WaSFJoRWXaI",
|
|
ExportName = "sceFontCreateRendererWithEdition",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int CreateRendererWithEdition(CpuContext ctx) =>
|
|
CreateOpaqueHandle(ctx, ctx[CpuRegister.Rcx], 0x100, magic: 0x0F07);
|
|
|
|
[SysAbiExport(
|
|
Nid = "3OdRkSjOcog",
|
|
ExportName = "sceFontBindRenderer",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int BindRenderer(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "N1EBMeGhf7E",
|
|
ExportName = "sceFontSetScalePixel",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SetScalePixel(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "TMtqoFQjjbA",
|
|
ExportName = "sceFontSetEffectSlant",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SetEffectSlant(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "v0phZwa4R5o",
|
|
ExportName = "sceFontSetEffectWeight",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SetEffectWeight(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "6vGCkkQJOcI",
|
|
ExportName = "sceFontSetupRenderScalePixel",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SetupRenderScalePixel(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "lz9y9UFO2UU",
|
|
ExportName = "sceFontSetupRenderEffectSlant",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SetupRenderEffectSlant(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "XIGorvLusDQ",
|
|
ExportName = "sceFontSetupRenderEffectWeight",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SetupRenderEffectWeight(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "imxVx8lm+KM",
|
|
ExportName = "sceFontGetHorizontalLayout",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int GetHorizontalLayout(CpuContext ctx)
|
|
{
|
|
var layoutAddress = ctx[CpuRegister.Rsi];
|
|
if (layoutAddress == 0)
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
|
}
|
|
|
|
// Baseline, line advance, decoration extent: the same invented geometry
|
|
// as GetRenderCharGlyphMetrics.
|
|
var values = new[] { 12.0f, 16.0f, 0.0f };
|
|
for (var index = 0; index < values.Length; index++)
|
|
{
|
|
if (!TryWriteUInt32(
|
|
ctx,
|
|
layoutAddress + (ulong)(index * sizeof(float)),
|
|
BitConverter.SingleToUInt32Bits(values[index])))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "3BrWWFU+4ts",
|
|
ExportName = "sceFontGetVerticalLayout",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int GetVerticalLayout(CpuContext ctx)
|
|
{
|
|
var layoutAddress = ctx[CpuRegister.Rsi];
|
|
if (layoutAddress == 0)
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
|
}
|
|
|
|
// Baseline (horizontal offset), line advance, decoration extent.
|
|
// Mirrors the same three-float layout as GetHorizontalLayout, but
|
|
// interpreted for vertical writing (e.g. CJK text rendered top-to-bottom).
|
|
var values = new[] { 8.0f, 16.0f, 0.0f };
|
|
for (var index = 0; index < values.Length; index++)
|
|
{
|
|
if (!TryWriteUInt32(
|
|
ctx,
|
|
layoutAddress + (ulong)(index * sizeof(float)),
|
|
BitConverter.SingleToUInt32Bits(values[index])))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "cKYtVmeSTcw",
|
|
ExportName = "sceFontOpenFontSet",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int OpenFontSet(CpuContext ctx) =>
|
|
CreateOpaqueHandle(ctx, ctx[CpuRegister.R8], 0x100, magic: 0x0F02);
|
|
|
|
[SysAbiExport(
|
|
Nid = "KXUpebrFk1U",
|
|
ExportName = "sceFontOpenFontMemory",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int OpenFontMemory(CpuContext ctx) =>
|
|
CreateOpaqueHandle(ctx, ctx[CpuRegister.R8], 0x100, magic: 0x0F02);
|
|
|
|
[SysAbiExport(
|
|
Nid = "JzCH3SCFnAU",
|
|
ExportName = "sceFontOpenFontInstance",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int OpenFontInstance(CpuContext ctx)
|
|
{
|
|
var sourceHandle = ctx[CpuRegister.Rdi];
|
|
var setupHandle = ctx[CpuRegister.Rsi];
|
|
var outputAddress = ctx[CpuRegister.Rdx];
|
|
if (outputAddress == 0)
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
|
}
|
|
|
|
if (setupHandle != 0)
|
|
{
|
|
return ctx.TryWriteUInt64(outputAddress, setupHandle)
|
|
? SetSuccess(ctx)
|
|
: SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
if (!TryAllocateOpaque(ctx, 0x100, out var handle))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
if (sourceHandle != 0)
|
|
{
|
|
Span<byte> source = stackalloc byte[0x100];
|
|
if (ctx.Memory.TryRead(sourceHandle, source))
|
|
{
|
|
_ = ctx.Memory.TryWrite(handle, source);
|
|
}
|
|
}
|
|
|
|
_ = TryWriteUInt16(ctx, handle, 0x0F02);
|
|
return ctx.TryWriteUInt64(outputAddress, handle)
|
|
? SetSuccess(ctx)
|
|
: SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "SsRbbCiWoGw",
|
|
ExportName = "sceFontSupportSystemFonts",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SupportSystemFonts(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "mz2iTY0MK4A",
|
|
ExportName = "sceFontSupportExternalFonts",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int SupportExternalFonts(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "CUKn5pX-NVY",
|
|
ExportName = "sceFontAttachDeviceCacheBuffer",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int AttachDeviceCacheBuffer(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "IQtleGLL5pQ",
|
|
ExportName = "sceFontGetRenderCharGlyphMetrics",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int GetRenderCharGlyphMetrics(CpuContext ctx)
|
|
{
|
|
var metricsAddress = ctx[CpuRegister.Rdx];
|
|
if (metricsAddress == 0)
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
|
}
|
|
|
|
var values = new[] { 8.0f, 16.0f, 0.0f, 12.0f, 8.0f, 0.0f, 0.0f, 16.0f };
|
|
for (var index = 0; index < values.Length; index++)
|
|
{
|
|
if (!TryWriteUInt32(
|
|
ctx,
|
|
metricsAddress + (ulong)(index * sizeof(float)),
|
|
BitConverter.SingleToUInt32Bits(values[index])))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "gdUCnU0gHdI",
|
|
ExportName = "sceFontRenderSurfaceInit",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int RenderSurfaceInit(CpuContext ctx)
|
|
{
|
|
var surfaceAddress = ctx[CpuRegister.Rdi];
|
|
var bufferAddress = ctx[CpuRegister.Rsi];
|
|
var widthBytes = (uint)ctx[CpuRegister.Rdx];
|
|
var pixelBytes = (uint)ctx[CpuRegister.Rcx] & 0xFF;
|
|
var width = (uint)ctx[CpuRegister.R8];
|
|
var height = (uint)ctx[CpuRegister.R9];
|
|
if (surfaceAddress == 0 ||
|
|
!ctx.TryWriteUInt64(surfaceAddress, bufferAddress) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x08, widthBytes) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x0C, pixelBytes) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x10, width) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x14, height) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x18, 0) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x1C, 0) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x20, width) ||
|
|
!TryWriteUInt32(ctx, surfaceAddress + 0x24, height))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "C-4Qw5Srlyw",
|
|
ExportName = "sceFontGenerateCharGlyph",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int GenerateCharGlyph(CpuContext ctx)
|
|
{
|
|
var outputAddress = ctx[CpuRegister.Rcx];
|
|
if (outputAddress == 0)
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
|
}
|
|
|
|
if (!TryRentGlyph(ctx, out var glyph) ||
|
|
!ctx.TryWriteUInt64(outputAddress, glyph))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "8-zmgsxkBek",
|
|
ExportName = "sceFontGlyphDefineAttribute",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int GlyphDefineAttribute(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "LHDoRWVFGqk",
|
|
ExportName = "sceFontDeleteGlyph",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int DeleteGlyph(CpuContext ctx)
|
|
{
|
|
var glyphPointerAddress = ctx[CpuRegister.Rsi];
|
|
if (glyphPointerAddress == 0)
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
|
}
|
|
|
|
if (!ctx.TryReadUInt64(glyphPointerAddress, out var glyph))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
if (glyph != 0)
|
|
{
|
|
lock (AllocationGate)
|
|
{
|
|
FreeGlyphs.Push(glyph);
|
|
}
|
|
}
|
|
|
|
return ctx.TryWriteUInt64(glyphPointerAddress, 0)
|
|
? SetSuccess(ctx)
|
|
: SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "kAenWy1Zw5o",
|
|
ExportName = "sceFontRenderCharGlyphImageHorizontal",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int RenderCharGlyphImageHorizontal(CpuContext ctx)
|
|
{
|
|
var metricsAddress = ctx[CpuRegister.Rcx];
|
|
var resultAddress = ctx[CpuRegister.R8];
|
|
|
|
if (metricsAddress != 0)
|
|
{
|
|
var values = new[] { 8.0f, 16.0f, 0.0f, 12.0f, 8.0f, 0.0f, 0.0f, 16.0f };
|
|
for (var index = 0; index < values.Length; index++)
|
|
{
|
|
if (!TryWriteUInt32(
|
|
ctx,
|
|
metricsAddress + (ulong)(index * sizeof(float)),
|
|
BitConverter.SingleToUInt32Bits(values[index])))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (resultAddress != 0)
|
|
{
|
|
Span<byte> cleared = stackalloc byte[RenderOutputSize];
|
|
cleared.Clear();
|
|
if (!ctx.Memory.TryWrite(resultAddress, cleared))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "vzHs3C8lWJk",
|
|
ExportName = "sceFontCloseFont",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int CloseFont(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "1QjhKxrsOB8",
|
|
ExportName = "sceFontUnbindRenderer",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int UnbindRenderer(CpuContext ctx) => SetSuccess(ctx);
|
|
|
|
[SysAbiExport(
|
|
Nid = "exAxkyVLt0s",
|
|
ExportName = "sceFontDestroyRenderer",
|
|
Target = Generation.Gen5,
|
|
LibraryName = "libSceFont")]
|
|
public static int DestroyRenderer(CpuContext ctx)
|
|
{
|
|
var rendererPointerAddress = ctx[CpuRegister.Rdi];
|
|
if (rendererPointerAddress == 0)
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
|
}
|
|
|
|
return ctx.TryWriteUInt64(rendererPointerAddress, 0)
|
|
? SetSuccess(ctx)
|
|
: SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
private static bool TryRentGlyph(CpuContext ctx, out ulong glyph)
|
|
{
|
|
lock (AllocationGate)
|
|
{
|
|
if (FreeGlyphs.Count > 0)
|
|
{
|
|
glyph = FreeGlyphs.Pop();
|
|
return TryWriteUInt16(ctx, glyph, GlyphMagic);
|
|
}
|
|
}
|
|
|
|
return TryAllocateOpaque(ctx, GlyphSize, out glyph) &&
|
|
TryWriteUInt16(ctx, glyph, GlyphMagic);
|
|
}
|
|
|
|
private static int ReturnSelection(CpuContext ctx, ref ulong selectionAddress, uint objectSize)
|
|
{
|
|
if (ctx[CpuRegister.Rdi] != 0)
|
|
{
|
|
ctx[CpuRegister.Rax] = 0;
|
|
return 0;
|
|
}
|
|
|
|
lock (AllocationGate)
|
|
{
|
|
if (selectionAddress == 0)
|
|
{
|
|
if (!TryAllocateOpaque(ctx, 0x20, out selectionAddress) ||
|
|
!TryWriteUInt32(ctx, selectionAddress, 0) ||
|
|
!TryWriteUInt32(ctx, selectionAddress + 4, objectSize))
|
|
{
|
|
selectionAddress = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
ctx[CpuRegister.Rax] = selectionAddress;
|
|
return 0;
|
|
}
|
|
|
|
private static int CreateOpaqueHandle(CpuContext ctx, ulong outputAddress, int size, ushort magic)
|
|
{
|
|
if (outputAddress == 0 || !TryAllocateOpaque(ctx, size, out var handle))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
if (!TryWriteUInt16(ctx, handle, magic) || !ctx.TryWriteUInt64(outputAddress, handle))
|
|
{
|
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
|
}
|
|
|
|
return SetSuccess(ctx);
|
|
}
|
|
|
|
private static bool TryAllocateOpaque(CpuContext ctx, int size, out ulong address)
|
|
{
|
|
address = 0;
|
|
if (ctx.Memory is not IGuestMemoryAllocator allocator ||
|
|
!allocator.TryAllocateGuestMemory((ulong)size, 0x10, out address))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Span<byte> bytes = stackalloc byte[size];
|
|
bytes.Clear();
|
|
return ctx.Memory.TryWrite(address, bytes);
|
|
}
|
|
|
|
private static bool TryWriteUInt16(CpuContext ctx, ulong address, ushort value)
|
|
{
|
|
Span<byte> bytes = stackalloc byte[sizeof(ushort)];
|
|
BinaryPrimitives.WriteUInt16LittleEndian(bytes, value);
|
|
return ctx.Memory.TryWrite(address, bytes);
|
|
}
|
|
|
|
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
{
|
|
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
|
BinaryPrimitives.WriteUInt32LittleEndian(bytes, value);
|
|
return ctx.Memory.TryWrite(address, bytes);
|
|
}
|
|
|
|
private static int SetSuccess(CpuContext ctx)
|
|
{
|
|
ctx[CpuRegister.Rax] = 0;
|
|
return 0;
|
|
}
|
|
|
|
private static int SetReturn(CpuContext ctx, OrbisGen2Result result)
|
|
{
|
|
ctx[CpuRegister.Rax] = unchecked((ulong)(int)result);
|
|
return (int)result;
|
|
}
|
|
}
|