using Ryujinx.Common; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Services.Mii.Types; using System; using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Services.Mii.StaticService { abstract class IDatabaseService : IpcService { [Command(0)] // IsUpdated(SourceFlag flag) -> bool public ResultCode IsUpdated(ServiceCtx context) { SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); context.ResponseData.Write(IsUpdated(flag)); return ResultCode.Success; } [Command(1)] // IsFullDatabase() -> bool public ResultCode IsFullDatabase(ServiceCtx context) { context.ResponseData.Write(IsFullDatabase()); return ResultCode.Success; } [Command(2)] // GetCount(SourceFlag flag) -> u32 public ResultCode GetCount(ServiceCtx context) { SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); context.ResponseData.Write(GetCount(flag)); return ResultCode.Success; } [Command(3)] // Get(SourceFlag flag) -> (s32 count, buffer) public ResultCode Get(ServiceCtx context) { SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); IpcBuffDesc outputBuffer = context.Request.ReceiveBuff[0]; Span elementsSpan = CreateSpanFromBuffer(context, outputBuffer, true); ResultCode result = Get(flag, out int count, elementsSpan); elementsSpan = elementsSpan.Slice(0, count); context.ResponseData.Write(count); WriteSpanToBuffer(context, outputBuffer, elementsSpan); return result; } [Command(4)] // Get1(SourceFlag flag) -> (s32 count, buffer) public ResultCode Get1(ServiceCtx context) { SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); IpcBuffDesc outputBuffer = context.Request.ReceiveBuff[0]; Span elementsSpan = CreateSpanFromBuffer(context, outputBuffer, true); ResultCode result = Get1(flag, out int count, elementsSpan); elementsSpan = elementsSpan.Slice(0, count); context.ResponseData.Write(count); WriteSpanToBuffer(context, outputBuffer, elementsSpan); return result; } [Command(5)] // UpdateLatest(nn::mii::CharInfo old_char_info, SourceFlag flag) -> nn::mii::CharInfo public ResultCode UpdateLatest(ServiceCtx context) { CharInfo oldCharInfo = context.RequestData.ReadStruct(); SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); ResultCode result = UpdateLatest(oldCharInfo, flag, out CharInfo newCharInfo); context.ResponseData.WriteStruct(newCharInfo); return result; } [Command(6)] // BuildRandom(Age age, Gender gender, Race race) -> nn::mii::CharInfo public ResultCode BuildRandom(ServiceCtx context) { Age age = (Age)context.RequestData.ReadInt32(); Gender gender = (Gender)context.RequestData.ReadInt32(); Race race = (Race)context.RequestData.ReadInt32(); ResultCode result = BuildRandom(age, gender, race, out CharInfo charInfo); context.ResponseData.WriteStruct(charInfo); return result; } [Command(7)] // BuildDefault(u32 index) -> nn::mii::CharInfoRaw public ResultCode BuildDefault(ServiceCtx context) { uint index = context.RequestData.ReadUInt32(); ResultCode result = BuildDefault(index, out CharInfo charInfo); context.ResponseData.WriteStruct(charInfo); return result; } [Command(8)] // Get2(SourceFlag flag) -> (u32 count, buffer) public ResultCode Get2(ServiceCtx context) { SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); IpcBuffDesc outputBuffer = context.Request.ReceiveBuff[0]; Span elementsSpan = CreateSpanFromBuffer(context, outputBuffer, true); ResultCode result = Get2(flag, out int count, elementsSpan); elementsSpan = elementsSpan.Slice(0, count); context.ResponseData.Write(count); WriteSpanToBuffer(context, outputBuffer, elementsSpan); return result; } [Command(9)] // Get3(SourceFlag flag) -> (u32 count, buffer) public ResultCode Get3(ServiceCtx context) { SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); IpcBuffDesc outputBuffer = context.Request.ReceiveBuff[0]; Span elementsSpan = CreateSpanFromBuffer(context, outputBuffer, true); ResultCode result = Get3(flag, out int count, elementsSpan); elementsSpan = elementsSpan.Slice(0, count); context.ResponseData.Write(count); WriteSpanToBuffer(context, outputBuffer, elementsSpan); return result; } [Command(10)] // UpdateLatest1(nn::mii::StoreData old_store_data, SourceFlag flag) -> nn::mii::StoreData public ResultCode UpdateLatest1(ServiceCtx context) { StoreData oldStoreData = context.RequestData.ReadStruct(); SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32(); ResultCode result = UpdateLatest1(oldStoreData, flag, out StoreData newStoreData); context.ResponseData.WriteStruct(newStoreData); return result; } [Command(11)] // FindIndex(nn::mii::CreateId create_id, bool is_special) -> s32 public ResultCode FindIndex(ServiceCtx context) { CreateId createId = context.RequestData.ReadStruct(); bool isSpecial = context.RequestData.ReadBoolean(); ResultCode result = FindIndex(createId, isSpecial, out int index); context.ResponseData.Write(index); return result; } [Command(12)] // Move(nn::mii::CreateId create_id, s32 new_index) public ResultCode Move(ServiceCtx context) { CreateId createId = context.RequestData.ReadStruct(); int newIndex = context.RequestData.ReadInt32(); return Move(createId, newIndex); } [Command(13)] // AddOrReplace(nn::mii::StoreData store_data) public ResultCode AddOrReplace(ServiceCtx context) { StoreData storeData = context.RequestData.ReadStruct(); return AddOrReplace(storeData); } [Command(14)] // Delete(nn::mii::CreateId create_id) public ResultCode Delete(ServiceCtx context) { CreateId createId = context.RequestData.ReadStruct(); return Delete(createId); } [Command(15)] // DestroyFile() public ResultCode DestroyFile(ServiceCtx context) { return DestroyFile(); } [Command(16)] // DeleteFile() public ResultCode DeleteFile(ServiceCtx context) { return DeleteFile(); } [Command(17)] // Format() public ResultCode Format(ServiceCtx context) { return Format(); } [Command(18)] // Import(buffer) public ResultCode Import(ServiceCtx context) { ReadOnlySpan data = CreateByteSpanFromBuffer(context, context.Request.SendBuff[0], false); return Import(data); } [Command(19)] // Export() -> buffer public ResultCode Export(ServiceCtx context) { IpcBuffDesc outputBuffer = context.Request.ReceiveBuff[0]; Span data = CreateByteSpanFromBuffer(context, outputBuffer, true); ResultCode result = Export(data); context.Memory.WriteBytes(outputBuffer.Position, data.ToArray()); return result; } [Command(20)] // IsBrokenDatabaseWithClearFlag() -> bool public ResultCode IsBrokenDatabaseWithClearFlag(ServiceCtx context) { ResultCode result = IsBrokenDatabaseWithClearFlag(out bool isBrokenDatabase); context.ResponseData.Write(isBrokenDatabase); return result; } [Command(21)] // GetIndex(nn::mii::CharInfo char_info) -> s32 public ResultCode GetIndex(ServiceCtx context) { CharInfo charInfo = context.RequestData.ReadStruct(); ResultCode result = GetIndex(charInfo, out int index); context.ResponseData.Write(index); return result; } [Command(22)] // 5.0.0+ // SetInterfaceVersion(u32 version) public ResultCode SetInterfaceVersion(ServiceCtx context) { uint interfaceVersion = context.RequestData.ReadUInt32(); SetInterfaceVersion(interfaceVersion); return ResultCode.Success; } [Command(23)] // 5.0.0+ // Convert(nn::mii::Ver3StoreData ver3_store_data) -> nn::mii::CharInfo public ResultCode Convert(ServiceCtx context) { Ver3StoreData ver3StoreData = context.RequestData.ReadStruct(); ResultCode result = Convert(ver3StoreData, out CharInfo charInfo); context.ResponseData.WriteStruct(charInfo); return result; } [Command(24)] // 7.0.0+ // ConvertCoreDataToCharInfo(nn::mii::CoreData core_data) -> nn::mii::CharInfo public ResultCode ConvertCoreDataToCharInfo(ServiceCtx context) { CoreData coreData = context.RequestData.ReadStruct(); ResultCode result = ConvertCoreDataToCharInfo(coreData, out CharInfo charInfo); context.ResponseData.WriteStruct(charInfo); return result; } [Command(25)] // 7.0.0+ // ConvertCharInfoToCoreData(nn::mii::CharInfo char_info) -> nn::mii::CoreData public ResultCode ConvertCharInfoToCoreData(ServiceCtx context) { CharInfo charInfo = context.RequestData.ReadStruct(); ResultCode result = ConvertCharInfoToCoreData(charInfo, out CoreData coreData); context.ResponseData.WriteStruct(coreData); return result; } private Span CreateByteSpanFromBuffer(ServiceCtx context, IpcBuffDesc ipcBuff, bool isOutput) { byte[] rawData; if (isOutput) { rawData = new byte[ipcBuff.Size]; } else { rawData = context.Memory.ReadBytes(ipcBuff.Position, ipcBuff.Size); } return new Span(rawData); } private Span CreateSpanFromBuffer(ServiceCtx context, IpcBuffDesc ipcBuff, bool isOutput) where T: unmanaged { return MemoryMarshal.Cast(CreateByteSpanFromBuffer(context, ipcBuff, isOutput)); } private void WriteSpanToBuffer(ServiceCtx context, IpcBuffDesc ipcBuff, Span span) where T: unmanaged { Span rawData = MemoryMarshal.Cast(span); context.Memory.WriteBytes(ipcBuff.Position, rawData.ToArray()); } protected abstract bool IsUpdated(SourceFlag flag); protected abstract bool IsFullDatabase(); protected abstract uint GetCount(SourceFlag flag); protected abstract ResultCode Get(SourceFlag flag, out int count, Span elements); protected abstract ResultCode Get1(SourceFlag flag, out int count, Span elements); protected abstract ResultCode UpdateLatest(CharInfo oldCharInfo, SourceFlag flag, out CharInfo newCharInfo); protected abstract ResultCode BuildRandom(Age age, Gender gender, Race race, out CharInfo charInfo); protected abstract ResultCode BuildDefault(uint index, out CharInfo charInfo); protected abstract ResultCode Get2(SourceFlag flag, out int count, Span elements); protected abstract ResultCode Get3(SourceFlag flag, out int count, Span elements); protected abstract ResultCode UpdateLatest1(StoreData oldStoreData, SourceFlag flag, out StoreData newStoreData); protected abstract ResultCode FindIndex(CreateId createId, bool isSpecial, out int index); protected abstract ResultCode Move(CreateId createId, int newIndex); protected abstract ResultCode AddOrReplace(StoreData storeData); protected abstract ResultCode Delete(CreateId createId); protected abstract ResultCode DestroyFile(); protected abstract ResultCode DeleteFile(); protected abstract ResultCode Format(); protected abstract ResultCode Import(ReadOnlySpan data); protected abstract ResultCode Export(Span data); protected abstract ResultCode IsBrokenDatabaseWithClearFlag(out bool isBrokenDatabase); protected abstract ResultCode GetIndex(CharInfo charInfo, out int index); protected abstract void SetInterfaceVersion(uint interfaceVersion); protected abstract ResultCode Convert(Ver3StoreData ver3StoreData, out CharInfo charInfo); protected abstract ResultCode ConvertCoreDataToCharInfo(CoreData coreData, out CharInfo charInfo); protected abstract ResultCode ConvertCharInfoToCoreData(CharInfo charInfo, out CoreData coreData); } }