using Ryujinx.Horizon.Common; using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Horizon.Sdk.Sf.Cmif { class DomainServiceObjectDispatchTable : ServiceDispatchTableBase { public override Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan inRawData) { return ProcessMessageImpl(ref context, ((DomainServiceObject)context.ServiceObject).GetServerDomain(), inRawData); } private Result ProcessMessageImpl(ref ServiceDispatchContext context, ServerDomainBase domain, ReadOnlySpan inRawData) { if (inRawData.Length < Unsafe.SizeOf()) { return SfResult.InvalidHeaderSize; } var inHeader = MemoryMarshal.Cast(inRawData)[0]; ReadOnlySpan inDomainRawData = inRawData[Unsafe.SizeOf()..]; int targetObjectId = inHeader.ObjectId; switch (inHeader.Type) { case CmifDomainRequestType.SendMessage: var targetObject = domain.GetObject(targetObjectId); if (targetObject == null) { return SfResult.TargetNotFound; } if (inHeader.DataSize + inHeader.ObjectsCount * sizeof(int) > inDomainRawData.Length) { return SfResult.InvalidHeaderSize; } ReadOnlySpan inMessageRawData = inDomainRawData[..inHeader.DataSize]; if (inHeader.ObjectsCount > DomainServiceObjectProcessor.MaximumObjects) { return SfResult.InvalidInObjectsCount; } int[] inObjectIds = new int[inHeader.ObjectsCount]; var domainProcessor = new DomainServiceObjectProcessor(domain, inObjectIds); if (context.Processor == null) { context.Processor = domainProcessor; } else { context.Processor.SetImplementationProcessor(domainProcessor); } context.ServiceObject = targetObject.ServiceObject; return targetObject.ProcessMessage(ref context, inMessageRawData); case CmifDomainRequestType.Close: domain.UnregisterObject(targetObjectId); return Result.Success; default: return SfResult.InvalidInHeader; } } } }