diff --git a/Ryujinx.Common/Logging/LogClass.cs b/Ryujinx.Common/Logging/LogClass.cs index dc5bf7fefe..b7130d230d 100644 --- a/Ryujinx.Common/Logging/LogClass.cs +++ b/Ryujinx.Common/Logging/LogClass.cs @@ -37,6 +37,7 @@ namespace Ryujinx.Common.Logging ServiceLm, ServiceMm, ServiceNfp, + ServiceNgct, ServiceNifm, ServiceNim, ServiceNs, diff --git a/Ryujinx.HLE/HOS/Services/Ngct/IService.cs b/Ryujinx.HLE/HOS/Services/Ngct/IService.cs new file mode 100644 index 0000000000..c12a8de83f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ngct/IService.cs @@ -0,0 +1,24 @@ +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Ngct +{ + [Service("ngct:u")] // 9.0.0+ + class IService : IpcService + { + public IService(ServiceCtx context) { } + + [Command(0)] + // Match(buffer) -> b8 + public ResultCode Match(ServiceCtx context) + { + return NgctServer.Match(context); + } + + [Command(1)] + // Filter(buffer) -> buffer + public ResultCode Filter(ServiceCtx context) + { + return NgctServer.Filter(context); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ngct/IServiceWithManagementApi.cs b/Ryujinx.HLE/HOS/Services/Ngct/IServiceWithManagementApi.cs new file mode 100644 index 0000000000..732252ee4d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ngct/IServiceWithManagementApi.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.HOS.Services.Ngct +{ + [Service("ngct:s")] // 9.0.0+ + class IServiceWithManagementApi : IpcService + { + public IServiceWithManagementApi(ServiceCtx context) { } + + [Command(0)] + // Match(buffer) -> b8 + public ResultCode Match(ServiceCtx context) + { + return NgctServer.Match(context); + } + + [Command(1)] + // Filter(buffer) -> buffer + public ResultCode Filter(ServiceCtx context) + { + return NgctServer.Filter(context); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs b/Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs deleted file mode 100644 index 2baec58561..0000000000 --- a/Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Ngct -{ - [Service("ngct:s")] // 9.0.0+ - [Service("ngct:u")] // 9.0.0+ - class IUnknown1 : IpcService - { - public IUnknown1(ServiceCtx context) { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ngct/NgctServer.cs b/Ryujinx.HLE/HOS/Services/Ngct/NgctServer.cs new file mode 100644 index 0000000000..a1907d4ff0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ngct/NgctServer.cs @@ -0,0 +1,92 @@ +using Ryujinx.Common.Logging; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Ngct +{ + static class NgctServer + { + public static ResultCode Match(ServiceCtx context) + { + // NOTE: Service load the values of sys:set ngc.t!functionality_override_enabled and ngc.t!auto_reload_enabled in internal fields. + // Then it checks if ngc.t!functionality_override_enabled is enabled and if sys:set GetT is == 2. + // If both conditions are true, it does this following code. Since we currently stub it, it's fine to don't check settings service values. + + long bufferPosition = context.Request.PtrBuff[0].Position; + long bufferSize = context.Request.PtrBuff[0].Size; + + bool isMatch = false; + string text = ""; + + if (bufferSize != 0) + { + if (bufferSize > 1024) + { + isMatch = true; + } + else + { + byte[] buffer = new byte[bufferSize]; + + context.Memory.Read((ulong)bufferPosition, buffer); + + text = Encoding.ASCII.GetString(buffer); + + // NOTE: Ngct use the archive 0100000000001034 which contains a words table. This is pushed on Chinese Switchs using Bcat service. + // This call check if the string match with entries in the table and return the result if there is one (or more). + // Since we don't want to hide bad words. It's fine to returns false here. + + isMatch = false; + } + } + + Logger.Stub?.PrintStub(LogClass.ServiceNgct, new { isMatch, text }); + + context.ResponseData.Write(isMatch); + + return ResultCode.Success; + } + + public static ResultCode Filter(ServiceCtx context) + { + // NOTE: Service load the values of sys:set ngc.t!functionality_override_enabled and ngc.t!auto_reload_enabled in internal fields. + // Then it checks if ngc.t!functionality_override_enabled is enabled and if sys:set GetT is == 2. + // If both conditions are true, it does this following code. Since we currently stub it, it's fine to don't check settings service values. + + long bufferPosition = context.Request.PtrBuff[0].Position; + long bufferSize = context.Request.PtrBuff[0].Size; + + long bufferFilteredPosition = context.Request.RecvListBuff[0].Position; + + string text = ""; + string textFiltered = ""; + + if (bufferSize != 0) + { + if (bufferSize > 1024) + { + textFiltered = new string('*', text.Length); + + context.Memory.Write((ulong)bufferFilteredPosition, Encoding.ASCII.GetBytes(textFiltered)); + } + else + { + byte[] buffer = new byte[bufferSize]; + + context.Memory.Read((ulong)bufferPosition, buffer); + + // NOTE: Ngct use the archive 0100000000001034 which contains a words table. This is pushed on Chinese Switchs using Bcat service. + // This call check if the string contains words which are in the table then returns the same string with each matched words replaced by '*'. + // Since we don't want to hide bad words. It's fine to returns the same string. + + textFiltered = text = Encoding.ASCII.GetString(buffer); + + context.Memory.Write((ulong)bufferFilteredPosition, buffer); + } + } + + Logger.Stub?.PrintStub(LogClass.ServiceNgct, new { text, textFiltered }); + + return ResultCode.Success; + } + } +} \ No newline at end of file